From 1d9c210dcbc0c63893921fdef591edd9ffe4c48e Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 00:45:27 -0800 Subject: [PATCH 001/133] Version changes for release 0.9.0. --- docs/_config.yml | 2 +- ec2/spark_ec2.py | 4 ++-- project/SparkBuild.scala | 2 +- python/pyspark/shell.py | 2 +- .../src/main/scala/org/apache/spark/repl/SparkILoopInit.scala | 2 +- yarn/alpha/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index ce0fdf5fb4f03..3e96d2c1ea136 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -3,7 +3,7 @@ markdown: kramdown # These allow the documentation to be updated with nerw releases # of Spark, Scala, and Mesos. -SPARK_VERSION: 0.9.0-incubating-SNAPSHOT +SPARK_VERSION: 0.9.0-incubating SPARK_VERSION_SHORT: 0.9.0 SCALA_VERSION: "2.10" MESOS_VERSION: 0.13.0 diff --git a/ec2/spark_ec2.py b/ec2/spark_ec2.py index e7cb5ab3ff9b0..e46e1f5e56442 100755 --- a/ec2/spark_ec2.py +++ b/ec2/spark_ec2.py @@ -70,7 +70,7 @@ def parse_args(): "slaves across multiple (an additional $0.01/Gb for bandwidth" + "between zones applies)") parser.add_option("-a", "--ami", help="Amazon Machine Image ID to use") - parser.add_option("-v", "--spark-version", default="0.8.0", + parser.add_option("-v", "--spark-version", default="0.9.0", help="Version of Spark to use: 'X.Y.Z' or a specific git hash") parser.add_option("--spark-git-repo", default="https://github.com/apache/incubator-spark", @@ -157,7 +157,7 @@ def is_active(instance): # Return correct versions of Spark and Shark, given the supplied Spark version def get_spark_shark_version(opts): - spark_shark_map = {"0.7.3": "0.7.1", "0.8.0": "0.8.0"} + spark_shark_map = {"0.7.3": "0.7.1", "0.8.0": "0.8.0", "0.8.1": "0.8.1", "0.9.0": "0.9.0"} version = opts.spark_version.replace("v", "") if version not in spark_shark_map: print >> stderr, "Don't know about Spark version: %s" % version diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index a9f9937cb168c..bcc286d7ea190 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -120,7 +120,7 @@ object SparkBuild extends Build { def sharedSettings = Defaults.defaultSettings ++ Seq( organization := "org.apache.spark", - version := "0.9.0-incubating-SNAPSHOT", + version := "0.9.0-incubating", scalaVersion := "2.10.3", scalacOptions := Seq("-Xmax-classfile-name", "120", "-unchecked", "-deprecation", "-target:" + SCALAC_JVM_VERSION), diff --git a/python/pyspark/shell.py b/python/pyspark/shell.py index 1602227a273e7..920334205c13e 100644 --- a/python/pyspark/shell.py +++ b/python/pyspark/shell.py @@ -35,7 +35,7 @@ ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ - /__ / .__/\_,_/_/ /_/\_\ version 0.9.0-SNAPSHOT + /__ / .__/\_,_/_/ /_/\_\ version 0.9.0 /_/ """ print "Using Python version %s (%s, %s)" % ( diff --git a/repl/src/main/scala/org/apache/spark/repl/SparkILoopInit.scala b/repl/src/main/scala/org/apache/spark/repl/SparkILoopInit.scala index 21b1ba305d110..ab5e283d65f07 100644 --- a/repl/src/main/scala/org/apache/spark/repl/SparkILoopInit.scala +++ b/repl/src/main/scala/org/apache/spark/repl/SparkILoopInit.scala @@ -24,7 +24,7 @@ trait SparkILoopInit { ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ - /___/ .__/\_,_/_/ /_/\_\ version 0.9.0-SNAPSHOT + /___/ .__/\_,_/_/ /_/\_\ version 0.9.0 /_/ """) import Properties._ diff --git a/yarn/alpha/pom.xml b/yarn/alpha/pom.xml index 8291e9e7a36ce..349c8358ecf90 100644 --- a/yarn/alpha/pom.xml +++ b/yarn/alpha/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 1b4adc21d77f801be795c2814fc0a501f0e6309b Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 01:18:34 -0800 Subject: [PATCH 002/133] Merge pull request #420 from pwendell/header-files Add missing header files (cherry picked from commit fa75e5e1c50da7d1e6c6f41c2d6d591c1e8a025f) Signed-off-by: Patrick Wendell --- .../main/scala/org/apache/spark/SparkConf.scala | 17 +++++++++++++++++ .../spark/deploy/worker/CommandUtils.scala | 17 +++++++++++++++++ .../spark/deploy/worker/DriverWrapper.scala | 17 +++++++++++++++++ .../spark/deploy/worker/WorkerWatcher.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/SparkConfSuite.scala | 17 +++++++++++++++++ .../spark/deploy/worker/DriverRunnerTest.scala | 17 +++++++++++++++++ .../deploy/worker/WorkerWatcherSuite.scala | 17 +++++++++++++++++ .../collection/ExternalAppendOnlyMapSuite.scala | 17 +++++++++++++++++ .../streaming/examples/StreamingExamples.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/graphx/Edge.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/EdgeDirection.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/graphx/EdgeRDD.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/EdgeTriplet.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/graphx/Graph.scala | 17 +++++++++++++++++ .../spark/graphx/GraphKryoRegistrator.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/GraphLoader.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/GraphOps.scala | 17 +++++++++++++++++ .../apache/spark/graphx/PartitionStrategy.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/graphx/Pregel.scala | 17 +++++++++++++++++ .../spark/graphx/impl/EdgePartition.scala | 17 +++++++++++++++++ .../graphx/impl/EdgePartitionBuilder.scala | 17 +++++++++++++++++ .../spark/graphx/impl/EdgeTripletIterator.scala | 17 +++++++++++++++++ .../apache/spark/graphx/impl/GraphImpl.scala | 17 +++++++++++++++++ .../spark/graphx/impl/MessageToPartition.scala | 17 +++++++++++++++++ .../graphx/impl/ReplicatedVertexView.scala | 17 +++++++++++++++++ .../apache/spark/graphx/impl/RoutingTable.scala | 17 +++++++++++++++++ .../apache/spark/graphx/impl/Serializers.scala | 17 +++++++++++++++++ .../spark/graphx/impl/VertexPartition.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/impl/package.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/lib/Analytics.scala | 17 +++++++++++++++++ .../spark/graphx/lib/ConnectedComponents.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/lib/PageRank.scala | 17 +++++++++++++++++ .../apache/spark/graphx/lib/SVDPlusPlus.scala | 17 +++++++++++++++++ .../lib/StronglyConnectedComponents.scala | 17 +++++++++++++++++ .../apache/spark/graphx/lib/TriangleCount.scala | 17 +++++++++++++++++ .../scala/org/apache/spark/graphx/package.scala | 17 +++++++++++++++++ .../spark/graphx/util/BytecodeUtils.scala | 17 +++++++++++++++++ .../spark/graphx/util/GraphGenerators.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/GraphOpsSuite.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/GraphSuite.scala | 17 +++++++++++++++++ .../apache/spark/graphx/LocalSparkContext.scala | 17 +++++++++++++++++ .../org/apache/spark/graphx/PregelSuite.scala | 17 +++++++++++++++++ .../apache/spark/graphx/SerializerSuite.scala | 17 +++++++++++++++++ .../apache/spark/graphx/VertexRDDSuite.scala | 17 +++++++++++++++++ .../spark/graphx/impl/EdgePartitionSuite.scala | 17 +++++++++++++++++ .../graphx/impl/VertexPartitionSuite.scala | 17 +++++++++++++++++ .../graphx/lib/ConnectedComponentsSuite.scala | 17 +++++++++++++++++ .../apache/spark/graphx/lib/PageRankSuite.scala | 17 +++++++++++++++++ .../spark/graphx/lib/SVDPlusPlusSuite.scala | 17 +++++++++++++++++ .../lib/StronglyConnectedComponentsSuite.scala | 17 +++++++++++++++++ .../spark/graphx/lib/TriangleCountSuite.scala | 17 +++++++++++++++++ .../spark/graphx/util/BytecodeUtilsSuite.scala | 17 +++++++++++++++++ .../classification/JavaNaiveBayesSuite.java | 17 +++++++++++++++++ .../scala/org/apache/spark/repl/ReplSuite.scala | 17 +++++++++++++++++ .../apache/spark/streaming/ContextWaiter.scala | 17 +++++++++++++++++ 55 files changed, 935 insertions(+) diff --git a/core/src/main/scala/org/apache/spark/SparkConf.scala b/core/src/main/scala/org/apache/spark/SparkConf.scala index 2de32231e8714..93d3d1f6972c3 100644 --- a/core/src/main/scala/org/apache/spark/SparkConf.scala +++ b/core/src/main/scala/org/apache/spark/SparkConf.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark import scala.collection.JavaConverters._ diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/CommandUtils.scala b/core/src/main/scala/org/apache/spark/deploy/worker/CommandUtils.scala index cf6a23339d961..460883ec7ae24 100644 --- a/core/src/main/scala/org/apache/spark/deploy/worker/CommandUtils.scala +++ b/core/src/main/scala/org/apache/spark/deploy/worker/CommandUtils.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.deploy.worker import java.io.{File, FileOutputStream, IOException, InputStream} diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/DriverWrapper.scala b/core/src/main/scala/org/apache/spark/deploy/worker/DriverWrapper.scala index 1640d5fee0f77..6f6c101547c3c 100644 --- a/core/src/main/scala/org/apache/spark/deploy/worker/DriverWrapper.scala +++ b/core/src/main/scala/org/apache/spark/deploy/worker/DriverWrapper.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.deploy.worker import akka.actor._ diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/WorkerWatcher.scala b/core/src/main/scala/org/apache/spark/deploy/worker/WorkerWatcher.scala index 0e0d0cd6264cf..1dc39c450ea16 100644 --- a/core/src/main/scala/org/apache/spark/deploy/worker/WorkerWatcher.scala +++ b/core/src/main/scala/org/apache/spark/deploy/worker/WorkerWatcher.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.deploy.worker import akka.actor.{Actor, Address, AddressFromURIString} diff --git a/core/src/test/scala/org/apache/spark/SparkConfSuite.scala b/core/src/test/scala/org/apache/spark/SparkConfSuite.scala index ef5936dd2f588..fa49974db445b 100644 --- a/core/src/test/scala/org/apache/spark/SparkConfSuite.scala +++ b/core/src/test/scala/org/apache/spark/SparkConfSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark import org.scalatest.FunSuite diff --git a/core/src/test/scala/org/apache/spark/deploy/worker/DriverRunnerTest.scala b/core/src/test/scala/org/apache/spark/deploy/worker/DriverRunnerTest.scala index 45dbcaffae94f..0c502612647a2 100644 --- a/core/src/test/scala/org/apache/spark/deploy/worker/DriverRunnerTest.scala +++ b/core/src/test/scala/org/apache/spark/deploy/worker/DriverRunnerTest.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.deploy.worker import java.io.File diff --git a/core/src/test/scala/org/apache/spark/deploy/worker/WorkerWatcherSuite.scala b/core/src/test/scala/org/apache/spark/deploy/worker/WorkerWatcherSuite.scala index 94d88d307a163..1f1d8d138005b 100644 --- a/core/src/test/scala/org/apache/spark/deploy/worker/WorkerWatcherSuite.scala +++ b/core/src/test/scala/org/apache/spark/deploy/worker/WorkerWatcherSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.deploy.worker diff --git a/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala b/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala index c3391f3e535bc..bb4dc0fcd31a3 100644 --- a/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala +++ b/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.util.collection import scala.collection.mutable.ArrayBuffer diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/StreamingExamples.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/StreamingExamples.scala index d41d84a980dc7..99f1502046f53 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/StreamingExamples.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/StreamingExamples.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.streaming.examples import org.apache.spark.Logging diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala b/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala index 738a38b27f0e4..32f1602698134 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx /** diff --git a/graphx/src/main/scala/org/apache/spark/graphx/EdgeDirection.scala b/graphx/src/main/scala/org/apache/spark/graphx/EdgeDirection.scala index f265764006234..6f03eb1439773 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/EdgeDirection.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/EdgeDirection.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx /** diff --git a/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala b/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala index 832b7816fe833..6efef061d7510 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import scala.reflect.{classTag, ClassTag} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala b/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala index 4253b24b5ac55..2c659cb070b99 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx /** diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala b/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala index 9dd05ade0aef2..7f65244cd95cd 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala b/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala index d79bdf961841b..6db8a34937244 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import com.esotericsoftware.kryo.Kryo diff --git a/graphx/src/main/scala/org/apache/spark/graphx/GraphLoader.scala b/graphx/src/main/scala/org/apache/spark/graphx/GraphLoader.scala index 5904aa3a28c71..18858466db27b 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/GraphLoader.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/GraphLoader.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.apache.spark.{Logging, SparkContext} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala b/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala index f10e63f059aed..9b864c1290bd2 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala b/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala index 6d2990a3f6642..8ba87976f1136 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx /** diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala b/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala index fc18f7e785a99..0f6d4135934cb 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala index ee95ead3ada9b..6067ee8c7e0fb 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala index 9d072f933503c..960eeaccf1352 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala index bad840f1cdf36..819e3ba93ac9b 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala index 56d1d9efeafa9..eee2d58c3d8e1 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.{classTag, ClassTag} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala index 05508ff716eb1..cea9d11ebe8cd 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.{classTag, ClassTag} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala index 4ebe0b02671d9..5bdc9339e9fec 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.{classTag, ClassTag} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala index f342fd7437903..b365d4914e95b 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import org.apache.spark.SparkContext._ diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala index cbd6318f33cdc..bcad1fbc58802 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import java.io.{EOFException, InputStream, OutputStream} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala index f97ff75fb2f93..f13bdded7564d 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala index cfc3281b6407e..f493d2dd01541 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.apache.spark.util.collection.OpenHashSet diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/Analytics.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/Analytics.scala index e0aff5644e40d..f914e0565ca21 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/Analytics.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/Analytics.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.apache.spark._ diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala index 4d1f5e74df59f..2a6c0aa6b554c 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala index 2f4d6d686499a..2bdd8c9f985d7 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala index ba6517e012d28..9c7a212c5a3bb 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import scala.util.Random diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala index d3d496e335481..ed84f72156a55 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala index 23c9c40594e8b..a124c892dcba5 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import scala.reflect.ClassTag diff --git a/graphx/src/main/scala/org/apache/spark/graphx/package.scala b/graphx/src/main/scala/org/apache/spark/graphx/package.scala index 60dfc1dc37a53..e1ff3ea0d1d42 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/package.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/package.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark import org.apache.spark.util.collection.OpenHashSet diff --git a/graphx/src/main/scala/org/apache/spark/graphx/util/BytecodeUtils.scala b/graphx/src/main/scala/org/apache/spark/graphx/util/BytecodeUtils.scala index 1c5b234d74791..d1528e2f07cf2 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/util/BytecodeUtils.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/util/BytecodeUtils.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.util import java.io.{ByteArrayInputStream, ByteArrayOutputStream} diff --git a/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala b/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala index 57422ce3f1934..9805eb3285d69 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.util import scala.annotation.tailrec diff --git a/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala index 280f50e39aa5f..4a792c0dabeac 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.apache.spark.SparkContext diff --git a/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala index 9587f04c3e716..b18bc98e6d579 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/LocalSparkContext.scala b/graphx/src/test/scala/org/apache/spark/graphx/LocalSparkContext.scala index aa9ba840840e0..51f02f94e00d5 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/LocalSparkContext.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/LocalSparkContext.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.scalatest.Suite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala index bceff11b8e6c4..936e5c9c86fb7 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala index 3ba412c1f84f4..0c756400f4eff 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import java.io.{EOFException, ByteArrayInputStream, ByteArrayOutputStream} diff --git a/graphx/src/test/scala/org/apache/spark/graphx/VertexRDDSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/VertexRDDSuite.scala index d94a3aa67c925..cc86bafd2d644 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/VertexRDDSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/VertexRDDSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx import org.apache.spark.SparkContext diff --git a/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala index eb82436f0964c..1195beba5873c 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import scala.reflect.ClassTag diff --git a/graphx/src/test/scala/org/apache/spark/graphx/impl/VertexPartitionSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/impl/VertexPartitionSuite.scala index d37d64e8c849e..a048d13fd12b8 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/impl/VertexPartitionSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/impl/VertexPartitionSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.impl import org.apache.spark.graphx._ diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala index 27c8705bca2ff..eba8d7b716284 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/PageRankSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/PageRankSuite.scala index fe7e4261f8d03..fc491ae327c2a 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/PageRankSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/PageRankSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala index e173c652a53b6..057d9b3d518e0 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/StronglyConnectedComponentsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/StronglyConnectedComponentsSuite.scala index 0458311661452..df54aa37cad68 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/StronglyConnectedComponentsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/StronglyConnectedComponentsSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/TriangleCountSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/TriangleCountSuite.scala index 3452ce9764752..293c7f3ba4c21 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/TriangleCountSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/TriangleCountSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.lib import org.scalatest.FunSuite diff --git a/graphx/src/test/scala/org/apache/spark/graphx/util/BytecodeUtilsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/util/BytecodeUtilsSuite.scala index 11db339750920..f3b3738db0dad 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/util/BytecodeUtilsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/util/BytecodeUtilsSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.graphx.util import org.scalatest.FunSuite diff --git a/mllib/src/test/java/org/apache/spark/mllib/classification/JavaNaiveBayesSuite.java b/mllib/src/test/java/org/apache/spark/mllib/classification/JavaNaiveBayesSuite.java index 23ea3548b95b6..073ded6f36933 100644 --- a/mllib/src/test/java/org/apache/spark/mllib/classification/JavaNaiveBayesSuite.java +++ b/mllib/src/test/java/org/apache/spark/mllib/classification/JavaNaiveBayesSuite.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.mllib.classification; import org.apache.spark.api.java.JavaRDD; diff --git a/repl/src/test/scala/org/apache/spark/repl/ReplSuite.scala b/repl/src/test/scala/org/apache/spark/repl/ReplSuite.scala index 8aad27366524a..8203b8f6122e1 100644 --- a/repl/src/test/scala/org/apache/spark/repl/ReplSuite.scala +++ b/repl/src/test/scala/org/apache/spark/repl/ReplSuite.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.repl import java.io._ diff --git a/streaming/src/main/scala/org/apache/spark/streaming/ContextWaiter.scala b/streaming/src/main/scala/org/apache/spark/streaming/ContextWaiter.scala index 1f5dacb543db8..86753360a07e4 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/ContextWaiter.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/ContextWaiter.scala @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.spark.streaming private[streaming] class ContextWaiter { From bf3b1506957bd419b6bee4d8ade9fc3c78761dbf Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 09:44:43 -0800 Subject: [PATCH 003/133] Merge pull request #423 from jegonzal/GraphXProgrammingGuide Improving the graphx-programming-guide This PR will track a few minor improvements to the content and formatting of the graphx-programming-guide. (cherry picked from commit 3fcc68bfa5e9ef4b7abfd5051b6847a833e1ad2f) Signed-off-by: Reynold Xin --- docs/graphx-programming-guide.md | 63 +++++++++++++++++++------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/docs/graphx-programming-guide.md b/docs/graphx-programming-guide.md index 9fbde4eb09575..5641f9f137b76 100644 --- a/docs/graphx-programming-guide.md +++ b/docs/graphx-programming-guide.md @@ -18,7 +18,7 @@ title: GraphX Programming Guide GraphX is the new (alpha) Spark API for graphs and graph-parallel computation. At a high-level, GraphX extends the Spark [RDD](api/core/index.html#org.apache.spark.rdd.RDD) by introducing the -[Resilient Distributed property Graph (RDG)](#property_graph): a directed multigraph with properties +[Resilient Distributed Property Graph](#property_graph): a directed multigraph with properties attached to each vertex and edge. To support graph computation, GraphX exposes a set of fundamental operators (e.g., [subgraph](#structural_operators), [joinVertices](#join_operators), and [mapReduceTriplets](#mrTriplets)) as well as an optimized variant of the [Pregel](#pregel) API. In @@ -29,7 +29,7 @@ addition, GraphX includes a growing collection of graph [algorithms](#graph_algo From social networks to language modeling, the growing scale and importance of graph data has driven the development of numerous new *graph-parallel* systems -(e.g., [Giraph](http://http://giraph.apache.org) and +(e.g., [Giraph](http://giraph.apache.org) and [GraphLab](http://graphlab.org)). By restricting the types of computation that can be expressed and introducing new techniques to partition and distribute graphs, these systems can efficiently execute sophisticated graph algorithms orders of @@ -43,12 +43,25 @@ magnitude faster than more general *data-parallel* systems.

-However, the same restrictions that enable these substantial performance gains -also make it difficult to express many of the important stages in a typical graph-analytics pipeline: -constructing the graph, modifying its structure, or expressing computation that -spans multiple graphs. As a consequence, existing graph analytics pipelines -compose graph-parallel and data-parallel systems, leading to extensive data -movement and duplication and a complicated programming model. +However, the same restrictions that enable these substantial performance gains also make it +difficult to express many of the important stages in a typical graph-analytics pipeline: +constructing the graph, modifying its structure, or expressing computation that spans multiple +graphs. Furthermore, how we look at data depends on our objectives and the same raw data may have +many different table and graph views. + +

+ Tables and Graphs + +

+ +As a consequence, it is often necessary to be able to move between table and graph views of the same +physical data and to leverage the properties of each view to easily and efficiently express +computation. However, existing graph analytics pipelines must compose graph-parallel and data- +parallel systems, leading to extensive data movement and duplication and a complicated programming +model.

GraphX optimizes the representation of `VD` and `ED` when they are plain old data-types (e.g., -> int, double, etc...) reducing the in memory footprint. +> GraphX optimizes the representation of vertex and edge types when they are plain old data-types +> (e.g., int, double, etc...) reducing the in memory footprint by storing them in specialized +> arrays. -In some cases we may wish to have vertices with different property types in the same graph. This can -be accomplished through inheritance. For example to model users and products as a bipartite graph -we might do the following: +In some cases it may be desirable to have vertices with different property types in the same graph. +This can be accomplished through inheritance. For example to model users and products as a +bipartite graph we might do the following: {% highlight scala %} class VertexProperty() @@ -116,9 +132,11 @@ var graph: Graph[VertexProperty, String] = null {% endhighlight %} Like RDDs, property graphs are immutable, distributed, and fault-tolerant. Changes to the values or -structure of the graph are accomplished by producing a new graph with the desired changes. The graph -is partitioned across the workers using a range of vertex-partitioning heuristics. As with RDDs, -each partition of the graph can be recreated on a different machine in the event of a failure. +structure of the graph are accomplished by producing a new graph with the desired changes. Note +that substantial parts of the original graph (i.e., unaffected structure, attributes, and indicies) +are reused in the new graph reducing the cost of this inherently functional data-structure. The +graph is partitioned across the workers using a range of vertex-partitioning heuristics. As with +RDDs, each partition of the graph can be recreated on a different machine in the event of a failure. Logically the property graph corresponds to a pair of typed collections (RDDs) encoding the properties for each vertex and edge. As a consequence, the graph class contains members to access @@ -953,13 +971,6 @@ val triCountByUsername = users.join(triCounts).map { case (id, (username, tc)) = println(triCountByUsername.collect().mkString("\n")) {% endhighlight %} -

- Tables and Graphs - -

# Examples From 119b6c524c659951e6abe791f2559048444b5c22 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 13:28:44 -0800 Subject: [PATCH 004/133] Merge pull request #425 from rxin/scaladoc API doc update & make Broadcast public In #413 Broadcast was mistakenly made private[spark]. I changed it to public again. Also exposing id in public given the R frontend requires that. Copied some of the documentation from the programming guide to API Doc for Broadcast and Accumulator. This should be cherry picked into branch-0.9 as well for 0.9.0 release. (cherry picked from commit 2ce23a55a3c4033873bb262919d89e5afabb9134) Signed-off-by: Reynold Xin --- .../scala/org/apache/spark/Accumulators.scala | 40 ++++++++++++++----- .../spark/api/java/JavaSparkContext.scala | 11 ++--- .../org/apache/spark/api/java/package.scala | 23 +++++++++++ .../apache/spark/broadcast/Broadcast.scala | 33 +++++++++++++-- .../org/apache/spark/broadcast/package.scala | 25 ++++++++++++ 5 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 core/src/main/scala/org/apache/spark/api/java/package.scala create mode 100644 core/src/main/scala/org/apache/spark/broadcast/package.scala diff --git a/core/src/main/scala/org/apache/spark/Accumulators.scala b/core/src/main/scala/org/apache/spark/Accumulators.scala index 2ba871a6007d7..df01b2e942180 100644 --- a/core/src/main/scala/org/apache/spark/Accumulators.scala +++ b/core/src/main/scala/org/apache/spark/Accumulators.scala @@ -17,17 +17,17 @@ package org.apache.spark -import java.io._ +import java.io.{ObjectInputStream, Serializable} import scala.collection.mutable.Map import scala.collection.generic.Growable import org.apache.spark.serializer.JavaSerializer /** - * A datatype that can be accumulated, ie has an commutative and associative "add" operation, + * A data type that can be accumulated, ie has an commutative and associative "add" operation, * but where the result type, `R`, may be different from the element type being added, `T`. * - * You must define how to add data, and how to merge two of these together. For some datatypes, + * You must define how to add data, and how to merge two of these together. For some data types, * such as a counter, these might be the same operation. In that case, you can use the simpler * [[org.apache.spark.Accumulator]]. They won't always be the same, though -- e.g., imagine you are * accumulating a set. You will add items to the set, and you will union two sets together. @@ -45,7 +45,7 @@ class Accumulable[R, T] ( val id = Accumulators.newId @transient private var value_ = initialValue // Current value on master val zero = param.zero(initialValue) // Zero value to be passed to workers - var deserialized = false + private var deserialized = false Accumulators.register(this, true) @@ -127,7 +127,7 @@ class Accumulable[R, T] ( /** * Helper object defining how to accumulate values of a particular type. An implicit - * AccumulableParam needs to be available when you create Accumulables of a specific type. + * AccumulableParam needs to be available when you create [[Accumulable]]s of a specific type. * * @tparam R the full accumulated data (result type) * @tparam T partial data that can be added in @@ -186,7 +186,29 @@ class GrowableAccumulableParam[R <% Growable[T] with TraversableOnce[T] with Ser /** * A simpler value of [[Accumulable]] where the result type being accumulated is the same - * as the types of elements being merged. + * as the types of elements being merged, i.e. variables that are only "added" to through an + * associative operation and can therefore be efficiently supported in parallel. They can be used + * to implement counters (as in MapReduce) or sums. Spark natively supports accumulators of type + * `Int` and `Double`, and programmers can add support for new types. + * + * An accumulator is created from an initial value `v` by calling [[SparkContext#accumulator]]. + * Tasks running on the cluster can then add to it using the [[Accumulable#+=]] operator. + * However, they cannot read its value. Only the driver program can read the accumulator's value, + * using its value method. + * + * The interpreter session below shows an accumulator being used to add up the elements of an array: + * + * {{{ + * scala> val accum = sc.accumulator(0) + * accum: spark.Accumulator[Int] = 0 + * + * scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum += x) + * ... + * 10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s + * + * scala> accum.value + * res2: Int = 10 + * }}} * * @param initialValue initial value of accumulator * @param param helper object defining how to add elements of type `T` @@ -196,9 +218,9 @@ class Accumulator[T](@transient initialValue: T, param: AccumulatorParam[T]) extends Accumulable[T,T](initialValue, param) /** - * A simpler version of [[org.apache.spark.AccumulableParam]] where the only datatype you can add in is the same type - * as the accumulated value. An implicit AccumulatorParam object needs to be available when you create - * Accumulators of a specific type. + * A simpler version of [[org.apache.spark.AccumulableParam]] where the only data type you can add + * in is the same type as the accumulated value. An implicit AccumulatorParam object needs to be + * available when you create Accumulators of a specific type. * * @tparam T type of value to accumulate */ diff --git a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala index 7a6f044965027..8041163e3d748 100644 --- a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala +++ b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala @@ -34,11 +34,11 @@ import org.apache.spark.SparkContext.IntAccumulatorParam import org.apache.spark.SparkContext.DoubleAccumulatorParam import org.apache.spark.broadcast.Broadcast import org.apache.spark.rdd.RDD -import scala.Tuple2 + /** - * A Java-friendly version of [[org.apache.spark.SparkContext]] that returns [[org.apache.spark.api.java.JavaRDD]]s and - * works with Java collections instead of Scala ones. + * A Java-friendly version of [[org.apache.spark.SparkContext]] that returns + * [[org.apache.spark.api.java.JavaRDD]]s and works with Java collections instead of Scala ones. */ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWorkaround { /** @@ -333,8 +333,9 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork sc.accumulable(initialValue)(param) /** - * Broadcast a read-only variable to the cluster, returning a [[org.apache.spark.Broadcast]] object for - * reading it in distributed functions. The variable will be sent to each cluster only once. + * Broadcast a read-only variable to the cluster, returning a + * [[org.apache.spark.broadcast.Broadcast]] object for reading it in distributed functions. + * The variable will be sent to each cluster only once. */ def broadcast[T](value: T): Broadcast[T] = sc.broadcast(value) diff --git a/core/src/main/scala/org/apache/spark/api/java/package.scala b/core/src/main/scala/org/apache/spark/api/java/package.scala new file mode 100644 index 0000000000000..8ec770046abe9 --- /dev/null +++ b/core/src/main/scala/org/apache/spark/api/java/package.scala @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.spark.api + +/** Spark Java programming APIs. */ +package object java { + // For package docs only +} diff --git a/core/src/main/scala/org/apache/spark/broadcast/Broadcast.scala b/core/src/main/scala/org/apache/spark/broadcast/Broadcast.scala index 6bfe2cb4a29cf..d113d4040594d 100644 --- a/core/src/main/scala/org/apache/spark/broadcast/Broadcast.scala +++ b/core/src/main/scala/org/apache/spark/broadcast/Broadcast.scala @@ -17,13 +17,40 @@ package org.apache.spark.broadcast -import java.io._ +import java.io.Serializable import java.util.concurrent.atomic.AtomicLong import org.apache.spark._ -private[spark] -abstract class Broadcast[T](private[spark] val id: Long) extends Serializable { +/** + * A broadcast variable. Broadcast variables allow the programmer to keep a read-only variable + * cached on each machine rather than shipping a copy of it with tasks. They can be used, for + * example, to give every node a copy of a large input dataset in an efficient manner. Spark also + * attempts to distribute broadcast variables using efficient broadcast algorithms to reduce + * communication cost. + * + * Broadcast variables are created from a variable `v` by calling [[SparkContext#broadcast]]. + * The broadcast variable is a wrapper around `v`, and its value can be accessed by calling the + * `value` method. The interpreter session below shows this: + * + * {{{ + * scala> val broadcastVar = sc.broadcast(Array(1, 2, 3)) + * broadcastVar: spark.Broadcast[Array[Int]] = spark.Broadcast(b5c40191-a864-4c7d-b9bf-d87e1a4e787c) + * + * scala> broadcastVar.value + * res0: Array[Int] = Array(1, 2, 3) + * }}} + * + * After the broadcast variable is created, it should be used instead of the value `v` in any + * functions run on the cluster so that `v` is not shipped to the nodes more than once. + * In addition, the object `v` should not be modified after it is broadcast in order to ensure + * that all nodes get the same value of the broadcast variable (e.g. if the variable is shipped + * to a new node later). + * + * @param id A unique identifier for the broadcast variable. + * @tparam T Type of the data contained in the broadcast variable. + */ +abstract class Broadcast[T](val id: Long) extends Serializable { def value: T // We cannot have an abstract readObject here due to some weird issues with diff --git a/core/src/main/scala/org/apache/spark/broadcast/package.scala b/core/src/main/scala/org/apache/spark/broadcast/package.scala new file mode 100644 index 0000000000000..01bf88629a7dd --- /dev/null +++ b/core/src/main/scala/org/apache/spark/broadcast/package.scala @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.spark + +/** + * Package for broadcast variables. See [[broadcast.Broadcast]] for details. + */ +package object broadcast { + // For package docs only +} From a14933dac1e8b866d49a161854453b56a6e1dfcc Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 14:52:24 -0800 Subject: [PATCH 005/133] Merge pull request #427 from pwendell/deprecate-aggregator Deprecate rather than remove old combineValuesByKey function (cherry picked from commit d601a76d1fdd25b95020b2e32bacde583cf6aa50) Signed-off-by: Reynold Xin --- .../scala/org/apache/spark/Aggregator.scala | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Aggregator.scala b/core/src/main/scala/org/apache/spark/Aggregator.scala index 6d439fdc684af..edbea6ea5680a 100644 --- a/core/src/main/scala/org/apache/spark/Aggregator.scala +++ b/core/src/main/scala/org/apache/spark/Aggregator.scala @@ -17,6 +17,8 @@ package org.apache.spark +import scala.{Option, deprecated} + import org.apache.spark.util.collection.{AppendOnlyMap, ExternalAppendOnlyMap} /** @@ -34,8 +36,12 @@ case class Aggregator[K, V, C] ( private val sparkConf = SparkEnv.get.conf private val externalSorting = sparkConf.getBoolean("spark.shuffle.spill", true) + @deprecated("use combineValuesByKey with TaskContext argument", "0.9.0") + def combineValuesByKey(iter: Iterator[_ <: Product2[K, V]]): Iterator[(K, C)] = + combineValuesByKey(iter, null) + def combineValuesByKey(iter: Iterator[_ <: Product2[K, V]], - context: TaskContext) : Iterator[(K, C)] = { + context: TaskContext): Iterator[(K, C)] = { if (!externalSorting) { val combiners = new AppendOnlyMap[K,C] var kv: Product2[K, V] = null @@ -53,12 +59,17 @@ case class Aggregator[K, V, C] ( val (k, v) = iter.next() combiners.insert(k, v) } - context.taskMetrics.memoryBytesSpilled = combiners.memoryBytesSpilled - context.taskMetrics.diskBytesSpilled = combiners.diskBytesSpilled + // TODO: Make this non optional in a future release + Option(context).foreach(c => c.taskMetrics.memoryBytesSpilled = combiners.memoryBytesSpilled) + Option(context).foreach(c => c.taskMetrics.diskBytesSpilled = combiners.diskBytesSpilled) combiners.iterator } } + @deprecated("use combineCombinersByKey with TaskContext argument", "0.9.0") + def combineCombinersByKey(iter: Iterator[(K, C)]) : Iterator[(K, C)] = + combineCombinersByKey(iter, null) + def combineCombinersByKey(iter: Iterator[(K, C)], context: TaskContext) : Iterator[(K, C)] = { if (!externalSorting) { val combiners = new AppendOnlyMap[K,C] @@ -77,8 +88,9 @@ case class Aggregator[K, V, C] ( val (k, c) = iter.next() combiners.insert(k, c) } - context.taskMetrics.memoryBytesSpilled = combiners.memoryBytesSpilled - context.taskMetrics.diskBytesSpilled = combiners.diskBytesSpilled + // TODO: Make this non optional in a future release + Option(context).foreach(c => c.taskMetrics.memoryBytesSpilled = combiners.memoryBytesSpilled) + Option(context).foreach(c => c.taskMetrics.diskBytesSpilled = combiners.diskBytesSpilled) combiners.iterator } } From 329c9df13670871acccd834eb042c59be12bb8f6 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 14:53:24 -0800 Subject: [PATCH 006/133] Merge pull request #429 from ankurdave/graphx-examples-pom.xml Add GraphX dependency to examples/pom.xml (cherry picked from commit 193a0757c87b717e3b6b4f005ecdbb56b04ad9b4) Signed-off-by: Reynold Xin --- examples/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/pom.xml b/examples/pom.xml index cb4f7ee33b4a1..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -71,6 +71,12 @@ ${project.version} provided + + org.apache.spark + spark-graphx_${scala.binary.version} + ${project.version} + provided + org.apache.spark spark-streaming-twitter_${scala.binary.version} From 2f930d5ae10d603370b49b91719259f17dc25628 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 14:59:13 -0800 Subject: [PATCH 007/133] Merge pull request #428 from pwendell/writeable-objects Don't clone records for text files (cherry picked from commit 74b46acdc57293c103ab5dd5af931d0d0e32c0ed) Signed-off-by: Reynold Xin --- core/src/main/scala/org/apache/spark/SparkContext.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/SparkContext.scala b/core/src/main/scala/org/apache/spark/SparkContext.scala index 55ac76bf63909..ba3e91effbdb4 100644 --- a/core/src/main/scala/org/apache/spark/SparkContext.scala +++ b/core/src/main/scala/org/apache/spark/SparkContext.scala @@ -340,8 +340,8 @@ class SparkContext( * Hadoop-supported file system URI, and return it as an RDD of Strings. */ def textFile(path: String, minSplits: Int = defaultMinSplits): RDD[String] = { - hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text], minSplits) - .map(pair => pair._2.toString) + hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text], + minSplits, cloneRecords = false).map(pair => pair._2.toString) } /** From ce66ca78b7c67b8dfc865d2aa32f7c4a71493ca4 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 15:16:46 -0800 Subject: [PATCH 008/133] Small change to maven build --- pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pom.xml b/pom.xml index b25d9d7ef891d..f14d9667ccc7d 100644 --- a/pom.xml +++ b/pom.xml @@ -727,6 +727,14 @@ + + + release + + true + + yarn-alpha From 40c97afce8be3c45590aaf5f789cbff058443892 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 15:57:53 -0800 Subject: [PATCH 009/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl-bin/pom.xml | 2 +- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 54a25910ced7d..ca993eea4f23c 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 3e5faf230dbc9..c7897bcc2e4a5 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index f14d9667ccc7d..2075fbe6a41d7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl-bin/pom.xml b/repl-bin/pom.xml index 869dbdb9b095a..80d0b9f47f34a 100644 --- a/repl-bin/pom.xml +++ b/repl-bin/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 51131bf820330bd2475a9676d151f5d488c150a7 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 15:57:59 -0800 Subject: [PATCH 010/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl-bin/pom.xml | 2 +- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index ca993eea4f23c..1b2d8f531ffb7 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index c7897bcc2e4a5..8080075e9395a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 2075fbe6a41d7..c14685da5f232 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl-bin/pom.xml b/repl-bin/pom.xml index 80d0b9f47f34a..37debdf73a6d3 100644 --- a/repl-bin/pom.xml +++ b/repl-bin/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From 6fa4e02dd19308c9629fb898061334d554def641 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 21:51:06 -0800 Subject: [PATCH 011/133] Merge pull request #431 from ankurdave/graphx-caching-doc Describe caching and uncaching in GraphX programming guide (cherry picked from commit ad294db326f57beb98f9734e2b4c45d9da1a4c89) Signed-off-by: Reynold Xin --- docs/graphx-programming-guide.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/graphx-programming-guide.md b/docs/graphx-programming-guide.md index 5641f9f137b76..03940d836b698 100644 --- a/docs/graphx-programming-guide.md +++ b/docs/graphx-programming-guide.md @@ -611,11 +611,20 @@ class GraphOps[VD, ED] { > substantial communication. If possible try expressing the same computation using the > `mapReduceTriplets` operator directly. +## Caching and Uncaching + +In Spark, RDDs are not persisted in memory by default. To avoid recomputation, they must be explicitly cached when using them multiple times (see the [Spark Programming Guide][RDD Persistence]). Graphs in GraphX behave the same way. **When using a graph multiple times, make sure to call [`Graph.cache()`][Graph.cache] on it first.** + +[RDD Persistence]: scala-programming-guide.html#rdd-persistence +[Graph.cache]: api/graphx/index.html#org.apache.spark.graphx.Graph@cache():Graph[VD,ED] + +In iterative computations, *uncaching* may also be necessary for best performance. By default, cached RDDs and graphs will remain in memory until memory pressure forces them to be evicted in LRU order. For iterative computation, intermediate results from previous iterations will fill up the cache. Though they will eventually be evicted, the unnecessary data stored in memory will slow down garbage collection. It would be more efficient to uncache intermediate results as soon as they are no longer necessary. This involves materializing (caching and forcing) a graph or RDD every iteration, uncaching all other datasets, and only using the materialized dataset in future iterations. However, because graphs are composed of multiple RDDs, it can be difficult to unpersist them correctly. **For iterative computation we recommend using the Pregel API, which correctly unpersists intermediate results.** + # Pregel API Graphs are inherently recursive data-structures as properties of vertices depend on properties of -their neighbors which intern depend on properties of *their* neighbors. As a +their neighbors which in turn depend on properties of *their* neighbors. As a consequence many important graph algorithms iteratively recompute the properties of each vertex until a fixed-point condition is reached. A range of graph-parallel abstractions have been proposed to express these iterative algorithms. GraphX exposes a Pregel-like operator which is a fusion of From 2c6c07f428079f390901f662d893cd932c90a70a Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 21:52:50 -0800 Subject: [PATCH 012/133] Merge pull request #424 from jegonzal/GraphXProgrammingGuide Additional edits for clarity in the graphx programming guide. Added an overview of the Graph and GraphOps functions and fixed numerous typos. (cherry picked from commit 3a386e238984c48a6ac07974b92647beae1199b3) Signed-off-by: Reynold Xin --- docs/graphx-programming-guide.md | 173 +++++++++++++++++++++---------- 1 file changed, 121 insertions(+), 52 deletions(-) diff --git a/docs/graphx-programming-guide.md b/docs/graphx-programming-guide.md index 03940d836b698..4bf47434571f5 100644 --- a/docs/graphx-programming-guide.md +++ b/docs/graphx-programming-guide.md @@ -108,7 +108,7 @@ with user defined objects attached to each vertex and edge. A directed multigra graph with potentially multiple parallel edges sharing the same source and destination vertex. The ability to support parallel edges simplifies modeling scenarios where there can be multiple relationships (e.g., co-worker and friend) between the same vertices. Each vertex is keyed by a -*unique* 64-bit long identifier (`VertexId`). GraphX does not impose any ordering constraints on +*unique* 64-bit long identifier (`VertexID`). GraphX does not impose any ordering constraints on the vertex identifiers. Similarly, edges have corresponding source and destination vertex identifiers. @@ -149,12 +149,12 @@ class Graph[VD, ED] { } {% endhighlight %} -The classes `VertexRDD[VD]` and `EdgeRDD[ED]` extend and are optimized versions of `RDD[(VertexId, +The classes `VertexRDD[VD]` and `EdgeRDD[ED]` extend and are optimized versions of `RDD[(VertexID, VD)]` and `RDD[Edge[ED]]` respectively. Both `VertexRDD[VD]` and `EdgeRDD[ED]` provide additional functionality built around graph computation and leverage internal optimizations. We discuss the `VertexRDD` and `EdgeRDD` API in greater detail in the section on [vertex and edge RDDs](#vertex_and_edge_rdds) but for now they can be thought of as simply RDDs of the form: -`RDD[(VertexId, VD)]` and `RDD[Edge[ED]]`. +`RDD[(VertexID, VD)]` and `RDD[Edge[ED]]`. ### Example Property Graph @@ -201,7 +201,7 @@ val graph = Graph(users, relationships, defaultUser) In the above example we make use of the [`Edge`][Edge] case class. Edges have a `srcId` and a `dstId` corresponding to the source and destination vertex identifiers. In addition, the `Edge` -class contains the `attr` member which contains the edge property. +class has an `attr` member which stores the edge property. [Edge]: api/graphx/index.html#org.apache.spark.graphx.Edge @@ -217,7 +217,7 @@ graph.edges.filter(e => e.srcId > e.dstId).count {% endhighlight %} > Note that `graph.vertices` returns an `VertexRDD[(String, String)]` which extends -> `RDD[(VertexId, (String, String))]` and so we use the scala `case` expression to deconstruct the +> `RDD[(VertexID, (String, String))]` and so we use the scala `case` expression to deconstruct the > tuple. On the other hand, `graph.edges` returns an `EdgeRDD` containing `Edge[String]` objects. > We could have also used the case class type constructor as in the following: > {% highlight scala %} @@ -284,6 +284,75 @@ able to support different graph representations in the future. Each graph repre provide implementations of the core operations and reuse many of the useful operations defined in [`GraphOps`][GraphOps]. +### Summary List of Operators +The following is a quick summary of the functionality defined in both [`Graph`][Graph] and +[`GraphOps`][GraphOps] but presented as members of Graph for simplicity. Note that some function +signatures have been simplified (e.g., default arguments and type constraints removed) and some more +advanced functionality has been removed so please consult the API docs for the official list of +operations. + +{% highlight scala %} +/** Summary of the functionality in the property graph */ +class Graph[VD, ED] { + // Information about the Graph =================================================================== + val numEdges: Long + val numVertices: Long + val inDegrees: VertexRDD[Int] + val outDegrees: VertexRDD[Int] + val degrees: VertexRDD[Int] + // Views of the graph as collections ============================================================= + val vertices: VertexRDD[VD] + val edges: EdgeRDD[ED] + val triplets: RDD[EdgeTriplet[VD, ED]] + // Functions for caching graphs ================================================================== + def persist(newLevel: StorageLevel = StorageLevel.MEMORY_ONLY): Graph[VD, ED] + def cache(): Graph[VD, ED] + def unpersistVertices(blocking: Boolean = true): Graph[VD, ED] + // Change the partitioning heuristic ============================================================ + def partitionBy(partitionStrategy: PartitionStrategy): Graph[VD, ED] + // Transform vertex and edge attributes ========================================================== + def mapVertices[VD2](map: (VertexID, VD) => VD2): Graph[VD2, ED] + def mapEdges[ED2](map: Edge[ED] => ED2): Graph[VD, ED2] + def mapEdges[ED2](map: (PartitionID, Iterator[Edge[ED]]) => Iterator[ED2]): Graph[VD, ED2] + def mapTriplets[ED2](map: EdgeTriplet[VD, ED] => ED2): Graph[VD, ED2] + def mapTriplets[ED2](map: (PartitionID, Iterator[EdgeTriplet[VD, ED]]) => Iterator[ED2]) + : Graph[VD, ED2] + // Modify the graph structure ==================================================================== + def reverse: Graph[VD, ED] + def subgraph( + epred: EdgeTriplet[VD,ED] => Boolean = (x => true), + vpred: (VertexID, VD) => Boolean = ((v, d) => true)) + : Graph[VD, ED] + def mask[VD2, ED2](other: Graph[VD2, ED2]): Graph[VD, ED] + def groupEdges(merge: (ED, ED) => ED): Graph[VD, ED] + // Join RDDs with the graph ====================================================================== + def joinVertices[U](table: RDD[(VertexID, U)])(mapFunc: (VertexID, VD, U) => VD): Graph[VD, ED] + def outerJoinVertices[U, VD2](other: RDD[(VertexID, U)]) + (mapFunc: (VertexID, VD, Option[U]) => VD2) + : Graph[VD2, ED] + // Aggregate information about adjacent triplets ================================================= + def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array[VertexID]] + def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[Array[(VertexID, VD)]] + def mapReduceTriplets[A: ClassTag]( + mapFunc: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + reduceFunc: (A, A) => A, + activeSetOpt: Option[(VertexRDD[_], EdgeDirection)] = None) + : VertexRDD[A] + // Iterative graph-parallel computation ========================================================== + def pregel[A](initialMsg: A, maxIterations: Int, activeDirection: EdgeDirection)( + vprog: (VertexID, VD, A) => VD, + sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexID,A)], + mergeMsg: (A, A) => A) + : Graph[VD, ED] + // Basic graph algorithms ======================================================================== + def pageRank(tol: Double, resetProb: Double = 0.15): Graph[Double, Double] + def connectedComponents(): Graph[VertexID, ED] + def triangleCount(): Graph[Int, ED] + def stronglyConnectedComponents(numIter: Int): Graph[VertexID, ED] +} +{% endhighlight %} + + ## Property Operators In direct analogy to the RDD `map` operator, the property @@ -443,7 +512,7 @@ original value. > is therefore recommended that the input RDD be first made unique using the following which will > also *pre-index* the resulting values to substantially accelerate the subsequent join. > {% highlight scala %} -val nonUniqueCosts: RDD[(VertexId, Double)] +val nonUniqueCosts: RDD[(VertexID, Double)] val uniqueCosts: VertexRDD[Double] = graph.vertices.aggregateUsingIndex(nonUnique, (a,b) => a + b) val joinedGraph = graph.joinVertices(uniqueCosts)( @@ -475,7 +544,7 @@ val degreeGraph = graph.outerJoinVertices(outDegrees) { (id, oldAttr, outDegOpt) > provide type annotation for the user defined function: > {% highlight scala %} val joinedGraph = graph.joinVertices(uniqueCosts, - (id: VertexId, oldCost: Double, extraCost: Double) => oldCost + extraCost) + (id: VertexID, oldCost: Double, extraCost: Double) => oldCost + extraCost) {% endhighlight %} @@ -513,26 +582,26 @@ containing the aggregate message (of type `A`) destined to each vertex. Vertice receive a message are not included in the returned `VertexRDD`.
-

-Note that mapReduceTriplets takes an additional optional activeSet -(see API docs) which restricts the map phase to edges adjacent to the vertices in the provided -VertexRDD: -

+ +

Note that mapReduceTriplets takes an additional optional activeSet +(not shown above see API docs for details) which restricts the map phase to edges adjacent to the +vertices in the provided VertexRDD:

+ {% highlight scala %} activeSetOpt: Option[(VertexRDD[_], EdgeDirection)] = None {% endhighlight %} -

-The EdgeDirection specifies which edges adjacent to the vertex set are included in the map phase. If -the direction is In, mapFunc will only be run only on edges with -destination in the active set. If the direction is Out, mapFunc will only -be run only on edges originating from vertices in the active set. If the direction is -Either, mapFunc will be run only on edges with either vertex in the -active set. If the direction is Both, mapFunc will be run only on edges -with both vertices in the active set. The active set must be derived from the set of vertices in -the graph. Restricting computation to triplets adjacent to a subset of the vertices is often -necessary in incremental iterative computation and is a key part of the GraphX implementation of -Pregel. -

+ +

The EdgeDirection specifies which edges adjacent to the vertex set are included in the map +phase. If the direction is In, then the user defined map function will +only be run only on edges with the destination vertex in the active set. If the direction is +Out, then the map function will only be run only on edges originating from +vertices in the active set. If the direction is Either, then the map +function will be run only on edges with either vertex in the active set. If the direction is +Both, then the map function will be run only on edges with both vertices +in the active set. The active set must be derived from the set of vertices in the graph. +Restricting computation to triplets adjacent to a subset of the vertices is often necessary in +incremental iterative computation and is a key part of the GraphX implementation of Pregel.

+
In the following example we use the `mapReduceTriplets` operator to compute the average age of the @@ -565,8 +634,8 @@ val avgAgeOfOlderFollowers: VertexRDD[Double] = avgAgeOfOlderFollowers.collect.foreach(println(_)) {% endhighlight %} -> Note that the `mapReduceTriplets` operation performs optimally when the messages (and their sums) -> are constant sized (e.g., floats and addition instead of lists and concatenation). More +> Note that the `mapReduceTriplets` operation performs optimally when the messages (and the sums of +> messages) are constant sized (e.g., floats and addition instead of lists and concatenation). More > precisely, the result of `mapReduceTriplets` should ideally be sub-linear in the degree of each > vertex. @@ -788,16 +857,16 @@ respectively. In this section we review some of the additional useful functiona ## VertexRDDs -The `VertexRDD[A]` extends the more traditional `RDD[(VertexId, A)]` but adds the additional -constraint that each `VertexId` occurs only *once*. Moreover, `VertexRDD[A]` represents a *set* of -vertices each with an attribute of type `A`. Internally, this is achieved by storing the vertex -attributes in a reusable hash-map data-structure. As a consequence if two `VertexRDD`s are derived -from the same base `VertexRDD` (e.g., by `filter` or `mapValues`) they can be joined in constant -time without hash evaluations. To leverage this indexed data-structure, the `VertexRDD` exposes the -following additional functionality: +The `VertexRDD[A]` extends `RDD[(VertexID, A)]` and adds the additional constraint that each +`VertexID` occurs only *once*. Moreover, `VertexRDD[A]` represents a *set* of vertices each with an +attribute of type `A`. Internally, this is achieved by storing the vertex attributes in a reusable +hash-map data-structure. As a consequence if two `VertexRDD`s are derived from the same base +`VertexRDD` (e.g., by `filter` or `mapValues`) they can be joined in constant time without hash +evaluations. To leverage this indexed data-structure, the `VertexRDD` exposes the following +additional functionality: {% highlight scala %} -class VertexRDD[VD] { +class VertexRDD[VD] extends RDD[(VertexID, VD)] { // Filter the vertex set but preserves the internal index def filter(pred: Tuple2[VertexID, VD] => Boolean): VertexRDD[VD] // Transform the values without changing the ids (preserves the internal index) @@ -816,15 +885,14 @@ class VertexRDD[VD] { Notice, for example, how the `filter` operator returns an `VertexRDD`. Filter is actually implemented using a `BitSet` thereby reusing the index and preserving the ability to do fast joins with other `VertexRDD`s. Likewise, the `mapValues` operators do not allow the `map` function to -change the `VertexId` thereby enabling the same `HashMap` data-structures to be reused. Both the +change the `VertexID` thereby enabling the same `HashMap` data-structures to be reused. Both the `leftJoin` and `innerJoin` are able to identify when joining two `VertexRDD`s derived from the same `HashMap` and implement the join by linear scan rather than costly point lookups. -The `aggregateUsingIndex` operator can be slightly confusing but is also useful for efficient -construction of a new `VertexRDD` from an `RDD[(VertexId, A)]`. Conceptually, if I have constructed -a `VertexRDD[B]` over a set of vertices, *which is a super-set* of the vertices in some -`RDD[(VertexId, A)]` then I can reuse the index to both aggregate and then subsequently index the -RDD. For example: +The `aggregateUsingIndex` operator is useful for efficient construction of a new `VertexRDD` from an +`RDD[(VertexID, A)]`. Conceptually, if I have constructed a `VertexRDD[B]` over a set of vertices, +*which is a super-set* of the vertices in some `RDD[(VertexID, A)]` then I can reuse the index to +both aggregate and then subsequently index the `RDD[(VertexID, A)]`. For example: {% highlight scala %} val setA: VertexRDD[Int] = VertexRDD(sc.parallelize(0L until 100L).map(id => (id, 1))) @@ -840,10 +908,10 @@ val setC: VertexRDD[Double] = setA.innerJoin(setB)((id, a, b) => a + b) ## EdgeRDDs -The `EdgeRDD[ED]`, which extends `RDD[Edge[ED]]` is considerably simpler than the `VertexRDD`. -GraphX organizes the edges in blocks partitioned using one of the various partitioning strategies -defined in [`PartitionStrategy`][PartitionStrategy]. Within each partition, edge attributes and -adjacency structure, are stored separately enabling maximum reuse when changing attribute values. +The `EdgeRDD[ED]`, which extends `RDD[Edge[ED]]` organizes the edges in blocks partitioned using one +of the various partitioning strategies defined in [`PartitionStrategy`][PartitionStrategy]. Within +each partition, edge attributes and adjacency structure, are stored separately enabling maximum +reuse when changing attribute values. [PartitionStrategy]: api/graphx/index.html#org.apache.spark.graphx.PartitionStrategy @@ -858,7 +926,7 @@ def innerJoin[ED2, ED3](other: EdgeRDD[ED2])(f: (VertexID, VertexID, ED, ED2) => {% endhighlight %} In most applications we have found that operations on the `EdgeRDD` are accomplished through the -graph or rely on operations defined in the base `RDD` class. +graph operators or rely on operations defined in the base `RDD` class. # Optimized Representation @@ -880,7 +948,9 @@ reduce both the communication and storage overhead. Logically, this corresponds to machines and allowing vertices to span multiple machines. The exact method of assigning edges depends on the [`PartitionStrategy`][PartitionStrategy] and there are several tradeoffs to the various heuristics. Users can choose between different strategies by repartitioning the graph with -the [`Graph.partitionBy`][Graph.partitionBy] operator. +the [`Graph.partitionBy`][Graph.partitionBy] operator. The default partitioning strategy is to use +the initial partitioning of the edges as provided on graph construction. However, users can easily +switch to 2D-partitioning or other heuristics included in GraphX. [Graph.partitionBy]: api/graphx/index.html#org.apache.spark.graphx.Graph$@partitionBy(partitionStrategy:org.apache.spark.graphx.PartitionStrategy):org.apache.spark.graphx.Graph[VD,ED] @@ -894,16 +964,15 @@ the [`Graph.partitionBy`][Graph.partitionBy] operator. Once the edges have be partitioned the key challenge to efficient graph-parallel computation is efficiently joining vertex attributes with the edges. Because real-world graphs typically have more -edges than vertices, we move vertex attributes to the edges. - - - - +edges than vertices, we move vertex attributes to the edges. Because not all partitions will +contain edges adjacent to all vertices we internally maintain a routing table which identifies where +to broadcast vertices when implementing the join required for operations like `triplets` and +`mapReduceTriplets`. # Graph Algorithms -GraphX includes a set of graph algorithms in to simplify analytics. The algorithms are contained in the `org.apache.spark.graphx.lib` package and can be accessed directly as methods on `Graph` via [`GraphOps`][GraphOps]. This section describes the algorithms and how they are used. +GraphX includes a set of graph algorithms to simplify analytics tasks. The algorithms are contained in the `org.apache.spark.graphx.lib` package and can be accessed directly as methods on `Graph` via [`GraphOps`][GraphOps]. This section describes the algorithms and how they are used. ## PageRank From 863dd722436598a390d7a0c319c6cf49b488b5f2 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 23:05:23 -0800 Subject: [PATCH 013/133] Reverting release plugin changes --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 2 +- repl-bin/pom.xml | 2 +- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 1b2d8f531ffb7..54a25910ced7d 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 8080075e9395a..3e5faf230dbc9 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index c14685da5f232..f14d9667ccc7d 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ diff --git a/repl-bin/pom.xml b/repl-bin/pom.xml index 37debdf73a6d3..869dbdb9b095a 100644 --- a/repl-bin/pom.xml +++ b/repl-bin/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml From fbfbb331db64dc1c5daef4585c7f85ce0323f5e8 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 22:50:36 -0800 Subject: [PATCH 014/133] Merge pull request #434 from rxin/graphxmaven Fixed SVDPlusPlusSuite in Maven build. This should go into 0.9.0 also. (cherry picked from commit 087487e90e4d6269d7a027f7cb718120f6c10505) Signed-off-by: Patrick Wendell --- graphx/src/test/resources/als-test.data | 16 ++++++++++++++++ .../spark/graphx/lib/SVDPlusPlusSuite.scala | 10 +++------- 2 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 graphx/src/test/resources/als-test.data diff --git a/graphx/src/test/resources/als-test.data b/graphx/src/test/resources/als-test.data new file mode 100644 index 0000000000000..e476cc23e047d --- /dev/null +++ b/graphx/src/test/resources/als-test.data @@ -0,0 +1,16 @@ +1,1,5.0 +1,2,1.0 +1,3,5.0 +1,4,1.0 +2,1,5.0 +2,2,1.0 +2,3,5.0 +2,4,1.0 +3,1,1.0 +3,2,5.0 +3,3,1.0 +3,4,5.0 +4,1,1.0 +4,2,5.0 +4,3,1.0 +4,4,5.0 diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala index 057d9b3d518e0..e01df56e94de9 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/SVDPlusPlusSuite.scala @@ -19,11 +19,7 @@ package org.apache.spark.graphx.lib import org.scalatest.FunSuite -import org.apache.spark.SparkContext -import org.apache.spark.SparkContext._ import org.apache.spark.graphx._ -import org.apache.spark.graphx.util.GraphGenerators -import org.apache.spark.rdd._ class SVDPlusPlusSuite extends FunSuite with LocalSparkContext { @@ -31,16 +27,16 @@ class SVDPlusPlusSuite extends FunSuite with LocalSparkContext { test("Test SVD++ with mean square error on training set") { withSpark { sc => val svdppErr = 8.0 - val edges = sc.textFile("mllib/data/als/test.data").map { line => + val edges = sc.textFile(getClass.getResource("/als-test.data").getFile).map { line => val fields = line.split(",") Edge(fields(0).toLong * 2, fields(1).toLong * 2 + 1, fields(2).toDouble) } val conf = new SVDPlusPlus.Conf(10, 2, 0.0, 5.0, 0.007, 0.007, 0.005, 0.015) // 2 iterations var (graph, u) = SVDPlusPlus.run(edges, conf) graph.cache() - val err = graph.vertices.collect.map{ case (vid, vd) => + val err = graph.vertices.collect().map{ case (vid, vd) => if (vid % 2 == 1) vd._4 else 0.0 - }.reduce(_ + _) / graph.triplets.collect.size + }.reduce(_ + _) / graph.triplets.collect().size assert(err <= svdppErr) } } From 2859cab2f50099d1a691aecb5f7e5dfa26dccdb1 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 14 Jan 2014 23:07:55 -0800 Subject: [PATCH 015/133] Merge pull request #435 from tdas/filestream-fix Fixed the flaky tests by making SparkConf not serializable SparkConf was being serialized with CoGroupedRDD and Aggregator, which somehow caused OptionalJavaException while being deserialized as part of a ShuffleMapTask. SparkConf should not even be serializable (according to conversation with Matei). This change fixes that. @mateiz @pwendell (cherry picked from commit 139c24ef08e6ffb090975c9808a2cba304eb79e0) Signed-off-by: Patrick Wendell --- .../scala/org/apache/spark/Aggregator.scala | 3 +- .../scala/org/apache/spark/SparkConf.scala | 3 +- .../org/apache/spark/rdd/CoGroupedRDD.scala | 3 +- .../flume/src/test/resources/log4j.properties | 2 +- .../kafka/src/test/resources/log4j.properties | 2 +- .../streaming/kafka/KafkaStreamSuite.scala | 1 + .../mqtt/src/test/resources/log4j.properties | 2 +- .../streaming/mqtt/MQTTStreamSuite.scala | 1 + .../src/test/resources/log4j.properties | 2 +- .../twitter/TwitterStreamSuite.scala | 1 + .../src/test/resources/log4j.properties | 2 +- .../streaming/zeromq/ZeroMQStreamSuite.scala | 1 + .../apache/spark/streaming/Checkpoint.scala | 10 ++++--- .../apache/spark/streaming/DStreamGraph.scala | 2 ++ .../dstream/DStreamCheckpointData.scala | 26 ++++++++++++++++- .../spark/streaming/CheckpointSuite.scala | 28 +++++++++++++------ 16 files changed, 66 insertions(+), 23 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Aggregator.scala b/core/src/main/scala/org/apache/spark/Aggregator.scala index edbea6ea5680a..c4579cf6ad560 100644 --- a/core/src/main/scala/org/apache/spark/Aggregator.scala +++ b/core/src/main/scala/org/apache/spark/Aggregator.scala @@ -33,8 +33,7 @@ case class Aggregator[K, V, C] ( mergeValue: (C, V) => C, mergeCombiners: (C, C) => C) { - private val sparkConf = SparkEnv.get.conf - private val externalSorting = sparkConf.getBoolean("spark.shuffle.spill", true) + private val externalSorting = SparkEnv.get.conf.getBoolean("spark.shuffle.spill", true) @deprecated("use combineValuesByKey with TaskContext argument", "0.9.0") def combineValuesByKey(iter: Iterator[_ <: Product2[K, V]]): Iterator[(K, C)] = diff --git a/core/src/main/scala/org/apache/spark/SparkConf.scala b/core/src/main/scala/org/apache/spark/SparkConf.scala index 93d3d1f6972c3..369c6ce78fa71 100644 --- a/core/src/main/scala/org/apache/spark/SparkConf.scala +++ b/core/src/main/scala/org/apache/spark/SparkConf.scala @@ -21,6 +21,7 @@ import scala.collection.JavaConverters._ import scala.collection.mutable.HashMap import com.typesafe.config.ConfigFactory +import java.io.{ObjectInputStream, ObjectOutputStream, IOException} /** * Configuration for a Spark application. Used to set various Spark parameters as key-value pairs. @@ -41,7 +42,7 @@ import com.typesafe.config.ConfigFactory * * @param loadDefaults whether to load values from the system properties and classpath */ -class SparkConf(loadDefaults: Boolean) extends Serializable with Cloneable with Logging { +class SparkConf(loadDefaults: Boolean) extends Cloneable with Logging { /** Create a SparkConf that loads defaults from system properties and the classpath */ def this() = this(true) diff --git a/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala b/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala index 9c6b308804c77..f2feb406f7783 100644 --- a/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala @@ -66,7 +66,6 @@ class CoGroupedRDD[K](@transient var rdds: Seq[RDD[_ <: Product2[K, _]]], part: private type CoGroupValue = (Any, Int) // Int is dependency number private type CoGroupCombiner = Seq[CoGroup] - private val sparkConf = SparkEnv.get.conf private var serializerClass: String = null def setSerializer(cls: String): CoGroupedRDD[K] = { @@ -106,7 +105,7 @@ class CoGroupedRDD[K](@transient var rdds: Seq[RDD[_ <: Product2[K, _]]], part: override val partitioner = Some(part) override def compute(s: Partition, context: TaskContext): Iterator[(K, CoGroupCombiner)] = { - + val sparkConf = SparkEnv.get.conf val externalSorting = sparkConf.getBoolean("spark.shuffle.externalSorting", true) val split = s.asInstanceOf[CoGroupPartition] val numRdds = split.deps.size diff --git a/external/flume/src/test/resources/log4j.properties b/external/flume/src/test/resources/log4j.properties index 063529a9cbc67..d1bd73a8430e1 100644 --- a/external/flume/src/test/resources/log4j.properties +++ b/external/flume/src/test/resources/log4j.properties @@ -20,7 +20,7 @@ log4j.rootCategory=INFO, file # log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.append=false -log4j.appender.file.file=streaming/target/unit-tests.log +log4j.appender.file.file=external/flume/target/unit-tests.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n diff --git a/external/kafka/src/test/resources/log4j.properties b/external/kafka/src/test/resources/log4j.properties index 063529a9cbc67..38910d113050a 100644 --- a/external/kafka/src/test/resources/log4j.properties +++ b/external/kafka/src/test/resources/log4j.properties @@ -20,7 +20,7 @@ log4j.rootCategory=INFO, file # log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.append=false -log4j.appender.file.file=streaming/target/unit-tests.log +log4j.appender.file.file=external/kafka/target/unit-tests.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n diff --git a/external/kafka/src/test/scala/org/apache/spark/streaming/kafka/KafkaStreamSuite.scala b/external/kafka/src/test/scala/org/apache/spark/streaming/kafka/KafkaStreamSuite.scala index 9c81f23c19118..d9809f6409d44 100644 --- a/external/kafka/src/test/scala/org/apache/spark/streaming/kafka/KafkaStreamSuite.scala +++ b/external/kafka/src/test/scala/org/apache/spark/streaming/kafka/KafkaStreamSuite.scala @@ -35,5 +35,6 @@ class KafkaStreamSuite extends TestSuiteBase { ssc, kafkaParams, topics, StorageLevel.MEMORY_AND_DISK_SER_2) // TODO: Actually test receiving data + ssc.stop() } } diff --git a/external/mqtt/src/test/resources/log4j.properties b/external/mqtt/src/test/resources/log4j.properties index 063529a9cbc67..d0462c7336df5 100644 --- a/external/mqtt/src/test/resources/log4j.properties +++ b/external/mqtt/src/test/resources/log4j.properties @@ -20,7 +20,7 @@ log4j.rootCategory=INFO, file # log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.append=false -log4j.appender.file.file=streaming/target/unit-tests.log +log4j.appender.file.file=external/mqtt/target/unit-tests.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n diff --git a/external/mqtt/src/test/scala/org/apache/spark/streaming/mqtt/MQTTStreamSuite.scala b/external/mqtt/src/test/scala/org/apache/spark/streaming/mqtt/MQTTStreamSuite.scala index 73e7ce6e968c6..89c40ad4619c9 100644 --- a/external/mqtt/src/test/scala/org/apache/spark/streaming/mqtt/MQTTStreamSuite.scala +++ b/external/mqtt/src/test/scala/org/apache/spark/streaming/mqtt/MQTTStreamSuite.scala @@ -32,5 +32,6 @@ class MQTTStreamSuite extends TestSuiteBase { val test2 = MQTTUtils.createStream(ssc, brokerUrl, topic, StorageLevel.MEMORY_AND_DISK_SER_2) // TODO: Actually test receiving data + ssc.stop() } } diff --git a/external/twitter/src/test/resources/log4j.properties b/external/twitter/src/test/resources/log4j.properties index 063529a9cbc67..c918335fcdc70 100644 --- a/external/twitter/src/test/resources/log4j.properties +++ b/external/twitter/src/test/resources/log4j.properties @@ -20,7 +20,7 @@ log4j.rootCategory=INFO, file # log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.append=false -log4j.appender.file.file=streaming/target/unit-tests.log +log4j.appender.file.file=external/twitter/target/unit-tests.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n diff --git a/external/twitter/src/test/scala/org/apache/spark/streaming/twitter/TwitterStreamSuite.scala b/external/twitter/src/test/scala/org/apache/spark/streaming/twitter/TwitterStreamSuite.scala index ccc38784ef671..06ab0cdaf3b4e 100644 --- a/external/twitter/src/test/scala/org/apache/spark/streaming/twitter/TwitterStreamSuite.scala +++ b/external/twitter/src/test/scala/org/apache/spark/streaming/twitter/TwitterStreamSuite.scala @@ -39,5 +39,6 @@ class TwitterStreamSuite extends TestSuiteBase { // Note that actually testing the data receiving is hard as authentication keys are // necessary for accessing Twitter live stream + ssc.stop() } } diff --git a/external/zeromq/src/test/resources/log4j.properties b/external/zeromq/src/test/resources/log4j.properties index 063529a9cbc67..304683dd0bac3 100644 --- a/external/zeromq/src/test/resources/log4j.properties +++ b/external/zeromq/src/test/resources/log4j.properties @@ -20,7 +20,7 @@ log4j.rootCategory=INFO, file # log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.append=false -log4j.appender.file.file=streaming/target/unit-tests.log +log4j.appender.file.file=external/zeromq/target/unit-tests.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss.SSS} %p %c{1}: %m%n diff --git a/external/zeromq/src/test/scala/org/apache/spark/streaming/zeromq/ZeroMQStreamSuite.scala b/external/zeromq/src/test/scala/org/apache/spark/streaming/zeromq/ZeroMQStreamSuite.scala index 4193b8a02f14a..92d55a7a7b6e4 100644 --- a/external/zeromq/src/test/scala/org/apache/spark/streaming/zeromq/ZeroMQStreamSuite.scala +++ b/external/zeromq/src/test/scala/org/apache/spark/streaming/zeromq/ZeroMQStreamSuite.scala @@ -40,5 +40,6 @@ class ZeroMQStreamSuite extends TestSuiteBase { StorageLevel.MEMORY_AND_DISK_SER_2, SupervisorStrategy.defaultStrategy) // TODO: Actually test data receiving + ssc.stop() } } diff --git a/streaming/src/main/scala/org/apache/spark/streaming/Checkpoint.scala b/streaming/src/main/scala/org/apache/spark/streaming/Checkpoint.scala index 5046a1d53fa41..4d778dc4d43b4 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/Checkpoint.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/Checkpoint.scala @@ -42,11 +42,13 @@ class Checkpoint(@transient ssc: StreamingContext, val checkpointTime: Time) val checkpointDuration = ssc.checkpointDuration val pendingTimes = ssc.scheduler.getPendingTimes().toArray val delaySeconds = MetadataCleaner.getDelaySeconds(ssc.conf) - val sparkConf = ssc.conf + val sparkConfPairs = ssc.conf.getAll - // These should be unset when a checkpoint is deserialized, - // otherwise the SparkContext won't initialize correctly. - sparkConf.remove("spark.driver.host").remove("spark.driver.port") + def sparkConf = { + new SparkConf(false).setAll(sparkConfPairs) + .remove("spark.driver.host") + .remove("spark.driver.port") + } def validate() { assert(master != null, "Checkpoint.master is null") diff --git a/streaming/src/main/scala/org/apache/spark/streaming/DStreamGraph.scala b/streaming/src/main/scala/org/apache/spark/streaming/DStreamGraph.scala index 8faa79f8c7e9d..0683113bd0b51 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/DStreamGraph.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/DStreamGraph.scala @@ -163,8 +163,10 @@ final private[streaming] class DStreamGraph extends Serializable with Logging { logDebug("DStreamGraph.writeObject used") this.synchronized { checkpointInProgress = true + logDebug("Enabled checkpoint mode") oos.defaultWriteObject() checkpointInProgress = false + logDebug("Disabled checkpoint mode") } } diff --git a/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStreamCheckpointData.scala b/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStreamCheckpointData.scala index 38bad5ac8042a..906a16e508cd8 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStreamCheckpointData.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStreamCheckpointData.scala @@ -19,7 +19,7 @@ package org.apache.spark.streaming.dstream import scala.collection.mutable.HashMap import scala.reflect.ClassTag -import java.io.{ObjectInputStream, IOException} +import java.io.{ObjectOutputStream, ObjectInputStream, IOException} import org.apache.hadoop.fs.Path import org.apache.hadoop.fs.FileSystem import org.apache.spark.Logging @@ -117,8 +117,32 @@ class DStreamCheckpointData[T: ClassTag] (dstream: DStream[T]) "[\n" + currentCheckpointFiles.size + " checkpoint files \n" + currentCheckpointFiles.mkString("\n") + "\n]" } + @throws(classOf[IOException]) + private def writeObject(oos: ObjectOutputStream) { + logDebug(this.getClass().getSimpleName + ".writeObject used") + if (dstream.context.graph != null) { + dstream.context.graph.synchronized { + if (dstream.context.graph.checkpointInProgress) { + oos.defaultWriteObject() + } else { + val msg = "Object of " + this.getClass.getName + " is being serialized " + + " possibly as a part of closure of an RDD operation. This is because " + + " the DStream object is being referred to from within the closure. " + + " Please rewrite the RDD operation inside this DStream to avoid this. " + + " This has been enforced to avoid bloating of Spark tasks " + + " with unnecessary objects." + throw new java.io.NotSerializableException(msg) + } + } + } else { + throw new java.io.NotSerializableException( + "Graph is unexpectedly null when DStream is being serialized.") + } + } + @throws(classOf[IOException]) private def readObject(ois: ObjectInputStream) { + logDebug(this.getClass().getSimpleName + ".readObject used") ois.defaultReadObject() timeToOldestCheckpointFileTime = new HashMap[Time, Time] timeToCheckpointFile = new HashMap[Time, String] diff --git a/streaming/src/test/scala/org/apache/spark/streaming/CheckpointSuite.scala b/streaming/src/test/scala/org/apache/spark/streaming/CheckpointSuite.scala index 89daf4758661b..831e7c1471a09 100644 --- a/streaming/src/test/scala/org/apache/spark/streaming/CheckpointSuite.scala +++ b/streaming/src/test/scala/org/apache/spark/streaming/CheckpointSuite.scala @@ -151,17 +151,29 @@ class CheckpointSuite extends TestSuiteBase { val value = "myvalue" System.setProperty(key, value) ssc = new StreamingContext(master, framework, batchDuration) + val originalConf = ssc.conf + val cp = new Checkpoint(ssc, Time(1000)) - assert(!cp.sparkConf.contains("spark.driver.host")) - assert(!cp.sparkConf.contains("spark.driver.port")) - assert(!cp.sparkConf.contains("spark.hostPort")) - assert(cp.sparkConf.get(key) === value) + val cpConf = cp.sparkConf + assert(cpConf.get("spark.master") === originalConf.get("spark.master")) + assert(cpConf.get("spark.app.name") === originalConf.get("spark.app.name")) + assert(cpConf.get(key) === value) ssc.stop() + + // Serialize/deserialize to simulate write to storage and reading it back val newCp = Utils.deserialize[Checkpoint](Utils.serialize(cp)) - assert(!newCp.sparkConf.contains("spark.driver.host")) - assert(!newCp.sparkConf.contains("spark.driver.port")) - assert(!newCp.sparkConf.contains("spark.hostPort")) - assert(newCp.sparkConf.get(key) === value) + + val newCpConf = newCp.sparkConf + assert(newCpConf.get("spark.master") === originalConf.get("spark.master")) + assert(newCpConf.get("spark.app.name") === originalConf.get("spark.app.name")) + assert(newCpConf.get(key) === value) + assert(!newCpConf.contains("spark.driver.host")) + assert(!newCpConf.contains("spark.driver.port")) + + // Check if all the parameters have been restored + ssc = new StreamingContext(null, newCp, null) + val restoredConf = ssc.conf + assert(restoredConf.get(key) === value) } From 2f015c2e77f991d8d880c73a241898b370708c56 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 14 Jan 2014 23:17:05 -0800 Subject: [PATCH 016/133] Merge pull request #436 from ankurdave/VertexId-case Rename VertexID -> VertexId in GraphX (cherry picked from commit 3d9e66d92ada4fa93dd0bd78cb4c80f8169e6393) Signed-off-by: Reynold Xin --- docs/graphx-programming-guide.md | 70 +++++++++---------- .../scala/org/apache/spark/graphx/Edge.scala | 8 +-- .../org/apache/spark/graphx/EdgeRDD.scala | 4 +- .../org/apache/spark/graphx/EdgeTriplet.scala | 4 +- .../scala/org/apache/spark/graphx/Graph.scala | 18 ++--- .../spark/graphx/GraphKryoRegistrator.scala | 2 +- .../org/apache/spark/graphx/GraphOps.scala | 32 ++++----- .../spark/graphx/PartitionStrategy.scala | 14 ++-- .../org/apache/spark/graphx/Pregel.scala | 8 +-- .../org/apache/spark/graphx/VertexRDD.scala | 42 +++++------ .../spark/graphx/impl/EdgePartition.scala | 16 ++--- .../graphx/impl/EdgePartitionBuilder.scala | 10 +-- .../graphx/impl/EdgeTripletIterator.scala | 2 +- .../apache/spark/graphx/impl/GraphImpl.scala | 32 ++++----- .../graphx/impl/MessageToPartition.scala | 12 ++-- .../graphx/impl/ReplicatedVertexView.scala | 30 ++++---- .../spark/graphx/impl/RoutingTable.scala | 16 ++--- .../spark/graphx/impl/Serializers.scala | 10 +-- .../spark/graphx/impl/VertexPartition.scala | 44 ++++++------ .../apache/spark/graphx/impl/package.scala | 2 +- .../graphx/lib/ConnectedComponents.scala | 4 +- .../apache/spark/graphx/lib/PageRank.scala | 4 +- .../apache/spark/graphx/lib/SVDPlusPlus.scala | 12 ++-- .../lib/StronglyConnectedComponents.scala | 6 +- .../spark/graphx/lib/TriangleCount.scala | 2 +- .../org/apache/spark/graphx/package.scala | 4 +- .../spark/graphx/util/GraphGenerators.scala | 12 ++-- .../apache/spark/graphx/GraphOpsSuite.scala | 10 +-- .../org/apache/spark/graphx/GraphSuite.scala | 28 ++++---- .../org/apache/spark/graphx/PregelSuite.scala | 8 +-- .../apache/spark/graphx/SerializerSuite.scala | 18 ++--- .../graphx/impl/EdgePartitionSuite.scala | 2 +- .../graphx/lib/ConnectedComponentsSuite.scala | 2 +- 33 files changed, 244 insertions(+), 244 deletions(-) diff --git a/docs/graphx-programming-guide.md b/docs/graphx-programming-guide.md index 4bf47434571f5..3dfed7bea9ea8 100644 --- a/docs/graphx-programming-guide.md +++ b/docs/graphx-programming-guide.md @@ -186,7 +186,7 @@ code constructs a graph from a collection of RDDs: // Assume the SparkContext has already been constructed val sc: SparkContext // Create an RDD for the vertices -val users: RDD[(VertexID, (String, String))] = +val users: RDD[(VertexId, (String, String))] = sc.parallelize(Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")), (5L, ("franklin", "prof")), (2L, ("istoica", "prof")))) // Create an RDD for edges @@ -360,7 +360,7 @@ graph contains the following: {% highlight scala %} class Graph[VD, ED] { - def mapVertices[VD2](map: (VertexID, VD) => VD2): Graph[VD2, ED] + def mapVertices[VD2](map: (VertexId, VD) => VD2): Graph[VD2, ED] def mapEdges[ED2](map: Edge[ED] => ED2): Graph[VD, ED2] def mapTriplets[ED2](map: EdgeTriplet[VD, ED] => ED2): Graph[VD, ED2] } @@ -382,7 +382,7 @@ val newGraph = Graph(newVertices, graph.edges) val newGraph = graph.mapVertices((id, attr) => mapUdf(id, attr)) {% endhighlight %} -[Graph.mapVertices]: api/graphx/index.html#org.apache.spark.graphx.Graph@mapVertices[VD2]((VertexID,VD)⇒VD2)(ClassTag[VD2]):Graph[VD2,ED] +[Graph.mapVertices]: api/graphx/index.html#org.apache.spark.graphx.Graph@mapVertices[VD2]((VertexId,VD)⇒VD2)(ClassTag[VD2]):Graph[VD2,ED] These operators are often used to initialize the graph for a particular computation or project away unnecessary properties. For example, given a graph with the out-degrees as the vertex properties @@ -408,7 +408,7 @@ add more in the future. The following is a list of the basic structural operato class Graph[VD, ED] { def reverse: Graph[VD, ED] def subgraph(epred: EdgeTriplet[VD,ED] => Boolean, - vpred: (VertexID, VD) => Boolean): Graph[VD, ED] + vpred: (VertexId, VD) => Boolean): Graph[VD, ED] def mask[VD2, ED2](other: Graph[VD2, ED2]): Graph[VD, ED] def groupEdges(merge: (ED, ED) => ED): Graph[VD,ED] } @@ -427,11 +427,11 @@ satisfy the edge predicate *and connect vertices that satisfy the vertex predica operator can be used in number of situations to restrict the graph to the vertices and edges of interest or eliminate broken links. For example in the following code we remove broken links: -[Graph.subgraph]: api/graphx/index.html#org.apache.spark.graphx.Graph@subgraph((EdgeTriplet[VD,ED])⇒Boolean,(VertexID,VD)⇒Boolean):Graph[VD,ED] +[Graph.subgraph]: api/graphx/index.html#org.apache.spark.graphx.Graph@subgraph((EdgeTriplet[VD,ED])⇒Boolean,(VertexId,VD)⇒Boolean):Graph[VD,ED] {% highlight scala %} // Create an RDD for the vertices -val users: RDD[(VertexID, (String, String))] = +val users: RDD[(VertexId, (String, String))] = sc.parallelize(Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")), (5L, ("franklin", "prof")), (2L, ("istoica", "prof")), (4L, ("peter", "student")))) @@ -494,9 +494,9 @@ using the *join* operators. Below we list the key join operators: {% highlight scala %} class Graph[VD, ED] { - def joinVertices[U](table: RDD[(VertexID, U)])(map: (VertexID, VD, U) => VD) + def joinVertices[U](table: RDD[(VertexId, U)])(map: (VertexId, VD, U) => VD) : Graph[VD, ED] - def outerJoinVertices[U, VD2](table: RDD[(VertexID, U)])(map: (VertexID, VD, Option[U]) => VD2) + def outerJoinVertices[U, VD2](table: RDD[(VertexId, U)])(map: (VertexId, VD, Option[U]) => VD2) : Graph[VD2, ED] } {% endhighlight %} @@ -506,7 +506,7 @@ returns a new graph with the vertex properties obtained by applying the user def to the result of the joined vertices. Vertices without a matching value in the RDD retain their original value. -[GraphOps.joinVertices]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@joinVertices[U](RDD[(VertexID,U)])((VertexID,VD,U)⇒VD)(ClassTag[U]):Graph[VD,ED] +[GraphOps.joinVertices]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@joinVertices[U](RDD[(VertexId,U)])((VertexId,VD,U)⇒VD)(ClassTag[U]):Graph[VD,ED] > Note that if the RDD contains more than one value for a given vertex only one will be used. It > is therefore recommended that the input RDD be first made unique using the following which will @@ -525,7 +525,7 @@ property type. Because not all vertices may have a matching value in the input function takes an `Option` type. For example, we can setup a graph for PageRank by initializing vertex properties with their `outDegree`. -[Graph.outerJoinVertices]: api/graphx/index.html#org.apache.spark.graphx.Graph@outerJoinVertices[U,VD2](RDD[(VertexID,U)])((VertexID,VD,Option[U])⇒VD2)(ClassTag[U],ClassTag[VD2]):Graph[VD2,ED] +[Graph.outerJoinVertices]: api/graphx/index.html#org.apache.spark.graphx.Graph@outerJoinVertices[U,VD2](RDD[(VertexId,U)])((VertexId,VD,Option[U])⇒VD2)(ClassTag[U],ClassTag[VD2]):Graph[VD2,ED] {% highlight scala %} @@ -559,7 +559,7 @@ PageRank Value, shortest path to the source, and smallest reachable vertex id). ### Map Reduce Triplets (mapReduceTriplets) -[Graph.mapReduceTriplets]: api/graphx/index.html#org.apache.spark.graphx.Graph@mapReduceTriplets[A](mapFunc:org.apache.spark.graphx.EdgeTriplet[VD,ED]=>Iterator[(org.apache.spark.graphx.VertexID,A)],reduceFunc:(A,A)=>A,activeSetOpt:Option[(org.apache.spark.graphx.VertexRDD[_],org.apache.spark.graphx.EdgeDirection)])(implicitevidence$10:scala.reflect.ClassTag[A]):org.apache.spark.graphx.VertexRDD[A] +[Graph.mapReduceTriplets]: api/graphx/index.html#org.apache.spark.graphx.Graph@mapReduceTriplets[A](mapFunc:org.apache.spark.graphx.EdgeTriplet[VD,ED]=>Iterator[(org.apache.spark.graphx.VertexId,A)],reduceFunc:(A,A)=>A,activeSetOpt:Option[(org.apache.spark.graphx.VertexRDD[_],org.apache.spark.graphx.EdgeDirection)])(implicitevidence$10:scala.reflect.ClassTag[A]):org.apache.spark.graphx.VertexRDD[A] The core (heavily optimized) aggregation primitive in GraphX is the [`mapReduceTriplets`][Graph.mapReduceTriplets] operator: @@ -567,7 +567,7 @@ The core (heavily optimized) aggregation primitive in GraphX is the {% highlight scala %} class Graph[VD, ED] { def mapReduceTriplets[A]( - map: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + map: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)], reduce: (A, A) => A) : VertexRDD[A] } @@ -649,13 +649,13 @@ compute the max in, out, and total degrees: {% highlight scala %} // Define a reduce operation to compute the highest degree vertex -def max(a: (VertexID, Int), b: (VertexID, Int)): (VertexID, Int) = { +def max(a: (VertexId, Int), b: (VertexId, Int)): (VertexId, Int) = { if (a._2 > b._2) a else b } // Compute the max degrees -val maxInDegree: (VertexID, Int) = graph.inDegrees.reduce(max) -val maxOutDegree: (VertexID, Int) = graph.outDegrees.reduce(max) -val maxDegrees: (VertexID, Int) = graph.degrees.reduce(max) +val maxInDegree: (VertexId, Int) = graph.inDegrees.reduce(max) +val maxOutDegree: (VertexId, Int) = graph.outDegrees.reduce(max) +val maxDegrees: (VertexId, Int) = graph.degrees.reduce(max) {% endhighlight %} ### Collecting Neighbors @@ -665,14 +665,14 @@ attributes at each vertex. This can be easily accomplished using the [`collectNeighborIds`][GraphOps.collectNeighborIds] and the [`collectNeighbors`][GraphOps.collectNeighbors] operators. -[GraphOps.collectNeighborIds]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@collectNeighborIds(EdgeDirection):VertexRDD[Array[VertexID]] -[GraphOps.collectNeighbors]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@collectNeighbors(EdgeDirection):VertexRDD[Array[(VertexID,VD)]] +[GraphOps.collectNeighborIds]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@collectNeighborIds(EdgeDirection):VertexRDD[Array[VertexId]] +[GraphOps.collectNeighbors]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@collectNeighbors(EdgeDirection):VertexRDD[Array[(VertexId,VD)]] {% highlight scala %} class GraphOps[VD, ED] { - def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array[VertexID]] - def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[ Array[(VertexID, VD)] ] + def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array[VertexId]] + def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[ Array[(VertexId, VD)] ] } {% endhighlight %} @@ -716,7 +716,7 @@ messages remaining. The following is the type signature of the [Pregel operator][GraphOps.pregel] as well as a *sketch* of its implementation (note calls to graph.cache have been removed): -[GraphOps.pregel]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@pregel[A](A,Int,EdgeDirection)((VertexID,VD,A)⇒VD,(EdgeTriplet[VD,ED])⇒Iterator[(VertexID,A)],(A,A)⇒A)(ClassTag[A]):Graph[VD,ED] +[GraphOps.pregel]: api/graphx/index.html#org.apache.spark.graphx.GraphOps@pregel[A](A,Int,EdgeDirection)((VertexId,VD,A)⇒VD,(EdgeTriplet[VD,ED])⇒Iterator[(VertexId,A)],(A,A)⇒A)(ClassTag[A]):Graph[VD,ED] {% highlight scala %} class GraphOps[VD, ED] { @@ -724,8 +724,8 @@ class GraphOps[VD, ED] { (initialMsg: A, maxIter: Int = Int.MaxValue, activeDir: EdgeDirection = EdgeDirection.Out) - (vprog: (VertexID, VD, A) => VD, - sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + (vprog: (VertexId, VD, A) => VD, + sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)], mergeMsg: (A, A) => A) : Graph[VD, ED] = { // Receive the initial message at each vertex @@ -770,7 +770,7 @@ import org.apache.spark.graphx.util.GraphGenerators // A graph with edge attributes containing distances val graph: Graph[Int, Double] = GraphGenerators.logNormalGraph(sc, numVertices = 100).mapEdges(e => e.attr.toDouble) -val sourceId: VertexID = 42 // The ultimate source +val sourceId: VertexId = 42 // The ultimate source // Initialize the graph such that all vertices except the root have distance infinity. val initialGraph = graph.mapVertices((id, _) => if (id == sourceId) 0.0 else Double.PositiveInfinity) val sssp = initialGraph.pregel(Double.PositiveInfinity)( @@ -817,7 +817,7 @@ It creates a `Graph` from the specified edges, automatically creating any vertic {% highlight scala %} object Graph { def apply[VD, ED]( - vertices: RDD[(VertexID, VD)], + vertices: RDD[(VertexId, VD)], edges: RDD[Edge[ED]], defaultVertexAttr: VD = null) : Graph[VD, ED] @@ -827,7 +827,7 @@ object Graph { defaultValue: VD): Graph[VD, ED] def fromEdgeTuples[VD]( - rawEdges: RDD[(VertexID, VertexID)], + rawEdges: RDD[(VertexId, VertexId)], defaultValue: VD, uniqueEdges: Option[PartitionStrategy] = None): Graph[VD, Int] @@ -843,8 +843,8 @@ object Graph { [PartitionStrategy]: api/graphx/index.html#org.apache.spark.graphx.PartitionStrategy$ [GraphLoader.edgeListFile]: api/graphx/index.html#org.apache.spark.graphx.GraphLoader$@edgeListFile(SparkContext,String,Boolean,Int):Graph[Int,Int] -[Graph.apply]: api/graphx/index.html#org.apache.spark.graphx.Graph$@apply[VD,ED](RDD[(VertexID,VD)],RDD[Edge[ED]],VD)(ClassTag[VD],ClassTag[ED]):Graph[VD,ED] -[Graph.fromEdgeTuples]: api/graphx/index.html#org.apache.spark.graphx.Graph$@fromEdgeTuples[VD](RDD[(VertexID,VertexID)],VD,Option[PartitionStrategy])(ClassTag[VD]):Graph[VD,Int] +[Graph.apply]: api/graphx/index.html#org.apache.spark.graphx.Graph$@apply[VD,ED](RDD[(VertexId,VD)],RDD[Edge[ED]],VD)(ClassTag[VD],ClassTag[ED]):Graph[VD,ED] +[Graph.fromEdgeTuples]: api/graphx/index.html#org.apache.spark.graphx.Graph$@fromEdgeTuples[VD](RDD[(VertexId,VertexId)],VD,Option[PartitionStrategy])(ClassTag[VD]):Graph[VD,Int] [Graph.fromEdges]: api/graphx/index.html#org.apache.spark.graphx.Graph$@fromEdges[VD,ED](RDD[Edge[ED]],VD)(ClassTag[VD],ClassTag[ED]):Graph[VD,ED] # Vertex and Edge RDDs @@ -868,17 +868,17 @@ additional functionality: {% highlight scala %} class VertexRDD[VD] extends RDD[(VertexID, VD)] { // Filter the vertex set but preserves the internal index - def filter(pred: Tuple2[VertexID, VD] => Boolean): VertexRDD[VD] + def filter(pred: Tuple2[VertexId, VD] => Boolean): VertexRDD[VD] // Transform the values without changing the ids (preserves the internal index) def mapValues[VD2](map: VD => VD2): VertexRDD[VD2] - def mapValues[VD2](map: (VertexID, VD) => VD2): VertexRDD[VD2] + def mapValues[VD2](map: (VertexId, VD) => VD2): VertexRDD[VD2] // Remove vertices from this set that appear in the other set def diff(other: VertexRDD[VD]): VertexRDD[VD] // Join operators that take advantage of the internal indexing to accelerate joins (substantially) - def leftJoin[VD2, VD3](other: RDD[(VertexID, VD2)])(f: (VertexID, VD, Option[VD2]) => VD3): VertexRDD[VD3] - def innerJoin[U, VD2](other: RDD[(VertexID, U)])(f: (VertexID, VD, U) => VD2): VertexRDD[VD2] + def leftJoin[VD2, VD3](other: RDD[(VertexId, VD2)])(f: (VertexId, VD, Option[VD2]) => VD3): VertexRDD[VD3] + def innerJoin[U, VD2](other: RDD[(VertexId, U)])(f: (VertexId, VD, U) => VD2): VertexRDD[VD2] // Use the index on this RDD to accelerate a `reduceByKey` operation on the input RDD. - def aggregateUsingIndex[VD2](other: RDD[(VertexID, VD2)], reduceFunc: (VD2, VD2) => VD2): VertexRDD[VD2] + def aggregateUsingIndex[VD2](other: RDD[(VertexId, VD2)], reduceFunc: (VD2, VD2) => VD2): VertexRDD[VD2] } {% endhighlight %} @@ -896,7 +896,7 @@ both aggregate and then subsequently index the `RDD[(VertexID, A)]`. For exampl {% highlight scala %} val setA: VertexRDD[Int] = VertexRDD(sc.parallelize(0L until 100L).map(id => (id, 1))) -val rddB: RDD[(VertexID, Double)] = sc.parallelize(0L until 100L).flatMap(id => List((id, 1.0), (id, 2.0))) +val rddB: RDD[(VertexId, Double)] = sc.parallelize(0L until 100L).flatMap(id => List((id, 1.0), (id, 2.0))) // There should be 200 entries in rddB rddB.count val setB: VertexRDD[Double] = setA.aggregateUsingIndex(rddB, _ + _) @@ -922,7 +922,7 @@ def mapValues[ED2](f: Edge[ED] => ED2): EdgeRDD[ED2] // Revere the edges reusing both attributes and structure def reverse: EdgeRDD[ED] // Join two `EdgeRDD`s partitioned using the same partitioning strategy. -def innerJoin[ED2, ED3](other: EdgeRDD[ED2])(f: (VertexID, VertexID, ED, ED2) => ED3): EdgeRDD[ED3] +def innerJoin[ED2, ED3](other: EdgeRDD[ED2])(f: (VertexId, VertexId, ED, ED2) => ED3): EdgeRDD[ED3] {% endhighlight %} In most applications we have found that operations on the `EdgeRDD` are accomplished through the diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala b/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala index 32f1602698134..580faa0866789 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Edge.scala @@ -28,8 +28,8 @@ package org.apache.spark.graphx * @param attr The attribute associated with the edge */ case class Edge[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) ED] ( - var srcId: VertexID = 0, - var dstId: VertexID = 0, + var srcId: VertexId = 0, + var dstId: VertexId = 0, var attr: ED = null.asInstanceOf[ED]) extends Serializable { @@ -39,7 +39,7 @@ case class Edge[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) ED] * @param vid the id one of the two vertices on the edge. * @return the id of the other vertex on the edge. */ - def otherVertexId(vid: VertexID): VertexID = + def otherVertexId(vid: VertexId): VertexId = if (srcId == vid) dstId else { assert(dstId == vid); srcId } /** @@ -50,7 +50,7 @@ case class Edge[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) ED] * @return the relative direction of the edge to the corresponding * vertex. */ - def relativeDirection(vid: VertexID): EdgeDirection = + def relativeDirection(vid: VertexId): EdgeDirection = if (vid == srcId) EdgeDirection.Out else { assert(vid == dstId); EdgeDirection.In } } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala b/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala index 6efef061d7510..fe03ae4a629b9 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/EdgeRDD.scala @@ -102,7 +102,7 @@ class EdgeRDD[@specialized ED: ClassTag]( */ def innerJoin[ED2: ClassTag, ED3: ClassTag] (other: EdgeRDD[ED2]) - (f: (VertexID, VertexID, ED, ED2) => ED3): EdgeRDD[ED3] = { + (f: (VertexId, VertexId, ED, ED2) => ED3): EdgeRDD[ED3] = { val ed2Tag = classTag[ED2] val ed3Tag = classTag[ED3] new EdgeRDD[ED3](partitionsRDD.zipPartitions(other.partitionsRDD, true) { @@ -113,7 +113,7 @@ class EdgeRDD[@specialized ED: ClassTag]( }) } - private[graphx] def collectVertexIDs(): RDD[VertexID] = { + private[graphx] def collectVertexIds(): RDD[VertexId] = { partitionsRDD.flatMap { case (_, p) => Array.concat(p.srcIds, p.dstIds) } } } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala b/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala index 2c659cb070b99..fea43c3b2bbf1 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/EdgeTriplet.scala @@ -50,7 +50,7 @@ class EdgeTriplet[VD, ED] extends Edge[ED] { * @param vid the id one of the two vertices on the edge * @return the attribute for the other vertex on the edge */ - def otherVertexAttr(vid: VertexID): VD = + def otherVertexAttr(vid: VertexId): VD = if (srcId == vid) dstAttr else { assert(dstId == vid); srcAttr } /** @@ -59,7 +59,7 @@ class EdgeTriplet[VD, ED] extends Edge[ED] { * @param vid the id of one of the two vertices on the edge * @return the attr for the vertex with that id */ - def vertexAttr(vid: VertexID): VD = + def vertexAttr(vid: VertexId): VD = if (srcId == vid) srcAttr else { assert(dstId == vid); dstAttr } override def toString = ((srcId, srcAttr), (dstId, dstAttr), attr).toString() diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala b/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala index 7f65244cd95cd..eea95d38d5016 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Graph.scala @@ -126,7 +126,7 @@ abstract class Graph[VD: ClassTag, ED: ClassTag] protected () extends Serializab * }}} * */ - def mapVertices[VD2: ClassTag](map: (VertexID, VD) => VD2): Graph[VD2, ED] + def mapVertices[VD2: ClassTag](map: (VertexId, VD) => VD2): Graph[VD2, ED] /** * Transforms each edge attribute in the graph using the map function. The map function is not @@ -242,7 +242,7 @@ abstract class Graph[VD: ClassTag, ED: ClassTag] protected () extends Serializab */ def subgraph( epred: EdgeTriplet[VD,ED] => Boolean = (x => true), - vpred: (VertexID, VD) => Boolean = ((v, d) => true)) + vpred: (VertexId, VD) => Boolean = ((v, d) => true)) : Graph[VD, ED] /** @@ -292,7 +292,7 @@ abstract class Graph[VD: ClassTag, ED: ClassTag] protected () extends Serializab * vertex * {{{ * val rawGraph: Graph[(),()] = Graph.textFile("twittergraph") - * val inDeg: RDD[(VertexID, Int)] = + * val inDeg: RDD[(VertexId, Int)] = * mapReduceTriplets[Int](et => Iterator((et.dst.id, 1)), _ + _) * }}} * @@ -304,7 +304,7 @@ abstract class Graph[VD: ClassTag, ED: ClassTag] protected () extends Serializab * */ def mapReduceTriplets[A: ClassTag]( - mapFunc: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + mapFunc: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)], reduceFunc: (A, A) => A, activeSetOpt: Option[(VertexRDD[_], EdgeDirection)] = None) : VertexRDD[A] @@ -328,14 +328,14 @@ abstract class Graph[VD: ClassTag, ED: ClassTag] protected () extends Serializab * * {{{ * val rawGraph: Graph[_, _] = Graph.textFile("webgraph") - * val outDeg: RDD[(VertexID, Int)] = rawGraph.outDegrees() + * val outDeg: RDD[(VertexId, Int)] = rawGraph.outDegrees() * val graph = rawGraph.outerJoinVertices(outDeg) { * (vid, data, optDeg) => optDeg.getOrElse(0) * } * }}} */ - def outerJoinVertices[U: ClassTag, VD2: ClassTag](other: RDD[(VertexID, U)]) - (mapFunc: (VertexID, VD, Option[U]) => VD2) + def outerJoinVertices[U: ClassTag, VD2: ClassTag](other: RDD[(VertexId, U)]) + (mapFunc: (VertexId, VD, Option[U]) => VD2) : Graph[VD2, ED] /** @@ -364,7 +364,7 @@ object Graph { * (if `uniqueEdges` is `None`) and vertex attributes containing the total degree of each vertex. */ def fromEdgeTuples[VD: ClassTag]( - rawEdges: RDD[(VertexID, VertexID)], + rawEdges: RDD[(VertexId, VertexId)], defaultValue: VD, uniqueEdges: Option[PartitionStrategy] = None): Graph[VD, Int] = { @@ -405,7 +405,7 @@ object Graph { * mentioned in edges but not in vertices */ def apply[VD: ClassTag, ED: ClassTag]( - vertices: RDD[(VertexID, VD)], + vertices: RDD[(VertexId, VD)], edges: RDD[Edge[ED]], defaultVertexAttr: VD = null.asInstanceOf[VD]): Graph[VD, ED] = { GraphImpl(vertices, edges, defaultVertexAttr) diff --git a/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala b/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala index 6db8a34937244..dd380d8c182c9 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/GraphKryoRegistrator.scala @@ -33,7 +33,7 @@ class GraphKryoRegistrator extends KryoRegistrator { kryo.register(classOf[Edge[Object]]) kryo.register(classOf[MessageToPartition[Object]]) kryo.register(classOf[VertexBroadcastMsg[Object]]) - kryo.register(classOf[(VertexID, Object)]) + kryo.register(classOf[(VertexId, Object)]) kryo.register(classOf[EdgePartition[Object]]) kryo.register(classOf[BitSet]) kryo.register(classOf[VertexIdToIndexMap]) diff --git a/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala b/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala index 9b864c1290bd2..0fc1e4df6813c 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/GraphOps.scala @@ -80,19 +80,19 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * * @return the set of neighboring ids for each vertex */ - def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array[VertexID]] = { + def collectNeighborIds(edgeDirection: EdgeDirection): VertexRDD[Array[VertexId]] = { val nbrs = if (edgeDirection == EdgeDirection.Either) { - graph.mapReduceTriplets[Array[VertexID]]( + graph.mapReduceTriplets[Array[VertexId]]( mapFunc = et => Iterator((et.srcId, Array(et.dstId)), (et.dstId, Array(et.srcId))), reduceFunc = _ ++ _ ) } else if (edgeDirection == EdgeDirection.Out) { - graph.mapReduceTriplets[Array[VertexID]]( + graph.mapReduceTriplets[Array[VertexId]]( mapFunc = et => Iterator((et.srcId, Array(et.dstId))), reduceFunc = _ ++ _) } else if (edgeDirection == EdgeDirection.In) { - graph.mapReduceTriplets[Array[VertexID]]( + graph.mapReduceTriplets[Array[VertexId]]( mapFunc = et => Iterator((et.dstId, Array(et.srcId))), reduceFunc = _ ++ _) } else { @@ -100,7 +100,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali "direction. (EdgeDirection.Both is not supported; use EdgeDirection.Either instead.)") } graph.vertices.leftZipJoin(nbrs) { (vid, vdata, nbrsOpt) => - nbrsOpt.getOrElse(Array.empty[VertexID]) + nbrsOpt.getOrElse(Array.empty[VertexId]) } } // end of collectNeighborIds @@ -116,8 +116,8 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * * @return the vertex set of neighboring vertex attributes for each vertex */ - def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[Array[(VertexID, VD)]] = { - val nbrs = graph.mapReduceTriplets[Array[(VertexID,VD)]]( + def collectNeighbors(edgeDirection: EdgeDirection): VertexRDD[Array[(VertexId, VD)]] = { + val nbrs = graph.mapReduceTriplets[Array[(VertexId,VD)]]( edge => { val msgToSrc = (edge.srcId, Array((edge.dstId, edge.dstAttr))) val msgToDst = (edge.dstId, Array((edge.srcId, edge.srcAttr))) @@ -133,7 +133,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali (a, b) => a ++ b) graph.vertices.leftZipJoin(nbrs) { (vid, vdata, nbrsOpt) => - nbrsOpt.getOrElse(Array.empty[(VertexID, VD)]) + nbrsOpt.getOrElse(Array.empty[(VertexId, VD)]) } } // end of collectNeighbor @@ -164,9 +164,9 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * }}} * */ - def joinVertices[U: ClassTag](table: RDD[(VertexID, U)])(mapFunc: (VertexID, VD, U) => VD) + def joinVertices[U: ClassTag](table: RDD[(VertexId, U)])(mapFunc: (VertexId, VD, U) => VD) : Graph[VD, ED] = { - val uf = (id: VertexID, data: VD, o: Option[U]) => { + val uf = (id: VertexId, data: VD, o: Option[U]) => { o match { case Some(u) => mapFunc(id, data, u) case None => data @@ -197,7 +197,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * val degrees: VertexRDD[Int] = graph.outDegrees * graph.outerJoinVertices(degrees) {(vid, data, deg) => deg.getOrElse(0)} * }, - * vpred = (vid: VertexID, deg:Int) => deg > 0 + * vpred = (vid: VertexId, deg:Int) => deg > 0 * ) * }}} * @@ -205,7 +205,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali def filter[VD2: ClassTag, ED2: ClassTag]( preprocess: Graph[VD, ED] => Graph[VD2, ED2], epred: (EdgeTriplet[VD2, ED2]) => Boolean = (x: EdgeTriplet[VD2, ED2]) => true, - vpred: (VertexID, VD2) => Boolean = (v:VertexID, d:VD2) => true): Graph[VD, ED] = { + vpred: (VertexId, VD2) => Boolean = (v:VertexId, d:VD2) => true): Graph[VD, ED] = { graph.mask(preprocess(graph).subgraph(epred, vpred)) } @@ -260,8 +260,8 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali initialMsg: A, maxIterations: Int = Int.MaxValue, activeDirection: EdgeDirection = EdgeDirection.Either)( - vprog: (VertexID, VD, A) => VD, - sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexID,A)], + vprog: (VertexId, VD, A) => VD, + sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexId,A)], mergeMsg: (A, A) => A) : Graph[VD, ED] = { Pregel(graph, initialMsg, maxIterations, activeDirection)(vprog, sendMsg, mergeMsg) @@ -293,7 +293,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * * @see [[org.apache.spark.graphx.lib.ConnectedComponents$#run]] */ - def connectedComponents(): Graph[VertexID, ED] = { + def connectedComponents(): Graph[VertexId, ED] = { ConnectedComponents.run(graph) } @@ -312,7 +312,7 @@ class GraphOps[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]) extends Seriali * * @see [[org.apache.spark.graphx.lib.StronglyConnectedComponents$#run]] */ - def stronglyConnectedComponents(numIter: Int): Graph[VertexID, ED] = { + def stronglyConnectedComponents(numIter: Int): Graph[VertexId, ED] = { StronglyConnectedComponents.run(graph, numIter) } } // end of GraphOps diff --git a/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala b/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala index 8ba87976f1136..929915362c1c9 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/PartitionStrategy.scala @@ -23,7 +23,7 @@ package org.apache.spark.graphx */ trait PartitionStrategy extends Serializable { /** Returns the partition number for a given edge. */ - def getPartition(src: VertexID, dst: VertexID, numParts: PartitionID): PartitionID + def getPartition(src: VertexId, dst: VertexId, numParts: PartitionID): PartitionID } /** @@ -73,9 +73,9 @@ object PartitionStrategy { * is used. */ case object EdgePartition2D extends PartitionStrategy { - override def getPartition(src: VertexID, dst: VertexID, numParts: PartitionID): PartitionID = { + override def getPartition(src: VertexId, dst: VertexId, numParts: PartitionID): PartitionID = { val ceilSqrtNumParts: PartitionID = math.ceil(math.sqrt(numParts)).toInt - val mixingPrime: VertexID = 1125899906842597L + val mixingPrime: VertexId = 1125899906842597L val col: PartitionID = ((math.abs(src) * mixingPrime) % ceilSqrtNumParts).toInt val row: PartitionID = ((math.abs(dst) * mixingPrime) % ceilSqrtNumParts).toInt (col * ceilSqrtNumParts + row) % numParts @@ -87,8 +87,8 @@ object PartitionStrategy { * source. */ case object EdgePartition1D extends PartitionStrategy { - override def getPartition(src: VertexID, dst: VertexID, numParts: PartitionID): PartitionID = { - val mixingPrime: VertexID = 1125899906842597L + override def getPartition(src: VertexId, dst: VertexId, numParts: PartitionID): PartitionID = { + val mixingPrime: VertexId = 1125899906842597L (math.abs(src) * mixingPrime).toInt % numParts } } @@ -99,7 +99,7 @@ object PartitionStrategy { * random vertex cut that colocates all same-direction edges between two vertices. */ case object RandomVertexCut extends PartitionStrategy { - override def getPartition(src: VertexID, dst: VertexID, numParts: PartitionID): PartitionID = { + override def getPartition(src: VertexId, dst: VertexId, numParts: PartitionID): PartitionID = { math.abs((src, dst).hashCode()) % numParts } } @@ -111,7 +111,7 @@ object PartitionStrategy { * regardless of direction. */ case object CanonicalRandomVertexCut extends PartitionStrategy { - override def getPartition(src: VertexID, dst: VertexID, numParts: PartitionID): PartitionID = { + override def getPartition(src: VertexId, dst: VertexId, numParts: PartitionID): PartitionID = { val lower = math.min(src, dst) val higher = math.max(src, dst) math.abs((lower, higher).hashCode()) % numParts diff --git a/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala b/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala index 0f6d4135934cb..ac07a594a12e4 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/Pregel.scala @@ -40,9 +40,9 @@ import scala.reflect.ClassTag * // Set the vertex attributes to the initial pagerank values * .mapVertices((id, attr) => 1.0) * - * def vertexProgram(id: VertexID, attr: Double, msgSum: Double): Double = + * def vertexProgram(id: VertexId, attr: Double, msgSum: Double): Double = * resetProb + (1.0 - resetProb) * msgSum - * def sendMessage(id: VertexID, edge: EdgeTriplet[Double, Double]): Iterator[(VertexId, Double)] = + * def sendMessage(id: VertexId, edge: EdgeTriplet[Double, Double]): Iterator[(VertexId, Double)] = * Iterator((edge.dstId, edge.srcAttr * edge.attr)) * def messageCombiner(a: Double, b: Double): Double = a + b * val initialMessage = 0.0 @@ -113,8 +113,8 @@ object Pregel { initialMsg: A, maxIterations: Int = Int.MaxValue, activeDirection: EdgeDirection = EdgeDirection.Either) - (vprog: (VertexID, VD, A) => VD, - sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + (vprog: (VertexId, VD, A) => VD, + sendMsg: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)], mergeMsg: (A, A) => A) : Graph[VD, ED] = { diff --git a/graphx/src/main/scala/org/apache/spark/graphx/VertexRDD.scala b/graphx/src/main/scala/org/apache/spark/graphx/VertexRDD.scala index 9a95364cb16dd..edd59bcf32943 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/VertexRDD.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/VertexRDD.scala @@ -28,7 +28,7 @@ import org.apache.spark.graphx.impl.MsgRDDFunctions import org.apache.spark.graphx.impl.VertexPartition /** - * Extends `RDD[(VertexID, VD)]` by ensuring that there is only one entry for each vertex and by + * Extends `RDD[(VertexId, VD)]` by ensuring that there is only one entry for each vertex and by * pre-indexing the entries for fast, efficient joins. Two VertexRDDs with the same index can be * joined efficiently. All operations except [[reindex]] preserve the index. To construct a * `VertexRDD`, use the [[org.apache.spark.graphx.VertexRDD$ VertexRDD object]]. @@ -36,12 +36,12 @@ import org.apache.spark.graphx.impl.VertexPartition * @example Construct a `VertexRDD` from a plain RDD: * {{{ * // Construct an initial vertex set - * val someData: RDD[(VertexID, SomeType)] = loadData(someFile) + * val someData: RDD[(VertexId, SomeType)] = loadData(someFile) * val vset = VertexRDD(someData) * // If there were redundant values in someData we would use a reduceFunc * val vset2 = VertexRDD(someData, reduceFunc) * // Finally we can use the VertexRDD to index another dataset - * val otherData: RDD[(VertexID, OtherType)] = loadData(otherFile) + * val otherData: RDD[(VertexId, OtherType)] = loadData(otherFile) * val vset3 = vset2.innerJoin(otherData) { (vid, a, b) => b } * // Now we can construct very fast joins between the two sets * val vset4: VertexRDD[(SomeType, OtherType)] = vset.leftJoin(vset3) @@ -51,7 +51,7 @@ import org.apache.spark.graphx.impl.VertexPartition */ class VertexRDD[@specialized VD: ClassTag]( val partitionsRDD: RDD[VertexPartition[VD]]) - extends RDD[(VertexID, VD)](partitionsRDD.context, List(new OneToOneDependency(partitionsRDD))) { + extends RDD[(VertexId, VD)](partitionsRDD.context, List(new OneToOneDependency(partitionsRDD))) { require(partitionsRDD.partitioner.isDefined) @@ -92,9 +92,9 @@ class VertexRDD[@specialized VD: ClassTag]( } /** - * Provides the `RDD[(VertexID, VD)]` equivalent output. + * Provides the `RDD[(VertexId, VD)]` equivalent output. */ - override def compute(part: Partition, context: TaskContext): Iterator[(VertexID, VD)] = { + override def compute(part: Partition, context: TaskContext): Iterator[(VertexId, VD)] = { firstParent[VertexPartition[VD]].iterator(part, context).next.iterator } @@ -114,9 +114,9 @@ class VertexRDD[@specialized VD: ClassTag]( * rather than allocating new memory. * * @param pred the user defined predicate, which takes a tuple to conform to the - * `RDD[(VertexID, VD)]` interface + * `RDD[(VertexId, VD)]` interface */ - override def filter(pred: Tuple2[VertexID, VD] => Boolean): VertexRDD[VD] = + override def filter(pred: Tuple2[VertexId, VD] => Boolean): VertexRDD[VD] = this.mapVertexPartitions(_.filter(Function.untupled(pred))) /** @@ -140,7 +140,7 @@ class VertexRDD[@specialized VD: ClassTag]( * @return a new VertexRDD with values obtained by applying `f` to each of the entries in the * original VertexRDD. The resulting VertexRDD retains the same index. */ - def mapValues[VD2: ClassTag](f: (VertexID, VD) => VD2): VertexRDD[VD2] = + def mapValues[VD2: ClassTag](f: (VertexId, VD) => VD2): VertexRDD[VD2] = this.mapVertexPartitions(_.map(f)) /** @@ -172,7 +172,7 @@ class VertexRDD[@specialized VD: ClassTag]( * @return a VertexRDD containing the results of `f` */ def leftZipJoin[VD2: ClassTag, VD3: ClassTag] - (other: VertexRDD[VD2])(f: (VertexID, VD, Option[VD2]) => VD3): VertexRDD[VD3] = { + (other: VertexRDD[VD2])(f: (VertexId, VD, Option[VD2]) => VD3): VertexRDD[VD3] = { val newPartitionsRDD = partitionsRDD.zipPartitions( other.partitionsRDD, preservesPartitioning = true ) { (thisIter, otherIter) => @@ -200,8 +200,8 @@ class VertexRDD[@specialized VD: ClassTag]( * by `f`. */ def leftJoin[VD2: ClassTag, VD3: ClassTag] - (other: RDD[(VertexID, VD2)]) - (f: (VertexID, VD, Option[VD2]) => VD3) + (other: RDD[(VertexId, VD2)]) + (f: (VertexId, VD, Option[VD2]) => VD3) : VertexRDD[VD3] = { // Test if the other vertex is a VertexRDD to choose the optimal join strategy. // If the other set is a VertexRDD then we use the much more efficient leftZipJoin @@ -225,7 +225,7 @@ class VertexRDD[@specialized VD: ClassTag]( * [[innerJoin]] for the behavior of the join. */ def innerZipJoin[U: ClassTag, VD2: ClassTag](other: VertexRDD[U]) - (f: (VertexID, VD, U) => VD2): VertexRDD[VD2] = { + (f: (VertexId, VD, U) => VD2): VertexRDD[VD2] = { val newPartitionsRDD = partitionsRDD.zipPartitions( other.partitionsRDD, preservesPartitioning = true ) { (thisIter, otherIter) => @@ -247,8 +247,8 @@ class VertexRDD[@specialized VD: ClassTag]( * @return a VertexRDD co-indexed with `this`, containing only vertices that appear in both `this` * and `other`, with values supplied by `f` */ - def innerJoin[U: ClassTag, VD2: ClassTag](other: RDD[(VertexID, U)]) - (f: (VertexID, VD, U) => VD2): VertexRDD[VD2] = { + def innerJoin[U: ClassTag, VD2: ClassTag](other: RDD[(VertexId, U)]) + (f: (VertexId, VD, U) => VD2): VertexRDD[VD2] = { // Test if the other vertex is a VertexRDD to choose the optimal join strategy. // If the other set is a VertexRDD then we use the much more efficient innerZipJoin other match { @@ -278,7 +278,7 @@ class VertexRDD[@specialized VD: ClassTag]( * messages. */ def aggregateUsingIndex[VD2: ClassTag]( - messages: RDD[(VertexID, VD2)], reduceFunc: (VD2, VD2) => VD2): VertexRDD[VD2] = { + messages: RDD[(VertexId, VD2)], reduceFunc: (VD2, VD2) => VD2): VertexRDD[VD2] = { val shuffled = MsgRDDFunctions.partitionForAggregation(messages, this.partitioner.get) val parts = partitionsRDD.zipPartitions(shuffled, true) { (thisIter, msgIter) => val vertexPartition: VertexPartition[VD] = thisIter.next() @@ -303,8 +303,8 @@ object VertexRDD { * * @param rdd the collection of vertex-attribute pairs */ - def apply[VD: ClassTag](rdd: RDD[(VertexID, VD)]): VertexRDD[VD] = { - val partitioned: RDD[(VertexID, VD)] = rdd.partitioner match { + def apply[VD: ClassTag](rdd: RDD[(VertexId, VD)]): VertexRDD[VD] = { + val partitioned: RDD[(VertexId, VD)] = rdd.partitioner match { case Some(p) => rdd case None => rdd.partitionBy(new HashPartitioner(rdd.partitions.size)) } @@ -323,8 +323,8 @@ object VertexRDD { * @param rdd the collection of vertex-attribute pairs * @param mergeFunc the associative, commutative merge function. */ - def apply[VD: ClassTag](rdd: RDD[(VertexID, VD)], mergeFunc: (VD, VD) => VD): VertexRDD[VD] = { - val partitioned: RDD[(VertexID, VD)] = rdd.partitioner match { + def apply[VD: ClassTag](rdd: RDD[(VertexId, VD)], mergeFunc: (VD, VD) => VD): VertexRDD[VD] = { + val partitioned: RDD[(VertexId, VD)] = rdd.partitioner match { case Some(p) => rdd case None => rdd.partitionBy(new HashPartitioner(rdd.partitions.size)) } @@ -338,7 +338,7 @@ object VertexRDD { * Constructs a VertexRDD from the vertex IDs in `vids`, taking attributes from `rdd` and using * `defaultVal` otherwise. */ - def apply[VD: ClassTag](vids: RDD[VertexID], rdd: RDD[(VertexID, VD)], defaultVal: VD) + def apply[VD: ClassTag](vids: RDD[VertexId], rdd: RDD[(VertexId, VD)], defaultVal: VD) : VertexRDD[VD] = { VertexRDD(vids.map(vid => (vid, defaultVal))).leftJoin(rdd) { (vid, default, value) => value.getOrElse(default) diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala index 6067ee8c7e0fb..57fa5eefd5e09 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartition.scala @@ -34,10 +34,10 @@ import org.apache.spark.graphx.util.collection.PrimitiveKeyOpenHashMap */ private[graphx] class EdgePartition[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) ED: ClassTag]( - val srcIds: Array[VertexID], - val dstIds: Array[VertexID], + val srcIds: Array[VertexId], + val dstIds: Array[VertexId], val data: Array[ED], - val index: PrimitiveKeyOpenHashMap[VertexID, Int]) extends Serializable { + val index: PrimitiveKeyOpenHashMap[VertexId, Int]) extends Serializable { /** * Reverse all the edges in this partition. @@ -118,8 +118,8 @@ class EdgePartition[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) */ def groupEdges(merge: (ED, ED) => ED): EdgePartition[ED] = { val builder = new EdgePartitionBuilder[ED] - var currSrcId: VertexID = null.asInstanceOf[VertexID] - var currDstId: VertexID = null.asInstanceOf[VertexID] + var currSrcId: VertexId = null.asInstanceOf[VertexId] + var currDstId: VertexId = null.asInstanceOf[VertexId] var currAttr: ED = null.asInstanceOf[ED] var i = 0 while (i < size) { @@ -153,7 +153,7 @@ class EdgePartition[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) */ def innerJoin[ED2: ClassTag, ED3: ClassTag] (other: EdgePartition[ED2]) - (f: (VertexID, VertexID, ED, ED2) => ED3): EdgePartition[ED3] = { + (f: (VertexId, VertexId, ED, ED2) => ED3): EdgePartition[ED3] = { val builder = new EdgePartitionBuilder[ED3] var i = 0 var j = 0 @@ -210,14 +210,14 @@ class EdgePartition[@specialized(Char, Int, Boolean, Byte, Long, Float, Double) * iterator is generated using an index scan, so it is efficient at skipping edges that don't * match srcIdPred. */ - def indexIterator(srcIdPred: VertexID => Boolean): Iterator[Edge[ED]] = + def indexIterator(srcIdPred: VertexId => Boolean): Iterator[Edge[ED]] = index.iterator.filter(kv => srcIdPred(kv._1)).flatMap(Function.tupled(clusterIterator)) /** * Get an iterator over the cluster of edges in this partition with source vertex id `srcId`. The * cluster must start at position `index`. */ - private def clusterIterator(srcId: VertexID, index: Int) = new Iterator[Edge[ED]] { + private def clusterIterator(srcId: VertexId, index: Int) = new Iterator[Edge[ED]] { private[this] val edge = new Edge[ED] private[this] var pos = index diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala index 960eeaccf1352..63ccccb056b48 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgePartitionBuilder.scala @@ -29,22 +29,22 @@ class EdgePartitionBuilder[@specialized(Long, Int, Double) ED: ClassTag](size: I var edges = new PrimitiveVector[Edge[ED]](size) /** Add a new edge to the partition. */ - def add(src: VertexID, dst: VertexID, d: ED) { + def add(src: VertexId, dst: VertexId, d: ED) { edges += Edge(src, dst, d) } def toEdgePartition: EdgePartition[ED] = { val edgeArray = edges.trim().array Sorting.quickSort(edgeArray)(Edge.lexicographicOrdering) - val srcIds = new Array[VertexID](edgeArray.size) - val dstIds = new Array[VertexID](edgeArray.size) + val srcIds = new Array[VertexId](edgeArray.size) + val dstIds = new Array[VertexId](edgeArray.size) val data = new Array[ED](edgeArray.size) - val index = new PrimitiveKeyOpenHashMap[VertexID, Int] + val index = new PrimitiveKeyOpenHashMap[VertexId, Int] // Copy edges into columnar structures, tracking the beginnings of source vertex id clusters and // adding them to the index if (edgeArray.length > 0) { index.update(srcIds(0), 0) - var currSrcId: VertexID = srcIds(0) + var currSrcId: VertexId = srcIds(0) var i = 0 while (i < edgeArray.size) { srcIds(i) = edgeArray(i).srcId diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala index 819e3ba93ac9b..886c250d7cffd 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/EdgeTripletIterator.scala @@ -41,7 +41,7 @@ class EdgeTripletIterator[VD: ClassTag, ED: ClassTag]( // allocating too many temporary Java objects. private val triplet = new EdgeTriplet[VD, ED] - private val vmap = new PrimitiveKeyOpenHashMap[VertexID, VD](vidToIndex, vertexArray) + private val vmap = new PrimitiveKeyOpenHashMap[VertexId, VD](vidToIndex, vertexArray) override def hasNext: Boolean = pos < edgePartition.size diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala index eee2d58c3d8e1..1d029bf009e8c 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/GraphImpl.scala @@ -105,7 +105,7 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( new GraphImpl(vertices, newETable, routingTable, replicatedVertexView) } - override def mapVertices[VD2: ClassTag](f: (VertexID, VD) => VD2): Graph[VD2, ED] = { + override def mapVertices[VD2: ClassTag](f: (VertexId, VD) => VD2): Graph[VD2, ED] = { if (classTag[VD] equals classTag[VD2]) { // The map preserves type, so we can use incremental replication val newVerts = vertices.mapVertexPartitions(_.map(f)).cache() @@ -153,7 +153,7 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( override def subgraph( epred: EdgeTriplet[VD, ED] => Boolean = x => true, - vpred: (VertexID, VD) => Boolean = (a, b) => true): Graph[VD, ED] = { + vpred: (VertexId, VD) => Boolean = (a, b) => true): Graph[VD, ED] = { // Filter the vertices, reusing the partitioner and the index from this graph val newVerts = vertices.mapVertexPartitions(_.filter(vpred)) @@ -195,7 +195,7 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( ////////////////////////////////////////////////////////////////////////////////////////////////// override def mapReduceTriplets[A: ClassTag]( - mapFunc: EdgeTriplet[VD, ED] => Iterator[(VertexID, A)], + mapFunc: EdgeTriplet[VD, ED] => Iterator[(VertexId, A)], reduceFunc: (A, A) => A, activeSetOpt: Option[(VertexRDD[_], EdgeDirection)] = None) = { @@ -225,7 +225,7 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( val edgeIter = activeDirectionOpt match { case Some(EdgeDirection.Both) => if (activeFraction < 0.8) { - edgePartition.indexIterator(srcVertexID => vPart.isActive(srcVertexID)) + edgePartition.indexIterator(srcVertexId => vPart.isActive(srcVertexId)) .filter(e => vPart.isActive(e.dstId)) } else { edgePartition.iterator.filter(e => vPart.isActive(e.srcId) && vPart.isActive(e.dstId)) @@ -236,7 +236,7 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( edgePartition.iterator.filter(e => vPart.isActive(e.srcId) || vPart.isActive(e.dstId)) case Some(EdgeDirection.Out) => if (activeFraction < 0.8) { - edgePartition.indexIterator(srcVertexID => vPart.isActive(srcVertexID)) + edgePartition.indexIterator(srcVertexId => vPart.isActive(srcVertexId)) } else { edgePartition.iterator.filter(e => vPart.isActive(e.srcId)) } @@ -267,8 +267,8 @@ class GraphImpl[VD: ClassTag, ED: ClassTag] protected ( } // end of mapReduceTriplets override def outerJoinVertices[U: ClassTag, VD2: ClassTag] - (other: RDD[(VertexID, U)]) - (updateF: (VertexID, VD, Option[U]) => VD2): Graph[VD2, ED] = + (other: RDD[(VertexId, U)]) + (updateF: (VertexId, VD, Option[U]) => VD2): Graph[VD2, ED] = { if (classTag[VD] equals classTag[VD2]) { // updateF preserves type, so we can use incremental replication @@ -312,7 +312,7 @@ object GraphImpl { } def apply[VD: ClassTag, ED: ClassTag]( - vertices: RDD[(VertexID, VD)], + vertices: RDD[(VertexId, VD)], edges: RDD[Edge[ED]], defaultVertexAttr: VD): GraphImpl[VD, ED] = { @@ -321,7 +321,7 @@ object GraphImpl { // Get the set of all vids val partitioner = Partitioner.defaultPartitioner(vertices) val vPartitioned = vertices.partitionBy(partitioner) - val vidsFromEdges = collectVertexIDsFromEdges(edgeRDD, partitioner) + val vidsFromEdges = collectVertexIdsFromEdges(edgeRDD, partitioner) val vids = vPartitioned.zipPartitions(vidsFromEdges) { (vertexIter, vidsFromEdgesIter) => vertexIter.map(_._1) ++ vidsFromEdgesIter.map(_._1) } @@ -355,7 +355,7 @@ object GraphImpl { /** * Create the edge RDD, which is much more efficient for Java heap storage than the normal edges - * data structure (RDD[(VertexID, VertexID, ED)]). + * data structure (RDD[(VertexId, VertexId, ED)]). * * The edge RDD contains multiple partitions, and each partition contains only one RDD key-value * pair: the key is the partition id, and the value is an EdgePartition object containing all the @@ -378,19 +378,19 @@ object GraphImpl { defaultVertexAttr: VD): GraphImpl[VD, ED] = { edges.cache() // Get the set of all vids - val vids = collectVertexIDsFromEdges(edges, new HashPartitioner(edges.partitions.size)) + val vids = collectVertexIdsFromEdges(edges, new HashPartitioner(edges.partitions.size)) // Create the VertexRDD. val vertices = VertexRDD(vids.mapValues(x => defaultVertexAttr)) GraphImpl(vertices, edges) } /** Collects all vids mentioned in edges and partitions them by partitioner. */ - private def collectVertexIDsFromEdges( + private def collectVertexIdsFromEdges( edges: EdgeRDD[_], - partitioner: Partitioner): RDD[(VertexID, Int)] = { + partitioner: Partitioner): RDD[(VertexId, Int)] = { // TODO: Consider doing map side distinct before shuffle. - new ShuffledRDD[VertexID, Int, (VertexID, Int)]( - edges.collectVertexIDs.map(vid => (vid, 0)), partitioner) - .setSerializer(classOf[VertexIDMsgSerializer].getName) + new ShuffledRDD[VertexId, Int, (VertexId, Int)]( + edges.collectVertexIds.map(vid => (vid, 0)), partitioner) + .setSerializer(classOf[VertexIdMsgSerializer].getName) } } // end of object GraphImpl diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala index cea9d11ebe8cd..e9ee09c3614c1 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/MessageToPartition.scala @@ -20,16 +20,16 @@ package org.apache.spark.graphx.impl import scala.reflect.{classTag, ClassTag} import org.apache.spark.Partitioner -import org.apache.spark.graphx.{PartitionID, VertexID} +import org.apache.spark.graphx.{PartitionID, VertexId} import org.apache.spark.rdd.{ShuffledRDD, RDD} private[graphx] class VertexBroadcastMsg[@specialized(Int, Long, Double, Boolean) T]( @transient var partition: PartitionID, - var vid: VertexID, + var vid: VertexId, var data: T) - extends Product2[PartitionID, (VertexID, T)] with Serializable { + extends Product2[PartitionID, (VertexId, T)] with Serializable { override def _1 = partition @@ -61,7 +61,7 @@ class MessageToPartition[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef private[graphx] class VertexBroadcastMsgRDDFunctions[T: ClassTag](self: RDD[VertexBroadcastMsg[T]]) { def partitionBy(partitioner: Partitioner): RDD[VertexBroadcastMsg[T]] = { - val rdd = new ShuffledRDD[PartitionID, (VertexID, T), VertexBroadcastMsg[T]](self, partitioner) + val rdd = new ShuffledRDD[PartitionID, (VertexId, T), VertexBroadcastMsg[T]](self, partitioner) // Set a custom serializer if the data is of int or double type. if (classTag[T] == ClassTag.Int) { @@ -99,8 +99,8 @@ object MsgRDDFunctions { new VertexBroadcastMsgRDDFunctions(rdd) } - def partitionForAggregation[T: ClassTag](msgs: RDD[(VertexID, T)], partitioner: Partitioner) = { - val rdd = new ShuffledRDD[VertexID, T, (VertexID, T)](msgs, partitioner) + def partitionForAggregation[T: ClassTag](msgs: RDD[(VertexId, T)], partitioner: Partitioner) = { + val rdd = new ShuffledRDD[VertexId, T, (VertexId, T)](msgs, partitioner) // Set a custom serializer if the data is of int or double type. if (classTag[T] == ClassTag.Int) { diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala index 5bdc9339e9fec..a8154b63ce5fb 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/ReplicatedVertexView.scala @@ -50,9 +50,9 @@ class ReplicatedVertexView[VD: ClassTag]( * vids from both the source and destination of edges. It must always include both source and * destination vids because some operations, such as GraphImpl.mapReduceTriplets, rely on this. */ - private val localVertexIDMap: RDD[(Int, VertexIdToIndexMap)] = prevViewOpt match { + private val localVertexIdMap: RDD[(Int, VertexIdToIndexMap)] = prevViewOpt match { case Some(prevView) => - prevView.localVertexIDMap + prevView.localVertexIdMap case None => edges.partitionsRDD.mapPartitions(_.map { case (pid, epart) => @@ -62,7 +62,7 @@ class ReplicatedVertexView[VD: ClassTag]( vidToIndex.add(e.dstId) } (pid, vidToIndex) - }, preservesPartitioning = true).cache().setName("ReplicatedVertexView localVertexIDMap") + }, preservesPartitioning = true).cache().setName("ReplicatedVertexView localVertexIdMap") } private lazy val bothAttrs: RDD[(PartitionID, VertexPartition[VD])] = create(true, true) @@ -75,7 +75,7 @@ class ReplicatedVertexView[VD: ClassTag]( srcAttrOnly.unpersist(blocking) dstAttrOnly.unpersist(blocking) noAttrs.unpersist(blocking) - // Don't unpersist localVertexIDMap because a future ReplicatedVertexView may be using it + // Don't unpersist localVertexIdMap because a future ReplicatedVertexView may be using it // without modification this } @@ -133,8 +133,8 @@ class ReplicatedVertexView[VD: ClassTag]( case None => // Within each edge partition, place the shipped vertex attributes into the correct - // locations specified in localVertexIDMap - localVertexIDMap.zipPartitions(shippedVerts) { (mapIter, shippedVertsIter) => + // locations specified in localVertexIdMap + localVertexIdMap.zipPartitions(shippedVerts) { (mapIter, shippedVertsIter) => val (pid, vidToIndex) = mapIter.next() assert(!mapIter.hasNext) // Populate the vertex array using the vidToIndex map @@ -157,15 +157,15 @@ class ReplicatedVertexView[VD: ClassTag]( private object ReplicatedVertexView { protected def buildBuffer[VD: ClassTag]( - pid2vidIter: Iterator[Array[Array[VertexID]]], + pid2vidIter: Iterator[Array[Array[VertexId]]], vertexPartIter: Iterator[VertexPartition[VD]]) = { - val pid2vid: Array[Array[VertexID]] = pid2vidIter.next() + val pid2vid: Array[Array[VertexId]] = pid2vidIter.next() val vertexPart: VertexPartition[VD] = vertexPartIter.next() Iterator.tabulate(pid2vid.size) { pid => val vidsCandidate = pid2vid(pid) val size = vidsCandidate.length - val vids = new PrimitiveVector[VertexID](pid2vid(pid).size) + val vids = new PrimitiveVector[VertexId](pid2vid(pid).size) val attrs = new PrimitiveVector[VD](pid2vid(pid).size) var i = 0 while (i < size) { @@ -181,16 +181,16 @@ private object ReplicatedVertexView { } protected def buildActiveBuffer( - pid2vidIter: Iterator[Array[Array[VertexID]]], + pid2vidIter: Iterator[Array[Array[VertexId]]], activePartIter: Iterator[VertexPartition[_]]) - : Iterator[(Int, Array[VertexID])] = { - val pid2vid: Array[Array[VertexID]] = pid2vidIter.next() + : Iterator[(Int, Array[VertexId])] = { + val pid2vid: Array[Array[VertexId]] = pid2vidIter.next() val activePart: VertexPartition[_] = activePartIter.next() Iterator.tabulate(pid2vid.size) { pid => val vidsCandidate = pid2vid(pid) val size = vidsCandidate.length - val actives = new PrimitiveVector[VertexID](vidsCandidate.size) + val actives = new PrimitiveVector[VertexId](vidsCandidate.size) var i = 0 while (i < size) { val vid = vidsCandidate(i) @@ -205,8 +205,8 @@ private object ReplicatedVertexView { } private[graphx] -class VertexAttributeBlock[VD: ClassTag](val vids: Array[VertexID], val attrs: Array[VD]) +class VertexAttributeBlock[VD: ClassTag](val vids: Array[VertexId], val attrs: Array[VD]) extends Serializable { - def iterator: Iterator[(VertexID, VD)] = + def iterator: Iterator[(VertexId, VD)] = (0 until vids.size).iterator.map { i => (vids(i), attrs(i)) } } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala index b365d4914e95b..fe44e1ee0c391 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/RoutingTable.scala @@ -32,12 +32,12 @@ import org.apache.spark.util.collection.PrimitiveVector private[impl] class RoutingTable(edges: EdgeRDD[_], vertices: VertexRDD[_]) { - val bothAttrs: RDD[Array[Array[VertexID]]] = createPid2Vid(true, true) - val srcAttrOnly: RDD[Array[Array[VertexID]]] = createPid2Vid(true, false) - val dstAttrOnly: RDD[Array[Array[VertexID]]] = createPid2Vid(false, true) - val noAttrs: RDD[Array[Array[VertexID]]] = createPid2Vid(false, false) + val bothAttrs: RDD[Array[Array[VertexId]]] = createPid2Vid(true, true) + val srcAttrOnly: RDD[Array[Array[VertexId]]] = createPid2Vid(true, false) + val dstAttrOnly: RDD[Array[Array[VertexId]]] = createPid2Vid(false, true) + val noAttrs: RDD[Array[Array[VertexId]]] = createPid2Vid(false, false) - def get(includeSrcAttr: Boolean, includeDstAttr: Boolean): RDD[Array[Array[VertexID]]] = + def get(includeSrcAttr: Boolean, includeDstAttr: Boolean): RDD[Array[Array[VertexId]]] = (includeSrcAttr, includeDstAttr) match { case (true, true) => bothAttrs case (true, false) => srcAttrOnly @@ -46,9 +46,9 @@ class RoutingTable(edges: EdgeRDD[_], vertices: VertexRDD[_]) { } private def createPid2Vid( - includeSrcAttr: Boolean, includeDstAttr: Boolean): RDD[Array[Array[VertexID]]] = { + includeSrcAttr: Boolean, includeDstAttr: Boolean): RDD[Array[Array[VertexId]]] = { // Determine which vertices each edge partition needs by creating a mapping from vid to pid. - val vid2pid: RDD[(VertexID, PartitionID)] = edges.partitionsRDD.mapPartitions { iter => + val vid2pid: RDD[(VertexId, PartitionID)] = edges.partitionsRDD.mapPartitions { iter => val (pid: PartitionID, edgePartition: EdgePartition[_]) = iter.next() val numEdges = edgePartition.size val vSet = new VertexSet @@ -71,7 +71,7 @@ class RoutingTable(edges: EdgeRDD[_], vertices: VertexRDD[_]) { val numPartitions = vertices.partitions.size vid2pid.partitionBy(vertices.partitioner.get).mapPartitions { iter => - val pid2vid = Array.fill(numPartitions)(new PrimitiveVector[VertexID]) + val pid2vid = Array.fill(numPartitions)(new PrimitiveVector[VertexId]) for ((vid, pid) <- iter) { pid2vid(pid) += vid } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala index bcad1fbc58802..c74d487e206db 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/Serializers.scala @@ -25,12 +25,12 @@ import org.apache.spark.graphx._ import org.apache.spark.serializer._ private[graphx] -class VertexIDMsgSerializer(conf: SparkConf) extends Serializer { +class VertexIdMsgSerializer(conf: SparkConf) extends Serializer { override def newInstance(): SerializerInstance = new ShuffleSerializerInstance { override def serializeStream(s: OutputStream) = new ShuffleSerializationStream(s) { def writeObject[T](t: T) = { - val msg = t.asInstanceOf[(VertexID, _)] + val msg = t.asInstanceOf[(VertexId, _)] writeVarLong(msg._1, optimizePositive = false) this } @@ -123,7 +123,7 @@ class IntAggMsgSerializer(conf: SparkConf) extends Serializer { override def serializeStream(s: OutputStream) = new ShuffleSerializationStream(s) { def writeObject[T](t: T) = { - val msg = t.asInstanceOf[(VertexID, Int)] + val msg = t.asInstanceOf[(VertexId, Int)] writeVarLong(msg._1, optimizePositive = false) writeUnsignedVarInt(msg._2) this @@ -147,7 +147,7 @@ class LongAggMsgSerializer(conf: SparkConf) extends Serializer { override def serializeStream(s: OutputStream) = new ShuffleSerializationStream(s) { def writeObject[T](t: T) = { - val msg = t.asInstanceOf[(VertexID, Long)] + val msg = t.asInstanceOf[(VertexId, Long)] writeVarLong(msg._1, optimizePositive = false) writeVarLong(msg._2, optimizePositive = true) this @@ -171,7 +171,7 @@ class DoubleAggMsgSerializer(conf: SparkConf) extends Serializer { override def serializeStream(s: OutputStream) = new ShuffleSerializationStream(s) { def writeObject[T](t: T) = { - val msg = t.asInstanceOf[(VertexID, Double)] + val msg = t.asInstanceOf[(VertexId, Double)] writeVarLong(msg._1, optimizePositive = false) writeDouble(msg._2) this diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala index f13bdded7564d..7a54b413dc8ca 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/VertexPartition.scala @@ -26,18 +26,18 @@ import org.apache.spark.util.collection.BitSet private[graphx] object VertexPartition { - def apply[VD: ClassTag](iter: Iterator[(VertexID, VD)]): VertexPartition[VD] = { - val map = new PrimitiveKeyOpenHashMap[VertexID, VD] + def apply[VD: ClassTag](iter: Iterator[(VertexId, VD)]): VertexPartition[VD] = { + val map = new PrimitiveKeyOpenHashMap[VertexId, VD] iter.foreach { case (k, v) => map(k) = v } new VertexPartition(map.keySet, map._values, map.keySet.getBitSet) } - def apply[VD: ClassTag](iter: Iterator[(VertexID, VD)], mergeFunc: (VD, VD) => VD) + def apply[VD: ClassTag](iter: Iterator[(VertexId, VD)], mergeFunc: (VD, VD) => VD) : VertexPartition[VD] = { - val map = new PrimitiveKeyOpenHashMap[VertexID, VD] + val map = new PrimitiveKeyOpenHashMap[VertexId, VD] iter.foreach { case (k, v) => map.setMerge(k, v, mergeFunc) } @@ -60,15 +60,15 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( def size: Int = mask.cardinality() /** Return the vertex attribute for the given vertex ID. */ - def apply(vid: VertexID): VD = values(index.getPos(vid)) + def apply(vid: VertexId): VD = values(index.getPos(vid)) - def isDefined(vid: VertexID): Boolean = { + def isDefined(vid: VertexId): Boolean = { val pos = index.getPos(vid) pos >= 0 && mask.get(pos) } /** Look up vid in activeSet, throwing an exception if it is None. */ - def isActive(vid: VertexID): Boolean = { + def isActive(vid: VertexId): Boolean = { activeSet.get.contains(vid) } @@ -88,7 +88,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( * each of the entries in the original VertexRDD. The resulting * VertexPartition retains the same index. */ - def map[VD2: ClassTag](f: (VertexID, VD) => VD2): VertexPartition[VD2] = { + def map[VD2: ClassTag](f: (VertexId, VD) => VD2): VertexPartition[VD2] = { // Construct a view of the map transformation val newValues = new Array[VD2](capacity) var i = mask.nextSetBit(0) @@ -108,7 +108,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( * RDD can be easily joined with the original vertex-set. Furthermore, the filter only * modifies the bitmap index and so no new values are allocated. */ - def filter(pred: (VertexID, VD) => Boolean): VertexPartition[VD] = { + def filter(pred: (VertexId, VD) => Boolean): VertexPartition[VD] = { // Allocate the array to store the results into val newMask = new BitSet(capacity) // Iterate over the active bits in the old mask and evaluate the predicate @@ -146,7 +146,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( /** Left outer join another VertexPartition. */ def leftJoin[VD2: ClassTag, VD3: ClassTag] (other: VertexPartition[VD2]) - (f: (VertexID, VD, Option[VD2]) => VD3): VertexPartition[VD3] = { + (f: (VertexId, VD, Option[VD2]) => VD3): VertexPartition[VD3] = { if (index != other.index) { logWarning("Joining two VertexPartitions with different indexes is slow.") leftJoin(createUsingIndex(other.iterator))(f) @@ -165,14 +165,14 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( /** Left outer join another iterator of messages. */ def leftJoin[VD2: ClassTag, VD3: ClassTag] - (other: Iterator[(VertexID, VD2)]) - (f: (VertexID, VD, Option[VD2]) => VD3): VertexPartition[VD3] = { + (other: Iterator[(VertexId, VD2)]) + (f: (VertexId, VD, Option[VD2]) => VD3): VertexPartition[VD3] = { leftJoin(createUsingIndex(other))(f) } /** Inner join another VertexPartition. */ def innerJoin[U: ClassTag, VD2: ClassTag](other: VertexPartition[U]) - (f: (VertexID, VD, U) => VD2): VertexPartition[VD2] = { + (f: (VertexId, VD, U) => VD2): VertexPartition[VD2] = { if (index != other.index) { logWarning("Joining two VertexPartitions with different indexes is slow.") innerJoin(createUsingIndex(other.iterator))(f) @@ -192,15 +192,15 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( * Inner join an iterator of messages. */ def innerJoin[U: ClassTag, VD2: ClassTag] - (iter: Iterator[Product2[VertexID, U]]) - (f: (VertexID, VD, U) => VD2): VertexPartition[VD2] = { + (iter: Iterator[Product2[VertexId, U]]) + (f: (VertexId, VD, U) => VD2): VertexPartition[VD2] = { innerJoin(createUsingIndex(iter))(f) } /** * Similar effect as aggregateUsingIndex((a, b) => a) */ - def createUsingIndex[VD2: ClassTag](iter: Iterator[Product2[VertexID, VD2]]) + def createUsingIndex[VD2: ClassTag](iter: Iterator[Product2[VertexId, VD2]]) : VertexPartition[VD2] = { val newMask = new BitSet(capacity) val newValues = new Array[VD2](capacity) @@ -218,7 +218,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( * Similar to innerJoin, but vertices from the left side that don't appear in iter will remain in * the partition, hidden by the bitmask. */ - def innerJoinKeepLeft(iter: Iterator[Product2[VertexID, VD]]): VertexPartition[VD] = { + def innerJoinKeepLeft(iter: Iterator[Product2[VertexId, VD]]): VertexPartition[VD] = { val newMask = new BitSet(capacity) val newValues = new Array[VD](capacity) System.arraycopy(values, 0, newValues, 0, newValues.length) @@ -233,7 +233,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( } def aggregateUsingIndex[VD2: ClassTag]( - iter: Iterator[Product2[VertexID, VD2]], + iter: Iterator[Product2[VertexId, VD2]], reduceFunc: (VD2, VD2) => VD2): VertexPartition[VD2] = { val newMask = new BitSet(capacity) val newValues = new Array[VD2](capacity) @@ -253,7 +253,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( new VertexPartition[VD2](index, newValues, newMask) } - def replaceActives(iter: Iterator[VertexID]): VertexPartition[VD] = { + def replaceActives(iter: Iterator[VertexId]): VertexPartition[VD] = { val newActiveSet = new VertexSet iter.foreach(newActiveSet.add(_)) new VertexPartition(index, values, mask, Some(newActiveSet)) @@ -263,7 +263,7 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( * Construct a new VertexPartition whose index contains only the vertices in the mask. */ def reindex(): VertexPartition[VD] = { - val hashMap = new PrimitiveKeyOpenHashMap[VertexID, VD] + val hashMap = new PrimitiveKeyOpenHashMap[VertexId, VD] val arbitraryMerge = (a: VD, b: VD) => a for ((k, v) <- this.iterator) { hashMap.setMerge(k, v, arbitraryMerge) @@ -271,8 +271,8 @@ class VertexPartition[@specialized(Long, Int, Double) VD: ClassTag]( new VertexPartition(hashMap.keySet, hashMap._values, hashMap.keySet.getBitSet) } - def iterator: Iterator[(VertexID, VD)] = + def iterator: Iterator[(VertexId, VD)] = mask.iterator.map(ind => (index.getValue(ind), values(ind))) - def vidIterator: Iterator[VertexID] = mask.iterator.map(ind => index.getValue(ind)) + def vidIterator: Iterator[VertexId] = mask.iterator.map(ind => index.getValue(ind)) } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala b/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala index f493d2dd01541..79549fe060457 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/impl/package.scala @@ -20,5 +20,5 @@ package org.apache.spark.graphx import org.apache.spark.util.collection.OpenHashSet package object impl { - private[graphx] type VertexIdToIndexMap = OpenHashSet[VertexID] + private[graphx] type VertexIdToIndexMap = OpenHashSet[VertexId] } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala index 2a6c0aa6b554c..e2f6cc138958e 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/ConnectedComponents.scala @@ -35,9 +35,9 @@ object ConnectedComponents { * @return a graph with vertex attributes containing the smallest vertex in each * connected component */ - def run[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]): Graph[VertexID, ED] = { + def run[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED]): Graph[VertexId, ED] = { val ccGraph = graph.mapVertices { case (vid, _) => vid } - def sendMessage(edge: EdgeTriplet[VertexID, ED]) = { + def sendMessage(edge: EdgeTriplet[VertexId, ED]) = { if (edge.srcAttr < edge.dstAttr) { Iterator((edge.dstId, edge.srcAttr)) } else if (edge.srcAttr > edge.dstAttr) { diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala index 2bdd8c9f985d7..614555a054dfb 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/PageRank.scala @@ -92,7 +92,7 @@ object PageRank extends Logging { // Define the three functions needed to implement PageRank in the GraphX // version of Pregel - def vertexProgram(id: VertexID, attr: Double, msgSum: Double): Double = + def vertexProgram(id: VertexId, attr: Double, msgSum: Double): Double = resetProb + (1.0 - resetProb) * msgSum def sendMessage(edge: EdgeTriplet[Double, Double]) = Iterator((edge.dstId, edge.srcAttr * edge.attr)) @@ -137,7 +137,7 @@ object PageRank extends Logging { // Define the three functions needed to implement PageRank in the GraphX // version of Pregel - def vertexProgram(id: VertexID, attr: (Double, Double), msgSum: Double): (Double, Double) = { + def vertexProgram(id: VertexId, attr: (Double, Double), msgSum: Double): (Double, Double) = { val (oldPR, lastDelta) = attr val newPR = oldPR + (1.0 - resetProb) * msgSum (newPR, newPR - oldPR) diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala index 9c7a212c5a3bb..c327ce7935147 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala @@ -79,13 +79,13 @@ object SVDPlusPlus { (g1: (Long, Double), g2: (Long, Double)) => (g1._1 + g2._1, g1._2 + g2._2)) g = g.outerJoinVertices(t0) { - (vid: VertexID, vd: (RealVector, RealVector, Double, Double), msg: Option[(Long, Double)]) => + (vid: VertexId, vd: (RealVector, RealVector, Double, Double), msg: Option[(Long, Double)]) => (vd._1, vd._2, msg.get._2 / msg.get._1, 1.0 / scala.math.sqrt(msg.get._1)) } def mapTrainF(conf: Conf, u: Double) (et: EdgeTriplet[(RealVector, RealVector, Double, Double), Double]) - : Iterator[(VertexID, (RealVector, RealVector, Double))] = { + : Iterator[(VertexId, (RealVector, RealVector, Double))] = { val (usr, itm) = (et.srcAttr, et.dstAttr) val (p, q) = (usr._1, itm._1) var pred = u + usr._3 + itm._3 + q.dotProduct(usr._2) @@ -112,7 +112,7 @@ object SVDPlusPlus { et => Iterator((et.srcId, et.dstAttr._2)), (g1: RealVector, g2: RealVector) => g1.add(g2)) g = g.outerJoinVertices(t1) { - (vid: VertexID, vd: (RealVector, RealVector, Double, Double), msg: Option[RealVector]) => + (vid: VertexId, vd: (RealVector, RealVector, Double, Double), msg: Option[RealVector]) => if (msg.isDefined) (vd._1, vd._1.add(msg.get.mapMultiply(vd._4)), vd._3, vd._4) else vd } @@ -123,7 +123,7 @@ object SVDPlusPlus { (g1: (RealVector, RealVector, Double), g2: (RealVector, RealVector, Double)) => (g1._1.add(g2._1), g1._2.add(g2._2), g1._3 + g2._3)) g = g.outerJoinVertices(t2) { - (vid: VertexID, + (vid: VertexId, vd: (RealVector, RealVector, Double, Double), msg: Option[(RealVector, RealVector, Double)]) => (vd._1.add(msg.get._1), vd._2.add(msg.get._2), vd._3 + msg.get._3, vd._4) @@ -133,7 +133,7 @@ object SVDPlusPlus { // calculate error on training set def mapTestF(conf: Conf, u: Double) (et: EdgeTriplet[(RealVector, RealVector, Double, Double), Double]) - : Iterator[(VertexID, Double)] = + : Iterator[(VertexId, Double)] = { val (usr, itm) = (et.srcAttr, et.dstAttr) val (p, q) = (usr._1, itm._1) @@ -146,7 +146,7 @@ object SVDPlusPlus { g.cache() val t3 = g.mapReduceTriplets(mapTestF(conf, u), (g1: Double, g2: Double) => g1 + g2) g = g.outerJoinVertices(t3) { - (vid: VertexID, vd: (RealVector, RealVector, Double, Double), msg: Option[Double]) => + (vid: VertexId, vd: (RealVector, RealVector, Double, Double), msg: Option[Double]) => if (msg.isDefined) (vd._1, vd._2, vd._3, msg.get) else vd } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala index ed84f72156a55..46da38eeb725a 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/StronglyConnectedComponents.scala @@ -35,7 +35,7 @@ object StronglyConnectedComponents { * * @return a graph with vertex attributes containing the smallest vertex id in each SCC */ - def run[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED], numIter: Int): Graph[VertexID, ED] = { + def run[VD: ClassTag, ED: ClassTag](graph: Graph[VD, ED], numIter: Int): Graph[VertexId, ED] = { // the graph we update with final SCC ids, and the graph we return at the end var sccGraph = graph.mapVertices { case (vid, _) => vid } @@ -71,7 +71,7 @@ object StronglyConnectedComponents { // collect min of all my neighbor's scc values, update if it's smaller than mine // then notify any neighbors with scc values larger than mine - sccWorkGraph = Pregel[(VertexID, Boolean), ED, VertexID]( + sccWorkGraph = Pregel[(VertexId, Boolean), ED, VertexId]( sccWorkGraph, Long.MaxValue, activeDirection = EdgeDirection.Out)( (vid, myScc, neighborScc) => (math.min(myScc._1, neighborScc), myScc._2), e => { @@ -85,7 +85,7 @@ object StronglyConnectedComponents { // start at root of SCCs. Traverse values in reverse, notify all my neighbors // do not propagate if colors do not match! - sccWorkGraph = Pregel[(VertexID, Boolean), ED, Boolean]( + sccWorkGraph = Pregel[(VertexId, Boolean), ED, Boolean]( sccWorkGraph, false, activeDirection = EdgeDirection.In)( // vertex is final if it is the root of a color // or it has the same color as a neighbor that is final diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala index a124c892dcba5..7c396e6e66a28 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/TriangleCount.scala @@ -61,7 +61,7 @@ object TriangleCount { (vid, _, optSet) => optSet.getOrElse(null) } // Edge function computes intersection of smaller vertex with larger vertex - def edgeFunc(et: EdgeTriplet[VertexSet, ED]): Iterator[(VertexID, Int)] = { + def edgeFunc(et: EdgeTriplet[VertexSet, ED]): Iterator[(VertexId, Int)] = { assert(et.srcAttr != null) assert(et.dstAttr != null) val (smallSet, largeSet) = if (et.srcAttr.size < et.dstAttr.size) { diff --git a/graphx/src/main/scala/org/apache/spark/graphx/package.scala b/graphx/src/main/scala/org/apache/spark/graphx/package.scala index e1ff3ea0d1d42..425a5164cad24 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/package.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/package.scala @@ -25,11 +25,11 @@ package object graphx { * A 64-bit vertex identifier that uniquely identifies a vertex within a graph. It does not need * to follow any ordering or any constraints other than uniqueness. */ - type VertexID = Long + type VertexId = Long /** Integer identifer of a graph partition. */ // TODO: Consider using Char. type PartitionID = Int - private[graphx] type VertexSet = OpenHashSet[VertexID] + private[graphx] type VertexSet = OpenHashSet[VertexId] } diff --git a/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala b/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala index 9805eb3285d69..7677641bfede6 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/util/GraphGenerators.scala @@ -50,7 +50,7 @@ object GraphGenerators { val mu = 4 val sigma = 1.3 - val vertices: RDD[(VertexID, Int)] = sc.parallelize(0 until numVertices).map{ + val vertices: RDD[(VertexId, Int)] = sc.parallelize(0 until numVertices).map{ src => (src, sampleLogNormal(mu, sigma, numVertices)) } val edges = vertices.flatMap { v => @@ -59,9 +59,9 @@ object GraphGenerators { Graph(vertices, edges, 0) } - def generateRandomEdges(src: Int, numEdges: Int, maxVertexID: Int): Array[Edge[Int]] = { + def generateRandomEdges(src: Int, numEdges: Int, maxVertexId: Int): Array[Edge[Int]] = { val rand = new Random() - Array.fill(maxVertexID) { Edge[Int](src, rand.nextInt(maxVertexID), 1) } + Array.fill(maxVertexId) { Edge[Int](src, rand.nextInt(maxVertexId), 1) } } /** @@ -206,9 +206,9 @@ object GraphGenerators { */ def gridGraph(sc: SparkContext, rows: Int, cols: Int): Graph[(Int,Int), Double] = { // Convert row column address into vertex ids (row major order) - def sub2ind(r: Int, c: Int): VertexID = r * cols + c + def sub2ind(r: Int, c: Int): VertexId = r * cols + c - val vertices: RDD[(VertexID, (Int,Int))] = + val vertices: RDD[(VertexId, (Int,Int))] = sc.parallelize(0 until rows).flatMap( r => (0 until cols).map( c => (sub2ind(r,c), (r,c)) ) ) val edges: RDD[Edge[Double]] = vertices.flatMap{ case (vid, (r,c)) => @@ -228,7 +228,7 @@ object GraphGenerators { * being the center vertex. */ def starGraph(sc: SparkContext, nverts: Int): Graph[Int, Int] = { - val edges: RDD[(VertexID, VertexID)] = sc.parallelize(1 until nverts).map(vid => (vid, 0)) + val edges: RDD[(VertexId, VertexId)] = sc.parallelize(1 until nverts).map(vid => (vid, 0)) Graph.fromEdgeTuples(edges, 1) } // end of starGraph diff --git a/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala index 4a792c0dabeac..bc2ad5677f806 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/GraphOpsSuite.scala @@ -28,12 +28,12 @@ class GraphOpsSuite extends FunSuite with LocalSparkContext { test("joinVertices") { withSpark { sc => val vertices = - sc.parallelize(Seq[(VertexID, String)]((1, "one"), (2, "two"), (3, "three")), 2) + sc.parallelize(Seq[(VertexId, String)]((1, "one"), (2, "two"), (3, "three")), 2) val edges = sc.parallelize((Seq(Edge(1, 2, "onetwo")))) val g: Graph[String, String] = Graph(vertices, edges) - val tbl = sc.parallelize(Seq[(VertexID, Int)]((1, 10), (2, 20))) - val g1 = g.joinVertices(tbl) { (vid: VertexID, attr: String, u: Int) => attr + u } + val tbl = sc.parallelize(Seq[(VertexId, Int)]((1, 10), (2, 20))) + val g1 = g.joinVertices(tbl) { (vid: VertexId, attr: String, u: Int) => attr + u } val v = g1.vertices.collect().toSet assert(v === Set((1, "one10"), (2, "two20"), (3, "three"))) @@ -60,7 +60,7 @@ class GraphOpsSuite extends FunSuite with LocalSparkContext { test ("filter") { withSpark { sc => val n = 5 - val vertices = sc.parallelize((0 to n).map(x => (x:VertexID, x))) + val vertices = sc.parallelize((0 to n).map(x => (x:VertexId, x))) val edges = sc.parallelize((1 to n).map(x => Edge(0, x, x))) val graph: Graph[Int, Int] = Graph(vertices, edges).cache() val filteredGraph = graph.filter( @@ -68,7 +68,7 @@ class GraphOpsSuite extends FunSuite with LocalSparkContext { val degrees: VertexRDD[Int] = graph.outDegrees graph.outerJoinVertices(degrees) {(vid, data, deg) => deg.getOrElse(0)} }, - vpred = (vid: VertexID, deg:Int) => deg > 0 + vpred = (vid: VertexId, deg:Int) => deg > 0 ).cache() val v = filteredGraph.vertices.collect().toSet diff --git a/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala index b18bc98e6d579..28d34dd9a1a41 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/GraphSuite.scala @@ -27,7 +27,7 @@ import org.apache.spark.rdd._ class GraphSuite extends FunSuite with LocalSparkContext { def starGraph(sc: SparkContext, n: Int): Graph[String, Int] = { - Graph.fromEdgeTuples(sc.parallelize((1 to n).map(x => (0: VertexID, x: VertexID)), 3), "v") + Graph.fromEdgeTuples(sc.parallelize((1 to n).map(x => (0: VertexId, x: VertexId)), 3), "v") } test("Graph.fromEdgeTuples") { @@ -57,7 +57,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { withSpark { sc => val rawEdges = (0L to 98L).zip((1L to 99L) :+ 0L) val edges: RDD[Edge[Int]] = sc.parallelize(rawEdges).map { case (s, t) => Edge(s, t, 1) } - val vertices: RDD[(VertexID, Boolean)] = sc.parallelize((0L until 10L).map(id => (id, true))) + val vertices: RDD[(VertexId, Boolean)] = sc.parallelize((0L until 10L).map(id => (id, true))) val graph = Graph(vertices, edges, false) assert( graph.edges.count() === rawEdges.size ) // Vertices not explicitly provided but referenced by edges should be created automatically @@ -74,7 +74,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { val n = 5 val star = starGraph(sc, n) assert(star.triplets.map(et => (et.srcId, et.dstId, et.srcAttr, et.dstAttr)).collect.toSet === - (1 to n).map(x => (0: VertexID, x: VertexID, "v", "v")).toSet) + (1 to n).map(x => (0: VertexId, x: VertexId, "v", "v")).toSet) } } @@ -110,7 +110,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { val p = 100 val verts = 1 to n val graph = Graph.fromEdgeTuples(sc.parallelize(verts.flatMap(x => - verts.filter(y => y % x == 0).map(y => (x: VertexID, y: VertexID))), p), 0) + verts.filter(y => y % x == 0).map(y => (x: VertexId, y: VertexId))), p), 0) assert(graph.edges.partitions.length === p) val partitionedGraph = graph.partitionBy(EdgePartition2D) assert(graph.edges.partitions.length === p) @@ -136,10 +136,10 @@ class GraphSuite extends FunSuite with LocalSparkContext { val star = starGraph(sc, n) // mapVertices preserving type val mappedVAttrs = star.mapVertices((vid, attr) => attr + "2") - assert(mappedVAttrs.vertices.collect.toSet === (0 to n).map(x => (x: VertexID, "v2")).toSet) + assert(mappedVAttrs.vertices.collect.toSet === (0 to n).map(x => (x: VertexId, "v2")).toSet) // mapVertices changing type val mappedVAttrs2 = star.mapVertices((vid, attr) => attr.length) - assert(mappedVAttrs2.vertices.collect.toSet === (0 to n).map(x => (x: VertexID, 1)).toSet) + assert(mappedVAttrs2.vertices.collect.toSet === (0 to n).map(x => (x: VertexId, 1)).toSet) } } @@ -168,7 +168,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { withSpark { sc => val n = 5 val star = starGraph(sc, n) - assert(star.reverse.outDegrees.collect.toSet === (1 to n).map(x => (x: VertexID, 1)).toSet) + assert(star.reverse.outDegrees.collect.toSet === (1 to n).map(x => (x: VertexId, 1)).toSet) } } @@ -191,7 +191,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { test("mask") { withSpark { sc => val n = 5 - val vertices = sc.parallelize((0 to n).map(x => (x:VertexID, x))) + val vertices = sc.parallelize((0 to n).map(x => (x:VertexId, x))) val edges = sc.parallelize((1 to n).map(x => Edge(0, x, x))) val graph: Graph[Int, Int] = Graph(vertices, edges).cache() @@ -218,7 +218,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { val star = starGraph(sc, n) val doubleStar = Graph.fromEdgeTuples( sc.parallelize((1 to n).flatMap(x => - List((0: VertexID, x: VertexID), (0: VertexID, x: VertexID))), 1), "v") + List((0: VertexId, x: VertexId), (0: VertexId, x: VertexId))), 1), "v") val star2 = doubleStar.groupEdges { (a, b) => a} assert(star2.edges.collect.toArray.sorted(Edge.lexicographicOrdering[Int]) === star.edges.collect.toArray.sorted(Edge.lexicographicOrdering[Int])) @@ -237,7 +237,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { assert(neighborDegreeSums.collect().toSet === (0 to n).map(x => (x, n)).toSet) // activeSetOpt - val allPairs = for (x <- 1 to n; y <- 1 to n) yield (x: VertexID, y: VertexID) + val allPairs = for (x <- 1 to n; y <- 1 to n) yield (x: VertexId, y: VertexId) val complete = Graph.fromEdgeTuples(sc.parallelize(allPairs, 3), 0) val vids = complete.mapVertices((vid, attr) => vid).cache() val active = vids.vertices.filter { case (vid, attr) => attr % 2 == 0 } @@ -248,10 +248,10 @@ class GraphSuite extends FunSuite with LocalSparkContext { } Iterator((et.srcId, 1)) }, (a: Int, b: Int) => a + b, Some((active, EdgeDirection.In))).collect.toSet - assert(numEvenNeighbors === (1 to n).map(x => (x: VertexID, n / 2)).toSet) + assert(numEvenNeighbors === (1 to n).map(x => (x: VertexId, n / 2)).toSet) // outerJoinVertices followed by mapReduceTriplets(activeSetOpt) - val ringEdges = sc.parallelize((0 until n).map(x => (x: VertexID, (x+1) % n: VertexID)), 3) + val ringEdges = sc.parallelize((0 until n).map(x => (x: VertexId, (x+1) % n: VertexId)), 3) val ring = Graph.fromEdgeTuples(ringEdges, 0) .mapVertices((vid, attr) => vid).cache() val changed = ring.vertices.filter { case (vid, attr) => attr % 2 == 1 }.mapValues(-_).cache() val changedGraph = ring.outerJoinVertices(changed) { (vid, old, newOpt) => newOpt.getOrElse(old) } @@ -262,7 +262,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { } Iterator((et.dstId, 1)) }, (a: Int, b: Int) => a + b, Some(changed, EdgeDirection.Out)).collect.toSet - assert(numOddNeighbors === (2 to n by 2).map(x => (x: VertexID, 1)).toSet) + assert(numOddNeighbors === (2 to n by 2).map(x => (x: VertexId, 1)).toSet) } } @@ -277,7 +277,7 @@ class GraphSuite extends FunSuite with LocalSparkContext { val neighborDegreeSums = reverseStarDegrees.mapReduceTriplets( et => Iterator((et.srcId, et.dstAttr), (et.dstId, et.srcAttr)), (a: Int, b: Int) => a + b).collect.toSet - assert(neighborDegreeSums === Set((0: VertexID, n)) ++ (1 to n).map(x => (x: VertexID, 0))) + assert(neighborDegreeSums === Set((0: VertexId, n)) ++ (1 to n).map(x => (x: VertexId, 0))) // outerJoinVertices preserving type val messages = reverseStar.vertices.mapValues { (vid, attr) => vid.toString } val newReverseStar = diff --git a/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala index 936e5c9c86fb7..490b94429ea1f 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/PregelSuite.scala @@ -27,7 +27,7 @@ class PregelSuite extends FunSuite with LocalSparkContext { test("1 iteration") { withSpark { sc => val n = 5 - val starEdges = (1 to n).map(x => (0: VertexID, x: VertexID)) + val starEdges = (1 to n).map(x => (0: VertexId, x: VertexId)) val star = Graph.fromEdgeTuples(sc.parallelize(starEdges, 3), "v").cache() val result = Pregel(star, 0)( (vid, attr, msg) => attr, @@ -41,12 +41,12 @@ class PregelSuite extends FunSuite with LocalSparkContext { withSpark { sc => val n = 5 val chain = Graph.fromEdgeTuples( - sc.parallelize((1 until n).map(x => (x: VertexID, x + 1: VertexID)), 3), + sc.parallelize((1 until n).map(x => (x: VertexId, x + 1: VertexId)), 3), 0).cache() - assert(chain.vertices.collect.toSet === (1 to n).map(x => (x: VertexID, 0)).toSet) + assert(chain.vertices.collect.toSet === (1 to n).map(x => (x: VertexId, 0)).toSet) val chainWithSeed = chain.mapVertices { (vid, attr) => if (vid == 1) 1 else 0 }.cache() assert(chainWithSeed.vertices.collect.toSet === - Set((1: VertexID, 1)) ++ (2 to n).map(x => (x: VertexID, 0)).toSet) + Set((1: VertexId, 1)) ++ (2 to n).map(x => (x: VertexId, 0)).toSet) val result = Pregel(chainWithSeed, 0)( (vid, attr, msg) => math.max(msg, attr), et => if (et.dstAttr != et.srcAttr) Iterator((et.dstId, et.srcAttr)) else Iterator.empty, diff --git a/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala index 0c756400f4eff..e5a582b47ba05 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/SerializerSuite.scala @@ -99,7 +99,7 @@ class SerializerSuite extends FunSuite with LocalSparkContext { test("IntAggMsgSerializer") { val conf = new SparkConf(false) - val outMsg = (4: VertexID, 5) + val outMsg = (4: VertexId, 5) val bout = new ByteArrayOutputStream val outStrm = new IntAggMsgSerializer(conf).newInstance().serializeStream(bout) outStrm.writeObject(outMsg) @@ -107,8 +107,8 @@ class SerializerSuite extends FunSuite with LocalSparkContext { bout.flush() val bin = new ByteArrayInputStream(bout.toByteArray) val inStrm = new IntAggMsgSerializer(conf).newInstance().deserializeStream(bin) - val inMsg1: (VertexID, Int) = inStrm.readObject() - val inMsg2: (VertexID, Int) = inStrm.readObject() + val inMsg1: (VertexId, Int) = inStrm.readObject() + val inMsg2: (VertexId, Int) = inStrm.readObject() assert(outMsg === inMsg1) assert(outMsg === inMsg2) @@ -119,7 +119,7 @@ class SerializerSuite extends FunSuite with LocalSparkContext { test("LongAggMsgSerializer") { val conf = new SparkConf(false) - val outMsg = (4: VertexID, 1L << 32) + val outMsg = (4: VertexId, 1L << 32) val bout = new ByteArrayOutputStream val outStrm = new LongAggMsgSerializer(conf).newInstance().serializeStream(bout) outStrm.writeObject(outMsg) @@ -127,8 +127,8 @@ class SerializerSuite extends FunSuite with LocalSparkContext { bout.flush() val bin = new ByteArrayInputStream(bout.toByteArray) val inStrm = new LongAggMsgSerializer(conf).newInstance().deserializeStream(bin) - val inMsg1: (VertexID, Long) = inStrm.readObject() - val inMsg2: (VertexID, Long) = inStrm.readObject() + val inMsg1: (VertexId, Long) = inStrm.readObject() + val inMsg2: (VertexId, Long) = inStrm.readObject() assert(outMsg === inMsg1) assert(outMsg === inMsg2) @@ -139,7 +139,7 @@ class SerializerSuite extends FunSuite with LocalSparkContext { test("DoubleAggMsgSerializer") { val conf = new SparkConf(false) - val outMsg = (4: VertexID, 5.0) + val outMsg = (4: VertexId, 5.0) val bout = new ByteArrayOutputStream val outStrm = new DoubleAggMsgSerializer(conf).newInstance().serializeStream(bout) outStrm.writeObject(outMsg) @@ -147,8 +147,8 @@ class SerializerSuite extends FunSuite with LocalSparkContext { bout.flush() val bin = new ByteArrayInputStream(bout.toByteArray) val inStrm = new DoubleAggMsgSerializer(conf).newInstance().deserializeStream(bin) - val inMsg1: (VertexID, Double) = inStrm.readObject() - val inMsg2: (VertexID, Double) = inStrm.readObject() + val inMsg1: (VertexId, Double) = inStrm.readObject() + val inMsg2: (VertexId, Double) = inStrm.readObject() assert(outMsg === inMsg1) assert(outMsg === inMsg2) diff --git a/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala index 1195beba5873c..e135d1d7ad6a3 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/impl/EdgePartitionSuite.scala @@ -79,7 +79,7 @@ class EdgePartitionSuite extends FunSuite { test("innerJoin") { def makeEdgePartition[A: ClassTag](xs: Iterable[(Int, Int, A)]): EdgePartition[A] = { val builder = new EdgePartitionBuilder[A] - for ((src, dst, attr) <- xs) { builder.add(src: VertexID, dst: VertexID, attr) } + for ((src, dst, attr) <- xs) { builder.add(src: VertexId, dst: VertexId, attr) } builder.toEdgePartition } val aList = List((0, 1, 0), (1, 0, 0), (1, 2, 0), (5, 4, 0), (5, 5, 0)) diff --git a/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala b/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala index eba8d7b716284..3915be15b3434 100644 --- a/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala +++ b/graphx/src/test/scala/org/apache/spark/graphx/lib/ConnectedComponentsSuite.scala @@ -100,7 +100,7 @@ class ConnectedComponentsSuite extends FunSuite with LocalSparkContext { test("Connected Components on a Toy Connected Graph") { withSpark { sc => // Create an RDD for the vertices - val users: RDD[(VertexID, (String, String))] = + val users: RDD[(VertexId, (String, String))] = sc.parallelize(Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")), (5L, ("franklin", "prof")), (2L, ("istoica", "prof")), (4L, ("peter", "student")))) From e12c374d223c67f57ac2ec4af55a9e413272dd10 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 10:00:50 -0800 Subject: [PATCH 017/133] Merge pull request #433 from markhamstra/debFix Updated Debian packaging (cherry picked from commit 494d3c077496735e6ebca3217de4f0cc6b6419f2) Signed-off-by: Patrick Wendell --- assembly/pom.xml | 116 ++++++++++- assembly/src/deb/RELEASE | 2 + .../src/deb/control/control | 0 docs/building-with-maven.md | 6 +- pom.xml | 10 - repl-bin/pom.xml | 184 ------------------ repl-bin/src/deb/bin/run | 57 ------ repl-bin/src/deb/bin/spark-executor | 22 --- repl-bin/src/deb/bin/spark-shell | 21 -- 9 files changed, 120 insertions(+), 298 deletions(-) create mode 100644 assembly/src/deb/RELEASE rename {repl-bin => assembly}/src/deb/control/control (100%) delete mode 100644 repl-bin/pom.xml delete mode 100755 repl-bin/src/deb/bin/run delete mode 100755 repl-bin/src/deb/bin/spark-executor delete mode 100755 repl-bin/src/deb/bin/spark-shell diff --git a/assembly/pom.xml b/assembly/pom.xml index 54a25910ced7d..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -30,6 +30,13 @@ Spark Project Assembly http://spark.incubator.apache.org/ + + ${project.build.directory}/scala-${scala.binary.version}/${project.artifactId}-${project.version}-hadoop${hadoop.version}.jar + spark + /usr/share/spark + root + + @@ -79,7 +86,7 @@ maven-shade-plugin false - ${project.build.directory}/scala-${scala.binary.version}/${project.artifactId}-${project.version}-hadoop${hadoop.version}.jar + ${spark.jar} *:* @@ -171,5 +178,112 @@
+ + deb + + + + org.codehaus.mojo + buildnumber-maven-plugin + 1.1 + + + validate + + create + + + 8 + + + + + + org.vafer + jdeb + 0.11 + + + package + + jdeb + + + ${project.build.directory}/${deb.pkg.name}_${project.version}-${buildNumber}_all.deb + false + gzip + + + ${spark.jar} + file + + perm + ${deb.user} + ${deb.user} + ${deb.install.path}/jars + + + + ${basedir}/src/deb/RELEASE + file + + perm + ${deb.user} + ${deb.user} + ${deb.install.path} + + + + ${basedir}/../conf + directory + + perm + ${deb.user} + ${deb.user} + ${deb.install.path}/conf + 744 + + + + ${basedir}/../bin + directory + + perm + ${deb.user} + ${deb.user} + ${deb.install.path}/bin + 744 + + + + ${basedir}/../sbin + directory + + perm + ${deb.user} + ${deb.user} + ${deb.install.path}/sbin + 744 + + + + ${basedir}/../python + directory + + perm + ${deb.user} + ${deb.user} + ${deb.install.path}/python + 744 + + + + + + + + + +
diff --git a/assembly/src/deb/RELEASE b/assembly/src/deb/RELEASE new file mode 100644 index 0000000000000..aad50ee73aa45 --- /dev/null +++ b/assembly/src/deb/RELEASE @@ -0,0 +1,2 @@ +compute-classpath.sh uses the existence of this file to decide whether to put the assembly jar on the +classpath or instead to use classfiles in the source tree. \ No newline at end of file diff --git a/repl-bin/src/deb/control/control b/assembly/src/deb/control/control similarity index 100% rename from repl-bin/src/deb/control/control rename to assembly/src/deb/control/control diff --git a/docs/building-with-maven.md b/docs/building-with-maven.md index b9ff0af76f647..6a9a8d681742f 100644 --- a/docs/building-with-maven.md +++ b/docs/building-with-maven.md @@ -71,8 +71,8 @@ This setup works fine in IntelliJ IDEA 11.1.4. After opening the project via the ## Building Spark Debian Packages ## -It includes support for building a Debian package containing a 'fat-jar' which includes the repl, the examples and bagel. This can be created by specifying the following profiles: +The maven build includes support for building a Debian package containing the assembly 'fat-jar', PySpark, and the necessary scripts and configuration files. This can be created by specifying the following: - $ mvn -Prepl-bin -Pdeb clean package + $ mvn -Pdeb -DskipTests clean package -The debian package can then be found under repl/target. We added the short commit hash to the file name so that we can distinguish individual packages build for SNAPSHOT versions. +The debian package can then be found under assembly/target. We added the short commit hash to the file name so that we can distinguish individual packages built for SNAPSHOT versions. diff --git a/pom.xml b/pom.xml index f14d9667ccc7d..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -762,15 +762,5 @@ - - - repl-bin - - false - - - repl-bin - - diff --git a/repl-bin/pom.xml b/repl-bin/pom.xml deleted file mode 100644 index 869dbdb9b095a..0000000000000 --- a/repl-bin/pom.xml +++ /dev/null @@ -1,184 +0,0 @@ - - - - - 4.0.0 - - org.apache.spark - spark-parent - 0.9.0-incubating-SNAPSHOT - ../pom.xml - - - org.apache.spark - spark-repl-bin_2.10 - pom - Spark Project REPL binary packaging - http://spark.incubator.apache.org/ - - - spark - /usr/share/spark - root - - - - - org.apache.spark - spark-core_${scala.binary.version} - ${project.version} - - - org.apache.spark - spark-bagel_${scala.binary.version} - ${project.version} - runtime - - - org.apache.spark - spark-repl_${scala.binary.version} - ${project.version} - runtime - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - false - ${project.build.directory}/${project.artifactId}-${project.version}-shaded.jar - - - *:* - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - package - - shade - - - - - - reference.conf - - - spark.repl.Main - - - - - - - - - - - - deb - - - - org.codehaus.mojo - buildnumber-maven-plugin - 1.1 - - - validate - - create - - - 8 - - - - - - org.vafer - jdeb - 0.11 - - - package - - jdeb - - - ${project.build.directory}/${deb.pkg.name}_${project.version}-${buildNumber}_all.deb - false - gzip - - - ${project.build.directory}/${project.artifactId}-${project.version}-shaded.jar - file - - perm - ${deb.user} - ${deb.user} - ${deb.install.path} - - - - ${basedir}/src/deb/bin - directory - - perm - ${deb.user} - ${deb.user} - ${deb.install.path} - 744 - - - - ${basedir}/../conf - directory - - perm - ${deb.user} - ${deb.user} - ${deb.install.path}/conf - 744 - - - - - - - - - - - - diff --git a/repl-bin/src/deb/bin/run b/repl-bin/src/deb/bin/run deleted file mode 100755 index 3a6f22f41fca5..0000000000000 --- a/repl-bin/src/deb/bin/run +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -SCALA_VERSION=2.10 - -# Figure out where the Scala framework is installed -FWDIR="$(cd `dirname $0`; pwd)" - -# Export this as SPARK_HOME -export SPARK_HOME="$FWDIR" - -# Load environment variables from conf/spark-env.sh, if it exists -if [ -e $FWDIR/conf/spark-env.sh ] ; then - . $FWDIR/conf/spark-env.sh -fi - -# Figure out how much memory to use per executor and set it as an environment -# variable so that our process sees it and can report it to Mesos -if [ -z "$SPARK_MEM" ] ; then - SPARK_MEM="512m" -fi -export SPARK_MEM - -# Set JAVA_OPTS to be able to load native libraries and to set heap size -JAVA_OPTS="$SPARK_JAVA_OPTS" -JAVA_OPTS+=" -Djava.library.path=$SPARK_LIBRARY_PATH" -JAVA_OPTS+=" -Xms$SPARK_MEM -Xmx$SPARK_MEM" -# Load extra JAVA_OPTS from conf/java-opts, if it exists -if [ -e $FWDIR/conf/java-opts ] ; then - JAVA_OPTS+=" `cat $FWDIR/conf/java-opts`" -fi -export JAVA_OPTS - -# Build up classpath -CLASSPATH=":$FWDIR/conf" -for jar in `find $FWDIR -name '*jar'`; do - CLASSPATH+=":$jar" -done -export CLASSPATH - -exec java -Dscala.usejavacp=true -Djline.shutdownhook=true -cp "$CLASSPATH" $JAVA_OPTS $EXTRA_ARGS "$@" diff --git a/repl-bin/src/deb/bin/spark-executor b/repl-bin/src/deb/bin/spark-executor deleted file mode 100755 index 052d76fb8d81c..0000000000000 --- a/repl-bin/src/deb/bin/spark-executor +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -FWDIR="$(cd `dirname $0`; pwd)" -echo "Running spark-executor with framework dir = $FWDIR" -exec $FWDIR/run org.apache.spark.executor.MesosExecutorBackend diff --git a/repl-bin/src/deb/bin/spark-shell b/repl-bin/src/deb/bin/spark-shell deleted file mode 100755 index 118349d7c30f2..0000000000000 --- a/repl-bin/src/deb/bin/spark-shell +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -# -# 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. -# - -FWDIR="$(cd `dirname $0`; pwd)" -exec $FWDIR/run org.apache.spark.repl.Main "$@" From aca40aae87179b248da7d96290d19d4c59c01558 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 11:15:07 -0800 Subject: [PATCH 018/133] Merge pull request #441 from pwendell/graphx-build GraphX shouldn't list Spark as provided. I noticed this when building an application against GraphX to audit the released artifacts. (cherry picked from commit 5fecd2516dc8de28b76fe6e0fbdca7922cc28d1c) Signed-off-by: Patrick Wendell --- graphx/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/graphx/pom.xml b/graphx/pom.xml index 3e5faf230dbc9..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -36,7 +36,6 @@ org.apache.spark spark-core_${scala.binary.version} ${project.version} - provided
org.eclipse.jetty From 29c76d96b2489823a7ad4781129b707c73108bf8 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 13:54:45 -0800 Subject: [PATCH 019/133] Merge pull request #443 from tdas/filestream-fix Made some classes private[stremaing] and deprecated a method in JavaStreamingContext. Classes `RawTextHelper`, `RawTextSender` and `RateLimitedOutputStream` are not useful in the streaming API. There are not used by the core functionality and was there as a support classes for an obscure example. One of the classes is RawTextSender has a main function which can be executed using bin/spark-class even if it is made private[streaming]. In future, I will probably completely remove these classes. For the time being, I am just converting them to private[streaming]. Accessing underlying JavaSparkContext in JavaStreamingContext was through `JavaStreamingContext.sc` . This is deprecated and preferred method is `JavaStreamingContext.sparkContext` to keep it consistent with the `StreamingContext.sparkContext`. (cherry picked from commit 2a05403a7ced4ecf6084c96f582ee3a24f3cc874) Signed-off-by: Patrick Wendell --- .../spark/streaming/api/java/JavaStreamingContext.scala | 6 +++++- .../spark/streaming/util/RateLimitedOutputStream.scala | 1 + .../org/apache/spark/streaming/util/RawTextHelper.scala | 1 + .../org/apache/spark/streaming/util/RawTextSender.scala | 1 + .../test/java/org/apache/spark/streaming/JavaAPISuite.java | 6 +++--- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala index 4edf8fa13a205..613683ca40501 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala @@ -141,8 +141,12 @@ class JavaStreamingContext(val ssc: StreamingContext) { */ def this(path: String, hadoopConf: Configuration) = this(new StreamingContext(path, hadoopConf)) + + @deprecated("use sparkContext", "0.9.0") + val sc: JavaSparkContext = sparkContext + /** The underlying SparkContext */ - val sc: JavaSparkContext = new JavaSparkContext(ssc.sc) + val sparkContext = new JavaSparkContext(ssc.sc) /** * Create a input stream from network source hostname:port. Data is received using diff --git a/streaming/src/main/scala/org/apache/spark/streaming/util/RateLimitedOutputStream.scala b/streaming/src/main/scala/org/apache/spark/streaming/util/RateLimitedOutputStream.scala index b9c0596378b4f..179fd7593982c 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/util/RateLimitedOutputStream.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/util/RateLimitedOutputStream.scala @@ -22,6 +22,7 @@ import scala.annotation.tailrec import java.io.OutputStream import java.util.concurrent.TimeUnit._ +private[streaming] class RateLimitedOutputStream(out: OutputStream, bytesPerSec: Int) extends OutputStream { val SYNC_INTERVAL = NANOSECONDS.convert(10, SECONDS) val CHUNK_SIZE = 8192 diff --git a/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextHelper.scala b/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextHelper.scala index 5b6c048a39620..07021ebb5802a 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextHelper.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextHelper.scala @@ -22,6 +22,7 @@ import org.apache.spark.SparkContext._ import it.unimi.dsi.fastutil.objects.{Object2LongOpenHashMap => OLMap} import scala.collection.JavaConversions.mapAsScalaMap +private[streaming] object RawTextHelper { /** diff --git a/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextSender.scala b/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextSender.scala index 463617a713b22..684b38e8b3102 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextSender.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/util/RawTextSender.scala @@ -33,6 +33,7 @@ import org.apache.spark.util.IntParam * A helper program that sends blocks of Kryo-serialized text strings out on a socket at a * specified rate. Used to feed data into RawInputDStream. */ +private[streaming] object RawTextSender extends Logging { def main(args: Array[String]) { if (args.length != 4) { diff --git a/streaming/src/test/java/org/apache/spark/streaming/JavaAPISuite.java b/streaming/src/test/java/org/apache/spark/streaming/JavaAPISuite.java index 8b7d7709bf2c5..4fbbce9b8b90e 100644 --- a/streaming/src/test/java/org/apache/spark/streaming/JavaAPISuite.java +++ b/streaming/src/test/java/org/apache/spark/streaming/JavaAPISuite.java @@ -297,9 +297,9 @@ public void testQueueStream() { Arrays.asList(7,8,9)); JavaSparkContext jsc = new JavaSparkContext(ssc.ssc().sc()); - JavaRDD rdd1 = ssc.sc().parallelize(Arrays.asList(1, 2, 3)); - JavaRDD rdd2 = ssc.sc().parallelize(Arrays.asList(4, 5, 6)); - JavaRDD rdd3 = ssc.sc().parallelize(Arrays.asList(7,8,9)); + JavaRDD rdd1 = ssc.sparkContext().parallelize(Arrays.asList(1, 2, 3)); + JavaRDD rdd2 = ssc.sparkContext().parallelize(Arrays.asList(4, 5, 6)); + JavaRDD rdd3 = ssc.sparkContext().parallelize(Arrays.asList(7,8,9)); LinkedList> rdds = Lists.newLinkedList(); rdds.add(rdd1); From e3fa36f259b7ede73bc148891e2635bf41221660 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 13:55:14 -0800 Subject: [PATCH 020/133] Merge pull request #442 from pwendell/standalone Workers should use working directory as spark home if it's not specified If users don't set SPARK_HOME in their environment file when launching an application, the standalone cluster should default to the spark home of the worker. (cherry picked from commit 59f475c79fc8fd6d3485e4d0adf6768b6a9225a4) Signed-off-by: Patrick Wendell --- .../main/scala/org/apache/spark/deploy/worker/Worker.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala b/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala index 5182dcbb2abfd..312560d7063a4 100644 --- a/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala +++ b/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala @@ -209,8 +209,11 @@ private[spark] class Worker( logWarning("Invalid Master (" + masterUrl + ") attempted to launch executor.") } else { logInfo("Asked to launch executor %s/%d for %s".format(appId, execId, appDesc.name)) + // TODO (pwendell): We shuld make sparkHome an Option[String] in + // ApplicationDescription to be more explicit about this. + val effectiveSparkHome = Option(execSparkHome_).getOrElse(sparkHome.getAbsolutePath) val manager = new ExecutorRunner(appId, execId, appDesc, cores_, memory_, - self, workerId, host, new File(execSparkHome_), workDir, akkaUrl, ExecutorState.RUNNING) + self, workerId, host, new File(effectiveSparkHome), workDir, akkaUrl, ExecutorState.RUNNING) executors(appId + "/" + execId) = manager manager.start() coresUsed += cores_ From 4ccedb3d1d8c40d3ec914b2d17be9b43aa4744f4 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 14:25:45 -0800 Subject: [PATCH 021/133] Merge pull request #444 from mateiz/py-version Clarify that Python 2.7 is only needed for MLlib (cherry picked from commit 4f0c361b0e140f5f6879f019b2e1a16c683c705c) Signed-off-by: Patrick Wendell --- docs/mllib-guide.md | 3 ++- docs/python-programming-guide.md | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/mllib-guide.md b/docs/mllib-guide.md index 1a5c640d10df4..a22a22184b5c6 100644 --- a/docs/mllib-guide.md +++ b/docs/mllib-guide.md @@ -21,7 +21,8 @@ depends on native Fortran routines. You may need to install the if it is not already present on your nodes. MLlib will throw a linking error if it cannot detect these libraries automatically. -To use MLlib in Python, you will also need [NumPy](http://www.numpy.org) version 1.7 or newer. +To use MLlib in Python, you will need [NumPy](http://www.numpy.org) version 1.7 or newer +and Python 2.7. # Binary Classification diff --git a/docs/python-programming-guide.md b/docs/python-programming-guide.md index b07899c2e176d..7c5283fb0b6fb 100644 --- a/docs/python-programming-guide.md +++ b/docs/python-programming-guide.md @@ -52,7 +52,7 @@ In addition, PySpark fully supports interactive use---simply run `./bin/pyspark` # Installing and Configuring PySpark -PySpark requires Python 2.7 or higher. +PySpark requires Python 2.6 or higher. PySpark applications are executed using a standard CPython interpreter in order to support Python modules that use C extensions. We have not tested PySpark with Python 3 or with alternative Python interpreters, such as [PyPy](http://pypy.org/) or [Jython](http://www.jython.org/). @@ -152,7 +152,7 @@ Many of the methods also contain [doctests](http://docs.python.org/2/library/doc # Libraries [MLlib](mllib-guide.html) is also available in PySpark. To use it, you'll need -[NumPy](http://www.numpy.org) version 1.7 or newer. The [MLlib guide](mllib-guide.html) contains +[NumPy](http://www.numpy.org) version 1.7 or newer, and Python 2.7. The [MLlib guide](mllib-guide.html) contains some example applications. # Where to Go from Here From 7749b988dcc6f3abfd1d5b42f07f82eb680010e0 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 14:33:37 -0800 Subject: [PATCH 022/133] Change log for release 0.9.0-incubating --- CHANGES.txt | 2967 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2967 insertions(+) create mode 100644 CHANGES.txt diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000000000..d5ca405dcc198 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,2967 @@ +Spark Change Log + +Release 0.9.0-incubating + + 4ccedb3 Wed Jan 15 14:26:48 2014 -0800 + Merge pull request #444 from mateiz/py-version + [Clarify that Python 2.7 is only needed for MLlib] + + e3fa36f Wed Jan 15 13:56:04 2014 -0800 + Merge pull request #442 from pwendell/standalone + [Workers should use working directory as spark home if it's not specified] + + 29c76d9 Wed Jan 15 13:55:48 2014 -0800 + Merge pull request #443 from tdas/filestream-fix + [Made some classes private[stremaing] and deprecated a method in JavaStreamingContext.] + + aca40aa Wed Jan 15 11:15:47 2014 -0800 + Merge pull request #441 from pwendell/graphx-build + [GraphX shouldn't list Spark as provided.] + + e12c374 Wed Jan 15 10:01:43 2014 -0800 + Merge pull request #433 from markhamstra/debFix + [Updated Debian packaging] + + 2f015c2 Tue Jan 14 23:17:28 2014 -0800 + Merge pull request #436 from ankurdave/VertexId-case + [Rename VertexID -> VertexId in GraphX] + + 2859cab Tue Jan 14 23:08:19 2014 -0800 + Merge pull request #435 from tdas/filestream-fix + [Fixed the flaky tests by making SparkConf not serializable] + + fbfbb33 Tue Jan 14 23:06:29 2014 -0800 + Merge pull request #434 from rxin/graphxmaven + [Fixed SVDPlusPlusSuite in Maven build.] + + 2c6c07f Tue Jan 14 21:53:05 2014 -0800 + Merge pull request #424 from jegonzal/GraphXProgrammingGuide + [Additional edits for clarity in the graphx programming guide.] + + 6fa4e02 Tue Jan 14 21:51:25 2014 -0800 + Merge pull request #431 from ankurdave/graphx-caching-doc + [Describe caching and uncaching in GraphX programming guide] + + 2f930d5 Tue Jan 14 15:00:11 2014 -0800 + Merge pull request #428 from pwendell/writeable-objects + [Don't clone records for text files] + + 329c9df Tue Jan 14 14:53:36 2014 -0800 + Merge pull request #429 from ankurdave/graphx-examples-pom.xml + [Add GraphX dependency to examples/pom.xml] + + a14933d Tue Jan 14 14:52:42 2014 -0800 + Merge pull request #427 from pwendell/deprecate-aggregator + [Deprecate rather than remove old combineValuesByKey function] + + 119b6c5 Tue Jan 14 13:29:08 2014 -0800 + Merge pull request #425 from rxin/scaladoc + [API doc update & make Broadcast public] + + bf3b150 Tue Jan 14 09:45:22 2014 -0800 + Merge pull request #423 from jegonzal/GraphXProgrammingGuide + [Improving the graphx-programming-guide] + + 1b4adc2 Tue Jan 14 01:19:24 2014 -0800 + Merge pull request #420 from pwendell/header-files + [Add missing header files] + + b60840e Tue Jan 14 00:48:34 2014 -0800 + Merge pull request #418 from pwendell/0.9-versions + [Version changes for release 0.9.0.] + + 980250b Tue Jan 14 00:05:37 2014 -0800 + Merge pull request #416 from tdas/filestream-fix + [Removed unnecessary DStream operations and updated docs] + + 055be5c Mon Jan 13 23:26:44 2014 -0800 + Merge pull request #415 from pwendell/shuffle-compress + [Enable compression by default for spills] + + fdaabdc Mon Jan 13 23:08:26 2014 -0800 + Merge pull request #380 from mateiz/py-bayes + [Add Naive Bayes to Python MLlib, and some API fixes] + + 4a805af Mon Jan 13 22:58:38 2014 -0800 + Merge pull request #367 from ankurdave/graphx + [GraphX: Unifying Graphs and Tables] + + 945fe7a Mon Jan 13 22:56:12 2014 -0800 + Merge pull request #408 from pwendell/external-serializers + [Improvements to external sorting] + + 68641bc Mon Jan 13 22:54:13 2014 -0800 + Merge pull request #413 from rxin/scaladoc + [Adjusted visibility of various components and documentation for 0.9.0 release.] + + 0ca0d4d Mon Jan 13 22:32:21 2014 -0800 + Merge pull request #401 from andrewor14/master + [External sorting - Add number of bytes spilled to Web UI] + + 08b9fec Mon Jan 13 22:29:03 2014 -0800 + Merge pull request #409 from tdas/unpersist + [Automatically unpersisting RDDs that have been cleaned up from DStreams] + + b07bc02 Mon Jan 13 20:45:22 2014 -0800 + Merge pull request #412 from harveyfeng/master + [Add default value for HadoopRDD's `cloneRecords` constructor arg] + + a2fee38 Mon Jan 13 19:45:26 2014 -0800 + Merge pull request #411 from tdas/filestream-fix + [Improved logic of finding new files in FileInputDStream] + + 01c0d72 Mon Jan 13 16:24:30 2014 -0800 + Merge pull request #410 from rxin/scaladoc1 + [Updated JavaStreamingContext to make scaladoc compile.] + + 8038da2 Mon Jan 13 14:59:30 2014 -0800 + Merge pull request #2 from jegonzal/GraphXCCIssue + [Improving documentation and identifying potential bug in CC calculation.] + + b93f9d4 Mon Jan 13 12:18:05 2014 -0800 + Merge pull request #400 from tdas/dstream-move + [Moved DStream and PairDSream to org.apache.spark.streaming.dstream] + + e6ed13f Sun Jan 12 22:35:14 2014 -0800 + Merge pull request #397 from pwendell/host-port + [Remove now un-needed hostPort option] + + 0b96d85 Sun Jan 12 21:31:43 2014 -0800 + Merge pull request #399 from pwendell/consolidate-off + [Disable shuffle file consolidation by default] + + 0ab505a Sun Jan 12 21:31:04 2014 -0800 + Merge pull request #395 from hsaputra/remove_simpleredundantreturn_scala + [Remove simple redundant return statements for Scala methods/functions] + + 405bfe8 Sun Jan 12 20:04:21 2014 -0800 + Merge pull request #394 from tdas/error-handling + [Better error handling in Spark Streaming and more API cleanup] + + 28a6b0c Sun Jan 12 19:49:36 2014 -0800 + Merge pull request #398 from pwendell/streaming-api + [Rename DStream.foreach to DStream.foreachRDD] + + 074f502 Sun Jan 12 17:01:13 2014 -0800 + Merge pull request #396 from pwendell/executor-env + [Setting load defaults to true in executor] + + 82e2b92 Sun Jan 12 16:55:11 2014 -0800 + Merge pull request #392 from rxin/listenerbus + [Stop SparkListenerBus daemon thread when DAGScheduler is stopped.] + + 288a878 Sat Jan 11 21:53:19 2014 -0800 + Merge pull request #389 from rxin/clone-writables + [Minor update for clone writables and more documentation.] + + dbc11df Sat Jan 11 18:07:13 2014 -0800 + Merge pull request #388 from pwendell/master + [Fix UI bug introduced in #244.] + + 409866b Sat Jan 11 17:12:06 2014 -0800 + Merge pull request #393 from pwendell/revert-381 + [Revert PR 381] + + 6510f04 Sat Jan 11 12:48:26 2014 -0800 + Merge pull request #387 from jerryshao/conf-fix + [Fix configure didn't work small problem in ALS] + + ee6e7f9 Sat Jan 11 12:07:55 2014 -0800 + Merge pull request #359 from ScrapCodes/clone-writables + [We clone hadoop key and values by default and reuse objects if asked to.] + + 4216178 Sat Jan 11 09:46:48 2014 -0800 + Merge pull request #373 from jerryshao/kafka-upgrade + [Upgrade Kafka dependecy to 0.8.0 release version] + + 92ad18b Fri Jan 10 23:25:15 2014 -0800 + Merge pull request #376 from prabeesh/master + [Change clientId to random clientId] + + 0b5ce7a Fri Jan 10 23:23:21 2014 -0800 + Merge pull request #386 from pwendell/typo-fix + [Small typo fix] + + 1d7bef0 Fri Jan 10 18:53:03 2014 -0800 + Merge pull request #381 from mateiz/default-ttl + [Fix default TTL for metadata cleaner] + + 44d6a8e Fri Jan 10 17:51:50 2014 -0800 + Merge pull request #382 from RongGu/master + [Fix a type error in comment lines] + + 88faa30 Fri Jan 10 17:14:22 2014 -0800 + Merge pull request #385 from shivaram/add-i2-instances + [Add i2 instance types to Spark EC2.] + + f265531 Fri Jan 10 16:25:44 2014 -0800 + Merge pull request #383 from tdas/driver-test + [API for automatic driver recovery for streaming programs and other bug fixes] + + d37408f Fri Jan 10 16:25:01 2014 -0800 + Merge pull request #377 from andrewor14/master + [External Sorting for Aggregator and CoGroupedRDDs (Revisited)] + + 0eaf01c Fri Jan 10 15:32:19 2014 -0800 + Merge pull request #369 from pillis/master + [SPARK-961 Add a Vector.random() method] + + 7cef843 Fri Jan 10 15:34:15 2014 -0600 + Merge pull request #371 from tgravescs/yarn_client_addjar_misc_fixes + [Yarn client addjar and misc fixes] + + 7b58f11 Fri Jan 10 12:47:46 2014 -0800 + Merge pull request #384 from pwendell/debug-logs + [Make DEBUG-level logs consummable.] + + 23d2995 Fri Jan 10 10:20:02 2014 -0800 + Merge pull request #1 from jegonzal/graphx + [ProgrammingGuide] + + 0ebc973 Thu Jan 9 23:58:49 2014 -0800 + Merge pull request #375 from mateiz/option-fix + [Fix bug added when we changed AppDescription.maxCores to an Option] + + dd03cea Thu Jan 9 23:38:03 2014 -0800 + Merge pull request #378 from pwendell/consolidate_on + [Enable shuffle consolidation by default.] + + 997c830 Thu Jan 9 22:22:20 2014 -0800 + Merge pull request #363 from pwendell/streaming-logs + [Set default logging to WARN for Spark streaming examples.] + + 300eaa9 Thu Jan 9 20:29:51 2014 -0800 + Merge pull request #353 from pwendell/ipython-simplify + [Simplify and fix pyspark script.] + + 4b074fa Thu Jan 9 19:03:55 2014 -0800 + Merge pull request #374 from mateiz/completeness + [Add some missing Java API methods] + + a9d5333 Thu Jan 9 18:46:46 2014 -0800 + Merge pull request #294 from RongGu/master + [Bug fixes for updating the RDD block's memory and disk usage information] + + d86a85e Thu Jan 9 18:37:52 2014 -0800 + Merge pull request #293 from pwendell/standalone-driver + [SPARK-998: Support Launching Driver Inside of Standalone Mode] + + 26cdb5f Thu Jan 9 17:16:34 2014 -0800 + Merge pull request #372 from pwendell/log4j-fix-1 + [Send logs to stderr by default (instead of stdout).] + + 12f414e Thu Jan 9 15:31:30 2014 -0800 + Merge pull request #362 from mateiz/conf-getters + [Use typed getters for configuration settings] + + 365cac9 Thu Jan 9 00:56:16 2014 -0800 + Merge pull request #361 from rxin/clean + [Minor style cleanup. Mostly on indenting & line width changes.] + + 73c724e Thu Jan 9 00:32:19 2014 -0800 + Merge pull request #368 from pwendell/sbt-fix + [Don't delegate to users `sbt`.] + + dceedb4 Wed Jan 8 23:19:28 2014 -0800 + Merge pull request #364 from pwendell/fix + [Fixing config option "retained_stages" => "retainedStages".] + + 04d83fc Wed Jan 8 11:55:37 2014 -0800 + Merge pull request #360 from witgo/master + [fix make-distribution.sh show version: command not found] + + 56ebfea Wed Jan 8 11:50:06 2014 -0800 + Merge pull request #357 from hsaputra/set_boolean_paramname + [Set boolean param name for call to SparkHadoopMapReduceUtil.newTaskAttemptID] + + bdeaeaf Wed Jan 8 11:48:39 2014 -0800 + Merge pull request #358 from pwendell/add-cdh + [Add CDH Repository to Maven Build] + + 5cae05f Wed Jan 8 11:47:28 2014 -0800 + Merge pull request #356 from hsaputra/remove_deprecated_cleanup_method + [Remove calls to deprecated mapred's OutputCommitter.cleanupJob] + + 6eef78d Wed Jan 8 08:49:20 2014 -0600 + Merge pull request #345 from colorant/yarn + [support distributing extra files to worker for yarn client mode] + + bb6a39a Tue Jan 7 22:32:18 2014 -0800 + Merge pull request #322 from falaki/MLLibDocumentationImprovement + [SPARK-1009 Updated MLlib docs to show how to use it in Python] + + cb1b927 Tue Jan 7 22:26:28 2014 -0800 + Merge pull request #355 from ScrapCodes/patch-1 + [Update README.md] + + c0f0155 Tue Jan 7 22:21:52 2014 -0800 + Merge pull request #313 from tdas/project-refactor + [Refactored the streaming project to separate external libraries like Twitter, Kafka, Flume, etc.] + + f5f12dc Tue Jan 7 21:56:35 2014 -0800 + Merge pull request #336 from liancheng/akka-remote-lookup + [Get rid of `Either[ActorRef, ActorSelection]'] + + 11891e6 Wed Jan 8 00:32:18 2014 -0500 + Merge pull request #327 from lucarosellini/master + [Added ‘-i’ command line option to Spark REPL] + + 7d0aac9 Wed Jan 8 00:30:45 2014 -0500 + Merge pull request #354 from hsaputra/addasfheadertosbt + [Add ASF header to the new sbt script.] + + d75dc42 Wed Jan 8 00:30:03 2014 -0500 + Merge pull request #350 from mateiz/standalone-limit + [Add way to limit default # of cores used by apps in standalone mode] + + 61674bc Tue Jan 7 18:32:13 2014 -0800 + Merge pull request #352 from markhamstra/oldArch + [Don't leave os.arch unset after BlockManagerSuite] + + b2e690f Tue Jan 7 16:57:08 2014 -0800 + Merge pull request #328 from falaki/MatrixFactorizationModel-fix + [SPARK-1012: DAGScheduler Exception Fix] + + 6ccf8ce Tue Jan 7 15:49:14 2014 -0800 + Merge pull request #351 from pwendell/maven-fix + [Add log4j exclusion rule to maven.] + + 7d5fa17 Tue Jan 7 11:31:34 2014 -0800 + Merge pull request #337 from yinxusen/mllib-16-bugfix + [Mllib 16 bugfix] + + 71fc113 Tue Jan 7 11:30:35 2014 -0800 + Merge pull request #349 from CodingCat/support-worker_dir + [add the comments about SPARK_WORKER_DIR] + + 15d9534 Tue Jan 7 08:10:02 2014 -0800 + Merge pull request #318 from srowen/master + [Suggested small changes to Java code for slightly more standard style, encapsulation and in some cases performance] + + 468af0f Tue Jan 7 08:09:01 2014 -0800 + Merge pull request #348 from prabeesh/master + [spark -> org.apache.spark] + + c3cf047 Tue Jan 7 00:54:25 2014 -0800 + Merge pull request #339 from ScrapCodes/conf-improvements + [Conf improvements] + + a862caf Tue Jan 7 00:18:20 2014 -0800 + Merge pull request #331 from holdenk/master + [Add a script to download sbt if not present on the system] + + b97ef21 Mon Jan 6 20:12:57 2014 -0800 + Merge pull request #346 from sproblvem/patch-1 + [Update stop-slaves.sh] + + 7210257 Mon Jan 6 18:25:44 2014 -0800 + Merge pull request #128 from adamnovak/master + [Fix failing "sbt/sbt publish-local" by adding a no-argument PrimitiveKeyOpenHashMap constructor ] + + e4d6057 Mon Jan 6 14:56:54 2014 -0800 + Merge pull request #343 from pwendell/build-fix + [Fix test breaking downstream builds] + + 93bf962 Mon Jan 6 11:42:41 2014 -0800 + Merge pull request #340 from ScrapCodes/sbt-fixes + [Made java options to be applied during tests so that they become self explanatory.] + + 60edeb3 Mon Jan 6 11:40:32 2014 -0800 + Merge pull request #338 from ScrapCodes/ning-upgrade + [SPARK-1005 Ning upgrade] + + c708e81 Mon Jan 6 11:35:48 2014 -0800 + Merge pull request #341 from ash211/patch-5 + [Clarify spark.cores.max in docs] + + 33fcb91 Mon Jan 6 11:19:23 2014 -0800 + Merge pull request #342 from tgravescs/fix_maven_protobuf + [Change protobuf version for yarn alpha back to 2.4.1] + + 357083c Mon Jan 6 10:29:04 2014 -0800 + Merge pull request #330 from tgravescs/fix_addjars_null_handling + [Fix handling of empty SPARK_EXAMPLES_JAR] + + a2e7e04 Sun Jan 5 22:37:36 2014 -0800 + Merge pull request #333 from pwendell/logging-silence + [Quiet ERROR-level Akka Logs] + + 5b0986a Sun Jan 5 19:25:09 2014 -0800 + Merge pull request #334 from pwendell/examples-fix + [Removing SPARK_EXAMPLES_JAR in the code] + + f4b924f Sun Jan 5 17:11:47 2014 -0800 + Merge pull request #335 from rxin/ser + [Fall back to zero-arg constructor for Serializer initialization if there is no constructor that accepts SparkConf.] + + d43ad3e Sat Jan 4 16:29:30 2014 -0800 + Merge pull request #292 from soulmachine/naive-bayes + [standard Naive Bayes classifier] + + 86404da Sat Jan 4 14:55:54 2014 -0800 + Merge pull request #127 from jegonzal/MapByPartition + [Adding mapEdges and mapTriplets by Partition] + + e68cdb1 Sat Jan 4 13:46:02 2014 -0800 + Merge pull request #124 from jianpingjwang/master + [refactor and bug fix] + + 280ddf6 Sat Jan 4 12:54:41 2014 -0800 + Merge pull request #121 from ankurdave/more-simplify + [Simplify GraphImpl internals further] + + 10fe23b Fri Jan 3 23:50:14 2014 -0800 + Merge pull request #329 from pwendell/remove-binaries + [SPARK-1002: Remove Binaries from Spark Source] + + c4d6145 Fri Jan 3 16:30:53 2014 -0800 + Merge pull request #325 from witgo/master + [Modify spark on yarn to create SparkConf process] + + 4ae101f Fri Jan 3 11:24:35 2014 -0800 + Merge pull request #317 from ScrapCodes/spark-915-segregate-scripts + [Spark-915 segregate scripts] + + 87248bd Fri Jan 3 00:45:31 2014 -0800 + Merge pull request #1 from apache/master + [Merge latest Spark changes] + + 30b9db0 Thu Jan 2 23:15:55 2014 -0800 + Merge pull request #285 from colorant/yarn-refactor + [Yarn refactor] + + 498a5f0 Thu Jan 2 19:06:40 2014 -0800 + Merge pull request #323 from tgravescs/sparkconf_yarn_fix + [fix spark on yarn after the sparkConf changes] + + 0475ca8 Thu Jan 2 15:17:08 2014 -0800 + Merge pull request #320 from kayousterhout/erroneous_failed_msg + [Remove erroneous FAILED state for killed tasks.] + + 588a169 Thu Jan 2 13:20:54 2014 -0800 + Merge pull request #297 from tdas/window-improvement + [Improvements to DStream window ops and refactoring of Spark's CheckpointSuite] + + 5e67cdc Thu Jan 2 12:56:28 2014 -0800 + Merge pull request #319 from kayousterhout/remove_error_method + [Removed redundant TaskSetManager.error() function.] + + ca67909 Thu Jan 2 15:54:54 2014 -0500 + Merge pull request #311 from tmyklebu/master + [SPARK-991: Report information gleaned from a Python stacktrace in the UI] + + 3713f81 Wed Jan 1 21:29:12 2014 -0800 + Merge pull request #309 from mateiz/conf2 + [SPARK-544. Migrate configuration to a SparkConf class] + + c1d928a Wed Jan 1 17:03:48 2014 -0800 + Merge pull request #312 from pwendell/log4j-fix-2 + [SPARK-1008: Logging improvments] + + dc9cb83 Wed Jan 1 13:28:34 2014 -0800 + Merge pull request #126 from jegonzal/FixingPersist + [Fixing Persist Behavior] + + 9a0ff72 Tue Dec 31 21:50:24 2013 -0800 + Merge pull request #314 from witgo/master + [restore core/pom.xml file modification] + + 8b8e70e Tue Dec 31 17:48:24 2013 -0800 + Merge pull request #73 from falaki/ApproximateDistinctCount + [Approximate distinct count] + + 63b411d Tue Dec 31 14:31:28 2013 -0800 + Merge pull request #238 from ngbinh/upgradeNetty + [upgrade Netty from 4.0.0.Beta2 to 4.0.13.Final] + + 32d6ae9 Tue Dec 31 13:51:07 2013 -0800 + Merge pull request #120 from ankurdave/subgraph-reuses-view + [Reuse VTableReplicated in GraphImpl.subgraph] + + 55b7e2f Tue Dec 31 10:12:51 2013 -0800 + Merge pull request #289 from tdas/filestream-fix + [Bug fixes for file input stream and checkpointing] + + 2b71ab9 Mon Dec 30 11:01:30 2013 -0800 + Merge pull request from aarondav: Utilize DiskBlockManager pathway for temp file writing + [This gives us a couple advantages:] + + 50e3b8e Mon Dec 30 07:44:26 2013 -0800 + Merge pull request #308 from kayousterhout/stage_naming + [Changed naming of StageCompleted event to be consistent] + + 72a17b6 Sat Dec 28 21:25:40 2013 -1000 + Revert "Merge pull request #310 from jyunfan/master" + [This reverts commit 79b20e4dbe3dcd8559ec8316784d3334bb55868b, reversing] + + 79b20e4 Sat Dec 28 21:13:36 2013 -1000 + Merge pull request #310 from jyunfan/master + [Fix typo in the Accumulators section] + + 7375047 Sat Dec 28 13:25:06 2013 -0800 + Merge pull request #304 from kayousterhout/remove_unused + [Removed unused failed and causeOfFailure variables (in TaskSetManager)] + + ad3dfd1 Fri Dec 27 22:10:14 2013 -0500 + Merge pull request #307 from kayousterhout/other_failure + [Removed unused OtherFailure TaskEndReason.] + + b579b83 Fri Dec 27 22:09:04 2013 -0500 + Merge pull request #306 from kayousterhout/remove_pending + [Remove unused hasPendingTasks methods] + + 19672dc Fri Dec 27 13:37:10 2013 -0800 + Merge pull request #305 from kayousterhout/line_spacing + [Fixed >100char lines in DAGScheduler.scala] + + 7be1e57 Thu Dec 26 23:41:40 2013 -1000 + Merge pull request #298 from aarondav/minor + [Minor: Decrease margin of left side of Log page] + + 7d811ba Thu Dec 26 23:39:58 2013 -1000 + Merge pull request #302 from pwendell/SPARK-1007 + [SPARK-1007: spark-class2.cmd should change SCALA_VERSION to be 2.10] + + 5e69fc5 Thu Dec 26 19:10:39 2013 -0500 + Merge pull request #295 from markhamstra/JobProgressListenerNPE + [Avoid a lump of coal (NPE) in JobProgressListener's stocking.] + + da20270 Thu Dec 26 12:11:52 2013 -0800 + Merge pull request #1 from aarondav/driver + [Refactor DriverClient to be more Actor-based] + + e240bad Thu Dec 26 12:30:48 2013 -0500 + Merge pull request #296 from witgo/master + [Renamed ClusterScheduler to TaskSchedulerImpl for yarn and new-yarn package] + + c344ed0 Thu Dec 26 01:31:06 2013 -0500 + Merge pull request #283 from tmyklebu/master + [Python bindings for mllib] + + 56094bc Wed Dec 25 13:14:33 2013 -0500 + Merge pull request #290 from ash211/patch-3 + [Typo: avaiable -> available] + + 4842a07 Wed Dec 25 01:52:15 2013 -0800 + Merge pull request #287 from azuryyu/master + [Fixed job name in the java streaming example.] + + 85a344b Tue Dec 24 16:35:06 2013 -0800 + Merge pull request #127 from kayousterhout/consolidate_schedulers + [Deduplicate Local and Cluster schedulers.] + + c2dd6bc Tue Dec 24 14:36:47 2013 -0800 + Merge pull request #279 from aarondav/shuffle-cleanup0 + [Clean up shuffle files once their metadata is gone] + + 3bf7c70 Tue Dec 24 16:37:13 2013 -0500 + Merge pull request #275 from ueshin/wip/changeclasspathorder + [Change the order of CLASSPATH.] + + d63856c Mon Dec 23 22:07:26 2013 -0800 + Merge pull request #286 from rxin/build + [Show full stack trace and time taken in unit tests.] + + 23a9ae6 Tue Dec 24 00:08:48 2013 -0500 + Merge pull request #277 from tdas/scheduler-update + [Refactored the streaming scheduler and added StreamingListener interface] + + 11107c9 Mon Dec 23 10:38:20 2013 -0800 + Merge pull request #244 from leftnoteasy/master + [Added SPARK-968 implementation for review] + + 44e4205 Sun Dec 22 11:44:18 2013 -0800 + Merge pull request #116 from jianpingjwang/master + [remove unused variables and fix a bug] + + 4797c22 Fri Dec 20 13:30:39 2013 -0800 + Merge pull request #118 from ankurdave/VertexPartitionSuite + [Test VertexPartition and fix bugs] + + 0bc57c5 Fri Dec 20 11:56:54 2013 -0800 + Merge pull request #280 from aarondav/minor + [Minor cleanup for standalone scheduler] + + ac70b8f Fri Dec 20 10:56:10 2013 -0800 + Merge pull request #117 from ankurdave/more-tests + [More tests] + + 45310d4 Thu Dec 19 22:08:20 2013 -0800 + Merge pull request #115 from ankurdave/test-reorg + [Reorganize unit tests; improve GraphSuite test coverage] + + 9228ec8 Thu Dec 19 21:37:15 2013 -0800 + Merge pull request #1 from aarondav/127 + [Merge master into 127] + + eca68d4 Thu Dec 19 18:12:22 2013 -0800 + Merge pull request #272 from tmyklebu/master + [Track and report task result serialisation time.] + + 7990c56 Thu Dec 19 13:35:09 2013 -0800 + Merge pull request #276 from shivaram/collectPartition + [Add collectPartition to JavaRDD interface.] + + 440e531 Thu Dec 19 10:38:56 2013 -0800 + Merge pull request #278 from MLnick/java-python-tostring + [Add toString to Java RDD, and __repr__ to Python RDD] + + d8d3f3e Thu Dec 19 00:06:43 2013 -0800 + Merge pull request #183 from aarondav/spark-959 + [[SPARK-959] Explicitly depend on org.eclipse.jetty.orbit jar] + + bfba532 Wed Dec 18 22:22:21 2013 -0800 + Merge pull request #247 from aarondav/minor + [Increase spark.akka.askTimeout default to 30 seconds] + + da301b5 Wed Dec 18 20:03:29 2013 -0800 + Merge pull request #112 from amatsukawa/scc + [Strongly connected component algorithm] + + c64a53a Wed Dec 18 16:56:26 2013 -0800 + Merge pull request #267 from JoshRosen/cygwin + [Fix Cygwin support in several scripts.] + + a645ef6 Wed Dec 18 16:07:52 2013 -0800 + Merge pull request #48 from amatsukawa/add_project_to_graph + [Add mask operation on graph and filter graph primitive] + + d7ebff0 Wed Dec 18 15:38:48 2013 -0800 + Merge pull request #1 from ankurdave/add_project_to_graph + [Merge current master and reimplement Graph.mask using innerJoin] + + 5ea1872 Wed Dec 18 15:27:24 2013 -0800 + Merge pull request #274 from azuryy/master + [Fixed the example link in the Scala programing guid.] + + 3fd2e09 Wed Dec 18 12:52:36 2013 -0800 + Merge pull request #104 from jianpingjwang/master + [SVD++ demo] + + f4effb3 Tue Dec 17 22:26:21 2013 -0800 + Merge pull request #273 from rxin/top + [Fixed a performance problem in RDD.top and BoundedPriorityQueue] + + 1b5eacb Tue Dec 17 13:49:17 2013 -0800 + Merge pull request #102 from ankurdave/clustered-edge-index + [Add clustered index on edges by source vertex] + + 7a8169b Mon Dec 16 22:42:21 2013 -0800 + Merge pull request #268 from pwendell/shaded-protobuf + [Add support for 2.2. to master (via shaded jars)] + + 0476c84 Mon Dec 16 17:19:25 2013 -0800 + Merge pull request #100 from ankurdave/mrTriplets-active-set + [Support activeSet option in mapReduceTriplets] + + 964a3b6 Mon Dec 16 15:23:51 2013 -0800 + Merge pull request #270 from ewencp/really-force-ssh-pseudo-tty-master + [Force pseudo-tty allocation in spark-ec2 script.] + + 5192ef3 Mon Dec 16 15:08:08 2013 -0800 + Merge pull request #94 from ankurdave/load-edges-columnar + [Load edges in columnar format] + + 883e034 Mon Dec 16 14:16:02 2013 -0800 + Merge pull request #245 from gregakespret/task-maxfailures-fix + [Fix for spark.task.maxFailures not enforced correctly.] + + a51f340 Sun Dec 15 22:02:30 2013 -0800 + Merge pull request #265 from markhamstra/scala.binary.version + [DRY out the POMs with scala.binary.version] + + ded10ce Sun Dec 15 17:25:33 2013 -0800 + Merge pull request #103 from amplab/optimizations + [Optimizations cherry-picked from SIGMOD branches] + + d2ced6d Sun Dec 15 14:11:34 2013 -0800 + Merge pull request #256 from MLnick/master + [Fix 'IPYTHON=1 ./pyspark' throwing ValueError] + + c55e698 Sun Dec 15 12:49:02 2013 -0800 + Merge pull request #257 from tgravescs/sparkYarnFixName + [Fix the --name option for Spark on Yarn] + + ab85f88 Sun Dec 15 12:48:32 2013 -0800 + Merge pull request #264 from shivaram/spark-class-fix + [Use CoarseGrainedExecutorBackend in spark-class] + + 8a56c1f Sat Dec 14 16:29:24 2013 -0800 + Merge pull request #84 from amatsukawa/graphlab_enhancements + [GraphLab bug fix & set start vertex] + + 7db9165 Sat Dec 14 14:16:34 2013 -0800 + Merge pull request #251 from pwendell/master + [Fix list rendering in YARN markdown docs.] + + 2fd781d Sat Dec 14 12:59:37 2013 -0800 + Merge pull request #249 from ngbinh/partitionInJavaSortByKey + [Expose numPartitions parameter in JavaPairRDD.sortByKey()] + + 9bf192b Sat Dec 14 12:52:18 2013 -0800 + Merge pull request #91 from amplab/standalone-pagerank + [Standalone PageRank] + + 840af5e Sat Dec 14 12:51:51 2013 -0800 + Merge pull request #99 from ankurdave/only-dynamic-pregel + [Remove static Pregel; take maxIterations in dynamic Pregel] + + 97ac060 Sat Dec 14 00:22:45 2013 -0800 + Merge pull request #259 from pwendell/scala-2.10 + [Migration to Scala 2.10] + + 7ac944f Fri Dec 13 23:22:08 2013 -0800 + Merge pull request #262 from pwendell/mvn-fix + [Fix maven build issues in 2.10 branch] + + 6defb06 Fri Dec 13 21:18:57 2013 -0800 + Merge pull request #261 from ScrapCodes/scala-2.10 + [Added a comment about ActorRef and ActorSelection difference.] + + 76566b1 Fri Dec 13 10:11:02 2013 -0800 + Merge pull request #260 from ScrapCodes/scala-2.10 + [Review comments on the PR for scala 2.10 migration.] + + 0aeb182 Thu Dec 12 21:14:42 2013 -0800 + Merge pull request #255 from ScrapCodes/scala-2.10 + [Disabled yarn 2.2 in sbt and mvn build and added a message in the sbt build.] + + 2e89398 Wed Dec 11 23:10:53 2013 -0800 + Merge pull request #254 from ScrapCodes/scala-2.10 + [Scala 2.10 migration] + + ce6ca4e Wed Dec 11 22:30:54 2013 -0800 + Merge pull request #97 from dcrankshaw/fix-rddtop + [Added BoundedPriorityQueue kryo registrator. Fixes top issue.] + + d2efe13 Tue Dec 10 13:01:26 2013 -0800 + Merge pull request #250 from pwendell/master + [README incorrectly suggests build sources spark-env.sh] + + 6169fe1 Mon Dec 9 16:51:36 2013 -0800 + Merge pull request #246 from pwendell/master + [Add missing license headers] + + d992ec6 Sun Dec 8 20:49:20 2013 -0800 + Merge pull request #195 from dhardy92/fix_DebScriptPackage + [[Deb] fix package of Spark classes adding org.apache prefix in scripts embeded in .deb] + + 1f4a4bc Sat Dec 7 22:34:34 2013 -0800 + Merge pull request #242 from pwendell/master + [Update broken links and add HDP 2.0 version string] + + 6494d62 Sat Dec 7 11:56:16 2013 -0800 + Merge pull request #240 from pwendell/master + [SPARK-917 Improve API links in nav bar] + + f466f79 Sat Dec 7 11:51:52 2013 -0800 + Merge pull request #239 from aarondav/nit + [Correct spellling error in configuration.md] + + 3abfbfb Sat Dec 7 11:24:19 2013 -0800 + Merge pull request #92 from ankurdave/rdd-names + [Set RDD names for easy debugging] + + 31e8a14 Fri Dec 6 21:49:55 2013 -0800 + Merge pull request #90 from amplab/pregel-replicate-changed + [Replicate only changed vertices] + + 10c3c0c Fri Dec 6 20:29:45 2013 -0800 + Merge pull request #237 from pwendell/formatting-fix + [Formatting fix] + + 1b38f5f Fri Dec 6 20:16:15 2013 -0800 + Merge pull request #236 from pwendell/shuffle-docs + [Adding disclaimer for shuffle file consolidation] + + e5d5728 Fri Dec 6 20:14:56 2013 -0800 + Merge pull request #235 from pwendell/master + [Minor doc fixes and updating README] + + 241336a Fri Dec 6 17:29:03 2013 -0800 + Merge pull request #234 from alig/master + [Updated documentation about the YARN v2.2 build process] + + e039234 Fri Dec 6 11:49:59 2013 -0800 + Merge pull request #190 from markhamstra/Stages4Jobs + [stageId <--> jobId mapping in DAGScheduler] + + bfa6860 Fri Dec 6 11:04:03 2013 -0800 + Merge pull request #233 from hsaputra/changecontexttobackend + [Change the name of input argument in ClusterScheduler#initialize from context to backend.] + + 3fb302c Fri Dec 6 11:03:32 2013 -0800 + Merge pull request #205 from kayousterhout/logging + [Added logging of scheduler delays to UI] + + 87676a6 Fri Dec 6 11:01:42 2013 -0800 + Merge pull request #220 from rxin/zippart + [Memoize preferred locations in ZippedPartitionsBaseRDD] + + 0780498 Thu Dec 5 23:29:42 2013 -0800 + Merge pull request #232 from markhamstra/FiniteWait + [jobWaiter.synchronized before jobWaiter.wait] + + 1c8500e Thu Dec 5 16:25:44 2013 -0800 + Merge pull request #88 from amplab/varenc + [Fixed a bug that variable encoding doesn't work for ints that use all 64 bits.] + + e0bcaa0 Thu Dec 5 12:37:02 2013 -0800 + Merge pull request #86 from ankurdave/vid-varenc + [Finish work on #85] + + 5d46025 Thu Dec 5 12:31:24 2013 -0800 + Merge pull request #228 from pwendell/master + [Document missing configs and set shuffle consolidation to false.] + + 3e96b9a Thu Dec 5 12:07:36 2013 -0800 + Merge pull request #85 from ankurdave/vid-varenc + [Always write Vids using variable encoding] + + 72b6961 Wed Dec 4 23:33:04 2013 -0800 + Merge pull request #199 from harveyfeng/yarn-2.2 + [Hadoop 2.2 migration] + + e0347ba Wed Dec 4 17:38:06 2013 -0800 + Merge pull request #83 from ankurdave/fix-tests + [Fix compile errors in GraphSuite and SerializerSuite] + + 182f9ba Wed Dec 4 15:52:07 2013 -0800 + Merge pull request #227 from pwendell/master + [Fix small bug in web UI and minor clean-up.] + + cbd3b75 Wed Dec 4 15:35:26 2013 -0800 + Merge pull request #81 from amplab/clean1 + [Codebase refactoring] + + b9e7609 Wed Dec 4 14:42:09 2013 -0800 + Merge pull request #225 from ash211/patch-3 + [Add missing space after "Serialized" in StorageLevel] + + 055462c Wed Dec 4 14:02:11 2013 -0800 + Merge pull request #226 from ash211/patch-4 + [Typo: applicaton] + + d6e5473 Wed Dec 4 10:28:50 2013 -0800 + Merge pull request #223 from rxin/transient + [Mark partitioner, name, and generator field in RDD as @transient.] + + 8a3475a Tue Dec 3 14:21:40 2013 -0800 + Merge pull request #218 from JoshRosen/spark-970-pyspark-unicode-error + [Fix UnicodeEncodeError in PySpark saveAsTextFile() (SPARK-970)] + + 46b87b8 Tue Dec 3 00:41:11 2013 -0800 + Merge pull request #2 from colorant/yarn-client-2.2 + [Fix pom.xml for maven build] + + 58d9bbc Mon Dec 2 21:58:53 2013 -0800 + Merge pull request #217 from aarondav/mesos-urls + [Re-enable zk:// urls for Mesos SparkContexts] + + 740922f Sun Dec 1 12:46:58 2013 -0800 + Merge pull request #219 from sundeepn/schedulerexception + [Scheduler quits when newStage fails] + + 60e23a5 Sat Nov 30 23:38:49 2013 -0800 + Merge pull request #216 from liancheng/fix-spark-966 + [Bugfix: SPARK-965 & SPARK-966] + + 34ee814 Sat Nov 30 15:10:30 2013 -0800 + Merged Ankur's pull request #80 and fixed subgraph. + [] + + 743a31a Wed Nov 27 18:24:39 2013 -0800 + Merge pull request #210 from haitaoyao/http-timeout + [add http timeout for httpbroadcast] + + 993e293 Wed Nov 27 00:57:54 2013 -0800 + Merge pull request #1 from colorant/yarn-client-2.2 + [Port yarn-client mode for new-yarn] + + fb6875d Tue Nov 26 20:55:40 2013 -0800 + Merge pull request #146 from JoshRosen/pyspark-custom-serializers + [Custom Serializers for PySpark] + + 330ada1 Tue Nov 26 19:08:33 2013 -0800 + Merge pull request #207 from henrydavidge/master + [Log a warning if a task's serialized size is very big] + + 615213f Tue Nov 26 19:07:20 2013 -0800 + Merge pull request #212 from markhamstra/SPARK-963 + [[SPARK-963] Fixed races in JobLoggerSuite] + + cb976df Tue Nov 26 10:23:19 2013 -0800 + Merge pull request #209 from pwendell/better-docs + [Improve docs for shuffle instrumentation] + + 18d6df0 Tue Nov 26 00:00:07 2013 -0800 + Merge pull request #86 from holdenk/master + [Add histogram functionality to DoubleRDDFunctions] + + 0e2109d Mon Nov 25 20:48:37 2013 -0800 + Merge pull request #204 from rxin/hash + [OpenHashSet fixes] + + c46067f Mon Nov 25 19:09:31 2013 -0800 + Merge pull request #206 from ash211/patch-2 + [Update tuning.md] + + 14bb465 Mon Nov 25 18:50:18 2013 -0800 + Merge pull request #201 from rxin/mappartitions + [Use the proper partition index in mapPartitionsWIthIndex] + + eb4296c Mon Nov 25 15:25:29 2013 -0800 + Merge pull request #101 from colorant/yarn-client-scheduler + [For SPARK-527, Support spark-shell when running on YARN] + + 466fd06 Mon Nov 25 18:27:26 2013 +0800 + Incorporated ideas from pull request #200. - Use Murmur Hash 3 finalization step to scramble the bits of HashCode instead of the simpler version in java.util.HashMap; the latter one had trouble with ranges of consecutive integers. Murmur Hash 3 is used by fastutil. + [- Don't check keys for equality when re-inserting due to growing the] + + 088995f Mon Nov 25 00:57:51 2013 -0800 + Merge pull request #77 from amplab/upgrade + [Sync with Spark master] + + 62889c4 Mon Nov 25 11:27:45 2013 +0800 + Merge pull request #203 from witgo/master + [ Fix Maven build for metrics-graphite] + + 6af03ed Sun Nov 24 16:42:37 2013 -0800 + Merge pull request #76 from dcrankshaw/fix_partitioners + [Actually use partitioner command line args in Analytics.] + + 859d62d Sun Nov 24 16:19:51 2013 -0800 + Merge pull request #151 from russellcardullo/add-graphite-sink + [Add graphite sink for metrics] + + 65de73c Sun Nov 24 15:52:33 2013 -0800 + Merge pull request #185 from mkolod/random-number-generator + [XORShift RNG with unit tests and benchmark] + + 972171b Mon Nov 25 07:50:46 2013 +0800 + Merge pull request #197 from aarondav/patrick-fix + [Fix 'timeWriting' stat for shuffle files] + + a1a7e36 Sun Nov 24 05:15:09 2013 -0800 + Merge pull request #75 from amplab/simplify + [Simplify GraphImpl internals] + + 718cc80 Sun Nov 24 11:02:02 2013 +0800 + Merge pull request #200 from mateiz/hash-fix + [AppendOnlyMap fixes] + + 51aa9d6 Sat Nov 23 19:46:46 2013 +0800 + Merge pull request #198 from ankurdave/zipPartitions-preservesPartitioning + [Support preservesPartitioning in RDD.zipPartitions] + + 18ce7e9 Fri Nov 22 17:02:40 2013 -0800 + Merge pull request #73 from jegonzal/TriangleCount + [Triangle count] + + 086b097 Fri Nov 22 10:26:39 2013 +0800 + Merge pull request #193 from aoiwelle/patch-1 + [Fix Kryo Serializer buffer documentation inconsistency] + + f20093c Fri Nov 22 10:12:13 2013 +0800 + Merge pull request #196 from pwendell/master + [TimeTrackingOutputStream should pass on calls to close() and flush().] + + 4b89501 Wed Nov 20 10:36:10 2013 -0800 + Merge pull request #191 from hsaputra/removesemicolonscala + [Cleanup to remove semicolons (;) from Scala code] + + 202f8e6 Wed Nov 20 03:26:08 2013 -0800 + Merge pull request #74 from dcrankshaw/remove_sleep + [Removed sleep from pagerank in Analytics] + + 74ade9e Tue Nov 19 16:53:58 2013 -0800 + Merge pull request #62 from dcrankshaw/partitioners + [Allow user to choose a partitioner at runtime] + + f568912 Tue Nov 19 16:11:31 2013 -0800 + Merge pull request #181 from BlackNiuza/fix_tasks_number + [correct number of tasks in ExecutorsUI] + + aa638ed Tue Nov 19 16:05:44 2013 -0800 + Merge pull request #189 from tgravescs/sparkYarnErrorHandling + [Impove Spark on Yarn Error handling] + + 5592580 Tue Nov 19 16:04:01 2013 -0800 + Merge pull request #187 from aarondav/example-bcast-test + [Enable the Broadcast examples to work in a cluster setting] + + 99cfe89 Mon Nov 18 22:00:36 2013 -0500 + Updates to reflect pull request code review + [] + + e2ebc3a Sun Nov 17 18:42:18 2013 -0800 + Merge pull request #182 from rxin/vector + [Slightly enhanced PrimitiveVector:] + + 26f616d Sun Nov 17 18:18:16 2013 -0800 + Merge pull request #3 from aarondav/pv-test + [Add PrimitiveVectorSuite and fix bug in resize()] + + 1b5b358 Sat Nov 16 11:44:10 2013 -0800 + Merge pull request #178 from hsaputra/simplecleanupcode + [Simple cleanup on Spark's Scala code] + + 62a2a71 Fri Nov 15 13:12:07 2013 -0800 + Merge pull request #65 from amplab/varenc + [Use variable encoding for ints, longs, and doubles in the specialized serializers.] + + f6b2e59 Thu Nov 14 23:04:55 2013 -0800 + Merge pull request #1 from aarondav/scala210-master + [Various merge corrections] + + 96e0fb4 Thu Nov 14 22:29:28 2013 -0800 + Merge pull request #173 from kayousterhout/scheduler_hang + [Fix bug where scheduler could hang after task failure.] + + dfd40e9 Thu Nov 14 19:44:50 2013 -0800 + Merge pull request #175 from kayousterhout/no_retry_not_serializable + [Don't retry tasks when they fail due to a NotSerializableException] + + ed25105 Thu Nov 14 19:43:55 2013 -0800 + Merge pull request #174 from ahirreddy/master + [Write Spark UI url to driver file on HDFS] + + 1a4cfbe Thu Nov 14 10:32:11 2013 -0800 + Merge pull request #169 from kayousterhout/mesos_fix + [Don't ignore spark.cores.max when using Mesos Coarse mode] + + 5a4f483 Thu Nov 14 10:30:36 2013 -0800 + Merge pull request #170 from liancheng/hadooprdd-doc-typo + [Fixed a scaladoc typo in HadoopRDD.scala] + + d76f520 Thu Nov 14 10:25:48 2013 -0800 + Merge pull request #171 from RIA-pierre-borckmans/master + [Fixed typos in the CDH4 distributions version codes.] + + 2c39d80 Wed Nov 13 23:28:01 2013 -0800 + Merge pull request #69 from jegonzal/MissingVertices + [Addressing issue in Graph creation] + + 33b2dea Wed Nov 13 17:55:58 2013 -0800 + Merge pull request #1 from ankurdave/MissingVertices + [During graph creation, create eTable earlier] + + 2054c61 Wed Nov 13 16:49:55 2013 -0800 + Merge pull request #159 from liancheng/dagscheduler-actor-refine + [Migrate the daemon thread started by DAGScheduler to Akka actor] + + 9290e5b Wed Nov 13 16:48:44 2013 -0800 + Merge pull request #165 from NathanHowell/kerberos-master + [spark-assembly.jar fails to authenticate with YARN ResourceManager] + + a81fcb7 Wed Nov 13 10:41:01 2013 -0800 + Merge pull request #68 from jegonzal/BitSetSetUntilBug + [Addressing bug in BitSet.setUntil(ind)] + + 39af914 Wed Nov 13 08:39:05 2013 -0800 + Merge pull request #166 from ahirreddy/simr-spark-ui + [SIMR Backend Scheduler will now write Spark UI URL to HDFS, which is to ...] + + f49ea28 Tue Nov 12 19:13:39 2013 -0800 + Merge pull request #137 from tgravescs/sparkYarnJarsHdfsRebase + [Allow spark on yarn to be run from HDFS.] + + 87f2f4e Tue Nov 12 16:26:09 2013 -0800 + Merge pull request #153 from ankurdave/stop-spot-cluster + [Enable stopping and starting a spot cluster] + + b8bf04a Tue Nov 12 16:19:50 2013 -0800 + Merge pull request #160 from xiajunluan/JIRA-923 + [Fix bug JIRA-923] + + dfd1ebc Tue Nov 12 09:10:05 2013 -0800 + Merge pull request #164 from tdas/kafka-fix + [Made block generator thread safe to fix Kafka bug.] + + 2e8d450 Mon Nov 11 17:34:09 2013 -0800 + Merge pull request #63 from jegonzal/VertexSetCleanup + [Cleanup of VertexSetRDD] + + b8e294a Mon Nov 11 16:25:42 2013 -0800 + Merge pull request #61 from ankurdave/pid2vid + [Shuffle replicated vertex attributes efficiently in columnar format] + + 3d7277c Mon Nov 11 15:49:28 2013 -0800 + Merge pull request #55 from ankurdave/aggregateNeighbors-variants + [Specialize mapReduceTriplets for accessing subsets of vertex attributes] + + 23b53ef Mon Nov 11 12:30:02 2013 -0800 + Merge pull request #156 from haoyuan/master + [add tachyon module] + + 1a06f70 Sun Nov 10 10:54:44 2013 -0800 + Merge pull request #60 from amplab/rxin + [Looks good to me.] + + 58d4f6c Sun Nov 10 09:23:56 2013 -0800 + Merge pull request #157 from rxin/kryo + [3 Kryo related changes.] + + 3efc019 Sat Nov 9 17:53:49 2013 -0800 + Merge pull request #147 from JoshRosen/fix-java-api-completeness-checker + [Add spark-tools assembly to spark-class'ss classpath] + + 87954d4 Sat Nov 9 17:53:25 2013 -0800 + Merge pull request #154 from soulmachine/ClusterScheduler + [Replace the thread inside ClusterScheduler.start() with an Akka scheduler] + + f6c9462 Sat Nov 9 16:14:45 2013 -0800 + Merge pull request #58 from jegonzal/KryoMessages + [Kryo messages] + + 83bf192 Sat Nov 9 15:40:29 2013 -0800 + Merge pull request #155 from rxin/jobgroup + [Don't reset job group when a new job description is set.] + + 8af99f2 Sat Nov 9 13:48:00 2013 -0800 + Merge pull request #149 from tgravescs/fixSecureHdfsAccess + [Fix secure hdfs access for spark on yarn] + + 72a601e Sat Nov 9 11:55:16 2013 -0800 + Merge pull request #152 from rxin/repl + [Propagate SparkContext local properties from spark-repl caller thread to the repl execution thread.] + + 6ee05be Thu Nov 7 19:12:41 2013 -0800 + Merge pull request #49 from jegonzal/graphxshell + [GraphX Console with Logo Text] + + a9f96b5 Thu Nov 7 18:56:56 2013 -0800 + Merge pull request #56 from jegonzal/PregelAPIChanges + [Changing Pregel API to use mapReduceTriplets instead of aggregateNeighbors] + + 5907137 Thu Nov 7 16:58:31 2013 -0800 + Merge pull request #54 from amplab/rxin + [Converted for loops to while loops in EdgePartition.] + + edf4164 Thu Nov 7 16:22:43 2013 -0800 + Merge pull request #53 from amplab/rxin + [Added GraphX to classpath.] + + c379e10 Thu Nov 7 16:01:47 2013 -0800 + Merge pull request #51 from jegonzal/VertexSetRDD + [Reverting to Array based (materialized) output in VertexSetRDD] + + 3d4ad84 Thu Nov 7 11:08:27 2013 -0800 + Merge pull request #148 from squito/include_appId + [Include appId in executor cmd line args] + + be7e8da Wed Nov 6 23:22:47 2013 -0800 + Merge pull request #23 from jerryshao/multi-user + [Add Spark multi-user support for standalone mode and Mesos] + + aadeda5 Wed Nov 6 13:27:47 2013 -0800 + Merge pull request #144 from liancheng/runjob-clean + [Removed unused return value in SparkContext.runJob] + + 951024f Wed Nov 6 09:36:14 2013 -0800 + Merge pull request #145 from aarondav/sls-fix + [Attempt to fix SparkListenerSuite breakage] + + bf4e613 Tue Nov 5 23:14:09 2013 -0800 + Merge pull request #143 from rxin/scheduler-hang + [Ignore a task update status if the executor doesn't exist anymore.] + + 9f7b9bb Tue Nov 5 10:42:19 2013 -0800 + Merge pull request #142 from liancheng/dagscheduler-pattern-matching + [Using case class deep match to simplify code in DAGScheduler.processEvent] + + ca44b51 Tue Nov 5 01:32:55 2013 -0800 + Merge pull request #50 from amplab/mergemerge + [Merge Spark master into graphx] + + 8106532 Mon Nov 4 20:47:14 2013 -0800 + Merge pull request #139 from aarondav/shuffle-next + [Never store shuffle blocks in BlockManager] + + 0b26a39 Mon Nov 4 18:22:06 2013 -0800 + Merge pull request #128 from shimingfei/joblogger-doc + [add javadoc to JobLogger, and some small fix] + + 7a26104 Mon Nov 4 17:54:06 2013 -0800 + Merge pull request #130 from aarondav/shuffle + [Memory-optimized shuffle file consolidation] + + b5dc339 Sun Nov 3 20:43:15 2013 -0800 + Merge pull request #70 from rxin/hash1 + [Fast, memory-efficient hash set, hash table implementations optimized for primitive data types.] + + 41ead7a Sat Nov 2 14:41:50 2013 -0700 + Merge pull request #133 from Mistobaan/link_fix + [update default github] + + d407c07 Sat Nov 2 14:36:37 2013 -0700 + Merge pull request #134 from rxin/readme + [Fixed a typo in Hadoop version in README.] + + e7c7b80 Fri Nov 1 17:58:10 2013 -0700 + Merge pull request #132 from Mistobaan/doc_fix + [fix persistent-hdfs] + + d6d11c2 Fri Nov 1 15:40:33 2013 -0700 + Merge pull request #129 from velvia/2013-11/document-local-uris + [Document & finish support for local: URIs] + + 99bfcc9 Thu Oct 31 21:38:10 2013 -0700 + Merge pull request #46 from jegonzal/VertexSetWithHashSet + [Switched VertexSetRDD and GraphImpl to use OpenHashSet] + + fcaaf86 Thu Oct 31 18:27:30 2013 -0700 + Merge pull request #44 from jegonzal/rxinBitSet + [Switching to VertexSetRDD to use @rxin BitSet and OpenHash ] + + 3f3c727 Thu Oct 31 09:52:25 2013 -0700 + Merge pull request #41 from jegonzal/LineageTracking + [Optimizing Graph Lineage] + + 944f6b8 Thu Oct 31 09:40:35 2013 -0700 + Merge pull request #43 from amplab/FixBitSetCastException + [Fix BitSet cast exception] + + 8f1098a Wed Oct 30 20:11:48 2013 -0700 + Merge pull request #117 from stephenh/avoid_concurrent_modification_exception + [Handle ConcurrentModificationExceptions in SparkContext init.] + + dc9ce16 Wed Oct 30 17:01:56 2013 -0700 + Merge pull request #126 from kayousterhout/local_fix + [Fixed incorrect log message in local scheduler] + + 33de11c Wed Oct 30 16:58:27 2013 -0700 + Merge pull request #124 from tgravescs/sparkHadoopUtilFix + [Pull SparkHadoopUtil out of SparkEnv (jira SPARK-886)] + + a0c86c3 Wed Oct 30 15:34:39 2013 -0700 + Merge pull request #38 from jegonzal/Documentation + [Improving Documentation] + + 618c1f6 Wed Oct 30 12:03:44 2013 -0700 + Merge pull request #125 from velvia/2013-10/local-jar-uri + [Add support for local:// URI scheme for addJars()] + + 745dc42 Tue Oct 29 23:47:10 2013 -0700 + Merge pull request #118 from JoshRosen/blockinfo-memory-usage + [Reduce the memory footprint of BlockInfo objects] + + 06adf63 Tue Oct 29 16:43:46 2013 -0700 + Merge pull request #33 from kellrott/master + [Fixing graph/pom.xml] + + 098768e Tue Oct 29 15:08:36 2013 -0700 + Merge pull request #37 from jegonzal/AnalyticsCleanup + [Updated Connected Components and Pregel Docs] + + f0e23a0 Tue Oct 29 01:41:44 2013 -0400 + Merge pull request #119 from soulmachine/master + [A little revise for the document] + + aec9bf9 Sun Oct 27 19:32:00 2013 -0700 + Merge pull request #112 from kayousterhout/ui_task_attempt_id + [Display both task ID and task attempt ID in UI, and rename taskId to taskAttemptId] + + d4df474 Sun Oct 27 22:11:21 2013 -0400 + Merge pull request #115 from aarondav/shuffle-fix + [Eliminate extra memory usage when shuffle file consolidation is disabled] + + e018f2d Sat Oct 26 11:39:15 2013 -0700 + Merge pull request #113 from pwendell/master + [Improve error message when multiple assembly jars are present.] + + 662ee9f Sat Oct 26 11:35:59 2013 -0700 + Merge pull request #114 from soulmachine/master + [A little revise for the document] + + bab496c Fri Oct 25 18:28:43 2013 -0700 + Merge pull request #108 from alig/master + [Changes to enable executing by using HDFS as a synchronization point between driver and executors, as well as ensuring executors exit properly.] + + d307db6 Fri Oct 25 17:26:06 2013 -0700 + Merge pull request #102 from tdas/transform + [Added new Spark Streaming operations] + + 85e2cab Fri Oct 25 14:46:06 2013 -0700 + Merge pull request #111 from kayousterhout/ui_name + [Properly display the name of a stage in the UI.] + + ab35ec4 Fri Oct 25 10:16:18 2013 -0700 + Merge pull request #110 from pwendell/master + [Exclude jopt from kafka dependency.] + + 4f2c943 Thu Oct 24 22:32:02 2013 -0700 + Merge pull request #109 from pwendell/master + [Adding Java/Java Streaming versions of `repartition` with associated tests] + + 99ad4a6 Thu Oct 24 17:08:39 2013 -0700 + Merge pull request #106 from pwendell/master + [Add a `repartition` operator.] + + 5429d62 Thu Oct 24 11:15:55 2013 -0700 + Merge pull request #107 from ScrapCodes/scala-2.10 + [Updating to latest akka 2.2.3, which fixes our only failing test Driver Suite.] + + 6f82c42 Thu Oct 24 11:09:46 2013 -0700 + Merge pull request #34 from jegonzal/AnalyticsCleanup + [Analytics Cleanup] + + 1dc776b Wed Oct 23 22:05:52 2013 -0700 + Merge pull request #93 from kayousterhout/ui_new_state + [Show "GETTING_RESULTS" state in UI.] + + c4b187d Wed Oct 23 21:56:18 2013 -0700 + Merge pull request #105 from pwendell/doc-fix + [Fixing broken links in programming guide] + + a098438 Wed Oct 23 18:03:08 2013 -0700 + Merge pull request #103 from JoshRosen/unpersist-fix + [Add unpersist() to JavaDoubleRDD and JavaPairRDD.] + + dd65964 Wed Oct 23 15:07:59 2013 -0700 + Merge pull request #64 from prabeesh/master + [MQTT Adapter for Spark Streaming] + + 452aa36 Tue Oct 22 23:15:33 2013 -0700 + Merge pull request #97 from ewencp/pyspark-system-properties + [Add classmethod to SparkContext to set system properties.] + + 9dfcf53 Tue Oct 22 16:01:42 2013 -0700 + Merge pull request #100 from JoshRosen/spark-902 + [Remove redundant Java Function call() definitions] + + 49d5cda Tue Oct 22 15:38:02 2013 -0700 + Merge pull request #30 from jegonzal/VertexSetRDD_Tests + [Testing and Documenting VertexSetRDD] + + 97184de Tue Oct 22 13:10:14 2013 -0700 + Merge pull request #99 from pwendell/master + [Use correct formatting for comments in StoragePerfTester] + + c404adb Tue Oct 22 11:30:19 2013 -0700 + Merge pull request #90 from pwendell/master + [SPARK-940: Do not directly pass Stage objects to SparkListener.] + + aa9019f Tue Oct 22 10:30:02 2013 -0700 + Merge pull request #98 from aarondav/docs + [Docs: Fix links to RDD API documentation] + + a0e08f0 Tue Oct 22 10:20:43 2013 -0700 + Merge pull request #82 from JoshRosen/map-output-tracker-refactoring + [Split MapOutputTracker into Master/Worker classes] + + b84193c Mon Oct 21 23:35:13 2013 -0700 + Merge pull request #92 from tgravescs/sparkYarnFixClasspath + [Fix the Worker to use CoarseGrainedExecutorBackend and modify classpath ...] + + 731c94e Mon Oct 21 23:31:38 2013 -0700 + Merge pull request #56 from jerryshao/kafka-0.8-dev + [Upgrade Kafka 0.7.2 to Kafka 0.8.0-beta1 for Spark Streaming] + + 48952d6 Mon Oct 21 22:45:00 2013 -0700 + Merge pull request #87 from aarondav/shuffle-base + [Basic shuffle file consolidation] + + a51359c Mon Oct 21 20:33:29 2013 -0700 + Merge pull request #95 from aarondav/perftest + [Minor: Put StoragePerfTester in org/apache/] + + 39d2e9b Mon Oct 21 18:58:48 2013 -0700 + Merge pull request #94 from aarondav/mesos-fix + [Fix mesos urls] + + aa61bfd Mon Oct 21 11:57:05 2013 -0700 + Merge pull request #88 from rxin/clean + [Made the following traits/interfaces/classes non-public:] + + 35886f3 Sun Oct 20 22:20:32 2013 -0700 + Merge pull request #41 from pwendell/shuffle-benchmark + [Provide Instrumentation for Shuffle Write Performance] + + 5b9380e Sun Oct 20 21:03:51 2013 -0700 + Merge pull request #89 from rxin/executor + [Don't setup the uncaught exception handler in local mode.] + + 261bcf2 Sun Oct 20 17:59:51 2013 -0700 + Merge pull request #80 from rxin/build + [Exclusion rules for Maven build files.] + + edc5e3f Sun Oct 20 17:18:06 2013 -0700 + Merge pull request #75 from JoshRosen/block-manager-cleanup + [Code de-duplication in BlockManager] + + 2a7ae17 Sun Oct 20 11:45:21 2013 -0700 + Merge pull request #84 from rxin/kill1 + [Added documentation for setJobGroup. Also some minor cleanup in SparkContext.] + + e4abb75 Sun Oct 20 09:38:37 2013 -0700 + Merge pull request #85 from rxin/clean + [Moved the top level spark package object from spark to org.apache.spark] + + 136b9b3 Sun Oct 20 02:58:26 2013 -0700 + Basic shuffle file consolidation + [The Spark shuffle phase can produce a large number of files, as one file is created] + + 747f538 Sat Oct 19 23:40:40 2013 -0700 + Merge pull request #83 from ewencp/pyspark-accumulator-add-method + [Add an add() method to pyspark accumulators.] + + 6511bbe Sat Oct 19 11:34:56 2013 -0700 + Merge pull request #78 from mosharaf/master + [Removed BitTorrentBroadcast and TreeBroadcast.] + + f628804 Fri Oct 18 23:19:42 2013 -0700 + Merge pull request #76 from pwendell/master + [Clarify compression property.] + + 599dcb0 Fri Oct 18 22:49:00 2013 -0700 + Merge pull request #74 from rxin/kill + [Job cancellation via job group id.] + + 9cf43cf Fri Oct 18 22:07:21 2013 -0700 + Merge pull request #28 from jegonzal/VertexSetRDD + [Refactoring IndexedRDD to VertexSetRDD.] + + f888a5b Fri Oct 18 22:06:58 2013 -0700 + Merge pull request #29 from ankurdave/unit-tests + [Unit tests for Graph and GraphOps] + + 8de9706 Fri Oct 18 20:32:39 2013 -0700 + Merge pull request #66 from shivaram/sbt-assembly-deps + [Add SBT target to assemble dependencies] + + e5316d0 Fri Oct 18 20:30:56 2013 -0700 + Merge pull request #68 from mosharaf/master + [Faster and stable/reliable broadcast] + + 8d528af Fri Oct 18 20:24:10 2013 -0700 + Merge pull request #71 from aarondav/scdefaults + [Spark shell exits if it cannot create SparkContext] + + 0794bd7 Fri Oct 18 18:59:58 2013 -0700 + Merge pull request #27 from jegonzal/removed_indexedrdd_from_core + [Removing IndexedRDD changes for spark/core] + + 099977f Thu Oct 17 14:17:08 2013 -0700 + Merge pull request #26 from ankurdave/split-vTableReplicated + [Great work!] + + fc26e5b Thu Oct 17 13:21:07 2013 -0700 + Merge pull request #69 from KarthikTunga/master + [Fix for issue SPARK-627. Implementing --config argument in the scripts.] + + cf64f63 Thu Oct 17 11:12:28 2013 -0700 + Merge pull request #67 from kayousterhout/remove_tsl + [Removed TaskSchedulerListener interface.] + + f9973ca Wed Oct 16 15:58:41 2013 -0700 + Merge pull request #65 from tgravescs/fixYarn + [Fix yarn build] + + 28e9c2a Tue Oct 15 23:59:56 2013 -0700 + Merge pull request #63 from pwendell/master + [Fixing spark streaming example and a bug in examples build.] + + 4e46fde Tue Oct 15 23:14:27 2013 -0700 + Merge pull request #62 from harveyfeng/master + [Make TaskContext's stageId publicly accessible.] + + b534606 Tue Oct 15 21:25:03 2013 -0700 + Merge pull request #8 from vchekan/checkpoint-ttl-restore + [Serialize and restore spark.cleaner.ttl to savepoint] + + 6dbd220 Tue Oct 15 19:02:57 2013 -0700 + Merge pull request #34 from kayousterhout/rename + [Renamed StandaloneX to CoarseGrainedX.] + + 983b83f Tue Oct 15 19:02:46 2013 -0700 + Merge pull request #61 from kayousterhout/daemon_thread + [Unified daemon thread pools] + + 3249e0e Tue Oct 15 14:12:33 2013 -0700 + Merge pull request #59 from rxin/warning + [Bump up logging level to warning for failed tasks.] + + 678dec6 Tue Oct 15 10:51:46 2013 -0700 + Merge pull request #58 from hsaputra/update-pom-asf + [Update pom.xml to use version 13 of the ASF parent pom] + + e33b183 Mon Oct 14 22:25:47 2013 -0700 + Merge pull request #29 from rxin/kill + [Job killing] + + 3b11f43 Mon Oct 14 14:20:01 2013 -0700 + Merge pull request #57 from aarondav/bid + [Refactor BlockId into an actual type] + + 9979690 Sat Oct 12 21:23:26 2013 -0700 + Merge pull request #52 from harveyfeng/hadoop-closure + [Add an optional closure parameter to HadoopRDD instantiation to use when creating local JobConfs.] + + dca8009 Fri Oct 11 16:08:15 2013 -0700 + Merge pull request #54 from aoiwelle/remove_unused_imports + [Remove unnecessary mutable imports] + + 0e5052b Fri Oct 11 15:45:16 2013 -0700 + Merge pull request #51 from ScrapCodes/scala-2.10 + [Scala 2.10] + + fb25f32 Fri Oct 11 15:44:43 2013 -0700 + Merge pull request #53 from witgo/master + [Add a zookeeper compile dependency to fix build in maven] + + d6ead47 Fri Oct 11 15:43:01 2013 -0700 + Merge pull request #32 from mridulm/master + [Address review comments, move to incubator spark] + + c71499b Thu Oct 10 17:16:42 2013 -0700 + Merge pull request #19 from aarondav/master-zk + [Standalone Scheduler fault tolerance using ZooKeeper] + + 5867a82 Thu Oct 10 14:02:37 2013 -0700 + Merge pull request #19 from dcrankshaw/master + [Merge canonical 2d partitioner and group edges into benchmarks] + + cd08f73 Thu Oct 10 13:55:47 2013 -0700 + Merge pull request #44 from mateiz/fast-map + [A fast and low-memory append-only map for shuffle operations] + + 4b46d51 Thu Oct 10 13:35:36 2013 -0700 + Merge pull request #17 from amplab/product2 + [product 2 change] + + 320418f Wed Oct 9 16:55:30 2013 -0700 + Merge pull request #49 from mateiz/kryo-fix-2 + [Fix Chill serialization of Range objects] + + 215238c Wed Oct 9 16:49:44 2013 -0700 + Merge pull request #50 from kayousterhout/SPARK-908 + [Fix race condition in SparkListenerSuite (fixes SPARK-908).] + + 7827efc Wed Oct 9 15:07:25 2013 -0700 + Merge pull request #46 from mateiz/py-sort-update + [Fix PySpark docs and an overly long line of code after #38] + + 7b3ae04 Wed Oct 9 12:14:19 2013 -0700 + Merge pull request #45 from pwendell/metrics_units + [Use standard abbreviation in metrics description (MBytes -> MB)] + + b4fa11f Wed Oct 9 11:59:47 2013 -0700 + Merge pull request #38 from AndreSchumacher/pyspark_sorting + [SPARK-705: implement sortByKey() in PySpark] + + 19d445d Wed Oct 9 11:08:34 2013 -0700 + Merge pull request #22 from GraceH/metrics-naming + [SPARK-900 Use coarser grained naming for metrics] + + 7d50f9f Wed Oct 9 10:32:42 2013 -0700 + Merge pull request #35 from MartinWeindel/scala-2.10 + [Fixing inconsistencies and warnings on Scala 2.10 branch] + + 3218fa7 Tue Oct 8 23:44:55 2013 -0700 + Merge pull request #4 from MLnick/implicit-als + [Adding algorithm for implicit feedback data to ALS] + + e67d5b9 Tue Oct 8 22:57:38 2013 -0700 + Merge pull request #43 from mateiz/kryo-fix + [Don't allocate Kryo buffers unless needed] + + ea34c52 Mon Oct 7 20:45:58 2013 -0700 + Merge pull request #42 from pwendell/shuffle-read-perf + [Fix inconsistent and incorrect log messages in shuffle read path] + + 02f37ee Mon Oct 7 15:48:52 2013 -0700 + Merge pull request #39 from pwendell/master + [Adding Shark 0.7.1 to EC2 scripts] + + 213b70a Mon Oct 7 10:54:22 2013 -0700 + Merge pull request #31 from sundeepn/branch-0.8 + [Resolving package conflicts with hadoop 0.23.9] + + d585613 Sat Oct 5 22:57:05 2013 -0700 + Merge pull request #37 from pwendell/merge-0.8 + [merge in remaining changes from `branch-0.8`] + + 4a25b11 Sat Oct 5 19:28:55 2013 -0700 + Merge pull request #20 from harveyfeng/hadoop-config-cache + [Allow users to pass broadcasted Configurations and cache InputFormats across Hadoop file reads.] + + 8fc68d0 Sat Oct 5 17:24:35 2013 -0700 + Merge pull request #36 from pwendell/versions + [Bumping EC2 default version in master to .] + + 100222b Sat Oct 5 13:38:59 2013 -0700 + Merge pull request #27 from davidmccauley/master + [SPARK-920/921 - JSON endpoint updates] + + 0864193 Sat Oct 5 13:25:18 2013 -0700 + Merge pull request #33 from AndreSchumacher/pyspark_partition_key_change + [Fixing SPARK-602: PythonPartitioner] + + 61ffcde Fri Oct 4 10:52:17 2013 -0700 + Merge pull request #15 from dcrankshaw/master + [Add synthetic generators] + + 3fe12cc Fri Oct 4 10:51:28 2013 -0700 + Merge pull request #946 from ScrapCodes/scala-2.10 + [Fixed non termination of Executor backend, when sc.stop is not called and system.exit instead.] + + 232765f Thu Oct 3 12:00:48 2013 -0700 + Merge pull request #26 from Du-Li/master + [fixed a wildcard bug in make-distribution.sh; ask sbt to check local] + + 405e69b Thu Oct 3 10:52:41 2013 -0700 + Merge pull request #25 from CruncherBigData/master + [Update README: updated the link] + + 49dbfcc Thu Oct 3 10:52:06 2013 -0700 + Merge pull request #28 from tgravescs/sparYarnAppName + [Allow users to set the application name for Spark on Yarn] + + e597ea3 Wed Oct 2 21:14:24 2013 -0700 + Merge pull request #10 from kayousterhout/results_through-bm + [Send Task results through the block manager when larger than Akka frame size (fixes SPARK-669).] + + 714fdab Thu Sep 26 14:28:55 2013 -0700 + Merge pull request #17 from rxin/optimize + [Remove -optimize flag] + + 13eced7 Thu Sep 26 14:18:19 2013 -0700 + Merge pull request #16 from pwendell/master + [Bug fix in master build] + + 70a0b99 Thu Sep 26 14:11:54 2013 -0700 + Merge pull request #14 from kayousterhout/untangle_scheduler + [Improved organization of scheduling packages.] + + afd03b2 Thu Sep 26 14:09:55 2013 -0700 + Merge pull request #943 from ScrapCodes/scala-2.10 + [Scala 2.10 with akka 2.2] + + 76677b8 Thu Sep 26 14:03:46 2013 -0700 + Merge pull request #670 from jey/ec2-ssh-improvements + [EC2 SSH improvements] + + c514cd1 Thu Sep 26 13:48:20 2013 -0700 + Merge pull request #930 from holdenk/master + [Add mapPartitionsWithIndex] + + 560ee5c Thu Sep 26 11:27:34 2013 -0700 + Merge pull request #7 from wannabeast/memorystore-fixes + [some minor fixes to MemoryStore] + + 6566a19 Thu Sep 26 08:01:04 2013 -0700 + Merge pull request #9 from rxin/limit + [Smarter take/limit implementation.] + + 834686b Sun Sep 22 15:06:48 2013 -0700 + Merge pull request #928 from jerryshao/fairscheduler-refactor + [Refactor FairSchedulableBuilder] + + a2ea069 Sat Sep 21 23:04:42 2013 -0700 + Merge pull request #937 from jerryshao/localProperties-fix + [Fix PR926 local properties issues in Spark Streaming like scenarios] + + f06f2da Sat Sep 21 22:43:34 2013 -0700 + Merge pull request #941 from ilikerps/master + [Add "org.apache." prefix to packages in spark-class] + + 7bb12a2 Sat Sep 21 22:42:46 2013 -0700 + Merge pull request #940 from ankurdave/clear-port-properties-after-tests + [After unit tests, clear port properties unconditionally] + + a00317b Fri Sep 20 11:29:31 2013 -0700 + Merge pull request #1 from ankurdave/aggregateNeighbors-returns-graph + [Return Graph from Graph.aggregateNeighbors] + + 6a5e665 Thu Sep 19 22:41:44 2013 -0700 + Merge pull request #3 from ankurdave/clear-port-properties-after-tests + [After unit tests, clear port properties unconditionally ] + + 68ad33a Thu Sep 19 21:30:27 2013 -0700 + Merge pull request #2 from ankurdave/package-fixes + [Package fixes (spark.graph -> org.apache.spark.graph)] + + cd7222c Thu Sep 19 14:21:24 2013 -0700 + Merge pull request #938 from ilikerps/master + [Fix issue with spark_ec2 seeing empty security groups] + + e0dd24d Sat Aug 31 17:54:15 2013 -0700 + Merge pull request #879 from AndreSchumacher/scala-2.10 + [PySpark: replacing class manifest by class tag for Scala 2.10.2 in rdd.py] + + ad61349 Thu Jul 18 13:53:48 2013 -0700 + Merge pull request #709 from ScrapCodes/scala-2.10 + [Fixed warnings in scala 2.10 branch.] + + a289ded Mon Jul 15 15:59:43 2013 -0700 + Merge pull request #700 from ScrapCodes/scala-2.10 + [Scala 2.10 ] + + 1044a95 Fri Jun 14 20:04:24 2013 -0700 + Merge pull request #652 from ScrapCodes/scala-2.10 + [Fixed maven build without netty fix] + + 4b57f83 Sat Apr 20 10:40:07 2013 -0700 + Merge pull request #535 from ScrapCodes/scala-2.10-repl-port + [porting of repl to scala-2.10] + + 73b3fee Sun Jan 20 10:11:49 2013 -0800 + Merge pull request #388 from folone/master + [Updated maven build configuration for Scala 2.10] + + 20adf27 Tue Jan 15 11:03:49 2013 -0800 + Merge pull request #371 from folone/master + [Scala 2.10.0] + +Release 0.8.0-incubating + + 2aff798 Sun Sep 15 14:05:04 2013 -0700 + Merge pull request #933 from jey/yarn-typo-fix + [Fix typo in Maven build docs] + + dbd2c4f Sun Sep 15 13:20:41 2013 -0700 + Merge pull request #932 from pwendell/mesos-version + [Bumping Mesos version to 0.13.0] + + 9fb0b9d Sun Sep 15 13:02:53 2013 -0700 + Merge pull request #931 from pwendell/yarn-docs + [Explain yarn.version in Maven build docs] + + c4c1db2 Fri Sep 13 19:52:12 2013 -0700 + Merge pull request #929 from pwendell/master + [Use different Hadoop version for YARN artifacts.] + + a310de6 Wed Sep 11 19:36:11 2013 -0700 + Merge pull request #926 from kayousterhout/dynamic + [Changed localProperties to use ThreadLocal (not DynamicVariable).] + + 58c7d8b Wed Sep 11 17:33:42 2013 -0700 + Merge pull request #927 from benh/mesos-docs + [Updated Spark on Mesos documentation.] + + 91a59e6 Wed Sep 11 10:21:48 2013 -0700 + Merge pull request #919 from mateiz/jets3t + [Add explicit jets3t dependency, which is excluded in hadoop-client] + + b9128d3 Wed Sep 11 10:03:06 2013 -0700 + Merge pull request #922 from pwendell/port-change + [Change default port number from 3030 to 4030.] + + e07eef8 Wed Sep 11 07:35:39 2013 -0700 + Merge pull request #925 from davidmccauley/master + [SPARK-894 - Not all WebUI fields delivered VIA JSON] + + 8432f27 Tue Sep 10 23:19:53 2013 -0700 + Merge pull request #923 from haoyuan/master + [fix run-example script] + + d40f140 Tue Sep 10 23:05:29 2013 -0700 + Merge pull request #921 from pwendell/master + [Fix HDFS access bug with assembly build.] + + 0a6c051 Mon Sep 9 23:37:57 2013 -0700 + Merge pull request #918 from pwendell/branch-0.8 + [Update versions for 0.8.0 release.] + + 8c14f4b Mon Sep 9 22:07:58 2013 -0700 + Merge pull request #917 from pwendell/master + [Document libgfortran dependency for MLBase] + + c81377b Mon Sep 9 20:16:19 2013 -0700 + Merge pull request #915 from ooyala/master + [Get rid of / improve ugly NPE when Utils.deleteRecursively() fails] + + 61d2a01 Mon Sep 9 18:21:01 2013 -0700 + Merge pull request #916 from mateiz/mkdist-fix + [Fix copy issue in https://github.com/mesos/spark/pull/899] + + a85758c Mon Sep 9 13:45:40 2013 -0700 + Merge pull request #907 from stephenh/document_coalesce_shuffle + [Add better docs for coalesce.] + + 084fc36 Mon Sep 9 12:01:35 2013 -0700 + Merge pull request #912 from tgravescs/ganglia-pom + [Add metrics-ganglia to core pom file] + + 0456384 Mon Sep 9 09:57:54 2013 -0700 + Merge pull request #911 from pwendell/ganglia-sink + [Adding Manen dependency for Ganglia] + + bf984e2 Sun Sep 8 23:50:24 2013 -0700 + Merge pull request #890 from mridulm/master + [Fix hash bug] + + e9d4f44 Sun Sep 8 23:36:48 2013 -0700 + Merge pull request #909 from mateiz/exec-id-fix + [Fix an instance where full standalone mode executor IDs were passed to] + + 2447b1c Sun Sep 8 22:27:49 2013 -0700 + Merge pull request #910 from mateiz/ml-doc-tweaks + [Small tweaks to MLlib docs] + + 7d3204b Sun Sep 8 21:39:12 2013 -0700 + Merge pull request #905 from mateiz/docs2 + [Job scheduling and cluster mode docs] + + f1f8371 Sun Sep 8 21:26:11 2013 -0700 + Merge pull request #896 from atalwalkar/master + [updated content] + + f68848d Sun Sep 8 18:32:16 2013 -0700 + Merge pull request #906 from pwendell/ganglia-sink + [Clean-up of Metrics Code/Docs and Add Ganglia Sink] + + 0b95799 Sun Sep 8 15:30:16 2013 -0700 + Merge pull request #908 from pwendell/master + [Fix target JVM version in scala build] + + 04cfb3a Sun Sep 8 10:33:20 2013 -0700 + Merge pull request #898 from ilikerps/660 + [SPARK-660: Add StorageLevel support in Python] + + 38488ac Sun Sep 8 00:28:53 2013 -0700 + Merge pull request #900 from pwendell/cdh-docs + [Provide docs to describe running on CDH/HDP cluster.] + + a8e376e Sat Sep 7 21:16:01 2013 -0700 + Merge pull request #904 from pwendell/master + [Adding Apache license to two files] + + cfde85e Sat Sep 7 13:53:08 2013 -0700 + Merge pull request #901 from ooyala/2013-09/0.8-doc-changes + [0.8 Doc changes for make-distribution.sh] + + 4a7813a Sat Sep 7 13:52:24 2013 -0700 + Merge pull request #903 from rxin/resulttask + [Fixed the bug that ResultTask was not properly deserializing outputId.] + + afe46ba Sat Sep 7 07:28:51 2013 -0700 + Merge pull request #892 from jey/fix-yarn-assembly + [YARN build fixes] + + 2eebeff Fri Sep 6 15:25:22 2013 -0700 + Merge pull request #897 from pwendell/master + [Docs describing Spark monitoring and instrumentation] + + ddcb9d3 Thu Sep 5 23:54:09 2013 -0700 + Merge pull request #895 from ilikerps/821 + [SPARK-821: Don't cache results when action run locally on driver] + + 699c331 Thu Sep 5 20:21:53 2013 -0700 + Merge pull request #891 from xiajunluan/SPARK-864 + [[SPARK-864]DAGScheduler Exception if we delete Worker and StandaloneExecutorBackend then add Worker] + + 5c7494d Wed Sep 4 22:47:03 2013 -0700 + Merge pull request #893 from ilikerps/master + [SPARK-884: Add unit test to validate Spark JSON output] + + a547866 Wed Sep 4 21:11:56 2013 -0700 + Merge pull request #894 from c0s/master + [Updating assembly README to reflect recent changes in the build.] + + 19f7027 Tue Sep 3 14:29:10 2013 -0700 + Merge pull request #878 from tgravescs/yarnUILink + [Link the Spark UI up to the Yarn UI ] + + 68df246 Tue Sep 3 13:01:17 2013 -0700 + Merge pull request #889 from alig/master + [Return the port the WebUI is bound to (useful if port 0 was used)] + + d3dd48f Mon Sep 2 16:44:54 2013 -0700 + Merge pull request #887 from mateiz/misc-fixes + [Miscellaneous fixes for 0.8] + + 636fc0c Mon Sep 2 11:20:39 2013 -0700 + Merge pull request #886 from mateiz/codec + [Fix spark.io.compression.codec and change default codec to LZF] + + d9a53b9 Sun Sep 1 22:12:30 2013 -0700 + Merge pull request #885 from mateiz/win-py + [Allow PySpark to run on Windows] + + 3c520fe Sun Sep 1 17:26:55 2013 -0700 + Merge pull request #884 from mateiz/win-fixes + [Run script fixes for Windows after package & assembly change] + + f957c26 Sun Sep 1 14:53:57 2013 -0700 + Merge pull request #882 from mateiz/package-rename + [Rename spark package to org.apache.spark] + + a30fac1 Sun Sep 1 12:27:50 2013 -0700 + Merge pull request #883 from alig/master + [Don't require the spark home environment variable to be set for standalone mode (change needed by SIMR)] + + 03cc765 Sun Sep 1 10:20:56 2013 -0700 + Merge pull request #881 from pwendell/master + [Extend QuickStart to include next steps] + + 0e9565a Sat Aug 31 18:55:41 2013 -0700 + Merge pull request #880 from mateiz/ui-tweaks + [Various UI tweaks] + + 2b29a1d Sat Aug 31 17:49:45 2013 -0700 + Merge pull request #877 from mateiz/docs + [Doc improvements for 0.8] + + 6edef9c Sat Aug 31 13:39:24 2013 -0700 + Merge pull request #861 from AndreSchumacher/pyspark_sampling_function + [Pyspark sampling function] + + fd89835 Sat Aug 31 13:18:12 2013 -0700 + Merge pull request #870 from JoshRosen/spark-885 + [Don't send SIGINT / ctrl-c to Py4J gateway subprocess] + + 618f0ec Fri Aug 30 18:17:13 2013 -0700 + Merge pull request #869 from AndreSchumacher/subtract + [PySpark: implementing subtractByKey(), subtract() and keyBy()] + + 94bb7fd Fri Aug 30 12:05:13 2013 -0700 + Merge pull request #876 from mbautin/master_hadoop_rdd_conf + [Make HadoopRDD's configuration accessible] + + 9e17e45 Fri Aug 30 00:22:53 2013 -0700 + Merge pull request #875 from shivaram/build-fix + [Fix broken build by removing addIntercept] + + 016787d Thu Aug 29 22:15:14 2013 -0700 + Merge pull request #863 from shivaram/etrain-ridge + [Adding linear regression and refactoring Ridge regression to use SGD] + + 852d810 Thu Aug 29 22:13:15 2013 -0700 + Merge pull request #819 from shivaram/sgd-cleanup + [Change SVM to use {0,1} labels] + + ca71620 Thu Aug 29 21:51:14 2013 -0700 + Merge pull request #857 from mateiz/assembly + [Change build and run instructions to use assemblies] + + 1528776 Thu Aug 29 21:30:47 2013 -0700 + Merge pull request #874 from jerryshao/fix-report-bug + [Fix removed block zero size log reporting] + + abdbacf Wed Aug 28 21:11:31 2013 -0700 + Merge pull request #871 from pwendell/expose-local + [Expose `isLocal` in SparkContext.] + + afcade3 Wed Aug 28 20:15:40 2013 -0700 + Merge pull request #873 from pwendell/master + [Hot fix for command runner] + + baa84e7 Wed Aug 28 12:44:46 2013 -0700 + Merge pull request #865 from tgravescs/fixtmpdir + [Spark on Yarn should use yarn approved directories for spark.local.dir and tmp] + + cd043cf Tue Aug 27 19:50:32 2013 -0700 + Merge pull request #867 from tgravescs/yarnenvconfigs + [Spark on Yarn allow users to specify environment variables ] + + 898da7e Mon Aug 26 20:40:49 2013 -0700 + Merge pull request #859 from ianbuss/sbt_opts + [Pass SBT_OPTS environment through to sbt_launcher] + + 17bafea Mon Aug 26 11:59:32 2013 -0700 + Merge pull request #864 from rxin/json1 + [Revert json library change] + + f9fc5c1 Sat Aug 24 15:19:56 2013 -0700 + Merge pull request #603 from pwendell/ec2-updates + [Several Improvements to EC2 Scripts] + + d282c1e Fri Aug 23 11:20:20 2013 -0700 + Merge pull request #860 from jey/sbt-ide-fixes + [Fix IDE project generation under SBT] + + 5a6ac12 Thu Aug 22 22:08:03 2013 -0700 + Merge pull request #701 from ScrapCodes/documentation-suggestions + [Documentation suggestions for spark streaming.] + + 46ea0c1 Thu Aug 22 15:57:28 2013 -0700 + Merge pull request #814 from holdenk/master + [Create less instances of the random class during ALS initialization.] + + 9ac3d62 Thu Aug 22 15:51:10 2013 -0700 + Merge pull request #856 from jey/sbt-fix-hadoop-0.23.9 + [Re-add removed dependency to fix build under Hadoop 0.23.9] + + ae8ba83 Thu Aug 22 10:14:54 2013 -0700 + Merge pull request #855 from jey/update-build-docs + [Update build docs] + + 8a36fd0 Thu Aug 22 10:13:35 2013 -0700 + Merge pull request #854 from markhamstra/pomUpdate + [Synced sbt and maven builds to use the same dependencies, etc.] + + c2d00f1 Thu Aug 22 10:13:03 2013 -0700 + Merge pull request #832 from alig/coalesce + [Coalesced RDD with locality] + + e6d66c8 Wed Aug 21 17:44:31 2013 -0700 + Merge pull request #853 from AndreSchumacher/double_rdd + [Implementing SPARK-838: Add DoubleRDDFunctions methods to PySpark] + + 2905611 Tue Aug 20 17:36:14 2013 -0700 + Merge pull request #851 from markhamstra/MutablePairTE + [Removed meaningless types] + + d61337f Tue Aug 20 10:06:06 2013 -0700 + Merge pull request #844 from markhamstra/priorityRename + [Renamed 'priority' to 'jobId' and assorted minor changes] + + 8cae72e Mon Aug 19 23:40:04 2013 -0700 + Merge pull request #828 from mateiz/sched-improvements + [Scheduler fixes and improvements] + + efeb142 Mon Aug 19 19:23:50 2013 -0700 + Merge pull request #849 from mateiz/web-fixes + [Small fixes to web UI] + + abdc1f8 Mon Aug 19 18:30:56 2013 -0700 + Merge pull request #847 from rxin/rdd + [Allow subclasses of Product2 in all key-value related classes] + + 8fa0747 Sun Aug 18 17:02:54 2013 -0700 + Merge pull request #840 from AndreSchumacher/zipegg + [Implementing SPARK-878 for PySpark: adding zip and egg files to context ...] + + 1e137a5 Sat Aug 17 22:22:32 2013 -0700 + Merge pull request #846 from rxin/rdd + [Two minor RDD refactoring] + + e89ffc7 Fri Aug 16 14:02:34 2013 -0700 + Merge pull request #839 from jegonzal/zip_partitions + [Currying RDD.zipPartitions ] + + 1fb1b09 Thu Aug 15 22:15:05 2013 -0700 + Merge pull request #841 from rxin/json + [Use the JSON formatter from Scala library and removed dependency on lift-json.] + + c69c489 Thu Aug 15 20:55:09 2013 -0700 + Merge pull request #843 from Reinvigorate/bug-879 + [fixing typo in conf/slaves] + + 230ab27 Thu Aug 15 17:45:17 2013 -0700 + Merge pull request #834 from Daemoen/master + [Updated json output to allow for display of worker state] + + 659553b Thu Aug 15 16:56:31 2013 -0700 + Merge pull request #836 from pwendell/rename + [Rename `memoryBytesToString` and `memoryMegabytesToString`] + + 28369ff Thu Aug 15 16:44:02 2013 -0700 + Merge pull request #829 from JoshRosen/pyspark-unit-tests-python-2.6 + [Fix PySpark unit tests on Python 2.6] + + 1a13460 Thu Aug 15 15:50:44 2013 -0700 + Merge pull request #833 from rxin/ui + [Various UI improvements.] + + 044a088 Wed Aug 14 20:43:49 2013 -0700 + Merge pull request #831 from rxin/scheduler + [A few small scheduler / job description changes.] + + 839f2d4 Wed Aug 14 16:17:23 2013 -0700 + Merge pull request #822 from pwendell/ui-features + [Adding GC Stats to TaskMetrics (and three small fixes)] + + 63446f9 Wed Aug 14 00:17:07 2013 -0700 + Merge pull request #826 from kayousterhout/ui_fix + [Fixed 2 bugs in executor UI (incl. SPARK-877)] + + 3f14cba Tue Aug 13 20:09:51 2013 -0700 + Merge pull request #825 from shivaram/maven-repl-fix + [Set SPARK_CLASSPATH for maven repl tests] + + 596adc6 Tue Aug 13 19:41:34 2013 -0700 + Merge pull request #824 from mateiz/mesos-0.12.1 + [Update to Mesos 0.12.1] + + d316af9 Tue Aug 13 15:31:01 2013 -0700 + Merge pull request #821 from pwendell/print-launch-command + [Print run command to stderr rather than stdout] + + 1f79d21 Tue Aug 13 15:23:54 2013 -0700 + Merge pull request #818 from kayousterhout/killed_fix + [Properly account for killed tasks.] + + 622f83c Tue Aug 13 09:58:52 2013 -0700 + Merge pull request #817 from pwendell/pr_784 + [Minor clean-up in metrics servlet code] + + a0133bf Tue Aug 13 09:28:18 2013 -0700 + Merge pull request #784 from jerryshao/dev-metrics-servlet + [Add MetricsServlet for Spark metrics system] + + e2fdac6 Mon Aug 12 21:26:59 2013 -0700 + Merge pull request #802 from stayhf/SPARK-760-Python + [Simple PageRank algorithm implementation in Python for SPARK-760] + + d3525ba Mon Aug 12 21:02:39 2013 -0700 + Merge pull request #813 from AndreSchumacher/add_files_pyspark + [Implementing SPARK-865: Add the equivalent of ADD_JARS to PySpark] + + 9e02da2 Mon Aug 12 20:22:27 2013 -0700 + Merge pull request #812 from shivaram/maven-mllib-tests + [Create SparkContext in beforeAll for MLLib tests] + + 65d0d91 Mon Aug 12 19:00:57 2013 -0700 + Merge pull request #807 from JoshRosen/guava-optional + [Change scala.Option to Guava Optional in Java APIs] + + 4346f0a Mon Aug 12 12:12:12 2013 -0700 + Merge pull request #809 from shivaram/sgd-cleanup + [Clean up scaladoc in ML Lib.] + + ea1b4ba Mon Aug 12 08:09:58 2013 -0700 + Merge pull request #806 from apivovarov/yarn-205 + [Changed yarn.version to 2.0.5 in pom.xml] + + 2a39d2c Sun Aug 11 20:35:09 2013 -0700 + Merge pull request #810 from pwendell/dead_doc_code + [Remove now dead code inside of docs] + + e5b9ed2 Sun Aug 11 17:22:47 2013 -0700 + Merge pull request #808 from pwendell/ui_compressed_bytes + [Report compressed bytes read when calculating TaskMetrics] + + 3796486 Sun Aug 11 14:51:47 2013 -0700 + Merge pull request #805 from woggle/hadoop-rdd-jobconf + [Use new Configuration() instead of slower new JobConf() in SerializableWritable] + + ff9ebfa Sun Aug 11 10:52:55 2013 -0700 + Merge pull request #762 from shivaram/sgd-cleanup + [Refactor SGD options into a new class.] + + 95c62ca Sun Aug 11 10:30:52 2013 -0700 + Merge pull request #804 from apivovarov/master + [Fixed path to JavaALS.java and JavaKMeans.java, fixed hadoop2-yarn profi...] + + 06e4f2a Sat Aug 10 18:06:23 2013 -0700 + Merge pull request #789 from MLnick/master + [Adding Scala version of PageRank example] + + 71c63de Sat Aug 10 10:21:20 2013 -0700 + Merge pull request #795 from mridulm/master + [Fix bug reported in PR 791 : a race condition in ConnectionManager and Connection] + + d17eeb9 Sat Aug 10 09:02:27 2013 -0700 + Merge pull request #785 from anfeng/master + [expose HDFS file system stats via Executor metrics] + + dce5e47 Fri Aug 9 21:53:45 2013 -0700 + Merge pull request #800 from dlyubimov/HBASE_VERSION + [Pull HBASE_VERSION in the head of sbt build] + + cd247ba Fri Aug 9 20:41:13 2013 -0700 + Merge pull request #786 from shivaram/mllib-java + [Java fixes, tests and examples for ALS, KMeans] + + b09d4b7 Fri Aug 9 13:17:08 2013 -0700 + Merge pull request #799 from woggle/sync-fix + [Remove extra synchronization in ResultTask] + + 0bc63bf Fri Aug 9 13:16:25 2013 -0700 + Merge pull request #801 from pwendell/print-launch-command + [Print launch command [Branch 0.8 version]] + + cc6b92e Fri Aug 9 13:00:33 2013 -0700 + Merge pull request #775 from pwendell/print-launch-command + [Log the launch command for Spark daemons] + + f94fc75 Fri Aug 9 10:04:03 2013 -0700 + Merge pull request #788 from shane-huang/sparkjavaopts + [For standalone mode, add worker local env setting of SPARK_JAVA_OPTS as ...] + + 63b6e02 Thu Aug 8 14:02:02 2013 -0700 + Merge pull request #797 from mateiz/chill-0.3.1 + [Update to Chill 0.3.1] + + 9955e5a Thu Aug 8 11:03:38 2013 -0700 + Merge pull request #796 from pwendell/bootstrap-design + [Bootstrap re-design] + + 5133e4b Wed Aug 7 15:50:45 2013 -0700 + Merge pull request #790 from kayousterhout/fix_throughput + [Fixed issue in UI that decreased scheduler throughput by 5x or more] + + 3c8478e Tue Aug 6 23:25:03 2013 -0700 + Merge pull request #747 from mateiz/improved-lr + [Update the Python logistic regression example] + + 6b043a6 Tue Aug 6 22:31:02 2013 -0700 + Merge pull request #724 from dlyubimov/SPARK-826 + [SPARK-826: fold(), reduce(), collect() always attempt to use java serialization] + + de6c4c9 Tue Aug 6 17:09:50 2013 -0700 + Merge pull request #787 from ash211/master + [Update spark-standalone.md] + + df4d10d Tue Aug 6 15:44:05 2013 -0700 + Merge pull request #779 from adatao/adatao-global-SparkEnv + [[HOTFIX] Extend thread safety for SparkEnv.get()] + + d2b0f0c Tue Aug 6 14:49:39 2013 -0700 + Merge pull request #770 from stayhf/SPARK-760-Java + [Simple PageRank algorithm implementation in Java for SPARK-760] + + d031f73 Mon Aug 5 22:33:00 2013 -0700 + Merge pull request #782 from WANdisco/master + [SHARK-94 Log the files computed by HadoopRDD and NewHadoopRDD] + + 1b63dea Mon Aug 5 22:21:26 2013 -0700 + Merge pull request #769 from markhamstra/NegativeCores + [SPARK-847 + SPARK-845: Zombie workers and negative cores] + + 828aff7 Mon Aug 5 21:37:33 2013 -0700 + Merge pull request #776 from gingsmith/master + [adding matrix factorization data generator] + + 8b27789 Mon Aug 5 19:14:52 2013 -0700 + Merge pull request #774 from pwendell/job-description + [Show user-defined job name in UI] + + 550b0cf Mon Aug 5 12:10:32 2013 -0700 + Merge pull request #780 from cybermaster/master + [SPARK-850] + + 22abbc1 Fri Aug 2 16:37:59 2013 -0700 + Merge pull request #772 from karenfeng/ui-843 + [Show app duration] + + 9d7dfd2 Thu Aug 1 17:41:58 2013 -0700 + Merge pull request #743 from pwendell/app-metrics + [Add application metrics to standalone master] + + 6d7afd7 Thu Aug 1 17:13:28 2013 -0700 + Merge pull request #768 from pwendell/pr-695 + [Minor clean-up of fair scheduler UI] + + 5e7b38f Thu Aug 1 14:59:33 2013 -0700 + Merge pull request #695 from xiajunluan/pool_ui + [Enhance job ui in spark ui system with adding pool information] + + 0a96493 Thu Aug 1 11:27:17 2013 -0700 + Merge pull request #760 from karenfeng/heading-update + [Clean up web UI page headers] + + cb7dd86 Thu Aug 1 11:06:10 2013 -0700 + Merge pull request #758 from pwendell/master-json + [Add JSON path to master index page] + + 58756b7 Wed Jul 31 23:45:41 2013 -0700 + Merge pull request #761 from mateiz/kmeans-generator + [Add data generator for K-means] + + ecab635 Wed Jul 31 18:16:55 2013 -0700 + Merge pull request #763 from c0s/assembly + [SPARK-842. Maven assembly is including examples libs and dependencies] + + 39c75f3 Wed Jul 31 15:52:36 2013 -0700 + Merge pull request #757 from BlackNiuza/result_task_generation + [Bug fix: SPARK-837] + + b2b86c2 Wed Jul 31 15:51:39 2013 -0700 + Merge pull request #753 from shivaram/glm-refactor + [Build changes for ML lib] + + 14bf2fe Wed Jul 31 14:18:16 2013 -0700 + Merge pull request #749 from benh/spark-executor-uri + [Added property 'spark.executor.uri' for launching on Mesos.] + + 4ba4c3f Wed Jul 31 13:14:49 2013 -0700 + Merge pull request #759 from mateiz/split-fix + [Use the Char version of split() instead of the String one in MLUtils] + + a386ced Wed Jul 31 11:22:50 2013 -0700 + Merge pull request #754 from rxin/compression + [Compression codec change] + + 0be071a Wed Jul 31 11:11:59 2013 -0700 + Merge pull request #756 from cdshines/patch-1 + [Refactored Vector.apply(length, initializer) replacing excessive code with library method] + + d4556f4 Wed Jul 31 08:48:14 2013 -0700 + Merge pull request #751 from cdshines/master + [Cleaned Partitioner & PythonPartitioner source by taking out non-related logic to Utils] + + 29b8cd3 Tue Jul 30 21:30:33 2013 -0700 + Merge pull request #755 from jerryshao/add-apache-header + [Add Apache license header to metrics system] + + e87de03 Tue Jul 30 15:00:08 2013 -0700 + Merge pull request #744 from karenfeng/bootstrap-update + [Use Bootstrap progress bars in web UI] + + ae57020 Tue Jul 30 14:56:41 2013 -0700 + Merge pull request #752 from rxin/master + [Minor mllib cleanup] + + 8aee118 Tue Jul 30 10:27:54 2013 -0700 + Merge pull request #748 from atalwalkar/master + [made SimpleUpdater consistent with other updaters] + + 468a36c Mon Jul 29 19:44:33 2013 -0700 + Merge pull request #746 from rxin/cleanup + [Internal cleanup] + + 1e1ffb1 Mon Jul 29 19:26:19 2013 -0700 + Merge pull request #745 from shivaram/loss-update-fix + [Remove duplicate loss history in Gradient Descent] + + c99b674 Mon Jul 29 16:32:55 2013 -0700 + Merge pull request #735 from karenfeng/ui-807 + [Totals for shuffle data and CPU time] + + fe7298b Mon Jul 29 14:01:00 2013 -0700 + Merge pull request #741 from pwendell/usability + [Fix two small usability issues] + + c34c0f6 Mon Jul 29 13:18:10 2013 -0700 + Merge pull request #731 from pxinghao/master + [Adding SVM and Lasso] + + f3d72ff Fri Jul 26 17:19:27 2013 -0700 + Merge pull request #739 from markhamstra/toolsPom + [Missing tools/pom.xml scalatest dependency] + + cb36677 Fri Jul 26 16:59:30 2013 -0700 + Merge pull request #738 from harsha2010/pruning + [Fix bug in Partition Pruning.] + + f3cf094 Thu Jul 25 14:53:21 2013 -0700 + Merge pull request #734 from woggle/executor-env2 + [Get more env vars from driver rather than worker] + + 51c2427 Thu Jul 25 00:03:11 2013 -0700 + Merge pull request #732 from ryanlecompte/master + [Refactor Kryo serializer support to use chill/chill-java] + + 52723b9 Wed Jul 24 14:33:02 2013 -0700 + Merge pull request #728 from jey/examples-jar-env + [Fix setting of SPARK_EXAMPLES_JAR] + + 20338c2 Wed Jul 24 14:32:24 2013 -0700 + Merge pull request #729 from karenfeng/ui-811 + [Stage Page updates] + + 5584ebc Wed Jul 24 11:46:46 2013 -0700 + Merge pull request #675 from c0s/assembly + [Building spark assembly for further consumption of the Spark project with a deployed cluster] + + a73f3ee Wed Jul 24 08:59:14 2013 -0700 + Merge pull request #671 from jerryshao/master + [Add metrics system for Spark] + + b011329 Tue Jul 23 22:50:09 2013 -0700 + Merge pull request #727 from rxin/scheduler + [Scheduler code style cleanup.] + + 876125b Tue Jul 23 22:28:21 2013 -0700 + Merge pull request #726 from rxin/spark-826 + [SPARK-829: scheduler shouldn't hang if a task contains unserializable objects in its closure] + + 2f1736c Tue Jul 23 15:53:30 2013 -0700 + Merge pull request #725 from karenfeng/task-start + [Creates task start events] + + 5364f64 Tue Jul 23 13:40:34 2013 -0700 + Merge pull request #723 from rxin/mllib + [Made RegressionModel serializable and added unit tests to make sure predict methods would work.] + + f369e0e Tue Jul 23 13:22:27 2013 -0700 + Merge pull request #720 from ooyala/2013-07/persistent-rdds-api + [Add a public method getCachedRdds to SparkContext] + + 401aac8 Mon Jul 22 16:57:16 2013 -0700 + Merge pull request #719 from karenfeng/ui-808 + [Creates Executors tab for Jobs UI] + + 8ae1436 Mon Jul 22 16:03:04 2013 -0700 + Merge pull request #722 from JoshRosen/spark-825 + [Fix bug: DoubleRDDFunctions.sampleStdev() computed non-sample stdev()] + + 15fb394 Sun Jul 21 10:33:38 2013 -0700 + Merge pull request #716 from c0s/webui-port + [Regression: default webui-port can't be set via command line "--webui-port" anymore] + + c40f0f2 Fri Jul 19 13:33:04 2013 -0700 + Merge pull request #711 from shivaram/ml-generators + [Move ML lib data generator files to util/] + + 413b841 Fri Jul 19 13:31:38 2013 -0700 + Merge pull request #717 from viirya/dev1 + [Do not copy local jars given to SparkContext in yarn mode] + + 0d0a47c Thu Jul 18 12:06:37 2013 -0700 + Merge pull request #710 from shivaram/ml-updates + [Updates to LogisticRegression] + + c6235b5 Thu Jul 18 11:43:48 2013 -0700 + Merge pull request #714 from adatao/master + [[BUGFIX] Fix for sbt/sbt script SPARK_HOME setting] + + 009c79e Thu Jul 18 11:41:52 2013 -0700 + Merge pull request #715 from viirya/dev1 + [fix a bug in build process that pulls in two versions of ASM.] + + 985a9e3 Wed Jul 17 22:27:19 2013 -0700 + Merge pull request #712 from stayhf/SPARK-817 + [Consistently invoke bash with /usr/bin/env bash in scripts to make code ...] + + cad48ed Tue Jul 16 21:41:28 2013 -0700 + Merge pull request #708 from ScrapCodes/dependencies-upgrade + [Dependency upgrade Akka 2.0.3 -> 2.0.5] + + 8a8a8f2 Mon Jul 15 23:09:21 2013 -0700 + Merge pull request #705 from rxin/errormessages + [Throw a more meaningful message when runJob is called to launch tasks on non-existent partitions.] + + ed8415b Mon Jul 15 16:41:04 2013 -0700 + Merge pull request #703 from karenfeng/ui-802 + [Link to job UI from standalone deploy cluster web UI] + + e3d3e6f Mon Jul 15 14:59:44 2013 -0700 + Merge pull request #702 from karenfeng/ui-fixes + [Adds app name in HTML page titles on job web UI] + + c7877d5 Sun Jul 14 12:58:13 2013 -0700 + Merge pull request #689 from BlackNiuza/application_status + [Bug fix: SPARK-796] + + 10c0593 Sun Jul 14 11:45:18 2013 -0700 + Merge pull request #699 from pwendell/ui-env + [Add `Environment` tab to SparkUI.] + + 89e8549 Sat Jul 13 16:11:08 2013 -0700 + Merge pull request #698 from Reinvigorate/sm-deps-change + [changing com.google.code.findbugs maven coordinates] + + 77c69ae Fri Jul 12 23:05:21 2013 -0700 + Merge pull request #697 from pwendell/block-locations + [Show block locations in Web UI.] + + 5a7835c Fri Jul 12 20:28:21 2013 -0700 + Merge pull request #691 from karenfeng/logpaging + [Create log pages] + + 71ccca0 Fri Jul 12 20:25:06 2013 -0700 + Merge pull request #696 from woggle/executor-env + [Pass executor env vars (e.g. SPARK_CLASSPATH) to compute-classpath.sh] + + 90fc3f3 Fri Jul 12 20:23:36 2013 -0700 + Merge pull request #692 from Reinvigorate/takeOrdered + [adding takeOrdered() to RDD] + + 018d04c Thu Jul 11 12:48:37 2013 -0700 + Merge pull request #684 from woggle/mesos-classloader + [Explicitly set class loader for MesosSchedulerDriver callbacks.] + + bc19477 Wed Jul 10 22:29:41 2013 -0700 + Merge pull request #693 from c0s/readme + [Updating README to reflect Scala 2.9.3 requirements] + + 7dcda9a Mon Jul 8 23:24:23 2013 -0700 + Merge pull request #688 from markhamstra/scalaDependencies + [Fixed SPARK-795 with explicit dependencies] + + 638927b Mon Jul 8 22:58:50 2013 -0700 + Merge pull request #683 from shivaram/sbt-test-fix + [Remove some stack traces from sbt test output] + + 3c13178 Mon Jul 8 14:50:34 2013 -0700 + Merge pull request #687 from atalwalkar/master + [Added "Labeled" to util functions for labeled data] + + 744da8e Sun Jul 7 17:42:25 2013 -0700 + Merge pull request #679 from ryanlecompte/master + [Make binSearch method tail-recursive for RidgeRegression] + + 3cc6818 Sat Jul 6 19:51:20 2013 -0700 + Merge pull request #668 from shimingfei/guava-14.0.1 + [update guava version from 11.0.1 to 14.0.1] + + 2216188 Sat Jul 6 16:18:15 2013 -0700 + Merge pull request #676 from c0s/asf-avro + [Use standard ASF published avro module instead of a proprietory built one] + + 94871e4 Sat Jul 6 15:26:19 2013 -0700 + Merge pull request #655 from tgravescs/master + [Add support for running Spark on Yarn on a secure Hadoop Cluster] + + 3f918b3 Sat Jul 6 12:45:18 2013 -0700 + Merge pull request #672 from holdenk/master + [s/ActorSystemImpl/ExtendedActorSystem/ as ActorSystemImpl results in a warning] + + 2a36e54 Sat Jul 6 12:43:21 2013 -0700 + Merge pull request #673 from xiajunluan/master + [Add config template file for fair scheduler feature] + + 7ba7fa1 Sat Jul 6 11:45:08 2013 -0700 + Merge pull request #674 from liancheng/master + [Bug fix: SPARK-789] + + f4416a1 Sat Jul 6 11:41:58 2013 -0700 + Merge pull request #681 from BlackNiuza/memory_leak + [Remove active job from idToActiveJob when job finished or aborted] + + e063e29 Fri Jul 5 21:54:52 2013 -0700 + Merge pull request #680 from tdas/master + [Fixed major performance bug in Network Receiver] + + bf1311e Fri Jul 5 17:32:44 2013 -0700 + Merge pull request #678 from mateiz/ml-examples + [Start of ML package] + + 6ad85d0 Thu Jul 4 21:32:29 2013 -0700 + Merge pull request #677 from jerryshao/fix_stage_clean + [Clean StageToInfos periodically when spark.cleaner.ttl is enabled] + + 2e32fc8 Thu Jul 4 12:18:20 2013 -0700 + Merge pull request #666 from c0s/master + [hbase dependency is missed in hadoop2-yarn profile of examples module +] + + 6d60fe5 Mon Jul 1 18:24:03 2013 -0700 + Merge pull request #666 from c0s/master + [hbase dependency is missed in hadoop2-yarn profile of examples module] + + ccfe953 Sat Jun 29 17:57:53 2013 -0700 + Merge pull request #577 from skumargithub/master + [Example of cumulative counting using updateStateByKey] + + 50ca176 Thu Jun 27 22:24:52 2013 -0700 + Merge pull request #664 from pwendell/test-fix + [Removing incorrect test statement] + + e49bc8c Wed Jun 26 11:13:33 2013 -0700 + Merge pull request #663 from stephenh/option_and_getenv + [Be cute with Option and getenv.] + + f5e32ed Tue Jun 25 09:16:57 2013 -0700 + Merge pull request #661 from mesos/streaming + [Kafka fixes and DStream.count fix for master] + + 1249e91 Mon Jun 24 21:46:33 2013 -0700 + Merge pull request #572 from Reinvigorate/sm-block-interval + [Adding spark.streaming.blockInterval property] + + cfcda95 Mon Jun 24 21:44:50 2013 -0700 + Merge pull request #571 from Reinvigorate/sm-kafka-serializers + [Surfacing decoders on KafkaInputDStream] + + 575aff6 Mon Jun 24 21:35:50 2013 -0700 + Merge pull request #567 from Reinvigorate/sm-count-fix + [Fixing count() in Spark Streaming] + + 3e61bef Sat Jun 22 16:22:47 2013 -0700 + Merge pull request #648 from shivaram/netty-dbg + [Shuffle fixes and cleanup] + + 1ef5d0d Sat Jun 22 09:35:57 2013 -0700 + Merge pull request #644 from shimingfei/joblogger + [add Joblogger to Spark (on new Spark code)] + + 7e4b266 Sat Jun 22 07:53:18 2013 -0700 + Merge pull request #563 from jey/python-optimization + [Optimize PySpark worker invocation] + + 71030ba Wed Jun 19 15:21:03 2013 -0700 + Merge pull request #654 from lyogavin/enhance_pipe + [fix typo and coding style in #638] + + 73f4c7d Tue Jun 18 04:21:17 2013 -0700 + Merge pull request #605 from esjewett/SPARK-699 + [Add hBase example (retry of pull request #596)] + + 9933836 Tue Jun 18 02:41:10 2013 -0700 + Merge pull request #647 from jerryshao/master + [Reduce ZippedPartitionsRDD's getPreferredLocations complexity from O(2^2n) to O(2^n)] + + db42451 Mon Jun 17 15:26:36 2013 -0700 + Merge pull request #643 from adatao/master + [Bug fix: Zero-length partitions result in NaN for overall mean & variance] + + e82a2ff Mon Jun 17 15:13:15 2013 -0700 + Merge pull request #653 from rxin/logging + [SPARK-781: Log the temp directory path when Spark says "Failed to create temp directory."] + + e6d1277 Mon Jun 17 12:56:25 2013 -0700 + Merge pull request #638 from lyogavin/enhance_pipe + [Enhance pipe to support more features we can do in hadoop streaming] + + f961aac Sat Jun 15 00:53:41 2013 -0700 + Merge pull request #649 from ryanlecompte/master + [Add top K method to RDD using a bounded priority queue] + + 6602d94 Fri Jun 14 10:41:31 2013 -0700 + Merge pull request #651 from rxin/groupbykey + [SPARK-772 / SPARK-774: groupByKey and cogroup should disable map side combine] + + d93851a Thu Jun 13 13:38:45 2013 -0700 + Merge pull request #645 from pwendell/compression + [Adding compression to Hadoop save functions] + + f1da591 Wed Jun 12 17:55:08 2013 -0700 + Merge pull request #646 from markhamstra/jvmArgs + [Fixed jvmArgs in maven build.] + + 0e94b73 Mon Jun 10 13:00:31 2013 -0700 + Merge pull request #625 from stephenh/fix-start-slave + [Fix start-slave not passing instance number to spark-daemon.] + + 74b91d5 Sat Jun 8 01:19:40 2013 -0700 + Merge pull request #629 from c0s/master + [Sometime Maven build runs out of PermGen space.] + + c8fc423 Fri Jun 7 22:43:18 2013 -0700 + Merge pull request #631 from jerryshao/master + [Fix block manager UI display issue when enable spark.cleaner.ttl] + + 1ae60bc Fri Jun 7 22:39:06 2013 -0700 + Merge pull request #634 from xiajunluan/master + [[Spark-753] Fix ClusterSchedulSuite unit test failed ] + + fff3728 Tue Jun 4 16:09:50 2013 -0700 + Merge pull request #640 from pwendell/timeout-update + [Fixing bug in BlockManager timeout] + + f420d4f Tue Jun 4 15:25:58 2013 -0700 + Merge pull request #639 from pwendell/timeout-update + [Bump akka and blockmanager timeouts to 60 seconds] + + 84530ba Fri May 31 17:06:13 2013 -0700 + Merge pull request #636 from rxin/unpersist + [Unpersist More block manager cleanup.] + + ef77bb7 Thu May 30 14:50:06 2013 -0700 + Merge pull request #627 from shivaram/master + [Netty and shuffle bug fixes] + + 8cb8178 Thu May 30 14:17:44 2013 -0700 + Merge pull request #628 from shivaram/zero-block-size + [Skip fetching zero-sized blocks in NIO.] + + 6ed7139 Wed May 29 10:14:22 2013 -0700 + Merge pull request #626 from stephenh/remove-add-if-no-port + [Remove unused addIfNoPort.] + + 41d230c Tue May 28 23:35:24 2013 -0700 + Merge pull request #611 from squito/classloader + [Use default classloaders for akka & deserializing task results] + + 3db1e17 Mon May 27 21:31:43 2013 -0700 + Merge pull request #620 from jerryshao/master + [Fix CheckpointRDD java.io.FileNotFoundException when calling getPreferredLocations] + + 3d4891d Sat May 25 23:38:05 2013 -0700 + Merge pull request #621 from JoshRosen/spark-613 + [Use ec2-metadata in start-slave.sh to detect if running on EC2] + + e8d4b6c Sat May 25 21:09:03 2013 -0700 + Merge pull request #529 from xiajunluan/master + [[SPARK-663]Implement Fair Scheduler in Spark Cluster Scheduler ] + + 9a3c344 Sat May 25 17:53:43 2013 -0700 + Merge pull request #624 from rxin/master + [NonJavaSerializableClass should not be Java serializable...] + + 24e41aa Fri May 24 16:48:52 2013 -0700 + Merge pull request #623 from rxin/master + [Automatically configure Netty port.] + + 69161f9 Fri May 24 14:42:13 2013 -0700 + Merge pull request #622 from rxin/master + [bug fix: Shuffle block iterator is ignoring the shuffle serializer setting.] + + dbbedfc Thu May 23 23:11:06 2013 -0700 + Merge pull request #616 from jey/maven-netty-exclusion + [Exclude old versions of Netty from Maven-based build] + + a2b0a79 Tue May 21 18:16:20 2013 -0700 + Merge pull request #619 from woggling/adjust-sampling + [Use ARRAY_SAMPLE_SIZE constant instead of hard-coded 100.0 in SizeEstimator] + + 66dac44 Tue May 21 11:41:42 2013 -0700 + Merge pull request #618 from woggling/dead-code-disttest + [DistributedSuite: remove dead code] + + 5912cc4 Fri May 17 19:58:40 2013 -0700 + Merge pull request #610 from JoshRosen/spark-747 + [Throw exception if TaskResult exceeds Akka frame size] + + 6c27c38 Thu May 16 17:33:56 2013 -0700 + Merge pull request #615 from rxin/build-fix + [Maven build fix & two other small changes] + + 2f576ab Wed May 15 18:06:24 2013 -0700 + Merge pull request #602 from rxin/shufflemerge + [Manual merge & cleanup of Shane's Shuffle Performance Optimization] + + 48c6f46 Wed May 15 10:47:19 2013 -0700 + Merge pull request #612 from ash211/patch-4 + [Docs: Mention spark shell's default for MASTER] + + 203d7b7 Wed May 15 00:47:20 2013 -0700 + Merge pull request #593 from squito/driver_ui_link + [Master UI has link to Application UI] + + 016ac86 Mon May 13 21:45:36 2013 -0700 + Merge pull request #601 from rxin/emptyrdd-master + [EmptyRDD (master branch 0.8)] + + 4b354e0 Mon May 13 17:39:19 2013 -0700 + Merge pull request #589 from mridulm/master + [Add support for instance local scheduling] + + 5dbc9b2 Sun May 12 11:03:10 2013 -0700 + Merge pull request #608 from pwendell/SPARK-738 + [SPARK-738: Spark should detect and wrap nonserializable exceptions] + + 63e1999 Fri May 10 13:54:03 2013 -0700 + Merge pull request #606 from markhamstra/foreachPartition_fix + [Actually use the cleaned closure in foreachPartition] + + 42bbe89 Wed May 8 22:30:31 2013 -0700 + Merge pull request #599 from JoshRosen/spark-670 + [Fix SPARK-670: EC2 'start' command should require -i option.] + + 0f1b7a0 Wed May 8 13:38:50 2013 -0700 + Merge pull request #596 from esjewett/master + [hBase example] + + 7af92f2 Sat May 4 22:29:17 2013 -0700 + Merge pull request #597 from JoshRosen/webui-fixes + [Two minor bug fixes for Spark Web UI] + + c74ce60 Sat May 4 22:26:35 2013 -0700 + Merge pull request #598 from rxin/blockmanager + [Fixed flaky unpersist test in DistributedSuite.] + + 3bf2c86 Fri May 3 18:27:30 2013 -0700 + Merge pull request #594 from shivaram/master + [Add zip partitions to Java API] + + 2484ad7 Fri May 3 17:08:55 2013 -0700 + Merge pull request #587 from rxin/blockmanager + [A set of shuffle map output related changes] + + 6fe9d4e Thu May 2 21:33:56 2013 -0700 + Merge pull request #592 from woggling/localdir-fix + [Don't accept generated local directory names that can't be created] + + 538ee75 Thu May 2 09:01:42 2013 -0700 + Merge pull request #581 from jerryshao/master + [fix [SPARK-740] block manage UI throws exception when enabling Spark Streaming] + + 9abcbcc Wed May 1 22:45:10 2013 -0700 + Merge pull request #591 from rxin/removerdd + [RDD.unpersist: probably the most desired feature of Spark] + + aa8fe1a Tue Apr 30 22:30:18 2013 -0700 + Merge pull request #586 from mridulm/master + [Pull request to address issues Reynold Xin reported] + + f708dda Tue Apr 30 07:51:40 2013 -0700 + Merge pull request #585 from pwendell/listener-perf + [[Fix SPARK-742] Task Metrics should not employ per-record timing by default] + + 68c07ea Sun Apr 28 20:19:33 2013 -0700 + Merge pull request #582 from shivaram/master + [Add zip partitions interface] + + f6ee9a8 Sun Apr 28 15:36:04 2013 -0700 + Merge pull request #583 from mridulm/master + [Fix issues with streaming test cases after yarn branch merge] + + cf54b82 Thu Apr 25 11:45:58 2013 -0700 + Merge pull request #580 from pwendell/quickstart + [SPARK-739 Have quickstart standlone job use README] + + 118a6c7 Wed Apr 24 08:42:30 2013 -0700 + Merge pull request #575 from mridulm/master + [Manual merge of yarn branch to trunk] + + 5d8a71c Tue Apr 16 19:48:02 2013 -0700 + Merge pull request #570 from jey/increase-codecache-size + [Increase ReservedCodeCacheSize for sbt] + + ec5e553 Sun Apr 14 08:20:13 2013 -0700 + Merge pull request #558 from ash211/patch-jackson-conflict + [Don't pull in old versions of Jackson via hadoop-core] + + c1c219e Sun Apr 14 08:11:23 2013 -0700 + Merge pull request #564 from maspotts/master + [Allow latest scala in PATH, with SCALA_HOME as override (instead of vice-versa)] + + 7c10b3e Fri Apr 12 20:55:22 2013 -0700 + Merge pull request #565 from andyk/master + [Update wording of section on RDD operations in quick start guide in docs] + + 077ae0a Thu Apr 11 19:34:14 2013 -0700 + Merge pull request #561 from ash211/patch-4 + [Add details when BlockManager heartbeats time out] + + c91ff8d Wed Apr 10 15:08:23 2013 -0700 + Merge pull request #560 from ash211/patch-3 + [Typos: cluser -> cluster] + + 7cd83bf Tue Apr 9 22:07:35 2013 -0700 + Merge pull request #559 from ash211/patch-example-whitespace + [Uniform whitespace across scala examples] + + 271a4f3 Tue Apr 9 22:04:52 2013 -0700 + Merge pull request #555 from holdenk/master + [Retry failed ssh commands in the ec2 python script.] + + 8ac9efb Tue Apr 9 13:50:50 2013 -0700 + Merge pull request #527 from Reinvigorate/sm-kafka-cleanup + [KafkaInputDStream fixes and improvements] + + eed54a2 Mon Apr 8 09:44:30 2013 -0700 + Merge pull request #553 from pwendell/akka-standalone + [SPARK-724 - Have Akka logging enabled by default for standalone daemons] + + b362df3 Sun Apr 7 17:17:52 2013 -0700 + Merge pull request #552 from MLnick/master + [Bumping version for Twitter Algebird to latest] + + 4b30190 Sun Apr 7 17:15:10 2013 -0700 + Merge pull request #554 from andyk/scala2.9.3 + [Fixes SPARK-723 - Update build to Scala 2.9.3] + + dfe98ca Tue Apr 2 19:24:12 2013 -0700 + Merge pull request #550 from erikvanoosten/master + [corrected Algebird example] + + b5d7830 Tue Apr 2 19:23:45 2013 -0700 + Merge pull request #551 from jey/python-bugfixes + [Python bugfixes] + + 2be2295 Sun Mar 31 18:09:14 2013 -0700 + Merge pull request #548 from markhamstra/getWritableClass_filter + [Fixed broken filter in getWritableClass[T]] + + 9831bc1 Fri Mar 29 22:16:22 2013 -0700 + Merge pull request #539 from cgrothaus/fix-webui-workdirpath + [Bugfix: WorkerWebUI must respect workDirPath from Worker] + + 3cc8ab6 Fri Mar 29 22:14:07 2013 -0700 + Merge pull request #541 from stephenh/shufflecoalesce + [Add a shuffle parameter to coalesce.] + + cad507a Fri Mar 29 22:13:12 2013 -0700 + Merge pull request #547 from jey/maven-streaming-tests-initialization-fix + [Move streaming test initialization into 'before' blocks] + + a98996d Fri Mar 29 22:12:15 2013 -0700 + Merge pull request #545 from ash211/patch-1 + [Don't use deprecated Application in example] + + 104c694 Fri Mar 29 22:11:50 2013 -0700 + Merge pull request #546 from ash211/patch-2 + [Update tuning.md] + + bc36ee4 Tue Mar 26 15:05:13 2013 -0700 + Merge pull request #543 from holdenk/master + [Re-enable deprecation warnings and fix deprecated warning.] + + b8949ca Sat Mar 23 07:19:34 2013 -0700 + Merge pull request #505 from stephenh/volatile + [Make Executor fields volatile since they're read from the thread pool.] + + fd53f2f Sat Mar 23 07:13:21 2013 -0700 + Merge pull request #510 from markhamstra/WithThing + [mapWith, flatMapWith and filterWith] + + 4c5efcf Wed Mar 20 19:29:23 2013 -0700 + Merge pull request #532 from andyk/master + [SPARK-715: Adds instructions for building with Maven to documentation] + + 3558849 Wed Mar 20 19:27:47 2013 -0700 + Merge pull request #538 from rxin/cogroup + [Added mapSideCombine flag to CoGroupedRDD. Added unit test for CoGroupedRDD.] + + ca4d083 Wed Mar 20 11:22:36 2013 -0700 + Merge pull request #528 from MLnick/java-examples + [[SPARK-707] Adding Java versions of Pi, LogQuery and K-Means examples] + + b812e6b Wed Mar 20 11:21:02 2013 -0700 + Merge pull request #526 from markhamstra/foldByKey + [Add foldByKey] + + 945d1e7 Tue Mar 19 21:59:06 2013 -0700 + Merge pull request #536 from sasurfer/master + [CoalescedRDD for many partitions] + + 1cbbe94 Tue Mar 19 21:34:34 2013 -0700 + Merge pull request #534 from stephenh/removetrycatch + [Remove try/catch block that can't be hit.] + + 71e53f8 Tue Mar 19 21:31:41 2013 -0700 + Merge pull request #537 from wishbear/configurableInputFormat + [call setConf from input format if it is Configurable] + + c1e9cdc Sat Mar 16 11:47:45 2013 -0700 + Merge pull request #525 from stephenh/subtractByKey + [Add PairRDDFunctions.subtractByKey.] + + cdbfd1e Fri Mar 15 15:13:28 2013 -0700 + Merge pull request #516 from squito/fix_local_metrics + [Fix local metrics] + + f9fa2ad Fri Mar 15 15:12:43 2013 -0700 + Merge pull request #530 from mbautin/master-update-log4j-and-make-compile-in-IntelliJ + [Add a log4j compile dependency to fix build in IntelliJ] + + 4032beb Wed Mar 13 19:29:46 2013 -0700 + Merge pull request #521 from stephenh/earlyclose + [Close the reader in HadoopRDD as soon as iteration end.] + + 3c97276 Wed Mar 13 19:25:08 2013 -0700 + Merge pull request #524 from andyk/master + [Fix broken link to YARN documentation] + + 1c3d981 Wed Mar 13 19:23:48 2013 -0700 + Merge pull request #517 from Reinvigorate/sm-build-fixes + [Build fixes for streaming /w SBT] + + 2d477fd Wed Mar 13 06:49:16 2013 -0700 + Merge pull request #523 from andyk/master + [Fix broken link in Quick Start] + + 00c4d23 Tue Mar 12 22:19:00 2013 -0700 + Merge pull request #518 from woggling/long-bm-sizes + [Send block sizes as longs in BlockManager updates] + + cbf8f0d Mon Mar 11 00:23:57 2013 -0700 + Merge pull request #513 from MLnick/bagel-caching + [Adds choice of persistence level to Bagel.] + + 91a9d09 Sun Mar 10 15:48:23 2013 -0700 + Merge pull request #512 from patelh/fix-kryo-serializer + [Fix reference bug in Kryo serializer, add test, update version] + + 557cfd0 Sun Mar 10 15:44:57 2013 -0700 + Merge pull request #515 from woggling/deploy-app-death + [Notify standalone deploy client of application death.] + + 04fb81f Sun Mar 3 17:20:07 2013 -0800 + Merge pull request #506 from rxin/spark-706 + [Fixed SPARK-706: Failures in block manager put leads to read task hanging.] + + 6cf4be4 Sun Mar 3 17:16:22 2013 -0800 + Merge pull request #462 from squito/stageInfo + [Track assorted metrics for each task, report summaries to user at stage completion] + + 6bfc7ca Sat Mar 2 22:14:49 2013 -0800 + Merge pull request #504 from mosharaf/master + [Worker address was getting removed when removing an app.] + + 94b3db1 Sat Mar 2 22:13:52 2013 -0800 + Merge pull request #508 from markhamstra/TestServerInUse + [Avoid bind failure in InputStreamsSuite] + + 25c71d3 Fri Mar 1 08:00:18 2013 -0800 + Merge pull request #507 from markhamstra/poms271 + [bump version to 0.7.1-SNAPSHOT in the subproject poms] + From 7348893f0edd96dacce2f00970db1976266f7008 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 14:53:02 -0800 Subject: [PATCH 023/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 4ae8a4b39e738daf3f06c38de869b07927a927e1 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 15 Jan 2014 14:53:11 -0800 Subject: [PATCH 024/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From 7b0d5a5f306b0adb6590eb551096939d0c617142 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 16 Jan 2014 23:18:15 -0800 Subject: [PATCH 025/133] Merge pull request #451 from Qiuzhuang/master Fixed Window spark shell launch script error. JIRA SPARK-1029:https://spark-project.atlassian.net/browse/SPARK-1029 (cherry picked from commit d749d472b37448edb322bc7208a3db925c9a4fc2) Signed-off-by: Patrick Wendell --- bin/spark-class2.cmd | 2 +- bin/spark-shell.cmd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) mode change 100644 => 100755 bin/spark-class2.cmd mode change 100644 => 100755 bin/spark-shell.cmd diff --git a/bin/spark-class2.cmd b/bin/spark-class2.cmd old mode 100644 new mode 100755 index 460e6614766f8..80818c78ec24b --- a/bin/spark-class2.cmd +++ b/bin/spark-class2.cmd @@ -73,7 +73,7 @@ for %%d in ("%TOOLS_DIR%\target\scala-%SCALA_VERSION%\spark-tools*assembly*.jar" rem Compute classpath using external script set DONT_PRINT_CLASSPATH=1 -call "%FWDIR%sbin\compute-classpath.cmd" +call "%FWDIR%bin\compute-classpath.cmd" set DONT_PRINT_CLASSPATH=0 set CLASSPATH=%CLASSPATH%;%SPARK_TOOLS_JAR% diff --git a/bin/spark-shell.cmd b/bin/spark-shell.cmd old mode 100644 new mode 100755 index 23973e3e3dd43..99799128eb734 --- a/bin/spark-shell.cmd +++ b/bin/spark-shell.cmd @@ -18,6 +18,6 @@ rem limitations under the License. rem rem Find the path of sbin -set SBIN=%~dp0..\sbin\ +set BIN=%~dp0..\bin\ -cmd /V /E /C %SBIN%spark-class2.cmd org.apache.spark.repl.Main %* +cmd /V /E /C %BIN%spark-class2.cmd org.apache.spark.repl.Main %* From c8f92730f886fd91a96eb1090ac97cb34cf3709a Mon Sep 17 00:00:00 2001 From: Matei Zaharia Date: Sat, 18 Jan 2014 12:48:49 -0800 Subject: [PATCH 026/133] Remove Typesafe Config usage and conf files to fix nested property names With Typesafe Config we had the subtle problem of no longer allowing nested property names, which are used for a few of our properties: http://apache-spark-developers-list.1001551.n3.nabble.com/Config-properties-broken-in-master-td208.html --- .../scala/org/apache/spark/SparkConf.scala | 18 +++---- core/src/test/resources/spark.conf | 8 ---- .../org/apache/spark/SparkConfSuite.scala | 47 +++++++++++-------- docs/configuration.md | 28 +---------- project/SparkBuild.scala | 1 - python/pyspark/conf.py | 10 ++-- 6 files changed, 41 insertions(+), 71 deletions(-) delete mode 100644 core/src/test/resources/spark.conf diff --git a/core/src/main/scala/org/apache/spark/SparkConf.scala b/core/src/main/scala/org/apache/spark/SparkConf.scala index 369c6ce78fa71..951bfd79d0d6a 100644 --- a/core/src/main/scala/org/apache/spark/SparkConf.scala +++ b/core/src/main/scala/org/apache/spark/SparkConf.scala @@ -20,19 +20,17 @@ package org.apache.spark import scala.collection.JavaConverters._ import scala.collection.mutable.HashMap -import com.typesafe.config.ConfigFactory import java.io.{ObjectInputStream, ObjectOutputStream, IOException} /** * Configuration for a Spark application. Used to set various Spark parameters as key-value pairs. * * Most of the time, you would create a SparkConf object with `new SparkConf()`, which will load - * values from both the `spark.*` Java system properties and any `spark.conf` on your application's - * classpath (if it has one). In this case, system properties take priority over `spark.conf`, and - * any parameters you set directly on the `SparkConf` object take priority over both of those. + * values from any `spark.*` Java system properties set in your application as well. In this case, + * parameters you set directly on the `SparkConf` object take priority over system properties. * * For unit tests, you can also call `new SparkConf(false)` to skip loading external settings and - * get the same configuration no matter what is on the classpath. + * get the same configuration no matter what the system properties are. * * All setter methods in this class support chaining. For example, you can write * `new SparkConf().setMaster("local").setAppName("My app")`. @@ -40,7 +38,7 @@ import java.io.{ObjectInputStream, ObjectOutputStream, IOException} * Note that once a SparkConf object is passed to Spark, it is cloned and can no longer be modified * by the user. Spark does not support modifying the configuration at runtime. * - * @param loadDefaults whether to load values from the system properties and classpath + * @param loadDefaults whether to also load values from Java system properties */ class SparkConf(loadDefaults: Boolean) extends Cloneable with Logging { @@ -50,11 +48,9 @@ class SparkConf(loadDefaults: Boolean) extends Cloneable with Logging { private val settings = new HashMap[String, String]() if (loadDefaults) { - ConfigFactory.invalidateCaches() - val typesafeConfig = ConfigFactory.systemProperties() - .withFallback(ConfigFactory.parseResources("spark.conf")) - for (e <- typesafeConfig.entrySet().asScala if e.getKey.startsWith("spark.")) { - settings(e.getKey) = e.getValue.unwrapped.toString + // Load any spark.* system properties + for ((k, v) <- System.getProperties.asScala if k.startsWith("spark.")) { + settings(k) = v } } diff --git a/core/src/test/resources/spark.conf b/core/src/test/resources/spark.conf deleted file mode 100644 index aa4e7512354d3..0000000000000 --- a/core/src/test/resources/spark.conf +++ /dev/null @@ -1,8 +0,0 @@ -# A simple spark.conf file used only in our unit tests - -spark.test.intTestProperty = 1 - -spark.test { - stringTestProperty = "hi" - listTestProperty = ["a", "b"] -} diff --git a/core/src/test/scala/org/apache/spark/SparkConfSuite.scala b/core/src/test/scala/org/apache/spark/SparkConfSuite.scala index fa49974db445b..87e9012622456 100644 --- a/core/src/test/scala/org/apache/spark/SparkConfSuite.scala +++ b/core/src/test/scala/org/apache/spark/SparkConfSuite.scala @@ -20,35 +20,23 @@ package org.apache.spark import org.scalatest.FunSuite class SparkConfSuite extends FunSuite with LocalSparkContext { - // This test uses the spark.conf in core/src/test/resources, which has a few test properties - test("loading from spark.conf") { - val conf = new SparkConf() - assert(conf.get("spark.test.intTestProperty") === "1") - assert(conf.get("spark.test.stringTestProperty") === "hi") - // NOTE: we don't use list properties yet, but when we do, we'll have to deal with this syntax - assert(conf.get("spark.test.listTestProperty") === "[a, b]") - } - - // This test uses the spark.conf in core/src/test/resources, which has a few test properties - test("system properties override spark.conf") { + test("loading from system properties") { try { - System.setProperty("spark.test.intTestProperty", "2") + System.setProperty("spark.test.testProperty", "2") val conf = new SparkConf() - assert(conf.get("spark.test.intTestProperty") === "2") - assert(conf.get("spark.test.stringTestProperty") === "hi") + assert(conf.get("spark.test.testProperty") === "2") } finally { - System.clearProperty("spark.test.intTestProperty") + System.clearProperty("spark.test.testProperty") } } test("initializing without loading defaults") { try { - System.setProperty("spark.test.intTestProperty", "2") + System.setProperty("spark.test.testProperty", "2") val conf = new SparkConf(false) - assert(!conf.contains("spark.test.intTestProperty")) - assert(!conf.contains("spark.test.stringTestProperty")) + assert(!conf.contains("spark.test.testProperty")) } finally { - System.clearProperty("spark.test.intTestProperty") + System.clearProperty("spark.test.testProperty") } } @@ -124,4 +112,25 @@ class SparkConfSuite extends FunSuite with LocalSparkContext { assert(sc.master === "local[2]") assert(sc.appName === "My other app") } + + test("nested property names") { + // This wasn't supported by some external conf parsing libraries + try { + System.setProperty("spark.test.a", "a") + System.setProperty("spark.test.a.b", "a.b") + System.setProperty("spark.test.a.b.c", "a.b.c") + val conf = new SparkConf() + assert(conf.get("spark.test.a") === "a") + assert(conf.get("spark.test.a.b") === "a.b") + assert(conf.get("spark.test.a.b.c") === "a.b.c") + conf.set("spark.test.a.b", "A.B") + assert(conf.get("spark.test.a") === "a") + assert(conf.get("spark.test.a.b") === "A.B") + assert(conf.get("spark.test.a.b.c") === "a.b.c") + } finally { + System.clearProperty("spark.test.a") + System.clearProperty("spark.test.a.b") + System.clearProperty("spark.test.a.b.c") + } + } } diff --git a/docs/configuration.md b/docs/configuration.md index da70cabba2d9b..00864906b3c7b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -18,8 +18,8 @@ Spark provides three locations to configure the system: Spark properties control most application settings and are configured separately for each application. The preferred way to set them is by passing a [SparkConf](api/core/index.html#org.apache.spark.SparkConf) class to your SparkContext constructor. -Alternatively, Spark will also load them from Java system properties (for compatibility with old versions -of Spark) and from a [`spark.conf` file](#configuration-files) on your classpath. +Alternatively, Spark will also load them from Java system properties, for compatibility with old versions +of Spark. SparkConf lets you configure most of the common properties to initialize a cluster (e.g., master URL and application name), as well as arbitrary key-value pairs through the `set()` method. For example, we could @@ -468,30 +468,6 @@ Apart from these, the following properties are also available, and may be useful The application web UI at `http://:4040` lists Spark properties in the "Environment" tab. This is a useful place to check to make sure that your properties have been set correctly. -## Configuration Files - -You can also configure Spark properties through a `spark.conf` file on your Java classpath. -Because these properties are usually application-specific, we recommend putting this fine *only* on your -application's classpath, and not in a global Spark classpath. - -The `spark.conf` file uses Typesafe Config's [HOCON format](https://github.com/typesafehub/config#json-superset), -which is a superset of Java properties files and JSON. For example, the following is a simple config file: - -{% highlight awk %} -# Comments are allowed -spark.executor.memory = 512m -spark.serializer = org.apache.spark.serializer.KryoSerializer -{% endhighlight %} - -The format also allows hierarchical nesting, as follows: - -{% highlight awk %} -spark.akka { - threads = 8 - timeout = 200 -} -{% endhighlight %} - # Environment Variables Certain Spark settings can be configured through environment variables, which are read from the `conf/spark-env.sh` diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index bcc286d7ea190..075e912f2d96c 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -277,7 +277,6 @@ object SparkBuild extends Build { "com.codahale.metrics" % "metrics-graphite" % "3.0.0", "com.twitter" %% "chill" % "0.3.1", "com.twitter" % "chill-java" % "0.3.1", - "com.typesafe" % "config" % "1.0.2", "com.clearspring.analytics" % "stream" % "2.5.1" ) ) diff --git a/python/pyspark/conf.py b/python/pyspark/conf.py index d72aed6a30ec1..3870cd8f2b097 100644 --- a/python/pyspark/conf.py +++ b/python/pyspark/conf.py @@ -61,14 +61,12 @@ class SparkConf(object): Most of the time, you would create a SparkConf object with C{SparkConf()}, which will load values from C{spark.*} Java system - properties and any C{spark.conf} on your Spark classpath. In this - case, system properties take priority over C{spark.conf}, and any - parameters you set directly on the C{SparkConf} object take priority - over both of those. + properties as well. In this case, any parameters you set directly on + the C{SparkConf} object take priority over system properties. For unit tests, you can also call C{SparkConf(false)} to skip loading external settings and get the same configuration no matter - what is on the classpath. + what the system properties are. All setter methods in this class support chaining. For example, you can write C{conf.setMaster("local").setAppName("My app")}. @@ -82,7 +80,7 @@ def __init__(self, loadDefaults=True, _jvm=None): Create a new Spark configuration. @param loadDefaults: whether to load values from Java system - properties and classpath (True by default) + properties (True by default) @param _jvm: internal parameter used to pass a handle to the Java VM; does not need to be set by users """ From ff7201cf9e4f3af6943d6ff5d4b625404a174fec Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 12:49:21 -0800 Subject: [PATCH 027/133] Merge pull request #461 from pwendell/master Use renamed shuffle spill config in CoGroupedRDD.scala This one got missed when it was renamed. (cherry picked from commit aa981e4e97a11dbd5a4d012bfbdb395982968372) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala b/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala index f2feb406f7783..0e47f2e022610 100644 --- a/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/CoGroupedRDD.scala @@ -106,7 +106,7 @@ class CoGroupedRDD[K](@transient var rdds: Seq[RDD[_ <: Product2[K, _]]], part: override def compute(s: Partition, context: TaskContext): Iterator[(K, CoGroupCombiner)] = { val sparkConf = SparkEnv.get.conf - val externalSorting = sparkConf.getBoolean("spark.shuffle.externalSorting", true) + val externalSorting = sparkConf.getBoolean("spark.shuffle.spill", true) val split = s.asInstanceOf[CoGroupPartition] val numRdds = split.deps.size From 4ac8cab08141302c82c0388ccb98d627a144445d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 16:21:43 -0800 Subject: [PATCH 028/133] Merge pull request #426 from mateiz/py-ml-tests Re-enable Python MLlib tests (require Python 2.7 and NumPy 1.7+) We disabled these earlier because Jenkins didn't have these versions. (cherry picked from commit 4c16f79ce45a68ee613a3d565b0e8676b724f867) Signed-off-by: Patrick Wendell --- python/pyspark/mllib/__init__.py | 10 ++++++++++ python/run-tests | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/python/pyspark/mllib/__init__.py b/python/pyspark/mllib/__init__.py index b1a5df109b46e..b420d7a7f23ba 100644 --- a/python/pyspark/mllib/__init__.py +++ b/python/pyspark/mllib/__init__.py @@ -18,3 +18,13 @@ """ Python bindings for MLlib. """ + +# MLlib currently needs Python 2.7+ and NumPy 1.7+, so complain if lower + +import sys +if sys.version_info[0:2] < (2, 7): + raise Exception("MLlib requires Python 2.7+") + +import numpy +if numpy.version.version < '1.7': + raise Exception("MLlib requires NumPy 1.7+") diff --git a/python/run-tests b/python/run-tests index 2005f610b43b4..a986ac9380be4 100755 --- a/python/run-tests +++ b/python/run-tests @@ -40,11 +40,11 @@ run_test "-m doctest pyspark/broadcast.py" run_test "-m doctest pyspark/accumulators.py" run_test "-m doctest pyspark/serializers.py" run_test "pyspark/tests.py" -#run_test "pyspark/mllib/_common.py" -#run_test "pyspark/mllib/classification.py" -#run_test "pyspark/mllib/clustering.py" -#run_test "pyspark/mllib/recommendation.py" -#run_test "pyspark/mllib/regression.py" +run_test "pyspark/mllib/_common.py" +run_test "pyspark/mllib/classification.py" +run_test "pyspark/mllib/clustering.py" +run_test "pyspark/mllib/recommendation.py" +run_test "pyspark/mllib/regression.py" if [[ $FAILED != 0 ]]; then echo -en "\033[31m" # Red From 76147a290327c8ff76c845cbe347b5fe09de3da7 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 16:23:56 -0800 Subject: [PATCH 029/133] Merge pull request #437 from mridulm/master Minor api usability changes - Expose checkpoint directory - since it is autogenerated now - null check for jars - Expose SparkHadoopUtil : so that configuration creation is abstracted even from user code to avoid duplication of functionality already in spark. (cherry picked from commit 73dfd42fba5e526cc57e2a2ed78be323b63cb8fa) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/SparkContext.scala | 4 +++- .../scala/org/apache/spark/api/java/JavaSparkContext.scala | 2 ++ .../main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/SparkContext.scala b/core/src/main/scala/org/apache/spark/SparkContext.scala index ba3e91effbdb4..ddd7d60d96bd5 100644 --- a/core/src/main/scala/org/apache/spark/SparkContext.scala +++ b/core/src/main/scala/org/apache/spark/SparkContext.scala @@ -956,6 +956,8 @@ class SparkContext( } } + def getCheckpointDir = checkpointDir + /** Default level of parallelism to use when not given by user (e.g. parallelize and makeRDD). */ def defaultParallelism: Int = taskScheduler.defaultParallelism @@ -1125,7 +1127,7 @@ object SparkContext { if (sparkHome != null) { res.setSparkHome(sparkHome) } - if (!jars.isEmpty) { + if (jars != null && !jars.isEmpty) { res.setJars(jars) } res.setExecutorEnv(environment.toSeq) diff --git a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala index 8041163e3d748..33c931b1a7c8b 100644 --- a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala +++ b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala @@ -401,6 +401,8 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork sc.setCheckpointDir(dir) } + def getCheckpointDir = JavaUtils.optionToOptional(sc.getCheckpointDir) + protected def checkpointFile[T](path: String): JavaRDD[T] = { implicit val cm: ClassTag[T] = implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[T]] diff --git a/core/src/main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala b/core/src/main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala index 27dc42bf7e50e..b479225b45ee9 100644 --- a/core/src/main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala +++ b/core/src/main/scala/org/apache/spark/deploy/SparkHadoopUtil.scala @@ -28,7 +28,6 @@ import org.apache.spark.{SparkContext, SparkException} /** * Contains util methods to interact with Hadoop from Spark. */ -private[spark] class SparkHadoopUtil { val conf = newConfiguration() UserGroupInformation.setConfiguration(conf) From 03019d106becae3cca95428b462d661c1afac37e Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 16:29:23 -0800 Subject: [PATCH 030/133] Merge pull request #459 from srowen/UpdaterL2Regularization Correct L2 regularized weight update with canonical form Per thread on the user@ mailing list, and comments from Ameet, I believe the weight update for L2 regularization needs to be corrected. See http://mail-archives.apache.org/mod_mbox/spark-user/201401.mbox/%3CCAH3_EVMetuQuhj3__NdUniDLc4P-FMmmrmxw9TS14or8nT4BNQ%40mail.gmail.com%3E (cherry picked from commit fe8a3546f40394466a41fc750cb60f6fc73d8bbb) Signed-off-by: Patrick Wendell --- .../scala/org/apache/spark/mllib/optimization/Updater.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mllib/src/main/scala/org/apache/spark/mllib/optimization/Updater.scala b/mllib/src/main/scala/org/apache/spark/mllib/optimization/Updater.scala index 4c51f4f881f76..37124f261eeb9 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/optimization/Updater.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/optimization/Updater.scala @@ -86,13 +86,17 @@ class L1Updater extends Updater { /** * Updater that adjusts the learning rate and performs L2 regularization + * + * See, for example, explanation of gradient and loss with L2 regularization on slide 21-22 + * of + * these slides. */ class SquaredL2Updater extends Updater { override def compute(weightsOld: DoubleMatrix, gradient: DoubleMatrix, stepSize: Double, iter: Int, regParam: Double): (DoubleMatrix, Double) = { val thisIterStepSize = stepSize / math.sqrt(iter) val normGradient = gradient.mul(thisIterStepSize) - val newWeights = weightsOld.sub(normGradient).div(2.0 * thisIterStepSize * regParam + 1.0) + val newWeights = weightsOld.mul(1.0 - 2.0 * thisIterStepSize * regParam).sub(normGradient) (newWeights, pow(newWeights.norm2, 2.0) * regParam) } } From a4b316f27c0bf30fac941fb3e6e595ec7cada7a2 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 16:37:23 -0800 Subject: [PATCH 031/133] Rolling back versions for 0.9.0 release --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 2 +- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..292140acf4464 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..6f42dd9c90f5c 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..4f51a0e377db2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..231fc6dab211f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..9c658c16ec02a 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..63fc9e8c9a9dc 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..a71a0dd5dcae3 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..3fd15c65b532c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..8e044a906533f 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..4e053a19092cd 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..cdf0c38094990 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..154995ffaa10c 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..700d453299019 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..2064b9e7f9cdf 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..7d828296b361c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..f58687ebf9889 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..0ea48e15abad6 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating-SNASPHOT ../pom.xml From 49a2c8180271f438f7db57323ba4e95e0eafa9eb Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 16:58:44 -0800 Subject: [PATCH 032/133] Typo fix in build versions --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 2 +- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 292140acf4464..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 6f42dd9c90f5c..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 4f51a0e377db2..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 231fc6dab211f..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 9c658c16ec02a..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 63fc9e8c9a9dc..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index a71a0dd5dcae3..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 3fd15c65b532c..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 8e044a906533f..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4e053a19092cd..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index cdf0c38094990..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 154995ffaa10c..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ diff --git a/repl/pom.xml b/repl/pom.xml index 700d453299019..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 2064b9e7f9cdf..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 7d828296b361c..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index f58687ebf9889..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 0ea48e15abad6..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNASPHOT + 0.9.0-incubating-SNAPSHOT ../pom.xml From 77c32470a1b02d6f1475bda2cfb9ae5bd4b53dde Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 17:14:22 -0800 Subject: [PATCH 033/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 4f8f86c2c66dc2f6a17d5b0e4fdeeb06a71ba52f Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 17:14:28 -0800 Subject: [PATCH 034/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From 3368699c7c965cb42d7fa0064d8056ae16f172b2 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 21:29:31 -0800 Subject: [PATCH 035/133] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit 4f8f86c2c66dc2f6a17d5b0e4fdeeb06a71ba52f. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 91c970904782c71f9fd25c899d163a8c57321f88 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 21:29:40 -0800 Subject: [PATCH 036/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit 77c32470a1b02d6f1475bda2cfb9ae5bd4b53dde. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From eddd3476a741b5be5b15a1672a59ae965715647b Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 21:31:37 -0800 Subject: [PATCH 037/133] Updating CHANGES.txt file --- CHANGES.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index d5ca405dcc198..e6baf7bee61f2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,30 @@ Spark Change Log Release 0.9.0-incubating + 03019d1 Sat Jan 18 16:29:43 2014 -0800 + Merge pull request #459 from srowen/UpdaterL2Regularization + [Correct L2 regularized weight update with canonical form] + + 76147a2 Sat Jan 18 16:24:16 2014 -0800 + Merge pull request #437 from mridulm/master + [Minor api usability changes] + + 4ac8cab Sat Jan 18 16:22:46 2014 -0800 + Merge pull request #426 from mateiz/py-ml-tests + [Re-enable Python MLlib tests (require Python 2.7 and NumPy 1.7+)] + + 34e911c Sat Jan 18 16:17:34 2014 -0800 + Merge pull request #462 from mateiz/conf-file-fix + [Remove Typesafe Config usage and conf files to fix nested property names] + + ff7201c Sat Jan 18 12:50:02 2014 -0800 + Merge pull request #461 from pwendell/master + [Use renamed shuffle spill config in CoGroupedRDD.scala] + + 7b0d5a5 Thu Jan 16 23:18:48 2014 -0800 + Merge pull request #451 from Qiuzhuang/master + [Fixed Window spark shell launch script error.] + 4ccedb3 Wed Jan 15 14:26:48 2014 -0800 Merge pull request #444 from mateiz/py-version [Clarify that Python 2.7 is only needed for MLlib] From 00c847af1d4be2fe5fad887a57857eead1e517dc Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 21:45:13 -0800 Subject: [PATCH 038/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 34ae65b06128077751ec2b923c9740a429d8299d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 18 Jan 2014 21:45:20 -0800 Subject: [PATCH 039/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From 0f077b5b480cd6034b1e6c6f34d69e0c3c3854f2 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 10:29:54 -0800 Subject: [PATCH 040/133] Merge pull request #458 from tdas/docs-update Updated java API docs for streaming, along with very minor changes in the code examples. Docs updated for: Scala: StreamingContext, DStream, PairDStreamFunctions Java: JavaStreamingContext, JavaDStream, JavaPairDStream Example updated: JavaQueueStream: Not use deprecated method ActorWordCount: Use the public interface the right way. (cherry picked from commit 256a3553c447db0865ea8807a8fdbccb66a97b28) Signed-off-by: Patrick Wendell --- .../streaming/examples/JavaQueueStream.java | 3 +- .../streaming/examples/ActorWordCount.scala | 2 +- .../spark/streaming/StreamingContext.scala | 17 ++++-- .../streaming/api/java/JavaDStream.scala | 22 ++------ .../streaming/api/java/JavaPairDStream.scala | 4 ++ .../api/java/JavaStreamingContext.scala | 55 +++++++++---------- .../spark/streaming/dstream/DStream.scala | 6 +- .../dstream/PairDStreamFunctions.scala | 11 ++-- .../streaming/receivers/ActorReceiver.scala | 35 +++++++----- 9 files changed, 79 insertions(+), 76 deletions(-) diff --git a/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java b/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java index 7ef9c6c8f4aaf..e2d55f1a4e180 100644 --- a/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java +++ b/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java @@ -58,10 +58,9 @@ public static void main(String[] args) throws Exception { } for (int i = 0; i < 30; i++) { - rddQueue.add(ssc.sc().parallelize(list)); + rddQueue.add(ssc.sparkContext().parallelize(list)); } - // Create the QueueInputDStream and use it do some processing JavaDStream inputStream = ssc.queueStream(rddQueue); JavaPairDStream mappedStream = inputStream.map( diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala index 57e1b1f806e82..5a4aa7f3a2524 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala @@ -88,7 +88,7 @@ extends Actor with Receiver { override def preStart = remotePublisher ! SubscribeReceiver(context.self) def receive = { - case msg ⇒ context.parent ! pushBlock(msg.asInstanceOf[T]) + case msg ⇒ pushBlock(msg.asInstanceOf[T]) } override def postStop() = remotePublisher ! UnsubscribeReceiver(context.self) diff --git a/streaming/src/main/scala/org/apache/spark/streaming/StreamingContext.scala b/streaming/src/main/scala/org/apache/spark/streaming/StreamingContext.scala index 26257e652e537..5847b95e3f5d1 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/StreamingContext.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/StreamingContext.scala @@ -42,9 +42,15 @@ import org.apache.spark.streaming.scheduler._ import org.apache.hadoop.conf.Configuration /** - * A StreamingContext is the main entry point for Spark Streaming functionality. Besides the basic - * information (such as, cluster URL and job name) to internally create a SparkContext, it provides - * methods used to create DStream from various input sources. + * Main entry point for Spark Streaming functionality. It provides methods used to create + * [[org.apache.spark.streaming.dstream.DStream]]s from various input sources. It can be either + * created by providing a Spark master URL and an appName, or from a org.apache.spark.SparkConf + * configuration (see core Spark documentation), or from an existing org.apache.spark.SparkContext. + * The associated SparkContext can be accessed using `context.sparkContext`. After + * creating and transforming DStreams, the streaming computation can be started and stopped + * using `context.start()` and `context.stop()`, respectively. + * `context.awaitTransformation()` allows the current thread to wait for the termination + * of the context by `stop()` or by an exception. */ class StreamingContext private[streaming] ( sc_ : SparkContext, @@ -63,7 +69,7 @@ class StreamingContext private[streaming] ( /** * Create a StreamingContext by providing the configuration necessary for a new SparkContext. - * @param conf a [[org.apache.spark.SparkConf]] object specifying Spark parameters + * @param conf a org.apache.spark.SparkConf object specifying Spark parameters * @param batchDuration the time interval at which streaming data will be divided into batches */ def this(conf: SparkConf, batchDuration: Duration) = { @@ -88,7 +94,7 @@ class StreamingContext private[streaming] ( } /** - * Re-create a StreamingContext from a checkpoint file. + * Recreate a StreamingContext from a checkpoint file. * @param path Path to the directory that was specified as the checkpoint directory * @param hadoopConf Optional, configuration object if necessary for reading from * HDFS compatible filesystems @@ -151,6 +157,7 @@ class StreamingContext private[streaming] ( private[streaming] val scheduler = new JobScheduler(this) private[streaming] val waiter = new ContextWaiter + /** * Return the associated Spark context */ diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStream.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStream.scala index c92854ccd9a28..e23b725052864 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStream.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStream.scala @@ -27,22 +27,12 @@ import scala.reflect.ClassTag import org.apache.spark.streaming.dstream.DStream /** - * A Discretized Stream (DStream), the basic abstraction in Spark Streaming, is a continuous - * sequence of RDDs (of the same type) representing a continuous stream of data (see [[org.apache.spark.rdd.RDD]] - * for more details on RDDs). DStreams can either be created from live data (such as, data from - * HDFS, Kafka or Flume) or it can be generated by transformation existing DStreams using operations - * such as `map`, `window` and `reduceByKeyAndWindow`. While a Spark Streaming program is running, each - * DStream periodically generates a RDD, either from live data or by transforming the RDD generated - * by a parent DStream. - * - * This class contains the basic operations available on all DStreams, such as `map`, `filter` and - * `window`. In addition, [[org.apache.spark.streaming.api.java.JavaPairDStream]] contains operations available - * only on DStreams of key-value pairs, such as `groupByKeyAndWindow` and `join`. - * - * DStreams internally is characterized by a few basic properties: - * - A list of other DStreams that the DStream depends on - * - A time interval at which the DStream generates an RDD - * - A function that is used to generate an RDD after each time interval + * A Java-friendly interface to [[org.apache.spark.streaming.dstream.DStream]], the basic + * abstraction in Spark Streaming that represents a continuous stream of data. + * DStreams can either be created from live data (such as, data from TCP sockets, Kafka, Flume, + * etc.) or it can be generated by transforming existing DStreams using operations such as `map`, + * `window`. For operations applicable to key-value pair DStreams, see + * [[org.apache.spark.streaming.api.java.JavaPairDStream]]. */ class JavaDStream[T](val dstream: DStream[T])(implicit val classTag: ClassTag[T]) extends JavaDStreamLike[T, JavaDStream[T], JavaRDD[T]] { diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala index 6bb985ca540ff..79fa6a623d290 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala @@ -37,6 +37,10 @@ import org.apache.spark.rdd.RDD import org.apache.spark.rdd.PairRDDFunctions import org.apache.spark.streaming.dstream.DStream +/** + * A Java-friendly interface to a DStream of key-value pairs, which provides extra methods + * like `reduceByKey` and `join`. + */ class JavaPairDStream[K, V](val dstream: DStream[(K, V)])( implicit val kManifest: ClassTag[K], implicit val vManifest: ClassTag[V]) diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala index 613683ca40501..921b56143af25 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaStreamingContext.scala @@ -22,7 +22,6 @@ import scala.collection.JavaConversions._ import scala.reflect.ClassTag import java.io.InputStream -import java.lang.{Integer => JInt} import java.util.{List => JList, Map => JMap} import akka.actor.{Props, SupervisorStrategy} @@ -39,19 +38,20 @@ import org.apache.hadoop.conf.Configuration import org.apache.spark.streaming.dstream.DStream /** - * A StreamingContext is the main entry point for Spark Streaming functionality. Besides the basic - * information (such as, cluster URL and job name) to internally create a SparkContext, it provides - * methods used to create DStream from various input sources. + * A Java-friendly version of [[org.apache.spark.streaming.StreamingContext]] which is the main + * entry point for Spark Streaming functionality. It provides methods to create + * [[org.apache.spark.streaming.api.java.JavaDStream]] and + * [[org.apache.spark.streaming.api.java.JavaPairDStream.]] from input sources. The internal + * org.apache.spark.api.java.JavaSparkContext (see core Spark documentation) can be accessed + * using `context.sparkContext`. After creating and transforming DStreams, the streaming + * computation can be started and stopped using `context.start()` and `context.stop()`, + * respectively. `context.awaitTransformation()` allows the current thread to wait for the + * termination of a context by `stop()` or by an exception. */ class JavaStreamingContext(val ssc: StreamingContext) { - // TODOs: - // - Test to/from Hadoop functions - // - Support creating and registering InputStreams - - /** - * Creates a StreamingContext. + * Create a StreamingContext. * @param master Name of the Spark Master * @param appName Name to be used when registering with the scheduler * @param batchDuration The time interval at which streaming data will be divided into batches @@ -60,7 +60,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(master, appName, batchDuration, null, Nil, Map())) /** - * Creates a StreamingContext. + * Create a StreamingContext. * @param master Name of the Spark Master * @param appName Name to be used when registering with the scheduler * @param batchDuration The time interval at which streaming data will be divided into batches @@ -77,7 +77,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(master, appName, batchDuration, sparkHome, Seq(jarFile), Map())) /** - * Creates a StreamingContext. + * Create a StreamingContext. * @param master Name of the Spark Master * @param appName Name to be used when registering with the scheduler * @param batchDuration The time interval at which streaming data will be divided into batches @@ -94,7 +94,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(master, appName, batchDuration, sparkHome, jars, Map())) /** - * Creates a StreamingContext. + * Create a StreamingContext. * @param master Name of the Spark Master * @param appName Name to be used when registering with the scheduler * @param batchDuration The time interval at which streaming data will be divided into batches @@ -113,7 +113,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(master, appName, batchDuration, sparkHome, jars, environment)) /** - * Creates a StreamingContext using an existing SparkContext. + * Create a JavaStreamingContext using an existing JavaSparkContext. * @param sparkContext The underlying JavaSparkContext to use * @param batchDuration The time interval at which streaming data will be divided into batches */ @@ -121,7 +121,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(sparkContext.sc, batchDuration)) /** - * Creates a StreamingContext using an existing SparkContext. + * Create a JavaStreamingContext using a SparkConf configuration. * @param conf A Spark application configuration * @param batchDuration The time interval at which streaming data will be divided into batches */ @@ -129,19 +129,18 @@ class JavaStreamingContext(val ssc: StreamingContext) { this(new StreamingContext(conf, batchDuration)) /** - * Re-creates a StreamingContext from a checkpoint file. + * Recreate a JavaStreamingContext from a checkpoint file. * @param path Path to the directory that was specified as the checkpoint directory */ def this(path: String) = this(new StreamingContext(path, new Configuration)) /** - * Re-creates a StreamingContext from a checkpoint file. + * Re-creates a JavaStreamingContext from a checkpoint file. * @param path Path to the directory that was specified as the checkpoint directory * */ def this(path: String, hadoopConf: Configuration) = this(new StreamingContext(path, hadoopConf)) - @deprecated("use sparkContext", "0.9.0") val sc: JavaSparkContext = sparkContext @@ -149,7 +148,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { val sparkContext = new JavaSparkContext(ssc.sc) /** - * Create a input stream from network source hostname:port. Data is received using + * Create an input stream from network source hostname:port. Data is received using * a TCP socket and the receive bytes is interpreted as UTF8 encoded \n delimited * lines. * @param hostname Hostname to connect to for receiving data @@ -162,7 +161,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream from network source hostname:port. Data is received using + * Create an input stream from network source hostname:port. Data is received using * a TCP socket and the receive bytes is interpreted as UTF8 encoded \n delimited * lines. Storage level of the data will be the default StorageLevel.MEMORY_AND_DISK_SER_2. * @param hostname Hostname to connect to for receiving data @@ -173,7 +172,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream from network source hostname:port. Data is received using + * Create an input stream from network source hostname:port. Data is received using * a TCP socket and the receive bytes it interepreted as object using the given * converter. * @param hostname Hostname to connect to for receiving data @@ -195,7 +194,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream that monitors a Hadoop-compatible filesystem + * Create an input stream that monitors a Hadoop-compatible filesystem * for new files and reads them as text files (using key as LongWritable, value * as Text and input format as TextInputFormat). Files must be written to the * monitored directory by "moving" them from another location within the same @@ -207,7 +206,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream from network source hostname:port, where data is received + * Create an input stream from network source hostname:port, where data is received * as serialized blocks (serialized using the Spark's serializer) that can be directly * pushed into the block manager without deserializing them. This is the most efficient * way to receive data. @@ -226,7 +225,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream from network source hostname:port, where data is received + * Create an input stream from network source hostname:port, where data is received * as serialized blocks (serialized using the Spark's serializer) that can be directly * pushed into the block manager without deserializing them. This is the most efficient * way to receive data. @@ -241,7 +240,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Create a input stream that monitors a Hadoop-compatible filesystem + * Create an input stream that monitors a Hadoop-compatible filesystem * for new files and reads them using the given key-value types and input format. * Files must be written to the monitored directory by "moving" them from another * location within the same file system. File names starting with . are ignored. @@ -324,7 +323,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Creates a input stream from an queue of RDDs. In each batch, + * Creates an input stream from an queue of RDDs. In each batch, * it will process either one or all of the RDDs returned by the queue. * * NOTE: changes to the queue after the stream is created will not be recognized. @@ -340,7 +339,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Creates a input stream from an queue of RDDs. In each batch, + * Creates an input stream from an queue of RDDs. In each batch, * it will process either one or all of the RDDs returned by the queue. * * NOTE: changes to the queue after the stream is created will not be recognized. @@ -357,7 +356,7 @@ class JavaStreamingContext(val ssc: StreamingContext) { } /** - * Creates a input stream from an queue of RDDs. In each batch, + * Creates an input stream from an queue of RDDs. In each batch, * it will process either one or all of the RDDs returned by the queue. * * NOTE: changes to the queue after the stream is created will not be recognized. diff --git a/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStream.scala b/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStream.scala index 71a4c5c93e76a..6bff56a9d332a 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStream.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/dstream/DStream.scala @@ -37,8 +37,9 @@ import org.apache.spark.streaming.Duration * A Discretized Stream (DStream), the basic abstraction in Spark Streaming, is a continuous * sequence of RDDs (of the same type) representing a continuous stream of data (see * org.apache.spark.rdd.RDD in the Spark core documentation for more details on RDDs). - * DStreams can either be created from live data (such as, data from Kafka, Flume, sockets, HDFS) - * or it can be generated by transforming existing DStreams using operations such as `map`, + * DStreams can either be created from live data (such as, data from TCP sockets, Kafka, Flume, + * etc.) using a [[org.apache.spark.streaming.StreamingContext]] or it can be generated by + * transforming existing DStreams using operations such as `map`, * `window` and `reduceByKeyAndWindow`. While a Spark Streaming program is running, each DStream * periodically generates a RDD, either from live data or by transforming the RDD generated by a * parent DStream. @@ -540,7 +541,6 @@ abstract class DStream[T: ClassTag] ( * on each RDD of 'this' DStream. */ def transform[U: ClassTag](transformFunc: (RDD[T], Time) => RDD[U]): DStream[U] = { - //new TransformedDStream(this, context.sparkContext.clean(transformFunc)) val cleanedF = context.sparkContext.clean(transformFunc) val realTransformFunc = (rdds: Seq[RDD[_]], time: Time) => { assert(rdds.length == 1) diff --git a/streaming/src/main/scala/org/apache/spark/streaming/dstream/PairDStreamFunctions.scala b/streaming/src/main/scala/org/apache/spark/streaming/dstream/PairDStreamFunctions.scala index f57762321c40e..fb9df2f48eae3 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/dstream/PairDStreamFunctions.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/dstream/PairDStreamFunctions.scala @@ -18,20 +18,17 @@ package org.apache.spark.streaming.dstream import org.apache.spark.streaming.StreamingContext._ -import org.apache.spark.streaming.dstream._ import org.apache.spark.{Partitioner, HashPartitioner} import org.apache.spark.SparkContext._ -import org.apache.spark.rdd.{ClassTags, RDD, PairRDDFunctions} -import org.apache.spark.storage.StorageLevel +import org.apache.spark.rdd.RDD import scala.collection.mutable.ArrayBuffer -import scala.reflect.{ClassTag, classTag} +import scala.reflect.ClassTag -import org.apache.hadoop.mapred.{JobConf, OutputFormat} +import org.apache.hadoop.mapred.JobConf import org.apache.hadoop.mapreduce.{OutputFormat => NewOutputFormat} import org.apache.hadoop.mapred.OutputFormat -import org.apache.hadoop.security.UserGroupInformation import org.apache.hadoop.conf.Configuration import org.apache.spark.streaming.{Time, Duration} @@ -108,7 +105,7 @@ extends Serializable { /** * Combine elements of each key in DStream's RDDs using custom functions. This is similar to the * combineByKey for RDDs. Please refer to combineByKey in - * [[org.apache.spark.rdd.PairRDDFunctions]] for more information. + * org.apache.spark.rdd.PairRDDFunctions in the Spark core documentation for more information. */ def combineByKey[C: ClassTag]( createCombiner: V => C, diff --git a/streaming/src/main/scala/org/apache/spark/streaming/receivers/ActorReceiver.scala b/streaming/src/main/scala/org/apache/spark/streaming/receivers/ActorReceiver.scala index fdf5371a89587..79ed696814f07 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/receivers/ActorReceiver.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/receivers/ActorReceiver.scala @@ -44,40 +44,49 @@ object ReceiverSupervisorStrategy { /** * A receiver trait to be mixed in with your Actor to gain access to - * pushBlock API. + * the API for pushing received data into Spark Streaming for being processed. * * Find more details at: http://spark-project.org/docs/latest/streaming-custom-receivers.html * * @example {{{ * class MyActor extends Actor with Receiver{ * def receive { - * case anything :String => pushBlock(anything) + * case anything: String => pushBlock(anything) * } * } - * //Can be plugged in actorStream as follows + * + * // Can be used with an actorStream as follows * ssc.actorStream[String](Props(new MyActor),"MyActorReceiver") * * }}} * - * @note An important point to note: - * Since Actor may exist outside the spark framework, It is thus user's responsibility + * @note Since Actor may exist outside the spark framework, It is thus user's responsibility * to ensure the type safety, i.e parametrized type of push block and InputDStream * should be same. - * */ -trait Receiver { self: Actor ⇒ +trait Receiver { + + self: Actor ⇒ // to ensure that this can be added to Actor classes only + + /** + * Push an iterator received data into Spark Streaming for processing + */ def pushBlock[T: ClassTag](iter: Iterator[T]) { context.parent ! Data(iter) } + /** + * Push a single item of received data into Spark Streaming for processing + */ def pushBlock[T: ClassTag](data: T) { context.parent ! Data(data) } - } /** - * Statistics for querying the supervisor about state of workers + * Statistics for querying the supervisor about state of workers. Used in + * conjunction with `StreamingContext.actorStream` and + * [[org.apache.spark.streaming.receivers.Receiver]]. */ case class Statistics(numberOfMsgs: Int, numberOfWorkers: Int, @@ -96,17 +105,15 @@ private[streaming] case class Data[T: ClassTag](data: T) * his own Actor to run as receiver for Spark Streaming input source. * * This starts a supervisor actor which starts workers and also provides - * [http://doc.akka.io/docs/akka/2.0.5/scala/fault-tolerance.html fault-tolerance]. + * [http://doc.akka.io/docs/akka/snapshot/scala/fault-tolerance.html fault-tolerance]. * - * Here's a way to start more supervisor/workers as its children. + * Here's a way to start more supervisor/workers as its children. * * @example {{{ * context.parent ! Props(new Supervisor) * }}} OR {{{ - * context.parent ! Props(new Worker,"Worker") + * context.parent ! Props(new Worker, "Worker") * }}} - * - * */ private[streaming] class ActorReceiver[T: ClassTag]( props: Props, From 94ae25d4e66762e11881cdc9ed5c7cab6325eebb Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 11:33:11 -0800 Subject: [PATCH 041/133] Merge pull request #470 from tgravescs/fix_spark_examples_yarn Only log error on missing jar to allow spark examples to jar. Right now to run the spark examples on Yarn you have to use the --addJars option and put the jar in hdfs. To make that nicer so the user doesn't have to specify the --addJars option change it to simply log an error instead of throwing. (cherry picked from commit 792d9084e2bc9f778a00a56fa7dcfe4084153aea) Signed-off-by: Patrick Wendell --- .../main/scala/org/apache/spark/SparkContext.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/SparkContext.scala b/core/src/main/scala/org/apache/spark/SparkContext.scala index ddd7d60d96bd5..923b4ed68839c 100644 --- a/core/src/main/scala/org/apache/spark/SparkContext.scala +++ b/core/src/main/scala/org/apache/spark/SparkContext.scala @@ -708,8 +708,11 @@ class SparkContext( env.httpFileServer.addJar(new File(fileName)) } catch { case e: Exception => { + // For now just log an error but allow to go through so spark examples work. + // The spark examples don't really need the jar distributed since its also + // the app jar. logError("Error adding jar (" + e + "), was the --addJars option used?") - throw e + null } } } else { @@ -722,8 +725,10 @@ class SparkContext( path } } - addedJars(key) = System.currentTimeMillis - logInfo("Added JAR " + path + " at " + key + " with timestamp " + addedJars(key)) + if (key != null) { + addedJars(key) = System.currentTimeMillis + logInfo("Added JAR " + path + " at " + key + " with timestamp " + addedJars(key)) + } } } From 4b4011b5df8320fbd6e5009101df8b95aa106139 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 12:59:20 -0800 Subject: [PATCH 042/133] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit 34ae65b06128077751ec2b923c9740a429d8299d. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 303b33f89167d891293479eb9c980b6f52664878 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 12:59:22 -0800 Subject: [PATCH 043/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit 00c847af1d4be2fe5fad887a57857eead1e517dc. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From 130b543573e480e625f975ba0192ae78de69e963 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 13:00:44 -0800 Subject: [PATCH 044/133] Updating CHANGES.txt --- CHANGES.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index e6baf7bee61f2..2f234d205cf5c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,14 @@ Spark Change Log Release 0.9.0-incubating + 94ae25d Sun Jan 19 11:33:51 2014 -0800 + Merge pull request #470 from tgravescs/fix_spark_examples_yarn + [Only log error on missing jar to allow spark examples to jar.] + + 0f077b5 Sun Jan 19 10:30:29 2014 -0800 + Merge pull request #458 from tdas/docs-update + [Updated java API docs for streaming, along with very minor changes in the code examples.] + 03019d1 Sat Jan 18 16:29:43 2014 -0800 Merge pull request #459 from srowen/UpdaterL2Regularization [Correct L2 regularized weight update with canonical form] From a7760eff4ea6a474cab68896a88550f63bae8b0d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 13:15:33 -0800 Subject: [PATCH 045/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 50b88ffcc6f80c86438b19788ec0eaf8f3a10ee4 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 19 Jan 2014 13:15:39 -0800 Subject: [PATCH 046/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From f1379479998a40d8774b014459e58a90c82b2feb Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Mon, 20 Jan 2014 21:44:29 -0800 Subject: [PATCH 047/133] Merge pull request #483 from pwendell/gitignore Restricting /lib to top level directory in .gitignore This patch was proposed by Sean Mackrory. (cherry picked from commit 7373ffb5e794d3163d3f8d1801836c891e0d6cca) Signed-off-by: Patrick Wendell --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 39635d7eefbe7..3d178992123da 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ derby.log dist/ spark-*-bin.tar.gz unit-tests.log -lib/ +/lib/ From 410ba06ff0d7c7bfd31621f6d7d95d7eab00cb1a Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Mon, 20 Jan 2014 22:25:50 -0800 Subject: [PATCH 048/133] Merge pull request #482 from tdas/streaming-example-fix Added StreamingContext.awaitTermination to streaming examples StreamingContext.start() currently starts a non-daemon thread which prevents termination of a Spark Streaming program even if main function has exited. Since the expected behavior of a streaming program is to run until explicitly killed, this was sort of fine when spark streaming applications are launched from the command line. However, when launched in Yarn-standalone mode, this did not work as the driver effectively got terminated when the main function exits. So SparkStreaming examples did not work on Yarn. This addition to the examples ensures that the examples work on Yarn and also ensures that everyone learns that StreamingContext.awaitTermination() being necessary for SparkStreaming programs to wait. The true bug-fix of making sure all threads by Spark Streaming are daemon threads is left for post-0.9. (cherry picked from commit 0367981d47761cdccd8a44fc6fe803079979c5e3) Signed-off-by: Patrick Wendell --- .../org/apache/spark/streaming/examples/JavaFlumeEventCount.java | 1 + .../org/apache/spark/streaming/examples/JavaKafkaWordCount.java | 1 + .../apache/spark/streaming/examples/JavaNetworkWordCount.java | 1 + .../org/apache/spark/streaming/examples/JavaQueueStream.java | 1 + .../org/apache/spark/streaming/examples/ActorWordCount.scala | 1 + .../org/apache/spark/streaming/examples/FlumeEventCount.scala | 1 + .../org/apache/spark/streaming/examples/HdfsWordCount.scala | 1 + .../org/apache/spark/streaming/examples/KafkaWordCount.scala | 1 + .../org/apache/spark/streaming/examples/MQTTWordCount.scala | 1 + .../org/apache/spark/streaming/examples/NetworkWordCount.scala | 1 + .../org/apache/spark/streaming/examples/RawNetworkGrep.scala | 1 + .../spark/streaming/examples/RecoverableNetworkWordCount.scala | 1 + .../spark/streaming/examples/StatefulNetworkWordCount.scala | 1 + .../org/apache/spark/streaming/examples/TwitterAlgebirdCMS.scala | 1 + .../org/apache/spark/streaming/examples/TwitterAlgebirdHLL.scala | 1 + .../org/apache/spark/streaming/examples/TwitterPopularTags.scala | 1 + .../org/apache/spark/streaming/examples/ZeroMQWordCount.scala | 1 + 17 files changed, 17 insertions(+) diff --git a/examples/src/main/java/org/apache/spark/streaming/examples/JavaFlumeEventCount.java b/examples/src/main/java/org/apache/spark/streaming/examples/JavaFlumeEventCount.java index 7b5a243e26414..f061001dd264d 100644 --- a/examples/src/main/java/org/apache/spark/streaming/examples/JavaFlumeEventCount.java +++ b/examples/src/main/java/org/apache/spark/streaming/examples/JavaFlumeEventCount.java @@ -70,5 +70,6 @@ public String call(Long in) { }).print(); ssc.start(); + ssc.awaitTermination(); } } diff --git a/examples/src/main/java/org/apache/spark/streaming/examples/JavaKafkaWordCount.java b/examples/src/main/java/org/apache/spark/streaming/examples/JavaKafkaWordCount.java index 04f62ee204145..2ffd351b4e498 100644 --- a/examples/src/main/java/org/apache/spark/streaming/examples/JavaKafkaWordCount.java +++ b/examples/src/main/java/org/apache/spark/streaming/examples/JavaKafkaWordCount.java @@ -104,5 +104,6 @@ public Integer call(Integer i1, Integer i2) { wordCounts.print(); jssc.start(); + jssc.awaitTermination(); } } diff --git a/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java b/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java index 349d826ab5df7..7777c9832abd3 100644 --- a/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java +++ b/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java @@ -84,5 +84,6 @@ public Integer call(Integer i1, Integer i2) { wordCounts.print(); ssc.start(); + ssc.awaitTermination(); } } diff --git a/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java b/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java index e2d55f1a4e180..26c44620abec1 100644 --- a/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java +++ b/examples/src/main/java/org/apache/spark/streaming/examples/JavaQueueStream.java @@ -80,5 +80,6 @@ public Integer call(Integer i1, Integer i2) { reducedStream.print(); ssc.start(); + ssc.awaitTermination(); } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala index 5a4aa7f3a2524..a5888811cc5ea 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/ActorWordCount.scala @@ -171,5 +171,6 @@ object ActorWordCount { lines.flatMap(_.split("\\s+")).map(x => (x, 1)).reduceByKey(_ + _).print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/FlumeEventCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/FlumeEventCount.scala index a59be7899dd37..11c3aaad3c8a8 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/FlumeEventCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/FlumeEventCount.scala @@ -60,5 +60,6 @@ object FlumeEventCount { stream.count().map(cnt => "Received " + cnt + " flume events." ).print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/HdfsWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/HdfsWordCount.scala index 704b315ef8b22..954bcc9b6ef5d 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/HdfsWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/HdfsWordCount.scala @@ -50,6 +50,7 @@ object HdfsWordCount { val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _) wordCounts.print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/KafkaWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/KafkaWordCount.scala index 4a3d81c09a122..d9cb7326bb97d 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/KafkaWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/KafkaWordCount.scala @@ -61,6 +61,7 @@ object KafkaWordCount { wordCounts.print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/MQTTWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/MQTTWordCount.scala index 78b49fdcf1eb3..eb61caf8c85b9 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/MQTTWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/MQTTWordCount.scala @@ -101,5 +101,6 @@ object MQTTWordCount { val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _) wordCounts.print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala index 02264757123db..5656d487a57cc 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala @@ -54,5 +54,6 @@ object NetworkWordCount { val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _) wordCounts.print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/RawNetworkGrep.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/RawNetworkGrep.scala index 99b79c3949a4e..cdd7547d0d3b4 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/RawNetworkGrep.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/RawNetworkGrep.scala @@ -61,5 +61,6 @@ object RawNetworkGrep { union.filter(_.contains("the")).count().foreachRDD(r => println("Grep count: " + r.collect().mkString)) ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/RecoverableNetworkWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/RecoverableNetworkWordCount.scala index 8c5d0bd56845b..aa82bf3c6bd8e 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/RecoverableNetworkWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/RecoverableNetworkWordCount.scala @@ -114,5 +114,6 @@ object RecoverableNetworkWordCount { createContext(master, ip, port, outputPath) }) ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/StatefulNetworkWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/StatefulNetworkWordCount.scala index 1183eba84686b..88f1cef89b318 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/StatefulNetworkWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/StatefulNetworkWordCount.scala @@ -65,5 +65,6 @@ object StatefulNetworkWordCount { val stateDstream = wordDstream.updateStateByKey[Int](updateFunc) stateDstream.print() ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdCMS.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdCMS.scala index 483c4d311810f..bbd44948b6fa5 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdCMS.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdCMS.scala @@ -110,5 +110,6 @@ object TwitterAlgebirdCMS { }) ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdHLL.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdHLL.scala index 94c2bf29ac433..a0094d460feec 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdHLL.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterAlgebirdHLL.scala @@ -87,5 +87,6 @@ object TwitterAlgebirdHLL { }) ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterPopularTags.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterPopularTags.scala index 8a70d4a978cd4..896d010c68f18 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterPopularTags.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/TwitterPopularTags.scala @@ -69,5 +69,6 @@ object TwitterPopularTags { }) ssc.start() + ssc.awaitTermination() } } diff --git a/examples/src/main/scala/org/apache/spark/streaming/examples/ZeroMQWordCount.scala b/examples/src/main/scala/org/apache/spark/streaming/examples/ZeroMQWordCount.scala index 12d2a1084f900..85b4ce5e81950 100644 --- a/examples/src/main/scala/org/apache/spark/streaming/examples/ZeroMQWordCount.scala +++ b/examples/src/main/scala/org/apache/spark/streaming/examples/ZeroMQWordCount.scala @@ -91,5 +91,6 @@ object ZeroMQWordCount { val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _) wordCounts.print() ssc.start() + ssc.awaitTermination() } } From e5f8917fd75e1c6f596db7f1bbca5760e3b6c301 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Mon, 20 Jan 2014 23:34:35 -0800 Subject: [PATCH 049/133] Merge pull request #484 from tdas/run-example-fix Made run-example respect SPARK_JAVA_OPTS and SPARK_MEM. bin/run-example scripts was not passing Java properties set through the SPARK_JAVA_OPTS to the example. This is important for examples like Twitter** as the Twitter authentication information must be set through java properties. Hence added the same JAVA_OPTS code in run-example as it is in bin/spark-class script. Also added SPARK_MEM, in case someone wants to run the example with different amounts of memory. This can be removed if it is not tune with the intended semantics of the run-example scripts. @matei Please check this soon I want this to go in 0.9-rc4 (cherry picked from commit c67d3d8beb101fff2ea6397b759dd1bfdf9fcfa5) Signed-off-by: Patrick Wendell --- bin/run-example | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/run-example b/bin/run-example index 2e9d51440bd5d..adba7dd97aaf8 100755 --- a/bin/run-example +++ b/bin/run-example @@ -76,11 +76,20 @@ else fi fi +# Set JAVA_OPTS to be able to load native libraries and to set heap size +JAVA_OPTS="$SPARK_JAVA_OPTS" +JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$SPARK_LIBRARY_PATH" +# Load extra JAVA_OPTS from conf/java-opts, if it exists +if [ -e "$FWDIR/conf/java-opts" ] ; then + JAVA_OPTS="$JAVA_OPTS `cat $FWDIR/conf/java-opts`" +fi +export JAVA_OPTS + if [ "$SPARK_PRINT_LAUNCH_COMMAND" == "1" ]; then echo -n "Spark Command: " - echo "$RUNNER" -cp "$CLASSPATH" "$@" + echo "$RUNNER" -cp "$CLASSPATH" $JAVA_OPTS "$@" echo "========================================" echo fi -exec "$RUNNER" -cp "$CLASSPATH" "$@" +exec "$RUNNER" -cp "$CLASSPATH" $JAVA_OPTS "$@" From b6fd3cd33d667e6fda517c7c491462b68c48145c Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 00:09:42 -0800 Subject: [PATCH 050/133] Merge pull request #480 from pwendell/0.9-fixes Handful of 0.9 fixes This patch addresses a few fixes for Spark 0.9.0 based on the last release candidate. @mridulm gets credit for reporting most of the issues here. Many of the fixes here are based on his work in #477 and follow up discussion with him. (cherry picked from commit 77b986f6616e6f7e0be9e46bb355829686f9845b) Signed-off-by: Patrick Wendell --- .../scala/org/apache/spark/SparkConf.scala | 10 ++++- .../org/apache/spark/rdd/CheckpointRDD.scala | 4 +- .../spark/scheduler/TaskSetManager.scala | 2 +- .../spark/storage/BlockObjectWriter.scala | 5 ++- .../spark/storage/ShuffleBlockManager.scala | 16 ++++++-- .../collection/ExternalAppendOnlyMap.scala | 41 +++++++++++++++---- docs/configuration.md | 11 ++--- 7 files changed, 65 insertions(+), 24 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/SparkConf.scala b/core/src/main/scala/org/apache/spark/SparkConf.scala index 951bfd79d0d6a..45d19bcbfa6f2 100644 --- a/core/src/main/scala/org/apache/spark/SparkConf.scala +++ b/core/src/main/scala/org/apache/spark/SparkConf.scala @@ -192,7 +192,15 @@ class SparkConf(loadDefaults: Boolean) extends Cloneable with Logging { } /** Get all akka conf variables set on this SparkConf */ - def getAkkaConf: Seq[(String, String)] = getAll.filter {case (k, v) => k.startsWith("akka.")} + def getAkkaConf: Seq[(String, String)] = + /* This is currently undocumented. If we want to make this public we should consider + * nesting options under the spark namespace to avoid conflicts with user akka options. + * Otherwise users configuring their own akka code via system properties could mess up + * spark's akka options. + * + * E.g. spark.akka.option.x.y.x = "value" + */ + getAll.filter {case (k, v) => k.startsWith("akka.")} /** Does the configuration contain a given parameter? */ def contains(key: String): Boolean = settings.contains(key) diff --git a/core/src/main/scala/org/apache/spark/rdd/CheckpointRDD.scala b/core/src/main/scala/org/apache/spark/rdd/CheckpointRDD.scala index 83109d1a6f853..30e578dd93e8d 100644 --- a/core/src/main/scala/org/apache/spark/rdd/CheckpointRDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/CheckpointRDD.scala @@ -43,8 +43,8 @@ class CheckpointRDD[T: ClassTag](sc: SparkContext, val checkpointPath: String) val numPartitions = // listStatus can throw exception if path does not exist. if (fs.exists(cpath)) { - val dirContents = fs.listStatus(cpath) - val partitionFiles = dirContents.map(_.getPath.toString).filter(_.contains("part-")).sorted + val dirContents = fs.listStatus(cpath).map(_.getPath) + val partitionFiles = dirContents.filter(_.getName.startsWith("part-")).map(_.toString).sorted val numPart = partitionFiles.size if (numPart > 0 && (! partitionFiles(0).endsWith(CheckpointRDD.splitIdToFile(0)) || ! partitionFiles(numPart-1).endsWith(CheckpointRDD.splitIdToFile(numPart-1)))) { diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala index fc0ee070897dd..73d6972bb4204 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala @@ -233,7 +233,7 @@ private[spark] class TaskSetManager( /** Check whether a task is currently running an attempt on a given host */ private def hasAttemptOnHost(taskIndex: Int, host: String): Boolean = { - !taskAttempts(taskIndex).exists(_.host == host) + taskAttempts(taskIndex).exists(_.host == host) } /** diff --git a/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala b/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala index 48cec4be4111c..530712b5df4a8 100644 --- a/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala +++ b/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala @@ -138,6 +138,7 @@ private[spark] class DiskBlockObjectWriter( fos = null ts = null objOut = null + initialized = false } } @@ -145,7 +146,8 @@ private[spark] class DiskBlockObjectWriter( override def commit(): Long = { if (initialized) { - // NOTE: Flush the serializer first and then the compressed/buffered output stream + // NOTE: Because Kryo doesn't flush the underlying stream we explicitly flush both the + // serializer stream and the lower level stream. objOut.flush() bs.flush() val prevPos = lastValidPosition @@ -175,7 +177,6 @@ private[spark] class DiskBlockObjectWriter( } override def fileSegment(): FileSegment = { - val bytesWritten = lastValidPosition - initialPosition new FileSegment(file, initialPosition, bytesWritten) } diff --git a/core/src/main/scala/org/apache/spark/storage/ShuffleBlockManager.scala b/core/src/main/scala/org/apache/spark/storage/ShuffleBlockManager.scala index e2b24298a55e8..bb07c8cb134cc 100644 --- a/core/src/main/scala/org/apache/spark/storage/ShuffleBlockManager.scala +++ b/core/src/main/scala/org/apache/spark/storage/ShuffleBlockManager.scala @@ -23,10 +23,11 @@ import java.util.concurrent.atomic.AtomicInteger import scala.collection.JavaConversions._ +import org.apache.spark.Logging import org.apache.spark.serializer.Serializer -import org.apache.spark.util.{MetadataCleanerType, MetadataCleaner, TimeStampedHashMap} -import org.apache.spark.util.collection.{PrimitiveKeyOpenHashMap, PrimitiveVector} import org.apache.spark.storage.ShuffleBlockManager.ShuffleFileGroup +import org.apache.spark.util.{MetadataCleaner, MetadataCleanerType, TimeStampedHashMap} +import org.apache.spark.util.collection.{PrimitiveKeyOpenHashMap, PrimitiveVector} /** A group of writers for a ShuffleMapTask, one writer per reducer. */ private[spark] trait ShuffleWriterGroup { @@ -58,7 +59,7 @@ private[spark] trait ShuffleWriterGroup { * files within a ShuffleFileGroups associated with the block's reducer. */ private[spark] -class ShuffleBlockManager(blockManager: BlockManager) { +class ShuffleBlockManager(blockManager: BlockManager) extends Logging { def conf = blockManager.conf // Turning off shuffle file consolidation causes all shuffle Blocks to get their own file. @@ -106,6 +107,15 @@ class ShuffleBlockManager(blockManager: BlockManager) { Array.tabulate[BlockObjectWriter](numBuckets) { bucketId => val blockId = ShuffleBlockId(shuffleId, mapId, bucketId) val blockFile = blockManager.diskBlockManager.getFile(blockId) + // Because of previous failures, the shuffle file may already exist on this machine. + // If so, remove it. + if (blockFile.exists) { + if (blockFile.delete()) { + logInfo(s"Removed existing shuffle file $blockFile") + } else { + logWarning(s"Failed to remove existing shuffle file $blockFile") + } + } blockManager.getDiskWriter(blockId, blockFile, serializer, bufferSize) } } diff --git a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala index 64e9b436f04a2..fb73636162af9 100644 --- a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala +++ b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala @@ -20,14 +20,15 @@ package org.apache.spark.util.collection import java.io._ import java.util.Comparator -import it.unimi.dsi.fastutil.io.FastBufferedInputStream - import scala.collection.mutable import scala.collection.mutable.ArrayBuffer +import it.unimi.dsi.fastutil.io.FastBufferedInputStream + import org.apache.spark.{Logging, SparkEnv} -import org.apache.spark.serializer.{KryoDeserializationStream, KryoSerializationStream, Serializer} -import org.apache.spark.storage.{BlockId, BlockManager, DiskBlockManager, DiskBlockObjectWriter} +import org.apache.spark.io.LZFCompressionCodec +import org.apache.spark.serializer.{KryoDeserializationStream, Serializer} +import org.apache.spark.storage.{BlockId, BlockManager, DiskBlockObjectWriter} /** * An append-only map that spills sorted content to disk when there is insufficient space for it @@ -153,9 +154,33 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( .format(mapSize / (1024 * 1024), spillCount, if (spillCount > 1) "s" else "")) val (blockId, file) = diskBlockManager.createTempBlock() - val compressStream: OutputStream => OutputStream = blockManager.wrapForCompression(blockId, _) + /* IMPORTANT NOTE: To avoid having to keep large object graphs in memory, this approach + * closes and re-opens serialization and compression streams within each file. This makes some + * assumptions about the way that serialization and compression streams work, specifically: + * + * 1) The serializer input streams do not pre-fetch data from the underlying stream. + * + * 2) Several compression streams can be opened, written to, and flushed on the write path + * while only one compression input stream is created on the read path + * + * In practice (1) is only true for Java, so we add a special fix below to make it work for + * Kryo. (2) is only true for LZF and not Snappy, so we coerce this to use LZF. + * + * To avoid making these assumptions we should create an intermediate stream that batches + * objects and sends an EOF to the higher layer streams to make sure they never prefetch data. + * This is a bit tricky because, within each segment, you'd need to track the total number + * of bytes written and then re-wind and write it at the beginning of the segment. This will + * most likely require using the file channel API. + */ + + val shouldCompress = blockManager.shouldCompress(blockId) + val compressionCodec = new LZFCompressionCodec(sparkConf) + def wrapForCompression(outputStream: OutputStream) = { + if (shouldCompress) compressionCodec.compressedOutputStream(outputStream) else outputStream + } + def getNewWriter = new DiskBlockObjectWriter(blockId, file, serializer, fileBufferSize, - compressStream, syncWrites) + wrapForCompression, syncWrites) var writer = getNewWriter var objectsWritten = 0 @@ -168,6 +193,8 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( if (objectsWritten == serializerBatchSize) { writer.commit() + writer.close() + _diskBytesSpilled += writer.bytesWritten writer = getNewWriter objectsWritten = 0 } @@ -176,8 +203,8 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( if (objectsWritten > 0) writer.commit() } finally { // Partial failures cannot be tolerated; do not revert partial writes - _diskBytesSpilled += writer.bytesWritten writer.close() + _diskBytesSpilled += writer.bytesWritten } currentMap = new SizeTrackingAppendOnlyMap[K, C] spilledMaps.append(new DiskMapIterator(file, blockId)) diff --git a/docs/configuration.md b/docs/configuration.md index 00864906b3c7b..be548e372dcd4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -158,7 +158,9 @@ Apart from these, the following properties are also available, and may be useful spark.shuffle.spill.compress true - Whether to compress data spilled during shuffles. + Whether to compress data spilled during shuffles. If enabled, spill compression + always uses the `org.apache.spark.io.LZFCompressionCodec` codec, + regardless of the value of `spark.io.compression.codec`. @@ -379,13 +381,6 @@ Apart from these, the following properties are also available, and may be useful Too large a value decreases parallelism during broadcast (makes it slower); however, if it is too small, BlockManager might take a performance hit. - - akka.x.y.... - value - - An arbitrary akka configuration can be set directly on spark conf and it is applied for all the ActorSystems created spark wide for that SparkContext and its assigned executors as well. - - spark.shuffle.consolidateFiles From 808a9f0b231aa395cde06ca4b08c2de5bd88d1fe Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 00:12:32 -0800 Subject: [PATCH 051/133] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit 50b88ffcc6f80c86438b19788ec0eaf8f3a10ee4. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 6b31963a7afe6170cbd7517781fa0d7765796aab Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 00:12:35 -0800 Subject: [PATCH 052/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit a7760eff4ea6a474cab68896a88550f63bae8b0d. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From 32545664bec32749f8a6056748cfa7a9dafcd292 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 00:13:09 -0800 Subject: [PATCH 053/133] Updating CHANGES.txt file --- CHANGES.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 2f234d205cf5c..f42ed7f9d14d7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,22 @@ Spark Change Log Release 0.9.0-incubating + b6fd3cd Tue Jan 21 00:12:01 2014 -0800 + Merge pull request #480 from pwendell/0.9-fixes + [Handful of 0.9 fixes] + + e5f8917 Mon Jan 20 23:35:07 2014 -0800 + Merge pull request #484 from tdas/run-example-fix + [Made run-example respect SPARK_JAVA_OPTS and SPARK_MEM.] + + 410ba06 Mon Jan 20 22:26:14 2014 -0800 + Merge pull request #482 from tdas/streaming-example-fix + [Added StreamingContext.awaitTermination to streaming examples] + + f137947 Mon Jan 20 22:24:07 2014 -0800 + Merge pull request #483 from pwendell/gitignore + [Restricting /lib to top level directory in .gitignore] + 94ae25d Sun Jan 19 11:33:51 2014 -0800 Merge pull request #470 from tgravescs/fix_spark_examples_yarn [Only log error on missing jar to allow spark examples to jar.] From 7653cf39e851cb63f1fda899cd7904ffab9a7a51 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 01:23:01 -0800 Subject: [PATCH 054/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 51b5e048517eb049f1b2fb515f98923d1dcdff3d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 01:29:55 -0800 Subject: [PATCH 055/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit 7653cf39e851cb63f1fda899cd7904ffab9a7a51. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From cd65c150d7e4be55695ca54a1709d577fdd509ba Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 21 Jan 2014 10:10:06 +0000 Subject: [PATCH 056/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From ab188b57b75267b118a45dc1c5ce35c1839d2ad6 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 21 Jan 2014 10:10:12 +0000 Subject: [PATCH 057/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From a3bd28a7a0ca82db2bd40d09c6cc244e1464b425 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 02:15:50 -0800 Subject: [PATCH 058/133] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit ab188b57b75267b118a45dc1c5ce35c1839d2ad6. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 334a8481f9e8e7e9323bd1141d729231e21aa0a7 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 21 Jan 2014 02:19:04 -0800 Subject: [PATCH 059/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit cd65c150d7e4be55695ca54a1709d577fdd509ba. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..4eca4747ea96a 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From 0771df675363c69622404cb514bd751bc90526af Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 21 Jan 2014 10:30:33 +0000 Subject: [PATCH 060/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 4eca4747ea96a..daadc73774e8d 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From e1dc5bedb48d2ac9b9e1c9b3b1a15c41b7d90ad8 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 21 Jan 2014 10:30:40 +0000 Subject: [PATCH 061/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index daadc73774e8d..67a8e015872cc 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From dd533c9e42a01319ebcbc0b01c3190a25784a2e1 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 22 Jan 2014 14:10:07 -0800 Subject: [PATCH 062/133] Merge pull request #478 from sryza/sandy-spark-1033 SPARK-1033. Ask for cores in Yarn container requests Tested on a pseudo-distributed cluster against the Fair Scheduler and observed a worker taking more than a single core. (cherry picked from commit 576c4a4c502ccca5fcd6b3552dd93cc2f3c50666) Signed-off-by: Patrick Wendell --- docs/running-on-yarn.md | 2 +- .../apache/spark/deploy/yarn/YarnAllocationHandler.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/running-on-yarn.md b/docs/running-on-yarn.md index 3bd62646bab06..5dadd54492dca 100644 --- a/docs/running-on-yarn.md +++ b/docs/running-on-yarn.md @@ -133,7 +133,7 @@ See [Building Spark with Maven](building-with-maven.html) for instructions on ho # Important Notes -- We do not requesting container resources based on the number of cores. Thus the numbers of cores given via command line arguments cannot be guaranteed. +- Before Hadoop 2.2, YARN does not support cores in container resource requests. Thus, when running against an earlier version, the numbers of cores given via command line arguments cannot be passed to YARN. Whether core requests are honored in scheduling decisions depends on which scheduler is in use and how it is configured. - The local directories used for spark will be the local directories configured for YARN (Hadoop Yarn config yarn.nodemanager.local-dirs). If the user specifies spark.local.dir, it will be ignored. - The --files and --archives options support specifying file names with the # similar to Hadoop. For example you can specify: --files localtest.txt#appSees.txt and this will upload the file you have locally named localtest.txt into HDFS but this will be linked to by the name appSees.txt and your application should use the name as appSees.txt to reference it when running on YARN. - The --addJars option allows the SparkContext.addJar function to work if you are using it with local files. It does not need to be used if you are using it with HDFS, HTTP, HTTPS, or FTP files. diff --git a/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/YarnAllocationHandler.scala b/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/YarnAllocationHandler.scala index 738ff986d85a5..1ac61124cb028 100644 --- a/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/YarnAllocationHandler.scala +++ b/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/YarnAllocationHandler.scala @@ -532,15 +532,15 @@ private[yarn] class YarnAllocationHandler( priority: Int ): ArrayBuffer[ContainerRequest] = { - val memoryResource = Records.newRecord(classOf[Resource]) - memoryResource.setMemory(workerMemory + YarnAllocationHandler.MEMORY_OVERHEAD) + val memoryRequest = workerMemory + YarnAllocationHandler.MEMORY_OVERHEAD + val resource = Resource.newInstance(memoryRequest, workerCores) val prioritySetting = Records.newRecord(classOf[Priority]) prioritySetting.setPriority(priority) val requests = new ArrayBuffer[ContainerRequest]() for (i <- 0 until numWorkers) { - requests += new ContainerRequest(memoryResource, hosts, racks, prioritySetting) + requests += new ContainerRequest(resource, hosts, racks, prioritySetting) } requests } From dc5857a36d2b12208120a0968b8fc1cb38043894 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 22 Jan 2014 14:32:59 -0800 Subject: [PATCH 063/133] Merge pull request #492 from skicavs/master fixed job name and usage information for the JavaSparkPi example (cherry picked from commit a1238bb5fcab763d32c729ea7ed99cb3c05c896f) Signed-off-by: Patrick Wendell --- .../src/main/java/org/apache/spark/examples/JavaSparkPi.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/main/java/org/apache/spark/examples/JavaSparkPi.java b/examples/src/main/java/org/apache/spark/examples/JavaSparkPi.java index 3ec4a58d48ed6..ac8df02c4630b 100644 --- a/examples/src/main/java/org/apache/spark/examples/JavaSparkPi.java +++ b/examples/src/main/java/org/apache/spark/examples/JavaSparkPi.java @@ -30,11 +30,11 @@ public final class JavaSparkPi { public static void main(String[] args) throws Exception { if (args.length == 0) { - System.err.println("Usage: JavaLogQuery [slices]"); + System.err.println("Usage: JavaSparkPi [slices]"); System.exit(1); } - JavaSparkContext jsc = new JavaSparkContext(args[0], "JavaLogQuery", + JavaSparkContext jsc = new JavaSparkContext(args[0], "JavaSparkPi", System.getenv("SPARK_HOME"), JavaSparkContext.jarOfClass(JavaSparkPi.class)); int slices = (args.length == 2) ? Integer.parseInt(args[1]) : 2; From 828f7b46ea7c6f7cf7f72bc03c61eeb9b929ac07 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 22 Jan 2014 15:45:04 -0800 Subject: [PATCH 064/133] Merge pull request #495 from srowen/GraphXCommonsMathDependency Fix graphx Commons Math dependency `graphx` depends on Commons Math (2.x) in `SVDPlusPlus.scala`. However the module doesn't declare this dependency. It happens to work because it is included by Hadoop artifacts. But, I can tell you this isn't true as of a month or so ago. Building versus recent Hadoop would fail. (That's how we noticed.) The simple fix is to declare the dependency, as it should be. But it's also worth noting that `commons-math` is the old-ish 2.x line, while `commons-math3` is where newer 3.x releases are. Drop-in replacement, but different artifact and package name. Changing this only usage to `commons-math3` works, tests pass, and isn't surprising that it does, so is probably also worth changing. (A comment in some test code also references `commons-math3`, FWIW.) It does raise another question though: `mllib` looks like it uses the `jblas` `DoubleMatrix` for general purpose vector/matrix stuff. Should `graphx` really use Commons Math for this? Beyond the tiny scope here but worth asking. (cherry picked from commit 3184facdc5b1e9ded89133f9b1e4985c9ac78c55) Signed-off-by: Patrick Wendell --- graphx/pom.xml | 5 +++++ .../main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala | 2 +- project/SparkBuild.scala | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/graphx/pom.xml b/graphx/pom.xml index 67a8e015872cc..9073cf7aa66ec 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -37,6 +37,11 @@ spark-core_${scala.binary.version} ${project.version} + + org.apache.commons + commons-math3 + 3.2 + org.eclipse.jetty jetty-server diff --git a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala index c327ce7935147..79280f836f21d 100644 --- a/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala +++ b/graphx/src/main/scala/org/apache/spark/graphx/lib/SVDPlusPlus.scala @@ -18,7 +18,7 @@ package org.apache.spark.graphx.lib import scala.util.Random -import org.apache.commons.math.linear._ +import org.apache.commons.math3.linear._ import org.apache.spark.rdd._ import org.apache.spark.graphx._ diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index 075e912f2d96c..b891ffab3259b 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -316,7 +316,10 @@ object SparkBuild extends Build { ) ++ assemblySettings ++ extraAssemblySettings def graphxSettings = sharedSettings ++ Seq( - name := "spark-graphx" + name := "spark-graphx", + libraryDependencies ++= Seq( + "org.apache.commons" % "commons-math3" % "3.2" + ) ) def bagelSettings = sharedSettings ++ Seq( From 51960b88dcb4b00623ae49d859f9690f42665713 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 22 Jan 2014 19:37:29 -0800 Subject: [PATCH 065/133] Merge pull request #496 from pwendell/master Fix bug in worker clean-up in UI Introduced in d5a96fec (/cc @aarondav). This should be picked into 0.8 and 0.9 as well. The bug causes old (zombie) workers on a node to not disappear immediately from the UI when a new one registers. (cherry picked from commit a1cd185122602c96fb8ae16c0b506702283bf6e2) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/deploy/master/Master.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/deploy/master/Master.scala b/core/src/main/scala/org/apache/spark/deploy/master/Master.scala index d9ea96afcf52a..7be774980afa3 100644 --- a/core/src/main/scala/org/apache/spark/deploy/master/Master.scala +++ b/core/src/main/scala/org/apache/spark/deploy/master/Master.scala @@ -515,7 +515,7 @@ private[spark] class Master(host: String, port: Int, webUiPort: Int) extends Act // There may be one or more refs to dead workers on this same node (w/ different ID's), // remove them. workers.filter { w => - (w.host == host && w.port == port) && (w.state == WorkerState.DEAD) + (w.host == worker.host && w.port == worker.port) && (w.state == WorkerState.DEAD) }.foreach { w => workers -= w } From 7a62353247a613b6ed1c4942858a311f965b74b4 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 19:08:34 -0800 Subject: [PATCH 066/133] Merge pull request #501 from JoshRosen/cartesian-rdd-fixes Fix two bugs in PySpark cartesian(): SPARK-978 and SPARK-1034 This pull request fixes two bugs in PySpark's `cartesian()` method: - [SPARK-978](https://spark-project.atlassian.net/browse/SPARK-978): PySpark's cartesian method throws ClassCastException exception - [SPARK-1034](https://spark-project.atlassian.net/browse/SPARK-1034): Py4JException on PySpark Cartesian Result The JIRAs have more details describing the fixes. (cherry picked from commit cad3002fead89d3c9a8de4fa989e88f367bc0b05) Signed-off-by: Patrick Wendell --- .../apache/spark/api/java/JavaPairRDD.scala | 3 +- .../apache/spark/api/python/PythonRDD.scala | 59 ++++++++++++------- python/pyspark/tests.py | 16 +++++ 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/api/java/JavaPairRDD.scala b/core/src/main/scala/org/apache/spark/api/java/JavaPairRDD.scala index 0fb7e195b34c4..f430a33db1e4a 100644 --- a/core/src/main/scala/org/apache/spark/api/java/JavaPairRDD.scala +++ b/core/src/main/scala/org/apache/spark/api/java/JavaPairRDD.scala @@ -49,8 +49,7 @@ class JavaPairRDD[K, V](val rdd: RDD[(K, V)])(implicit val kClassTag: ClassTag[K override def wrapRDD(rdd: RDD[(K, V)]): JavaPairRDD[K, V] = JavaPairRDD.fromRDD(rdd) - override val classTag: ClassTag[(K, V)] = - implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K, V]]] + override val classTag: ClassTag[(K, V)] = rdd.elementClassTag import JavaPairRDD._ diff --git a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala index 82527fe663848..57bde8d85f1a8 100644 --- a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala +++ b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala @@ -78,9 +78,7 @@ private[spark] class PythonRDD[T: ClassTag]( dataOut.writeInt(command.length) dataOut.write(command) // Data values - for (elem <- parent.iterator(split, context)) { - PythonRDD.writeToStream(elem, dataOut) - } + PythonRDD.writeIteratorToStream(parent.iterator(split, context), dataOut) dataOut.flush() worker.shutdownOutput() } catch { @@ -206,20 +204,43 @@ private[spark] object PythonRDD { JavaRDD.fromRDD(sc.sc.parallelize(objs, parallelism)) } - def writeToStream(elem: Any, dataOut: DataOutputStream) { - elem match { - case bytes: Array[Byte] => - dataOut.writeInt(bytes.length) - dataOut.write(bytes) - case pair: (Array[Byte], Array[Byte]) => - dataOut.writeInt(pair._1.length) - dataOut.write(pair._1) - dataOut.writeInt(pair._2.length) - dataOut.write(pair._2) - case str: String => - dataOut.writeUTF(str) - case other => - throw new SparkException("Unexpected element type " + other.getClass) + def writeIteratorToStream[T](iter: Iterator[T], dataOut: DataOutputStream) { + // The right way to implement this would be to use TypeTags to get the full + // type of T. Since I don't want to introduce breaking changes throughout the + // entire Spark API, I have to use this hacky approach: + if (iter.hasNext) { + val first = iter.next() + val newIter = Seq(first).iterator ++ iter + first match { + case arr: Array[Byte] => + newIter.asInstanceOf[Iterator[Array[Byte]]].foreach { bytes => + dataOut.writeInt(bytes.length) + dataOut.write(bytes) + } + case string: String => + newIter.asInstanceOf[Iterator[String]].foreach { str => + dataOut.writeUTF(str) + } + case pair: Tuple2[_, _] => + pair._1 match { + case bytePair: Array[Byte] => + newIter.asInstanceOf[Iterator[Tuple2[Array[Byte], Array[Byte]]]].foreach { pair => + dataOut.writeInt(pair._1.length) + dataOut.write(pair._1) + dataOut.writeInt(pair._2.length) + dataOut.write(pair._2) + } + case stringPair: String => + newIter.asInstanceOf[Iterator[Tuple2[String, String]]].foreach { pair => + dataOut.writeUTF(pair._1) + dataOut.writeUTF(pair._2) + } + case other => + throw new SparkException("Unexpected Tuple2 element type " + pair._1.getClass) + } + case other => + throw new SparkException("Unexpected element type " + first.getClass) + } } } @@ -230,9 +251,7 @@ private[spark] object PythonRDD { def writeToFile[T](items: Iterator[T], filename: String) { val file = new DataOutputStream(new FileOutputStream(filename)) - for (item <- items) { - writeToStream(item, file) - } + writeIteratorToStream(items, file) file.close() } diff --git a/python/pyspark/tests.py b/python/pyspark/tests.py index 7acb6eaf10931..acd1ca5676209 100644 --- a/python/pyspark/tests.py +++ b/python/pyspark/tests.py @@ -152,6 +152,22 @@ def test_save_as_textfile_with_unicode(self): raw_contents = ''.join(input(glob(tempFile.name + "/part-0000*"))) self.assertEqual(x, unicode(raw_contents.strip(), "utf-8")) + def test_transforming_cartesian_result(self): + # Regression test for SPARK-1034 + rdd1 = self.sc.parallelize([1, 2]) + rdd2 = self.sc.parallelize([3, 4]) + cart = rdd1.cartesian(rdd2) + result = cart.map(lambda (x, y): x + y).collect() + + def test_cartesian_on_textfile(self): + # Regression test for + path = os.path.join(SPARK_HOME, "python/test_support/hello.txt") + a = self.sc.textFile(path) + result = a.cartesian(a).collect() + (x, y) = result[0] + self.assertEqual("Hello World!", x.strip()) + self.assertEqual("Hello World!", y.strip()) + class TestIO(PySparkTestCase): From e8d3f2b2fbc3bb57f694aad1e8e6667cf7c7318a Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 19:11:59 -0800 Subject: [PATCH 067/133] Merge pull request #502 from pwendell/clone-1 Remove Hadoop object cloning and warn users making Hadoop RDD's. The code introduced in #359 used Hadoop's WritableUtils.clone() to duplicate objects when reading from Hadoop files. Some users have reported exceptions when cloning data in various file formats, including Avro and another custom format. This patch removes that functionality to ensure stability for the 0.9 release. Instead, it puts a clear warning in the documentation that copying may be necessary for Hadoop data sets. (cherry picked from commit c3196171f3dffde6c9e67e3d35c398a01fbba846) Conflicts: core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala --- .../scala/org/apache/spark/SparkContext.scala | 127 +++++++++++------- .../spark/api/java/JavaSparkContext.scala | 52 ++++++- .../org/apache/spark/rdd/HadoopRDD.scala | 28 +--- .../org/apache/spark/rdd/NewHadoopRDD.scala | 24 +--- .../scala/org/apache/spark/util/Utils.scala | 23 +--- 5 files changed, 138 insertions(+), 116 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/SparkContext.scala b/core/src/main/scala/org/apache/spark/SparkContext.scala index 923b4ed68839c..566472e597958 100644 --- a/core/src/main/scala/org/apache/spark/SparkContext.scala +++ b/core/src/main/scala/org/apache/spark/SparkContext.scala @@ -341,7 +341,7 @@ class SparkContext( */ def textFile(path: String, minSplits: Int = defaultMinSplits): RDD[String] = { hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text], - minSplits, cloneRecords = false).map(pair => pair._2.toString) + minSplits).map(pair => pair._2.toString) } /** @@ -354,33 +354,37 @@ class SparkContext( * @param keyClass Class of the keys * @param valueClass Class of the values * @param minSplits Minimum number of Hadoop Splits to generate. - * @param cloneRecords If true, Spark will clone the records produced by Hadoop RecordReader. - * Most RecordReader implementations reuse wrapper objects across multiple - * records, and can cause problems in RDD collect or aggregation operations. - * By default the records are cloned in Spark. However, application - * programmers can explicitly disable the cloning for better performance. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ - def hadoopRDD[K: ClassTag, V: ClassTag]( + def hadoopRDD[K, V]( conf: JobConf, inputFormatClass: Class[_ <: InputFormat[K, V]], keyClass: Class[K], valueClass: Class[V], - minSplits: Int = defaultMinSplits, - cloneRecords: Boolean = true + minSplits: Int = defaultMinSplits ): RDD[(K, V)] = { // Add necessary security credentials to the JobConf before broadcasting it. SparkHadoopUtil.get.addCredentials(conf) - new HadoopRDD(this, conf, inputFormatClass, keyClass, valueClass, minSplits, cloneRecords) + new HadoopRDD(this, conf, inputFormatClass, keyClass, valueClass, minSplits) } - /** Get an RDD for a Hadoop file with an arbitrary InputFormat */ - def hadoopFile[K: ClassTag, V: ClassTag]( + /** Get an RDD for a Hadoop file with an arbitrary InputFormat + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + * */ + def hadoopFile[K, V]( path: String, inputFormatClass: Class[_ <: InputFormat[K, V]], keyClass: Class[K], valueClass: Class[V], - minSplits: Int = defaultMinSplits, - cloneRecords: Boolean = true + minSplits: Int = defaultMinSplits ): RDD[(K, V)] = { // A Hadoop configuration can be about 10 KB, which is pretty big, so broadcast it. val confBroadcast = broadcast(new SerializableWritable(hadoopConfiguration)) @@ -392,8 +396,7 @@ class SparkContext( inputFormatClass, keyClass, valueClass, - minSplits, - cloneRecords) + minSplits) } /** @@ -403,16 +406,20 @@ class SparkContext( * {{{ * val file = sparkContext.hadoopFile[LongWritable, Text, TextInputFormat](path, minSplits) * }}} + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def hadoopFile[K, V, F <: InputFormat[K, V]] - (path: String, minSplits: Int, cloneRecords: Boolean = true) + (path: String, minSplits: Int) (implicit km: ClassTag[K], vm: ClassTag[V], fm: ClassTag[F]): RDD[(K, V)] = { hadoopFile(path, fm.runtimeClass.asInstanceOf[Class[F]], km.runtimeClass.asInstanceOf[Class[K]], vm.runtimeClass.asInstanceOf[Class[V]], - minSplits, - cloneRecords) + minSplits) } /** @@ -422,68 +429,91 @@ class SparkContext( * {{{ * val file = sparkContext.hadoopFile[LongWritable, Text, TextInputFormat](path) * }}} + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ - def hadoopFile[K, V, F <: InputFormat[K, V]](path: String, cloneRecords: Boolean = true) + def hadoopFile[K, V, F <: InputFormat[K, V]](path: String) (implicit km: ClassTag[K], vm: ClassTag[V], fm: ClassTag[F]): RDD[(K, V)] = - hadoopFile[K, V, F](path, defaultMinSplits, cloneRecords) + hadoopFile[K, V, F](path, defaultMinSplits) /** Get an RDD for a Hadoop file with an arbitrary new API InputFormat. */ def newAPIHadoopFile[K, V, F <: NewInputFormat[K, V]] - (path: String, cloneRecords: Boolean = true) + (path: String) (implicit km: ClassTag[K], vm: ClassTag[V], fm: ClassTag[F]): RDD[(K, V)] = { newAPIHadoopFile( path, fm.runtimeClass.asInstanceOf[Class[F]], km.runtimeClass.asInstanceOf[Class[K]], - vm.runtimeClass.asInstanceOf[Class[V]], - cloneRecords = cloneRecords) + vm.runtimeClass.asInstanceOf[Class[V]]) } /** * Get an RDD for a given Hadoop file with an arbitrary new API InputFormat * and extra configuration options to pass to the input format. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ - def newAPIHadoopFile[K: ClassTag, V: ClassTag, F <: NewInputFormat[K, V]]( + def newAPIHadoopFile[K, V, F <: NewInputFormat[K, V]]( path: String, fClass: Class[F], kClass: Class[K], vClass: Class[V], - conf: Configuration = hadoopConfiguration, - cloneRecords: Boolean = true): RDD[(K, V)] = { + conf: Configuration = hadoopConfiguration): RDD[(K, V)] = { val job = new NewHadoopJob(conf) NewFileInputFormat.addInputPath(job, new Path(path)) val updatedConf = job.getConfiguration - new NewHadoopRDD(this, fClass, kClass, vClass, updatedConf, cloneRecords) + new NewHadoopRDD(this, fClass, kClass, vClass, updatedConf) } /** * Get an RDD for a given Hadoop file with an arbitrary new API InputFormat * and extra configuration options to pass to the input format. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ - def newAPIHadoopRDD[K: ClassTag, V: ClassTag, F <: NewInputFormat[K, V]]( + def newAPIHadoopRDD[K, V, F <: NewInputFormat[K, V]]( conf: Configuration = hadoopConfiguration, fClass: Class[F], kClass: Class[K], - vClass: Class[V], - cloneRecords: Boolean = true): RDD[(K, V)] = { - new NewHadoopRDD(this, fClass, kClass, vClass, conf, cloneRecords) - } - - /** Get an RDD for a Hadoop SequenceFile with given key and value types. */ - def sequenceFile[K: ClassTag, V: ClassTag](path: String, + vClass: Class[V]): RDD[(K, V)] = { + new NewHadoopRDD(this, fClass, kClass, vClass, conf) + } + + /** Get an RDD for a Hadoop SequenceFile with given key and value types. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + */ + def sequenceFile[K, V](path: String, keyClass: Class[K], valueClass: Class[V], - minSplits: Int, - cloneRecords: Boolean = true + minSplits: Int ): RDD[(K, V)] = { val inputFormatClass = classOf[SequenceFileInputFormat[K, V]] - hadoopFile(path, inputFormatClass, keyClass, valueClass, minSplits, cloneRecords) + hadoopFile(path, inputFormatClass, keyClass, valueClass, minSplits) } - /** Get an RDD for a Hadoop SequenceFile with given key and value types. */ - def sequenceFile[K: ClassTag, V: ClassTag](path: String, keyClass: Class[K], valueClass: Class[V], - cloneRecords: Boolean = true): RDD[(K, V)] = - sequenceFile(path, keyClass, valueClass, defaultMinSplits, cloneRecords) + /** Get an RDD for a Hadoop SequenceFile with given key and value types. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + * */ + def sequenceFile[K, V](path: String, keyClass: Class[K], valueClass: Class[V] + ): RDD[(K, V)] = + sequenceFile(path, keyClass, valueClass, defaultMinSplits) /** * Version of sequenceFile() for types implicitly convertible to Writables through a @@ -500,9 +530,14 @@ class SparkContext( * have a parameterized singleton object). We use functions instead to create a new converter * for the appropriate type. In addition, we pass the converter a ClassTag of its type to * allow it to figure out the Writable class to use in the subclass case. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def sequenceFile[K, V] - (path: String, minSplits: Int = defaultMinSplits, cloneRecords: Boolean = true) + (path: String, minSplits: Int = defaultMinSplits) (implicit km: ClassTag[K], vm: ClassTag[V], kcf: () => WritableConverter[K], vcf: () => WritableConverter[V]) : RDD[(K, V)] = { @@ -511,7 +546,7 @@ class SparkContext( val format = classOf[SequenceFileInputFormat[Writable, Writable]] val writables = hadoopFile(path, format, kc.writableClass(km).asInstanceOf[Class[Writable]], - vc.writableClass(vm).asInstanceOf[Class[Writable]], minSplits, cloneRecords) + vc.writableClass(vm).asInstanceOf[Class[Writable]], minSplits) writables.map { case (k, v) => (kc.convert(k), vc.convert(v)) } } @@ -1024,7 +1059,7 @@ object SparkContext { implicit def rddToAsyncRDDActions[T: ClassTag](rdd: RDD[T]) = new AsyncRDDActions(rdd) implicit def rddToSequenceFileRDDFunctions[K <% Writable: ClassTag, V <% Writable: ClassTag]( - rdd: RDD[(K, V)]) = + rdd: RDD[(K, V)]) = new SequenceFileRDDFunctions(rdd) implicit def rddToOrderedRDDFunctions[K <% Ordered[K]: ClassTag, V: ClassTag]( diff --git a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala index 33c931b1a7c8b..c777472cd7310 100644 --- a/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala +++ b/core/src/main/scala/org/apache/spark/api/java/JavaSparkContext.scala @@ -137,7 +137,13 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork */ def textFile(path: String, minSplits: Int): JavaRDD[String] = sc.textFile(path, minSplits) - /**Get an RDD for a Hadoop SequenceFile with given key and value types. */ + /** Get an RDD for a Hadoop SequenceFile with given key and value types. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + * */ def sequenceFile[K, V](path: String, keyClass: Class[K], valueClass: Class[V], @@ -148,7 +154,13 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork new JavaPairRDD(sc.sequenceFile(path, keyClass, valueClass, minSplits)) } - /**Get an RDD for a Hadoop SequenceFile. */ + /** Get an RDD for a Hadoop SequenceFile. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + */ def sequenceFile[K, V](path: String, keyClass: Class[K], valueClass: Class[V]): JavaPairRDD[K, V] = { implicit val kcm: ClassTag[K] = ClassTag(keyClass) @@ -184,6 +196,11 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork * Get an RDD for a Hadoop-readable dataset from a Hadooop JobConf giving its InputFormat and any * other necessary info (e.g. file name for a filesystem-based dataset, table name for HyperTable, * etc). + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def hadoopRDD[K, V, F <: InputFormat[K, V]]( conf: JobConf, @@ -201,6 +218,11 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork * Get an RDD for a Hadoop-readable dataset from a Hadooop JobConf giving its InputFormat and any * other necessary info (e.g. file name for a filesystem-based dataset, table name for HyperTable, * etc). + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def hadoopRDD[K, V, F <: InputFormat[K, V]]( conf: JobConf, @@ -213,7 +235,13 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork new JavaPairRDD(sc.hadoopRDD(conf, inputFormatClass, keyClass, valueClass)) } - /** Get an RDD for a Hadoop file with an arbitrary InputFormat */ + /** Get an RDD for a Hadoop file with an arbitrary InputFormat. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + */ def hadoopFile[K, V, F <: InputFormat[K, V]]( path: String, inputFormatClass: Class[F], @@ -226,7 +254,13 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork new JavaPairRDD(sc.hadoopFile(path, inputFormatClass, keyClass, valueClass, minSplits)) } - /** Get an RDD for a Hadoop file with an arbitrary InputFormat */ + /** Get an RDD for a Hadoop file with an arbitrary InputFormat + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. + */ def hadoopFile[K, V, F <: InputFormat[K, V]]( path: String, inputFormatClass: Class[F], @@ -242,6 +276,11 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork /** * Get an RDD for a given Hadoop file with an arbitrary new API InputFormat * and extra configuration options to pass to the input format. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def newAPIHadoopFile[K, V, F <: NewInputFormat[K, V]]( path: String, @@ -257,6 +296,11 @@ class JavaSparkContext(val sc: SparkContext) extends JavaSparkContextVarargsWork /** * Get an RDD for a given Hadoop file with an arbitrary new API InputFormat * and extra configuration options to pass to the input format. + * + * '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each + * record, directly caching the returned RDD will create many references to the same object. + * If you plan to directly cache Hadoop writable objects, you should first copy them using + * a `map` function. */ def newAPIHadoopRDD[K, V, F <: NewInputFormat[K, V]]( conf: Configuration, diff --git a/core/src/main/scala/org/apache/spark/rdd/HadoopRDD.scala b/core/src/main/scala/org/apache/spark/rdd/HadoopRDD.scala index dbe76f34316ae..ad74d4636fb1b 100644 --- a/core/src/main/scala/org/apache/spark/rdd/HadoopRDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/HadoopRDD.scala @@ -19,10 +19,7 @@ package org.apache.spark.rdd import java.io.EOFException -import scala.reflect.ClassTag - import org.apache.hadoop.conf.{Configuration, Configurable} -import org.apache.hadoop.io.Writable import org.apache.hadoop.mapred.InputFormat import org.apache.hadoop.mapred.InputSplit import org.apache.hadoop.mapred.JobConf @@ -34,7 +31,6 @@ import org.apache.spark._ import org.apache.spark.broadcast.Broadcast import org.apache.spark.deploy.SparkHadoopUtil import org.apache.spark.util.NextIterator -import org.apache.spark.util.Utils.cloneWritables /** @@ -64,21 +60,15 @@ private[spark] class HadoopPartition(rddId: Int, idx: Int, @transient s: InputSp * @param keyClass Class of the key associated with the inputFormatClass. * @param valueClass Class of the value associated with the inputFormatClass. * @param minSplits Minimum number of Hadoop Splits (HadoopRDD partitions) to generate. - * @param cloneRecords If true, Spark will clone the records produced by Hadoop RecordReader. - * Most RecordReader implementations reuse wrapper objects across multiple - * records, and can cause problems in RDD collect or aggregation operations. - * By default the records are cloned in Spark. However, application - * programmers can explicitly disable the cloning for better performance. */ -class HadoopRDD[K: ClassTag, V: ClassTag]( +class HadoopRDD[K, V]( sc: SparkContext, broadcastedConf: Broadcast[SerializableWritable[Configuration]], initLocalJobConfFuncOpt: Option[JobConf => Unit], inputFormatClass: Class[_ <: InputFormat[K, V]], keyClass: Class[K], valueClass: Class[V], - minSplits: Int, - cloneRecords: Boolean = true) + minSplits: Int) extends RDD[(K, V)](sc, Nil) with Logging { def this( @@ -87,8 +77,7 @@ class HadoopRDD[K: ClassTag, V: ClassTag]( inputFormatClass: Class[_ <: InputFormat[K, V]], keyClass: Class[K], valueClass: Class[V], - minSplits: Int, - cloneRecords: Boolean) = { + minSplits: Int) = { this( sc, sc.broadcast(new SerializableWritable(conf)) @@ -97,8 +86,7 @@ class HadoopRDD[K: ClassTag, V: ClassTag]( inputFormatClass, keyClass, valueClass, - minSplits, - cloneRecords) + minSplits) } protected val jobConfCacheKey = "rdd_%d_job_conf".format(id) @@ -170,9 +158,7 @@ class HadoopRDD[K: ClassTag, V: ClassTag]( // Register an on-task-completion callback to close the input stream. context.addOnCompleteCallback{ () => closeIfNeeded() } val key: K = reader.createKey() - val keyCloneFunc = cloneWritables[K](jobConf) val value: V = reader.createValue() - val valueCloneFunc = cloneWritables[V](jobConf) override def getNext() = { try { finished = !reader.next(key, value) @@ -180,11 +166,7 @@ class HadoopRDD[K: ClassTag, V: ClassTag]( case eof: EOFException => finished = true } - if (cloneRecords) { - (keyCloneFunc(key.asInstanceOf[Writable]), valueCloneFunc(value.asInstanceOf[Writable])) - } else { - (key, value) - } + (key, value) } override def close() { diff --git a/core/src/main/scala/org/apache/spark/rdd/NewHadoopRDD.scala b/core/src/main/scala/org/apache/spark/rdd/NewHadoopRDD.scala index 992bd4aa0ad5d..d1fff296878c3 100644 --- a/core/src/main/scala/org/apache/spark/rdd/NewHadoopRDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/NewHadoopRDD.scala @@ -20,15 +20,11 @@ package org.apache.spark.rdd import java.text.SimpleDateFormat import java.util.Date -import scala.reflect.ClassTag - import org.apache.hadoop.conf.{Configurable, Configuration} import org.apache.hadoop.io.Writable import org.apache.hadoop.mapreduce._ import org.apache.spark.{InterruptibleIterator, Logging, Partition, SerializableWritable, SparkContext, TaskContext} -import org.apache.spark.util.Utils.cloneWritables - private[spark] class NewHadoopPartition(rddId: Int, val index: Int, @transient rawSplit: InputSplit with Writable) @@ -48,19 +44,13 @@ class NewHadoopPartition(rddId: Int, val index: Int, @transient rawSplit: InputS * @param keyClass Class of the key associated with the inputFormatClass. * @param valueClass Class of the value associated with the inputFormatClass. * @param conf The Hadoop configuration. - * @param cloneRecords If true, Spark will clone the records produced by Hadoop RecordReader. - * Most RecordReader implementations reuse wrapper objects across multiple - * records, and can cause problems in RDD collect or aggregation operations. - * By default the records are cloned in Spark. However, application - * programmers can explicitly disable the cloning for better performance. */ -class NewHadoopRDD[K: ClassTag, V: ClassTag]( +class NewHadoopRDD[K, V]( sc : SparkContext, inputFormatClass: Class[_ <: InputFormat[K, V]], keyClass: Class[K], valueClass: Class[V], - @transient conf: Configuration, - cloneRecords: Boolean) + @transient conf: Configuration) extends RDD[(K, V)](sc, Nil) with SparkHadoopMapReduceUtil with Logging { @@ -107,8 +97,6 @@ class NewHadoopRDD[K: ClassTag, V: ClassTag]( // Register an on-task-completion callback to close the input stream. context.addOnCompleteCallback(() => close()) - val keyCloneFunc = cloneWritables[K](conf) - val valueCloneFunc = cloneWritables[V](conf) var havePair = false var finished = false @@ -125,13 +113,7 @@ class NewHadoopRDD[K: ClassTag, V: ClassTag]( throw new java.util.NoSuchElementException("End of stream") } havePair = false - val key = reader.getCurrentKey - val value = reader.getCurrentValue - if (cloneRecords) { - (keyCloneFunc(key.asInstanceOf[Writable]), valueCloneFunc(value.asInstanceOf[Writable])) - } else { - (key, value) - } + (reader.getCurrentKey, reader.getCurrentValue) } private def close() { diff --git a/core/src/main/scala/org/apache/spark/util/Utils.scala b/core/src/main/scala/org/apache/spark/util/Utils.scala index caa9bf4c9280e..64acfbd3526f3 100644 --- a/core/src/main/scala/org/apache/spark/util/Utils.scala +++ b/core/src/main/scala/org/apache/spark/util/Utils.scala @@ -26,7 +26,7 @@ import scala.collection.JavaConversions._ import scala.collection.Map import scala.collection.mutable.ArrayBuffer import scala.io.Source -import scala.reflect.{classTag, ClassTag} +import scala.reflect.ClassTag import com.google.common.io.Files import com.google.common.util.concurrent.ThreadFactoryBuilder @@ -46,27 +46,6 @@ import org.apache.spark.{SparkConf, SparkException, Logging} */ private[spark] object Utils extends Logging { - /** - * We try to clone for most common types of writables and we call WritableUtils.clone otherwise - * intention is to optimize, for example for NullWritable there is no need and for Long, int and - * String creating a new object with value set would be faster. - */ - def cloneWritables[T: ClassTag](conf: Configuration): Writable => T = { - val cloneFunc = classTag[T] match { - case ClassTag(_: Text) => - (w: Writable) => new Text(w.asInstanceOf[Text].getBytes).asInstanceOf[T] - case ClassTag(_: LongWritable) => - (w: Writable) => new LongWritable(w.asInstanceOf[LongWritable].get).asInstanceOf[T] - case ClassTag(_: IntWritable) => - (w: Writable) => new IntWritable(w.asInstanceOf[IntWritable].get).asInstanceOf[T] - case ClassTag(_: NullWritable) => - (w: Writable) => w.asInstanceOf[T] // TODO: should we clone this ? - case _ => - (w: Writable) => WritableUtils.clone(w, conf).asInstanceOf[T] // slower way of cloning. - } - cloneFunc - } - /** Serialize an object using Java serialization */ def serialize[T](o: T): Array[Byte] = { val bos = new ByteArrayOutputStream() From e66d4c27cadccaa8bb8b2a9ab486889ce2de37d0 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 19:47:00 -0800 Subject: [PATCH 068/133] Merge pull request #503 from pwendell/master Fix bug on read-side of external sort when using Snappy. This case wasn't handled correctly and this patch fixes it. (cherry picked from commit 3d6e75419330d27435becfdf8cfb0b6d20d56cf8) Signed-off-by: Patrick Wendell --- .../spark/util/collection/ExternalAppendOnlyMap.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala index fb73636162af9..3d9b09ec33e2a 100644 --- a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala +++ b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala @@ -358,7 +358,15 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( private class DiskMapIterator(file: File, blockId: BlockId) extends Iterator[(K, C)] { val fileStream = new FileInputStream(file) val bufferedStream = new FastBufferedInputStream(fileStream, fileBufferSize) - val compressedStream = blockManager.wrapForCompression(blockId, bufferedStream) + + val shouldCompress = blockManager.shouldCompress(blockId) + val compressionCodec = new LZFCompressionCodec(sparkConf) + val compressedStream = + if (shouldCompress) { + compressionCodec.compressedInputStream(bufferedStream) + } else { + bufferedStream + } var deserializeStream = ser.deserializeStream(compressedStream) var objectsRead = 0 From d0a105d4e5ec3c84bc5ee8c8d55cca40f43cb9b8 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 20:53:18 -0800 Subject: [PATCH 069/133] Merge pull request #505 from JoshRosen/SPARK-1026 Deprecate mapPartitionsWithSplit in PySpark (SPARK-1026) This commit deprecates `mapPartitionsWithSplit` in PySpark (see [SPARK-1026](https://spark-project.atlassian.net/browse/SPARK-1026) and removes the remaining references to it from the docs. (cherry picked from commit 05be7047744c88e64e7e6bd973f9bcfacd00da5f) Signed-off-by: Patrick Wendell --- docs/scala-programming-guide.md | 4 ++-- python/pyspark/rdd.py | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/scala-programming-guide.md b/docs/scala-programming-guide.md index c1ef46a1cded7..7c0f67bc99e83 100644 --- a/docs/scala-programming-guide.md +++ b/docs/scala-programming-guide.md @@ -168,9 +168,9 @@ The following tables list the transformations and actions currently supported (s Iterator[T] => Iterator[U] when running on an RDD of type T. - mapPartitionsWithSplit(func) + mapPartitionsWithIndex(func) Similar to mapPartitions, but also provides func with an integer value representing the index of - the split, so func must be of type (Int, Iterator[T]) => Iterator[U] when running on an RDD of type T. + the partition, so func must be of type (Int, Iterator[T]) => Iterator[U] when running on an RDD of type T. diff --git a/python/pyspark/rdd.py b/python/pyspark/rdd.py index 6fb4a7b3be25d..1ad4b5298758b 100644 --- a/python/pyspark/rdd.py +++ b/python/pyspark/rdd.py @@ -27,6 +27,7 @@ from subprocess import Popen, PIPE from tempfile import NamedTemporaryFile from threading import Thread +import warnings from pyspark.serializers import NoOpSerializer, CartesianDeserializer, \ BatchedSerializer, CloudPickleSerializer, pack_long @@ -179,7 +180,7 @@ def flatMap(self, f, preservesPartitioning=False): [(2, 2), (2, 2), (3, 3), (3, 3), (4, 4), (4, 4)] """ def func(s, iterator): return chain.from_iterable(imap(f, iterator)) - return self.mapPartitionsWithSplit(func, preservesPartitioning) + return self.mapPartitionsWithIndex(func, preservesPartitioning) def mapPartitions(self, f, preservesPartitioning=False): """ @@ -191,10 +192,24 @@ def mapPartitions(self, f, preservesPartitioning=False): [3, 7] """ def func(s, iterator): return f(iterator) - return self.mapPartitionsWithSplit(func) + return self.mapPartitionsWithIndex(func) + + def mapPartitionsWithIndex(self, f, preservesPartitioning=False): + """ + Return a new RDD by applying a function to each partition of this RDD, + while tracking the index of the original partition. + + >>> rdd = sc.parallelize([1, 2, 3, 4], 4) + >>> def f(splitIndex, iterator): yield splitIndex + >>> rdd.mapPartitionsWithIndex(f).sum() + 6 + """ + return PipelinedRDD(self, f, preservesPartitioning) def mapPartitionsWithSplit(self, f, preservesPartitioning=False): """ + Deprecated: use mapPartitionsWithIndex instead. + Return a new RDD by applying a function to each partition of this RDD, while tracking the index of the original partition. @@ -203,7 +218,9 @@ def mapPartitionsWithSplit(self, f, preservesPartitioning=False): >>> rdd.mapPartitionsWithSplit(f).sum() 6 """ - return PipelinedRDD(self, f, preservesPartitioning) + warnings.warn("mapPartitionsWithSplit is deprecated; " + "use mapPartitionsWithIndex instead", DeprecationWarning, stacklevel=2) + return self.mapPartitionsWithIndex(f, preservesPartitioning) def filter(self, f): """ @@ -235,7 +252,7 @@ def sample(self, withReplacement, fraction, seed): >>> sc.parallelize(range(0, 100)).sample(False, 0.1, 2).collect() #doctest: +SKIP [2, 3, 20, 21, 24, 41, 42, 66, 67, 89, 90, 98] """ - return self.mapPartitionsWithSplit(RDDSampler(withReplacement, fraction, seed).func, True) + return self.mapPartitionsWithIndex(RDDSampler(withReplacement, fraction, seed).func, True) # this is ported from scala/spark/RDD.scala def takeSample(self, withReplacement, num, seed): From 59921578d535873980f579622db8397103a6038d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 21:53:37 -0800 Subject: [PATCH 070/133] Revert "[maven-release-plugin] prepare for next development iteration" This reverts commit e1dc5bedb48d2ac9b9e1c9b3b1a15c41b7d90ad8. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 42e624402f77e..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index abf48935cd915..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 967556744c1e6..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 978b99f4a7054..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index a3d5fc64f070e..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 1f416dd8c06d4..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index f23091684f95c..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6a250b3916ead..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index 9073cf7aa66ec..b872c7a705a9c 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 41600c4c4b561..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 150dba8d636d8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 346c672165d7d..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 7e10ef6f471be..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index bb8f747ae9328..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 508317b5fc01c..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 04b29c76e5830..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.1-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From c91f44ad3ec25d75a5e4d96f339d7f1e499a361d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 21:53:42 -0800 Subject: [PATCH 071/133] Revert "[maven-release-plugin] prepare release v0.9.0-incubating" This reverts commit 0771df675363c69622404cb514bd751bc90526af. --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..dcd9601fe4a90 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..cb8e79f22535b 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..9e5a450d57a47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..7855706389709 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..443910a03a94e 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..23b2fead657e6 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..31b4fa87de772 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..216e6c1d8ff44 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..c240d595742cf 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index b872c7a705a9c..d97dbb804bc99 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..dda3900afebdf 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..70c17e9fc74a8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..2dfe7ac900b83 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..459756912dbe5 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..28f5ef14b1a35 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..aea8b0cddefa2 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..62fe3e274250f 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.0-incubating-SNAPSHOT ../pom.xml From 2ac96e7ee6fa1ab863c5bcc7eef3706a270a13f9 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Thu, 23 Jan 2014 21:55:49 -0800 Subject: [PATCH 072/133] Updating changes file --- CHANGES.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index f42ed7f9d14d7..8c78d55ccd862 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,38 @@ Spark Change Log Release 0.9.0-incubating + d0a105d Thu Jan 23 20:53:31 2014 -0800 + Merge pull request #505 from JoshRosen/SPARK-1026 + [Deprecate mapPartitionsWithSplit in PySpark (SPARK-1026)] + + e66d4c2 Thu Jan 23 19:47:16 2014 -0800 + Merge pull request #503 from pwendell/master + [Fix bug on read-side of external sort when using Snappy.] + + e8d3f2b Thu Jan 23 19:20:22 2014 -0800 + Merge pull request #502 from pwendell/clone-1 + [Remove Hadoop object cloning and warn users making Hadoop RDD's.] + + 7a62353 Thu Jan 23 19:09:25 2014 -0800 + Merge pull request #501 from JoshRosen/cartesian-rdd-fixes + [Fix two bugs in PySpark cartesian(): SPARK-978 and SPARK-1034] + + 51960b8 Wed Jan 22 19:37:50 2014 -0800 + Merge pull request #496 from pwendell/master + [Fix bug in worker clean-up in UI] + + 828f7b4 Wed Jan 22 15:45:18 2014 -0800 + Merge pull request #495 from srowen/GraphXCommonsMathDependency + [Fix graphx Commons Math dependency] + + dc5857a Wed Jan 22 14:33:25 2014 -0800 + Merge pull request #492 from skicavs/master + [fixed job name and usage information for the JavaSparkPi example] + + dd533c9 Wed Jan 22 14:15:58 2014 -0800 + Merge pull request #478 from sryza/sandy-spark-1033 + [SPARK-1033. Ask for cores in Yarn container requests] + b6fd3cd Tue Jan 21 00:12:01 2014 -0800 Merge pull request #480 from pwendell/0.9-fixes [Handful of 0.9 fixes] From 95d28ff3d0d20d9c583e184f9e2c5ae842d8a4d9 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 24 Jan 2014 06:15:08 +0000 Subject: [PATCH 073/133] [maven-release-plugin] prepare release v0.9.0-incubating --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index dcd9601fe4a90..2faa3ff33ca35 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index cb8e79f22535b..0dcc2983c821f 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 9e5a450d57a47..62ceba186ab46 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 7855706389709..a30d0b3fa0906 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index 443910a03a94e..f3da4f5abe101 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index 23b2fead657e6..f9c97673ad8ae 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 31b4fa87de772..7e438cca101b5 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 216e6c1d8ff44..2ec96be677946 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index c240d595742cf..6e644a5342325 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index d97dbb804bc99..b872c7a705a9c 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index dda3900afebdf..6f024f6f538ec 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/pom.xml b/pom.xml index 70c17e9fc74a8..e1cf107965fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - HEAD + v0.9.0-incubating diff --git a/repl/pom.xml b/repl/pom.xml index 2dfe7ac900b83..0d73cfa84126b 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 459756912dbe5..90b65fc118ec6 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 28f5ef14b1a35..be77741d591ae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index aea8b0cddefa2..3383a227590c5 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index 62fe3e274250f..cf915a1a259d8 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating-SNAPSHOT + 0.9.0-incubating ../pom.xml From 0f60ef2c4d3c1f3da3cf455fc86a8d603a499117 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 24 Jan 2014 06:15:15 +0000 Subject: [PATCH 074/133] [maven-release-plugin] prepare for next development iteration --- assembly/pom.xml | 2 +- bagel/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- external/flume/pom.xml | 2 +- external/kafka/pom.xml | 2 +- external/mqtt/pom.xml | 2 +- external/twitter/pom.xml | 2 +- external/zeromq/pom.xml | 2 +- graphx/pom.xml | 2 +- mllib/pom.xml | 2 +- pom.xml | 4 ++-- repl/pom.xml | 2 +- streaming/pom.xml | 2 +- tools/pom.xml | 2 +- yarn/pom.xml | 2 +- yarn/stable/pom.xml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 2faa3ff33ca35..a99e3d2a02569 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/bagel/pom.xml b/bagel/pom.xml index 0dcc2983c821f..42e624402f77e 100644 --- a/bagel/pom.xml +++ b/bagel/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 62ceba186ab46..abf48935cd915 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index a30d0b3fa0906..967556744c1e6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/external/flume/pom.xml b/external/flume/pom.xml index f3da4f5abe101..978b99f4a7054 100644 --- a/external/flume/pom.xml +++ b/external/flume/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/kafka/pom.xml b/external/kafka/pom.xml index f9c97673ad8ae..a3d5fc64f070e 100644 --- a/external/kafka/pom.xml +++ b/external/kafka/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/mqtt/pom.xml b/external/mqtt/pom.xml index 7e438cca101b5..1f416dd8c06d4 100644 --- a/external/mqtt/pom.xml +++ b/external/mqtt/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/twitter/pom.xml b/external/twitter/pom.xml index 2ec96be677946..f23091684f95c 100644 --- a/external/twitter/pom.xml +++ b/external/twitter/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/external/zeromq/pom.xml b/external/zeromq/pom.xml index 6e644a5342325..6a250b3916ead 100644 --- a/external/zeromq/pom.xml +++ b/external/zeromq/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../../pom.xml diff --git a/graphx/pom.xml b/graphx/pom.xml index b872c7a705a9c..9073cf7aa66ec 100644 --- a/graphx/pom.xml +++ b/graphx/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/mllib/pom.xml b/mllib/pom.xml index 6f024f6f538ec..41600c4c4b561 100644 --- a/mllib/pom.xml +++ b/mllib/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e1cf107965fb7..150dba8d636d8 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT pom Spark Project Parent POM http://spark.incubator.apache.org/ @@ -40,7 +40,7 @@ scm:git:git@github.com:apache/incubator-spark.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-spark.git scm:git:git@github.com:apache/incubator-spark.git - v0.9.0-incubating + HEAD diff --git a/repl/pom.xml b/repl/pom.xml index 0d73cfa84126b..346c672165d7d 100644 --- a/repl/pom.xml +++ b/repl/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/streaming/pom.xml b/streaming/pom.xml index 90b65fc118ec6..7e10ef6f471be 100644 --- a/streaming/pom.xml +++ b/streaming/pom.xml @@ -21,7 +21,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index be77741d591ae..bb8f747ae9328 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/pom.xml b/yarn/pom.xml index 3383a227590c5..508317b5fc01c 100644 --- a/yarn/pom.xml +++ b/yarn/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml diff --git a/yarn/stable/pom.xml b/yarn/stable/pom.xml index cf915a1a259d8..04b29c76e5830 100644 --- a/yarn/stable/pom.xml +++ b/yarn/stable/pom.xml @@ -20,7 +20,7 @@ org.apache.spark yarn-parent_2.10 - 0.9.0-incubating + 0.9.1-incubating-SNAPSHOT ../pom.xml From 5edbd175e07dc9704b1babb9c5e8d97fb644be65 Mon Sep 17 00:00:00 2001 From: Josh Rosen Date: Tue, 28 Jan 2014 21:30:20 -0800 Subject: [PATCH 075/133] Merge pull request #523 from JoshRosen/SPARK-1043 Switch from MUTF8 to UTF8 in PySpark serializers. This fixes SPARK-1043, a bug introduced in 0.9.0 where PySpark couldn't serialize strings > 64kB. This fix was written by @tyro89 and @bouk in #512. This commit squashes and rebases their pull request in order to fix some merge conflicts. (cherry picked from commit f8c742ce274fbae2a9e616d4c97469b6a22069bb) Signed-off-by: Patrick Wendell --- .../apache/spark/api/python/PythonRDD.scala | 18 +++++++--- .../spark/api/python/PythonRDDSuite.scala | 35 +++++++++++++++++++ python/pyspark/context.py | 4 +-- python/pyspark/serializers.py | 6 ++-- python/pyspark/worker.py | 8 ++--- 5 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 core/src/test/scala/org/apache/spark/api/python/PythonRDDSuite.scala diff --git a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala index 57bde8d85f1a8..46d53e3e66f7c 100644 --- a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala +++ b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala @@ -62,7 +62,7 @@ private[spark] class PythonRDD[T: ClassTag]( // Partition index dataOut.writeInt(split.index) // sparkFilesDir - dataOut.writeUTF(SparkFiles.getRootDirectory) + PythonRDD.writeUTF(SparkFiles.getRootDirectory, dataOut) // Broadcast variables dataOut.writeInt(broadcastVars.length) for (broadcast <- broadcastVars) { @@ -72,7 +72,9 @@ private[spark] class PythonRDD[T: ClassTag]( } // Python includes (*.zip and *.egg files) dataOut.writeInt(pythonIncludes.length) - pythonIncludes.foreach(dataOut.writeUTF) + for (include <- pythonIncludes) { + PythonRDD.writeUTF(include, dataOut) + } dataOut.flush() // Serialized command: dataOut.writeInt(command.length) @@ -219,7 +221,7 @@ private[spark] object PythonRDD { } case string: String => newIter.asInstanceOf[Iterator[String]].foreach { str => - dataOut.writeUTF(str) + writeUTF(str, dataOut) } case pair: Tuple2[_, _] => pair._1 match { @@ -232,8 +234,8 @@ private[spark] object PythonRDD { } case stringPair: String => newIter.asInstanceOf[Iterator[Tuple2[String, String]]].foreach { pair => - dataOut.writeUTF(pair._1) - dataOut.writeUTF(pair._2) + writeUTF(pair._1, dataOut) + writeUTF(pair._2, dataOut) } case other => throw new SparkException("Unexpected Tuple2 element type " + pair._1.getClass) @@ -244,6 +246,12 @@ private[spark] object PythonRDD { } } + def writeUTF(str: String, dataOut: DataOutputStream) { + val bytes = str.getBytes("UTF-8") + dataOut.writeInt(bytes.length) + dataOut.write(bytes) + } + def writeToFile[T](items: java.util.Iterator[T], filename: String) { import scala.collection.JavaConverters._ writeToFile(items.asScala, filename) diff --git a/core/src/test/scala/org/apache/spark/api/python/PythonRDDSuite.scala b/core/src/test/scala/org/apache/spark/api/python/PythonRDDSuite.scala new file mode 100644 index 0000000000000..1bebfe5ec84ec --- /dev/null +++ b/core/src/test/scala/org/apache/spark/api/python/PythonRDDSuite.scala @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.spark.api.python + +import org.scalatest.FunSuite +import org.scalatest.matchers.ShouldMatchers +import org.apache.spark.api.python.PythonRDD + +import java.io.{ByteArrayOutputStream, DataOutputStream} + +class PythonRDDSuite extends FunSuite { + + test("Writing large strings to the worker") { + val input: List[String] = List("a"*100000) + val buffer = new DataOutputStream(new ByteArrayOutputStream) + PythonRDD.writeIteratorToStream(input.iterator, buffer) + } + +} + diff --git a/python/pyspark/context.py b/python/pyspark/context.py index f955aad7a4f12..f318b5d9a73d7 100644 --- a/python/pyspark/context.py +++ b/python/pyspark/context.py @@ -27,7 +27,7 @@ from pyspark.conf import SparkConf from pyspark.files import SparkFiles from pyspark.java_gateway import launch_gateway -from pyspark.serializers import PickleSerializer, BatchedSerializer, MUTF8Deserializer +from pyspark.serializers import PickleSerializer, BatchedSerializer, UTF8Deserializer from pyspark.storagelevel import StorageLevel from pyspark.rdd import RDD @@ -234,7 +234,7 @@ def textFile(self, name, minSplits=None): """ minSplits = minSplits or min(self.defaultParallelism, 2) return RDD(self._jsc.textFile(name, minSplits), self, - MUTF8Deserializer()) + UTF8Deserializer()) def _checkpointFile(self, name, input_deserializer): jrdd = self._jsc.checkpointFile(name) diff --git a/python/pyspark/serializers.py b/python/pyspark/serializers.py index 2a500ab919bea..8c6ad79059c23 100644 --- a/python/pyspark/serializers.py +++ b/python/pyspark/serializers.py @@ -261,13 +261,13 @@ class MarshalSerializer(FramedSerializer): loads = marshal.loads -class MUTF8Deserializer(Serializer): +class UTF8Deserializer(Serializer): """ - Deserializes streams written by Java's DataOutputStream.writeUTF(). + Deserializes streams written by getBytes. """ def loads(self, stream): - length = struct.unpack('>H', stream.read(2))[0] + length = read_int(stream) return stream.read(length).decode('utf8') def load_stream(self, stream): diff --git a/python/pyspark/worker.py b/python/pyspark/worker.py index d77981f61fa36..4be4063dcf602 100644 --- a/python/pyspark/worker.py +++ b/python/pyspark/worker.py @@ -30,11 +30,11 @@ from pyspark.cloudpickle import CloudPickler from pyspark.files import SparkFiles from pyspark.serializers import write_with_length, write_int, read_long, \ - write_long, read_int, SpecialLengths, MUTF8Deserializer, PickleSerializer + write_long, read_int, SpecialLengths, UTF8Deserializer, PickleSerializer pickleSer = PickleSerializer() -mutf8_deserializer = MUTF8Deserializer() +utf8_deserializer = UTF8Deserializer() def report_times(outfile, boot, init, finish): @@ -51,7 +51,7 @@ def main(infile, outfile): return # fetch name of workdir - spark_files_dir = mutf8_deserializer.loads(infile) + spark_files_dir = utf8_deserializer.loads(infile) SparkFiles._root_directory = spark_files_dir SparkFiles._is_running_on_worker = True @@ -66,7 +66,7 @@ def main(infile, outfile): sys.path.append(spark_files_dir) # *.py files that were added will be copied here num_python_includes = read_int(infile) for _ in range(num_python_includes): - filename = mutf8_deserializer.loads(infile) + filename = utf8_deserializer.loads(infile) sys.path.append(os.path.join(spark_files_dir, filename)) command = pickleSer._read_with_length(infile) From d18fe1f3a32a98b9dfdbe2606ab16d6113a200e1 Mon Sep 17 00:00:00 2001 From: Tathagata Das Date: Tue, 28 Jan 2014 21:51:05 -0800 Subject: [PATCH 076/133] Merge pull request #497 from tdas/docs-update Updated Spark Streaming Programming Guide Here is the updated version of the Spark Streaming Programming Guide. This is still a work in progress, but the major changes are in place. So feedback is most welcome. In general, I have tried to make the guide to easier to understand even if the reader does not know much about Spark. The updated website is hosted here - http://www.eecs.berkeley.edu/~tdas/spark_docs/streaming-programming-guide.html The major changes are: - Overview illustrates the usecases of Spark Streaming - various input sources and various output sources - An example right after overview to quickly give an idea of what Spark Streaming program looks like - Made Java API and examples a first class citizen like Scala by using tabs to show both Scala and Java examples (similar to AMPCamp tutorial's code tabs) - Highlighted the DStream operations updateStateByKey and transform because of their powerful nature - Updated driver node failure recovery text to highlight automatic recovery in Spark standalone mode - Added information about linking and using the external input sources like Kafka and Flume - In general, reorganized the sections to better show the Basic section and the more advanced sections like Tuning and Recovery. Todos: - Links to the docs of external Kafka, Flume, etc - Illustrate window operation with figure as well as example. Author: Tathagata Das == Merge branch commits == commit 18ff10556570b39d672beeb0a32075215cfcc944 Author: Tathagata Das Date: Tue Jan 28 21:49:30 2014 -0800 Fixed a lot of broken links. commit 34a5a6008dac2e107624c7ff0db0824ee5bae45f Author: Tathagata Das Date: Tue Jan 28 18:02:28 2014 -0800 Updated github url to use SPARK_GITHUB_URL variable. commit f338a60ae8069e0a382d2cb170227e5757cc0b7a Author: Tathagata Das Date: Mon Jan 27 22:42:42 2014 -0800 More updates based on Patrick and Harvey's comments. commit 89a81ff25726bf6d26163e0dd938290a79582c0f Author: Tathagata Das Date: Mon Jan 27 13:08:34 2014 -0800 Updated docs based on Patricks PR comments. commit d5b6196b532b5746e019b959a79ea0cc013a8fc3 Author: Tathagata Das Date: Sun Jan 26 20:15:58 2014 -0800 Added spark.streaming.unpersist config and info on StreamingListener interface. commit e3dcb46ab83d7071f611d9b5008ba6bc16c9f951 Author: Tathagata Das Date: Sun Jan 26 18:41:12 2014 -0800 Fixed docs on StreamingContext.getOrCreate. commit 6c29524639463f11eec721e4d17a9d7159f2944b Author: Tathagata Das Date: Thu Jan 23 18:49:39 2014 -0800 Added example and figure for window operations, and links to Kafka and Flume API docs. commit f06b964a51bb3b21cde2ff8bdea7d9785f6ce3a9 Author: Tathagata Das Date: Wed Jan 22 22:49:12 2014 -0800 Fixed missing endhighlight tag in the MLlib guide. commit 036a7d46187ea3f2a0fb8349ef78f10d6c0b43a9 Merge: eab351d a1cd185 Author: Tathagata Das Date: Wed Jan 22 22:17:42 2014 -0800 Merge remote-tracking branch 'apache/master' into docs-update commit eab351d05c0baef1d4b549e1581310087158d78d Author: Tathagata Das Date: Wed Jan 22 22:17:15 2014 -0800 Update Spark Streaming Programming Guide. (cherry picked from commit 793020961489e16e924c4531da3a13884d2b9175) Conflicts: docs/mllib-guide.md --- docs/_config.yml | 1 + docs/_layouts/global.html | 11 + docs/_plugins/copy_api_dirs.rb | 5 +- docs/configuration.md | 11 +- docs/css/main.css | 44 +- docs/img/java-sm.png | Bin 0 -> 670 bytes docs/img/python-sm.png | Bin 0 -> 1455 bytes docs/img/scala-sm.png | Bin 0 -> 2241 bytes docs/img/streaming-arch.png | Bin 0 -> 78856 bytes docs/img/streaming-dstream-ops.png | Bin 0 -> 48429 bytes docs/img/streaming-dstream-window.png | Bin 0 -> 40938 bytes docs/img/streaming-dstream.png | Bin 0 -> 26823 bytes docs/img/streaming-figures.pptx | Bin 0 -> 887545 bytes docs/img/streaming-flow.png | Bin 0 -> 31544 bytes docs/index.md | 2 +- docs/js/main.js | 106 ++ docs/spark-standalone.md | 4 +- docs/streaming-programming-guide.md | 1278 +++++++++++++++++++------ 18 files changed, 1162 insertions(+), 300 deletions(-) create mode 100644 docs/img/java-sm.png create mode 100644 docs/img/python-sm.png create mode 100644 docs/img/scala-sm.png create mode 100644 docs/img/streaming-arch.png create mode 100644 docs/img/streaming-dstream-ops.png create mode 100644 docs/img/streaming-dstream-window.png create mode 100644 docs/img/streaming-dstream.png create mode 100644 docs/img/streaming-figures.pptx create mode 100644 docs/img/streaming-flow.png diff --git a/docs/_config.yml b/docs/_config.yml index 3e96d2c1ea136..97a2c4abf2998 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -8,3 +8,4 @@ SPARK_VERSION_SHORT: 0.9.0 SCALA_VERSION: "2.10" MESOS_VERSION: 0.13.0 SPARK_ISSUE_TRACKER_URL: https://spark-project.atlassian.net +SPARK_GITHUB_URL: https://github.com/apache/incubator-spark diff --git a/docs/_layouts/global.html b/docs/_layouts/global.html index c529d89ffd192..33525953ac4f6 100755 --- a/docs/_layouts/global.html +++ b/docs/_layouts/global.html @@ -82,6 +82,17 @@
  • MLlib (Machine Learning)
  • Bagel (Pregel on Spark)
  • GraphX (Graph Processing)
  • +
  • + diff --git a/docs/_plugins/copy_api_dirs.rb b/docs/_plugins/copy_api_dirs.rb index acc6bf08160eb..44d64057f4fb3 100644 --- a/docs/_plugins/copy_api_dirs.rb +++ b/docs/_plugins/copy_api_dirs.rb @@ -20,7 +20,10 @@ if not (ENV['SKIP_API'] == '1' or ENV['SKIP_SCALADOC'] == '1') # Build Scaladoc for Java/Scala - projects = ["core", "examples", "repl", "bagel", "graphx", "streaming", "mllib"] + core_projects = ["core", "examples", "repl", "bagel", "graphx", "streaming", "mllib"] + external_projects = ["flume", "kafka", "mqtt", "twitter", "zeromq"] + + projects = core_projects + external_projects.map { |project_name| "external/" + project_name } puts "Moving to project root and building scaladoc." curr_dir = pwd diff --git a/docs/configuration.md b/docs/configuration.md index be548e372dcd4..0cf9d231ab896 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -362,7 +362,16 @@ Apart from these, the following properties are also available, and may be useful spark.streaming.blockInterval 200 - Duration (milliseconds) of how long to batch new objects coming from network receivers. + Duration (milliseconds) of how long to batch new objects coming from network receivers used + in Spark Streaming. + + + + spark.streaming.unpersist + false + + Force RDDs generated and persisted by Spark Streaming to be automatically unpersisted from + Spark's memory. Setting this to true is likely to reduce Spark's RDD memory usage. diff --git a/docs/css/main.css b/docs/css/main.css index 31122d5633801..8566400f071c9 100755 --- a/docs/css/main.css +++ b/docs/css/main.css @@ -87,20 +87,54 @@ a:hover code { max-width: 914px; } -/** - * Make dropdown menus in nav bars show on hover instead of click - * using solution at http://stackoverflow.com/questions/8878033/how- - * to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click - **/ .dropdown-menu { /* Remove the default 2px top margin which causes a small gap between the hover trigger area and the popup menu */ margin-top: 0; + /* Avoid too much whitespace at the right for shorter menu items */ + min-width: 50px; } + +/** + * Make dropdown menus in nav bars show on hover instead of click + * using solution at http://stackoverflow.com/questions/8878033/how- + * to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click + **/ ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; } + a.menu:after, .dropdown-toggle:after { content: none; } +/** Make the submenus open on hover on the parent menu item */ +ul.nav li.dropdown ul.dropdown-menu li.dropdown-submenu:hover ul.dropdown-menu { + display: block; +} + +/** Make the submenus be invisible until the parent menu item is hovered upon */ +ul.nav li.dropdown ul.dropdown-menu li.dropdown-submenu ul.dropdown-menu { + display: none; +} + +/** + * Made the navigation bar buttons not grey out when clicked. + * Essentially making nav bar buttons not react to clicks, only hover events. + */ +.navbar .nav li.dropdown.open > .dropdown-toggle { + background-color: transparent; +} + +/** + * Made the active tab caption blue. Otherwise the active tab is black, and inactive tab is blue. + * That looks weird. Changed the colors to active - blue, inactive - black, and + * no color change on hover. + */ +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #08c; +} + +.nav-tabs > li > a, .nav-tabs > li > a:hover { + color: #333; +} diff --git a/docs/img/java-sm.png b/docs/img/java-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..a82ee7d682e497d2c905f6b51dfaf5a41cbb19a1 GIT binary patch literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^MnEjY!3-qzd~3G?DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MUw-3LR^8ggM&kTef`P<7xwSpfB*jd_wU~a1O!}p@Vvjj zKOrHZZsAS^1%=L)`_`{tfB*U0^XJdc2ZEia1Ox;&pSbqr`_F=cf|u_30uB{snrrlT6xp{rvum9^;=PY-gm1*56x8cH%2i2;~6}`H4QXl57$?M{? z;8%FQJ$>Tm-$lhWTr+>Y-Er%`i_kL*UiX7D76>KZ31P~cxY9oEm~|qLkBVG_(-QUY zZHss|$t{I@h4#1f=1$~b zI?r*K?G%gGlF2m-eHpi1J-0OC!Z+!bCn?vs(-@dpO!yyU2(Ga=6%x;VbMDZJ)x9UY zFSF}Te0}u$q=QuxT|zeby}r5covv$&z$Tf6Vi{U&g}V)Sb|1a7kwc>D6n{~Q<=(Wa zFCvu>wEGQL99lJP>c&fPnyDp!YL7oUtf&*So#XKijU{vEoBe*j)hDz5#j)KtgiHj# fzSsYzdVoRpSgu&$EGKbbWHETU`njxgN@xNA2%%eu literal 0 HcmV?d00001 diff --git a/docs/img/python-sm.png b/docs/img/python-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..ae01e05252abd38e7d4f3b9a79038ba6cd14e778 GIT binary patch literal 1455 zcmdT@`BM@I6h^bl?J&1vbGvk0o2_lE%+!QZ1X1(EdtJ9sG)+-L3y&lZLL;jkVqNn< zP0iGz$jT6}@^;J$JWx>-G*ZwMj}EQ3%>Ebq&Aj)$H}8jU-kbMbb9cpU)HTpWAP^fJ z9WZzeV>F?^Zj~nY8f2W;(9T$_U#w?zXe^aL2|?Hrqk}^BIg$wHLhvC3V*G`U5F`Sj zjdFMP!m3m%DwVppxJV+AWHK3ii0SU`ZfR*rNl6h11Z8DqFq6gMa84#ZuuG{rb@`zU z?Gcv#99HJxJqe@%cBxN6g15c$7-T^(9%fCw4^n@S1uuMFhJL#fm+rxkD<I^_wB1|AO2cDi0?b+Od>Mk7p|N5xklCAdR3DwP7!pduLXIYh2d0G-SO1qHrH9Iw@uwT;09 z?Y->B{J^5V`6DxgIJ*%4W5oI>4b^M;}?oV@>!5wg5`-J#cW)~ zTbm?q^BcZHh5*LtM`(aA2a2@38j&sSF${W`k@8Dhq#(Aprj|J|>yDEPVTx1S zByqX<(p*#b9l_oeyH%TdDHy%RwCDg;4epN#TGz!6Q=u>IP62kqeq(N#w(N zRnj~RBfd=DTTqq5*cr>%lJ1eIBj@kH%JiuuZdh)!Lq-iKF4$h-nUV6K4}Id2Mz{ zbP-#ag)e0r%>0L^FEri=cyjwqYvhv7=iSxwMjfsuZY=0xIJC{w)$_tX^~4LCHXJzm z^_r+_L{jYQ>i^(-|bjW2svHh$55C?K#-BY9Gda->yz=E$f3NtnoY`FO(@T!{l8uYmL_+Ry>)CI{uLym0XqbP~c)MYRQ0MEN z7MER0bZ@Ti<-)B=ym|E*Ea!Mb{c5;EeBS^7 literal 0 HcmV?d00001 diff --git a/docs/img/scala-sm.png b/docs/img/scala-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..30db034b70cf9440ca5e5b8a5c57e6a1df65f5a5 GIT binary patch literal 2241 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 M`lzH&r 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

    ?) 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

    hRQ0h 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%0Df27(Qlsm&=V6WQih4%N&U(C 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

    w6@z0)eg6W%RElNi)u!hbu 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

    !R|H|(X=gRtrwni}CY#KVB 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 z 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

    *K*o13I~)b$+z(A<3I*yBc(F5^a?P zE)?pz=TjjQ9ajU6d=(li*mjWnHmNIQ0vMVvG5IeBBvGf&JKsPy3sQY_v7#n~!oiD% zhcjf+LGsMPoPMuS2bo=OOTodf3U?u$&#w!jgmWsWU+W)d76TpMe^rt;o|Tw-XCKE|BsyEb#VKhN{*J0sqbd(70;|i(L$ArX;1yacr7f=R zsVXGybX+fSS{8avFq(*oxJgtj&~T)o|2p@q(VLB5BObFOM#3Jxmg-%M#vf#O1qSIe z-R%-)WqzLU=(c>5S;~Wo(*|>^H_(2Na0@nrk^0qxH?g|CYDJ|}0Gyjza0X`G#oEJ3 zEpfHTl9HuW@`HPLEHj){YeqXOS|Eu`&iUX0&!xqQ80r44{5k|I!<;NlkTdESETdLS zvQrK*5tF9+ngJ~k0|qzx8uJOnL6VU^el_+Ue`0>ih|4@9J?3S;%DUbW0*-Vdz|6Tw zk4bdrA->#wcO%$;(Z*{-@K{0{xx9XO-w)t(@8l}t7sb?=AOHpXKFbaxpxZ_ z{vEV*MUvWG208`)zZO)sx9*bGRT!I(RaEe2+7TfXX zG|;^gvGgR24$`rIKLjX7V*NldLc=Sf?Ao2JM1_*gf0ZFGmXzE(ePwjv*WBE3igrD^ zSa55Y;^SZ>n8x3A36tJ(@J1>nVUpq+&+)++J)#YLcwK_oZhBW%(ap2N=WGIm-q0j+ zq(ClAs6}N&O{&Lu{r9HX(pcO0B|cIYc$oR!WZ=T3|LP$Sz^OaB=%GY3z=)l+XRSlP z&h5AATBVWgv{<+_qtF7R==c03<{MCVao$&_O!})0ziO6x=rZ#~!794M5lzlEI-_6V z;rx#^e#^W7vSC4OsS(EYdhIL6^==PigaX}CDV7vKT5vaV)c34=t$rkmcs$d0la-#B8Sw|7=J=O>=?VI{ zlEzqM9EZ%|-Bp|!N< z(v(+GV3d!2|E7+LQw2A}+Sx8iz|W!=RzD9`dA-poNi++x-guLt6zk}2>S*t5$Ak_(x6Rf|@;EYq7jHu1husFC!Km3A-;BS1s_B0Vk(kcwxcXa>0lcZ~Rg`cZ9!h{9f{)7b)_&j%J z*Hlvh@?5cf9KK` zTw4_HJs3^{sj*S3!RN72w7`83A!SEqKYxUE4-OLK@h(4|n|2lE-fY|A+D5(6(SvP~ zoynkDF(jKy8m$0bWJu>_qwh&36o8gH1pZccE}zypyw~n3HA`oB-jio}zJeA0Q>;rtN#L0j%#{wnmGi|uliy)Q62yqc23-%X7_ zB%8ECP3YoNiGlu-=iY#olHNuv`fpf^^>;kJ9?r(6LBILPM20E8-LBGr*N0+P0H>%x zH#no$SVud2?^#5kmg|#R@$y_>@F}=3g8~} z^j^xep^s~+)7yHmt-f{e?{p=y-K|F=%~l1Vn9#uk}VK9hf?3Riyo9z5L)Rko^_+X z1wSKYL=K?j8#ByvDLQZk*bE3{AO>$j!qhlrVUbN$)VHS%-%FE`7eS!nKhGY%49P=s zQF>D$uoVntfUQ7kU-$#C*NMLGX8|MoWp{@#j(oorYh5s*lq>c@?za?Dh!1aKQF0(j zQH12nC&ly6s)H_>O04rEw|TJ!$qn^Ql96Bq{U@mPtf5&n@!{|9mr!PE;M=$s^-eH> z)E94umNTG?eC5a~4V4>};OKWZkPpwm6p*QCDG8h$pj=`f9+hH@B*7TP5Txv^z~aAN zI@W7|!S+ld15#~C6Lsx&9dc;*g8&^=J%RK4q<(@GPw){a0#Df9N{C<(hMUr`K z@3{9wQh~Z3Z(C7qmJ?XRt5o?g^+^d>`A`t=3bYtap#u5Q+tmTDlxN#=#fJIa74+!y z3Z5!i-xecFU}1s9e>!uwE|eZ-(i|1PZK;egZT;fts4g%oPsa0vL~e%)qHh>FzKGN2G|*HLzs!2#NPNkafZIQ1|3Sv1Zei0P&+BP< zoR8yz3V+P5GsEvi9%LYIlpwCKZ5diRc#Ql1J1D4UiLm=O4;xR#P<(m<)S2_Akn$F8 z(;V5AspPM5=FDrc}r)~=7Ri> zo(Q7&f8D&3lLRQ=gb`Ofz$4B%KX|ZfFq#hxAT}A8v$)*^2-dwzJ zzQ>mvuVQgJl9--M(kKSH!z7IoyO%FowVqV0$}XqsIg5s)Jy zuEoo~7;a(8pOvWXhkx|C?|ltkfu6GKC#hKZu^~h+u5D@p2KB1JvQS;$@M3 zwMFuBAJies6fyd6-tRM*5a}Jt?EcM-2?wcr#ME~r8jpnyx4EroRZxF*bw$p%m)xK=Sh&1-7;#!iE34cv+)3b;qbIfI9N>Puh>s; z&n-WW_s5j+2D|D;I6dgy2K#gMt)3AnGXo65FADi{g5$-Y1Pg+hTz=DqXPx~hT*(*; zEy1BPVndkYk`Ew4NpGPRJ#dVaW{__B1odiNc+tE@_!TioG*V`_FqRQ2Oz@m)YS>KP zwC%Qx4pww?8d&57E#_h^FuNp-=Nx1}d7&q))qF_X_H|9UfHhP^;QD!YM)1+O8J(%< z=0|XgrvP*Ie{O-7=fx{n>n(#OOMm>KTyXsFE%78AW3@KF`$YQ@NSiX^NNH0m59}$Q z$5ie?*d?crZRcLas-KF4M=l4lzYQ~PCUw$os(}IOTkhsB0`|cam~olYLNp?=U^ zJQ~`rTj^+~McQD}oo;Za58T}}>S{)O4xSae_va1s_5p+(8gMRhE>-NgJskvI5W3R88|H2qMU-JeOiB1Qob*qE;shfImD!ga6fc7V@-9_BcWc@KBipXmQp5 z2?EC$2@yRvb>kL13OdTo`b8h}h}RO)POc;rg~`*IP7&trwB}c62oJ{$CfenZLTKrd z!Jth)hkf%;aeSWmt}NTxqVDrKj(6|bN1#&wtD9kHYsj#)MCcR<-&23;fZNbshjW!E zmWkOux$k&*#508(CMIJm&(V4sAEzcvp?{{<8qSk!TH98||8zxD-aYSQRNT!4VFjah zVhJY(DVgd1AuNS(XtAWI+RolaQlQjSI~<+(q2EbcZ2Tovh4z4h{S^Xseb+p@*lv+msePw zGY_c{D-+!~T;nkud#*rB-J6PMa+NThzPgq4o~a%k&wPJfy))rkU9 zGGvr`>{i+~IjTvw&x#6BnEYba;glZl%h6_!$V-2y>O>oc6aa${eQ2#Fg$mz{Z87<3 z8={=)KCyXZ;C#%h-P>hvF1=SbdMiZH9F_t3W)im1ch#?h=gLT}(?nwBM241CR{q3` zSB>s3VtglR+AO~X$q_gpj$uG7>^v};dLT99d`QmOcZtu9;?_R~Sp=83q%{#+F?f&n zuR%srHEE$vJ%)6qV>M(U??>znuoh?_OEl+-+4&~abbQM#*Qh*e)GBu9Lmu=&lIbKn z?4m|kjuOZ0nh`1>aexySpFp^PZAfcsqHTj1gVYJ~U%AJ+vZJlwL!N`2@vL3{_SD)c zN49aUys^z+{5SA>kG`tU3vYCjoX#z`6|Bn}VTte6b)zO%9`Ac^dqm`vBjWjtZp(pr zt)IN=3SCCbTNS78N7(t63;(3J;gMvI0HaBdkvfPJ1I%iFh8uuMl9}!1Gg=>%|I1ag z%}d<+?S#7KL zC?pg}HB6sH_3x+afyDnx*H>u|SRLTAz=D<`e(F&`6*?nszX}Z#auQX0dx_@@P&gvP zJ@?r6>4_r>9fuDL?`KiQI$NF9*V_~ z3_Ez2@2`j*JQ(4}vdhYl5?=e`KuX9OX%W|!*51&LoKwb56}U-IBV7J*xIH$aIp1f_ z;gq67idvWpU$+JQhNAE`7brd4(I!4(rAm{0y08&V8fnueXnLDa9?f&aX5ZoNL{#(d zM1I)}=gSiJw)y|E4tQH+Czh--t&*|!{H+vN8 z0fOs(wR=WduswRM@PClwvjMC54v(zc&oP4R<~B=-BQ1Cqe?}8Y#EjEdMoup24r$RO zM?1_AucuSBYY16u*4G%0*M78g?wCdk;PC+t=?fEvAw&e`-YK4jY}F;E3Kfux%~*Z> zYg07p9t6{`f15u|ppRku{AE{xI2ZTRePuzVI zlq0e6xK9gjZlD5rqE`5IA?r*ygj>?$Ijuern`2f#9P?z5BXY_C=n5_n8crpvw#pn1 z%_sFx5^jNDF(MPra~jdW65`+V4_X^F*ZLm0tL!KTaekZExCqKj5As1qg^ZbLtz zVV2iJ2&Zhqk7=rsQo&!R%o7Vs0wTJ|9MpJR^v5DJ`G$`y| zND)?NxD>{S6P7Q0$Km}K0cV`iMHUV9KucEv1G7D>PGD(6nVdiwy>{uy*#nwm9adFkkjbup)Ri& zcWQPeMJ@c%|1eJe4JJvj<<*eNoNAF+f`!s;4d70uae4S5Y}} z8nHuA+v?Pzhqk(feep*iQm?+hzGuej@q};4agJ!+3Zy=*0Vig;kpeJ&4%nEDpN#Ie zfaUN!SNFmD@H3wiGv?CFZz@&HS3am)TIerz*`d{3io`(R!*u5{OcdyW)#l5uwo?=2 z0Hl;T`~nS=2C2YPqktTq5oeBilEWzhotgls9Q1<0XZv+tGef|7W`ghs!50HaOkt!F z7={;7D>@Hg1mGL{tUEwqCSp1+9(_wU5q0nzU-%uo5|kG987Bl&WHYbALGHI9&!R$q zO1t01hJuR_y7Tc1I?2E>PM6O-QPrbIp+lU89xfZBlU-A6_sgT)>E zc}lNPiV%TxveEhLQ!0wjKG%0xxmiu39x^HBFMppcmN`n4zY#5sg-X8wjuGpkgVN)d zXyyH^^P&5hQUcBHIX_NA9Qx+5P-&W08_PnbyAX5DKXWbqRdhy=h+_ zj8{@M4;1`c!tdZzadU$s82PN*4WkQunB_qwtHb2KU`77FxTxKk$k(pd2|E~^JOS_= z_k-4-V;qgrP%S1ic&&!IgN3a_*WP(_gbN5oj-48uRPE=JsK@~+iX$OKt^(xp>xZXq zAc&2ucdO8gX%Lar2cWi~KufbrkV_$PfX|B|1NkAut+`iR#EFE*Cp~ZZ`xux87iG#6 z_OiHi3bvT)ZIggAL6%aA6a6prABE;HCmRQTLuN8EEkS7*x1qG=&NH(x)W2X|8iVwj^KsaZGL}ErUDs>`8 z@G^bgH3zq?&aAuj&g`2}tdg{8x3tmO-0--WpXR+s(fg;=o9n^$4zhm|n-JB!J3w;A z0mn+QsC8vfTv{bZbtj7B{RY}W5nd68tHb`S1E0iu}I{OFI?HWix;7-5ROpBR&ZerfH`deyIH}a)Ook@ z7ILJrsd(x92Tu*Yk^4^iBE^`uTr?jQLzzy>kV-m`@__*Dmu39vwQ$8|xgwGIJ%_op z8lL)uq~A#7c!+oR_e-UKscu>zx~%6Vk0P@eu2NcSKI(3HG0?43o|!q|Enm1~&xsL^ zl$L@D_%TR@YshHCl`%?)=QarzHJv*%FMJxhq4ZdFzfTJ{YyT1FL_W@QEC(VaUw@@tyc7K#=Ju$*~lMN?p~{{X>Gb9pUAa@1Y) z(bgV^y|HI%D3e!VHnLZ(r8YNOKlOb@( zyL!wpQ?EIijBUr~PKy!5lh}p0Y3Yra!ksB%*oEn#j}|&VPBQLMlUx4|PX>}?GXc{3 z{mGCoQTOGi*rSIkt_{Yv)F+&iU$dDW8s(BX{#0-+1lG~^xF6sbUeY>vWDRaNh9b*m z2gDC1%xKXBj8=tcl~0DYhxte2^N$yXQ^K4(H8{#!jgs!ms7qbVf3!GfYc1QdEAkhG zfFAL8n;$~PZIjCEf*nI3Vj2z0Cl3bd1U%S!oB8x2*FKLK3ZTGaPBFl{w#^igA^w_g zd?P)nzOX-~PM$nh^ku2wBqM@oA|XWq!RJv32A(xbdYYn)Jf`oxY~fsfLu&=4dl8Zd z@-}&~AUo-!Ty@pUC$0H1ch#^KLY{ok(-OvoUBMYUGgmGkhs3^jZ@ymPem+1{abbws z_a+?Yo&cDuK7JU)_KX4CwZni8m?$91gu?6y`K%F3058R}TGhQBuK zZn_n*w=G|1)LPr!Jk$nf#fX9!S~+zl$n6VNRltVr?yI@BtG5~NPMD#-#5QI-g=ED( z@|+GC8kF=4uz5eEFWj^&;0%-@N{Fxn{|TtKUT0@NzgEi`;wg5yAWbDM0iJH%ZI4cp=}egmx#^^-BzLee8ma~W$l=MB5lHu zXGv?emgc$O(aVWtb3!d*Ez?8QsZCLdC$t-fz|9?l>eo4nS%C1bj2@(-X-m3dyCb_2hVdwX^wG5c4Ls&y{xsCqv z$eAl4cAXFm_dl;NGp7GV?&ii4Z{-eEwb?6iTY!8+A0Xa ztjeieQ7S)La_c5MGfdHfL?3Wxn8p749v*2|Xu7v`FT(lW!%i(x(=gXIYFz>h zmm$IPkO+i8470sV!Q>BY+K1)5SY6(#y}on$<+vu#@4;99d0Z^m&EU<0c|ts6-XDhE z1kddViAuZ}FfsPklc^NJwuoa{j4%0~8S9;d zwo+kIfszbC0OL*d);NiRkOI7cysF#Q?7;ax37Y$GV^Ii{m3F`sNM|+ZNR;YE&~NzBLN;=oNh3>lLw-2hB z*iB!k=W}iPr_ogC>ud>xqyz?p0kaQnK(0^28Gg1cX|^rHPe+$R5Pxgy7^7nd>y=4h z7A~uFUrtvW2o{@xG1l>cmM4e?K+~0d>L@Y{NRAdF4jK@LxN1NNTaT3O5_SD~42-UN zkWZY@vF_OJ@WvQ1fh6sxf*2zzfYvhwaIJrCmV`aBN&Lfq;-HHFu6$AQAs)LyN>N=p z!{JDdK)%z{_(0@5C*t`R$?Lb%!`eb$bp%L|_t(CVr6JL=1z}ub@}ozWoTDe=stTu8 zWBv&FR5`P4w3?Ngx-1*Q|KNe84A&eKC@+6ht?@1`xIy*hUDjb}^X1mN3tW{H7zqqr zpQC3+PvhPh9QA2RLOCsQsurE_kkQYVxiHLixA`~MSgcKi1T!Vf<6|ede{6&LowEz` zxRCh1H>fZlh*NSdj18&uH?#7ZM>WeZ7G727D&?*!q@7?1aq3wdvtL{4+PQsT>;8#k z;hI#uJMIoOiPehD86F;NH(qSlc4;e=nUdm4|D zbx-07tLB5?;mH3OVhaC9ihTyyf4VDB>HCoC30H0619_bfM2gaCsK-97F7_wn@mzZuqdYqET<(7a@Ox!8gLbKCngRg0MaN(4HM+a->;lSD}vb(HG_o zEj6iVOURr{5BzkgrEcR$|3}}?Gg>U1v#aklA}4lPQ$O-ouwo=(dN>(DGcqn{dmU5d zzZ_BW=I#BPm?N$3A|dTVzpP)zRE6orNs7f|C|+f>pXCub(Y!a(@==_}Wyvcpp=5CP$t>3KMZ&Z(yER+Fcn=Gzxz_vedl2-e z41m`CWPiKck4!!1=S}6aTEco#93;$N+l!U7q=V2l4i!Nr{QIZ&bh1_2a!fa?WJLm+ zgx%hphVVI%gNOhRpo;jX6+DW`z>v#BDRD%@c!oEf!%1pvZHE``7^9l`u-^nxq}ZMAUzI&Y(-%AJ zlHUBvaN^2<&&IAs{ayc#H?kn*eaKfh=8C;ylDkL+tm({k^prkt)PwUs%!oNIi?4-1 zAuOJLs3J9tUPQ02+Enh1j{o_m!|tAO@BH=tE_v^eUqt&Tu_t=f8O!iHAPnI1bJAUg z;rThF5)2?oVQDQEoQw6$`DN1%xTBqEQ1j_e&5)%g>5&lWH^!}`Eab$A`PI6(27izK zsO=atNBPip-{p^HrRG`Vwh#zP0J1=kqxJ!FRQ$K*`g+xgp@748`Z|^7N#VCUFk{vc zXGHq;*uU5LmcLm;u0!S_o-*U#3!W4@dv=}Uzq>5?qhxuhrQO+0s#qZ$r_wkC;W*H= z2>D9M#3{??D^hX+hSgVr+UT?q)2hdgUW~*GAL$%8zwTn!#{`2R=auro<{)^-He-X9 zT7Cz^|16-TvS+AKKOsIWMFD!vk!|SaQjte&7ZNoT?^JhIqkZ{cV(CiM)U9Y`Qjd{{ zM&k^oR{3mbDcN!rnzb<|^_PH)!1~1n`0aRzaJh^qDEc5p1qDB?lX`;RNlcnbLTnVs^h04?qY{gpH`ods?=~8 zM##QdNvIQwASt=QY#u*%h%`G<;&J1;ePWDZ?}IY?SOqmU`Sp)eAL!88R3OmRH)2SZ zU6~={cE~=Yn6C%ivVV*SGZ1j%sCyI)&Jet#>e|;Pd6`FJ{8$VUh6vfb8zA zc9vH?5Yhb_;L=)&puQ_PWq-=$=A~SPsdgm)-TMz7Fs$%TS*|`Ado!Jc5xSq8k(cw# zyDaBt2byOnP5=~m$VvTdlUVN!PBOGl}U)4KsId1OwF%P%CBR$$m zMub0QSX0MrkY5z?YO@B3ph(gYb;rw>1@%AQFpTIc49Olndz5J1^^ybCo=!&7KbQQO zo21JGB=lL-viLb(_$u+<)2-__o1k+6fn$OcL`1>EC@;$#0$GhqYuw!QY#Vs*nZmR3 zrCM}0^?OTuK!*(tONleCQfWDlot%|8)1S%=mh&J6TY)1Fe~adnP)Eo*o8HkjB`qgQ zeQeoXx8O?EW%o_n3|=*XRzU*7d@_U`g;7<5Fq8cq>@;dD zD!%iD9tt|=7|4az5?fN*4Qg@wdzm{urtH;x5?a-Nu|JD_P@~W^FD=EdyVNB-LRY)w1B{aZkwNx7w~aU9|Fm z1@}}am4fh4sx(?IR36T{>``6BDcojqGkMoC>YG$M5q&jyLu@ckV(<&mzJMpfy3daV?a-jW`dj<yfvw8UY}Je|1U8EeC+eg!-#uP9TCk+GsgUU^YqKpzKIk>c>}QiGL3G zo17J!>Ds-Xr2nhzoIj$Ihtg_Dy0d4c&s%JS*jrx{u-0Nf*{??dvJ{84C}I8;9<*Le ztSFnX*xp{LWI9`4cx{{Ceqet%gVvZ)=qvlt5ydUXX)MA`^9`~ z^xM&z7lNojF2_f`uTCEZJ~`#osKK~1|7B}W^I)!1za3-<5c#_1)uH^N*g(;n7{e9~NZkaDX zJOBDIu(TvqcURS7CHC%yVH&2!!$3Ve!r3R?LLJf^wT$TJ{J9@ zveK(dr|WT3xgYZ*t<sZVw<|I<{P-(ua-lbOQ~etZMPy|xma_Pw+!TM3yZtL46% zcEw!;H{M^2rdf`L7g~ws^aZ4t1xV8*jcE!qO?mSvEUDyJ&t%H22VZG=PM)~+ASfZx z^~;M8^K*Yn&sA?%bXg6XM?s~}lt|YBN(cAKfnLRbE_CW}y`E4+;{{~mWChNQ3<2|h3tC!6BGIhh*0l|Ol-r+u`wmX-Os>Sc$Jhjz2& z7h0|j##j*ztj>TElGF(a&nKvbu2x3r8|Yur2W&dEB~;qCnuv$yg& z8^?)^a=4dio;JBL>vtcHm-E=k{+`nR^K{uU9kyni&QZVZ_p9H6sEK4U8te3e*si`> zsjRY%Jei6HqD(b&@}Gec;EA8S@a9o-a>|AFvebt*(hm^3jBb8Q6WYD{Y!U35${FJ1 z4Oy8w4y@Vqr9xSQ9xfdbyLHAV>%^r;?qGLe`zA*<7$S?MEZR>!{!uZ4%pQhlxFUMn@wb_bEBBf*MVx)jh!rGcCD{-Oh1|x!-w8rSGUW;WYS%<(r znF25UcPN;0zLcpbTA?{V7NyU8iT&|xIHONV9aEK7L{e4exeE=^pUb+q-Mnk3wLDE9 zD;_YNv8rat{M{m3k?J$wygz?q1uBh!+~Pa4`)S>lv{2bqEb! zj~00vufSMRJms8ST%^~0CBOXiO62U_tPu0ao}3F&Dp`sK*+z3Ik-Vk79+wW5=@Ug? z>LkAx(t*bcyRL8OD;R&(A6_wfq+J<*u5>cyh3E5~;gyv`m8~x?9b+X5zHZkwO$)QK z@{u&_v(!uM&A4V+Q1au{l+hR8lsEi?-YKUpQz7h7#aXyx0=01m$$y3StknGG@?9-i z$U5WMADWo=Qt=CI&wxmE{>8_#&b-B281=bCY5qteKdoEn2Jj$cozeyR6L@8dl2qy` z;5qg4rYT)=u|GXq3%@^_z3DD@?8-DvTTRV%YXWXS<~`?QnJ&4q(^_;}xQ-U>Qhv>} z6a5L#>Bn!7+mg3gnWL zxq5?Ioo)Pnyv`$ub(ku)KIs|$k=&=48(XW5rxFtqQBxlqgJqqWu^rVdLqZqQ82AT? zv8a!vxPITsjYavsizzxr_58l?1@8a9OF<7FxwnZYFH-KS0(OiFl)(X$yhjyk{E57cF2Xv>BDS`+j6Iq}s(H?t6euxXs0fy( zHs^J`-FTG3=xIop#MbFh)!ru`ZAV0lxq2UdeP$YMwPTU3<$hD~q-RI@xuO8J_F0H3 z91&iuU!Q$RJ0)X$-lgVQ^Xx&~8}(PtxBI=`qLA62lo0tXG~fZlN6nOiwpQm4HY~1v zh6L*3jE5&tO;Fvxk%vjTEiz5X#DH z!dLsW@*H1j9h09gzf>--QFF-A_nXA>W%>-2y;GNIx|nGC(NPzD?_Yo4U03%%dYdA4 z=HO?vMr2uQUcB?RfcBUJ(EB~+0bklqwT zumK996h#n3>UYq4-|zm<{~e#`@ti%ov$NB7c6RnSYm@BLhRgl=f}FM7w8q?QvHsNY zL`nIKJSBrEry!qUK(LFv@nXNPxbHX_$5W^<{g8u1@aJS=z%xE}0t@MB$1|VOx9*;p z7Rws7Y0rY!yPJPl7hw?>`qo1>q$VtOZgu)+Xp}i&I^?EK&6TdDkGF-jn67r*p}YU( zO7R$!-iL6T2=C{~&Prti^X-(#{eZCl!4@ zrB*r*J)}&nO+4$=L{hn2y|fq(6C9O~m}<f>)8^F2Bw`TM_-686Nr;+u+C)T%G-~y6Xk2 z!{wFe_XeS6y9V`MF;ajLHI%LEQULkL9aAFrxqa3;F3KFQQ)@S#fP4hs(bp1%sVfe_g#Fe*S0AIiv>8paGFe)DBjQV98 z`OZrq?%#=~m31nR$T$SbxU>E(qkC3n9VnxnEH5J{PY~AN8Tj!>9~i&@k~Y4yQyyy$ zBk*aI0yJImPEk-M@l5=S>VU6(DdgD<1Z)6f)kL(^C0)T^=g+o_0bDc|4q`ZPqv41G zmPq*>o%$a8p3Z&Qw|@nzf8g?JGHh&BKk{S@5%e9LGIBn|TVxzP(SC0yUjl}d+C5C5xGAanQMHaqw+{c<}SF{xQ4;d!T z0AvVlGw27z>bv6p)N_L|kCFDoU*|o{eZ`%%fx2=&ZoZbLvEYwtJ9$Bm8n9AXI@i&kWDRZA-cl<~hn!SdB8iaZ>ra#*YSD7V?`yVsC%9aJ@DfpJB(hG=t^Z5xX!gtg z_j(59gugUDmw8(q|DI0ARJ}_4Nd+9bpzmyUm5eXpC$G|R!v{~-?W;T-1fS>gLib+E z?j$ttm9aOl5r`)8rf!Z2Yk|rbi-4PxV-#@YGhYz$LjeuRT9RJWCrHh;mnbT;yiNjN zDc;6^;Ea6f-e$n|w_m(~!gZurFDBN4fZhq&FJIA30eaV}%)?H=#+tkBmCzF;oi=l; zBP68W8mF5R=C{jQ!9eu{khvpL*Z1*ADJZhkTYw zM*@C@G|-L$j^v8p7=D+x(Vx09Ku_)b0irCgTDZIE==WUqp4P~*g}^>vxuTT!dU}26 zTGIIY@>2gHgZ|GUwtBK4U<`SNR;l!nGb)~0i-xnm93G`SyGwr++Y+=SoYx2ghVUD? zK%~k8wA8O1_cx^OgQ+q+W||E9yo9|Pz3GE|xuDz{)2dsiC&v-jgEa5Khp580?teC; z{PDcv?JnE|H|Tah%{`q-DB}kE4CiQ!jLuSWarDZvXYL148mHmlva06q0Xlc|N6j`L zcFJ2>*@l#P`3#i}=4Se;BZCWnySzQpMs-Oy*F}{(9ME3jW?dPxc>t=9iGPa6hQ?Y1hf};;-(@CnJgH zz@_NL?$^Ou1$~nK#x=B#&HfMPr?@Mk%msB;oyE_9M8yk~s4&(d@4Z5Bd5B+LeO*Fo z@q!XoN#Vv#n|;56>|Sj~$LW@X%VhR?fKvfrFKK5_t|o?gjb3~+SEDwN_siqUjWCbR z3}xTTM&#Eh!9bk}EL49w{y8{jSLw*egi2$rNAkY+k)-6Fg|JP?Tlea3Bd9c|0rGHP zfGYh$#z%6SnL1yF-oEv99o>?3Q)o~%N39F0iJA`ETmHE&_iCf;dPi$hQ}SnzV%C~Xt#x*Iw^Ou;$>68S4th? zpGglEtUk3Ed9+xk&fNSnXLQfFQAU=dTgyQ(h#Gtna_ISZsD#ohK`I&{G&C>S>5v*A zBcIunZVc{ET$vGF;b5H4kZHVG%T9o+AP9W-Bi8~A`-eVkS1c&J)jTrj_YI^Sx0iOd znE;8~j72H6(fOFCEZ7?JoOshql(7c)Cyo!I8NOx!Jz|kHqp^rChR&ynw7f=}lruJ4 zb*H~XP0lkq`&t@{C+N?O zaluMej?YE*)4fAWZ?{=TCoy?2sg=;^f4f?oLla#+n)9)&5d*`2R}|cK)5>YNM+@*K zU+$ewF|(*@V}!?(yASstoOi$ZdLhO0dvJ3g1C#*?wptCyT&}Yti0ru0sb4|^B1%K; z1krnI-yfQ6Bg2ts?CDZQW6_4D7IOp)R=2%n2kJEK%fW$r&|FR9JCz~aq!1%fk8 z?!4f`7^ZZux%H2I)(>16Gf0|!p$o_-HD2d&cBVZoQ zdw@W$6F50OjPj5W1pTgOu2IJVIDT`tl7=PL+-uW%HasQ3!gMs##}>=t(X3z_`{~Pf zlZ}H`%ISU6m0+*rwrk1}s{z{1W}jb)yZ-yp-q}ZiR9W^RSQa_|ficAqmc#tA-I^Oh zwl53%OKIoY;Ks;j;;pW^Lnsx*XpK#klqf-@%Jm0$yfsdIPwsoX7R$3c%khSG4N7~M zEra3Ov8O+HeF5R+>-Bz(I;nbeZLZx%LXAZzZ+Jx39_YB&d;>cmzgLBH4<9|Ktge%l z{T%GZAx7Z!^E%$9u9H~bMv5CwKd&(Exazw)!SR@uG~p1)V3qDRGRFNKLj1MtCg#NN zbmy|=)4`y{>I#q8x_G@pz5y@6#2@e9KhxhEk>C6{=7ovESpS%xJJBZZ{2Ir4Fmf=1 z5K3Iqk$o9BTl$%C-TJ4MaGg#RHuG_J2(Z?8@M5V`7dWlU z1(%`D$D`zOq6M4S*szMFBI0u&6q~GCDJj06{46G6vzp0!y-YA~#C>DBjcoZaf`Wo)`ix}uvi?%ow z_0fH~Hj>v|o5LEkX#MF^(1MM3ZJnab{_*#ONp;7F9s>XgXExLh7n~rpU}d*P%oWb! z4q)5-UR!tBa)*sk{ukPyv1Yc;#?z~xcf0p@Ryp4+6+>NCn39#i4$nxQ#GznZ!>Z-* z;dxHeYs^2|*LJS-qJ+Xz+$71;8!S@F3dLZ6IN)u&bHDm?_2J;q+-XhxFx5fvfhB2i z!CXf*w%dZvUC5zNktJyBhp@8Vok!<5spEghX%CVKr)XCK+lX~})Y>nb( zoY*f2X}D@2`x6aw6y*kTnyja@hVL~WUA5zPYZ^q2LL?GC$A_7Pzg~{6coa7g{Aog6 zWU$764@WE$t#qo#8rFPI9xsQ6?i^m}iJcK`2})po=Tv}w@yMiNDo{7){fp%yUPr(jFotLL;W7_LV2$?U~4#G&u$P*!^BzwwZL8LB}r(h9g5 zhaOL#Yd~96jhZved=Gxn)?U((big2+EWukEe-50%t)zCUoqO!_veWVT&u_xd8bdI%1wjf``0}eoU#;@?R!?blABtnq8_lR zlvPgGBimezW1Y&4PKdFnVUml)ad6u`12J$d?vcAn;EU zmSw!Ge$S^?Z5|}jVJQt*1Pl|-gA~>hT7;U9+1}RdH!T@PuI2Uf2srZvFwbWWTKuS% zg|rL0h|J#b881tFv~8*QaXceKc(w<#D1)swCrKDcK13h`t2y(*oo3VMkh-k=9YrNK zdW}H!CE&E{x7$K8F3whrL&?;Vbl|~s!jNj5cGt`e#$n@W-E~e&AvOr4a@;nJVIguh(~r15P$r-nU;tJsGQV1`fp*Bq@x1 zS`szcWo?kRl1kWQG+}g7lXTI)O|glz@HMNo*1u@omh9!_l?qSmlXx!VxH@TP_hzo` zcgBYQjnL4Qj820)d9-kPJh&NkH}g}9L=z2I^7M*UYG%#TeEygglh|r(iwgx$ zfoVP0IyyREdwY9rJ>S*lHQ1a>_Z+=q87DR#rzBUV zn>dH7y_{82U7k$nto9YNI~+NQxfR!+IX-&HZtpD%S4-#SME|$NRKZQVt&F{9+gXN9 z@1X~=IiJY|?*ew3k^N6%WI2XxqKJuOqW) zC8D(^^=84w&f8~H+-cw95)d*dFS9l8c%q^D%lX1+vw}{G3uD{$MrTO-KxV1o5%E+` zTen?H%5{%X12I}4Ccm5tn$LK8X>>m#)$#PY@%_>|r&TY3vC~uj^)IK|Jcl(jZRJ&3 zc3A)e!@pcrYCX`iX+2o4TzO)|to}7~uc6_qUsmqxfzmo)Wya{V%wVj2hwbaDt7>CU z`o4KBVDBDW(gSc2<V6_<+BqM)w+0w8J+Eb&A19?y$MpcsIMi@aCOpuzl=51)iC+KU zL=LC%YRF7$-{cG8$lGT@obEiTEoizgJ^;`df*8v^FBo-cwg8F!XkGSF+@-_zurB%p zfghGRKqGnF+l}!R!r9L!GelpRy%9~ZdS%7uPjy=@c8)cm-}hdvMEwSo-NodMo3`_v z5`0FKA?vYoCR1UnWsQ2^`5i_}v^XsToX>3)rLNjKUpmlIdDhY*MKT*y|kJGqFfBBECC!yyfYBow@L9XSJ0i z)yGe-=XcljZXDZ4L9aakS!D2B-W7|)jAeL^D&gcI;;1PVvBurU&CWr`u`FGhjdgB} z>5cy0bsY5%`)}QIN$3!Ae=KM}F{h?)71!!fQK_$;&0ar!_bD$QCew-WcV|Is((Yg* zwg?T(O)yW3pUFBqTV=jm)AjxUX&=mHS%00ni+y@8Hlo!2v^E~f37L-r<<_h1O5V@|`Offj~Hra+TCi}A>*;v7~<{w;qIu3_MM0&P8 zEf`()9^>9l9`e45eG5cc?IdU|P@;J+QY+1@rd-Q(#d90Q^+!-0bA2ym_DK5$uUxeD z+!ara!l!_$J+aPpIfz(WOHR2dbAPG{8m<7LVQ4Hm34T+U?zfl0-oUk@d->wqhd1|( zrw)Efq_w7>lj#C8sxvd=S2s`wHeiYn2Dsj7hTSojSm5-VFK3ew08jHWFZxh`FW))P zRrWczkF|_(n8iI-OTN-VoYeP6%7A0VzKXUkaWb_Xv5Itv)HkB-?4|7Ok^ke z?E#)=K0w3E#-tzJF^j^CJvFV8)RU-b&ARs@H@H2(*FwO6ZRtKxtj8MWZ#MN=wj^-1 zKWuz~JiciE42rIE8o5}zC{Gucs^7)UMoBN<2z4tF?9%kjmYGV@E0mn%Hs9IxHl9T| zqNZ%H4=2qNf5n0W^C%{fqOw54>TW=IF}}L2Hf?LPB~SL1H0EkWDXWqEa(rhpFwdv9 z=x-8|wEc4e9gwU{w}?Z|)kM_t>y^4s{j+a_YIwae$+xwO>Xi5HU~(>A{ko142(X#R zCUnsl|J;$iIB<6ID6lxmk0!DEP=-pe=x+U7@v*hgGR?E)k^EXB!;4(5_@{NsjBkFZ z@lEs3{}^p&&*!JuysNbY0{Z-S0Z}(XNhNVkLO$f>_YIZRml}cgU~VT@Sq%Cxsf2y8tvrm};sE|L9S?pUdAR z6&sLv*O`RoAC&ZbIdf6uTL>tMU8AllQ#D5L zm(^<4?IPdMus$FL>}>Evvz6qkUNX04$kv#AZNe-$CP+S_@DtiZaJ?r`(*vEnl<;dg z`uA9}O=s5=vccnHA0V>hY%LoExl6ZYk@5CmbLL>mp+@_)ZPm-c>%UHzzXOph<}@ro zxJQVksN$c(L(u>;sv$A?`xxr+XGx%wy1)D&(>!E2*ow({ulY-MozoBgl97DDY7-o2YK zZmFbW)%?h7ox23QY=WOh{6-f;$e|I+<9GQ%u%zppUx*!xR^{#MCL2(Qr)SjKS}{J)Wv z0_v1OsG~(qIS3OMf-&<^v)c079(6DILl824h9Re9PUA3+XXS&c+SYEN{~};H59DF; z`JK`owhutEKF8s0SJMH~KYZcGt7N*8cg~>c+mlDu2p!W)jS@h@T420}qQfRDf39EY zo;jJEP*r3}Q_z0&d6bUt!=}QW?b-~(?n_oaU}M7}FzNpV&%hAuY+^dIm3H->pqR4* zyg!u;u!qhTSBo4WfJ@ZFrz>5yta{|9{z!H37uuahg5bi3&O`e;$1B<2q9J9K$p{@O z^nIE?gAh)Dy9+txj;Y8vo_^(w(F={w%qncQ6#ib`04(~4SM(=GUWn$Q;-32(WuXRb zavHc~Ru_NF?Xp3!`i@k0An%9GfX!4_izxP^b5K5aRArBfH5;r~Hbhzp#<@7$m2;w+pC zYz_bdh&td!w4t^b!_-^4k`FMVs7y?<{ojZT9-b+mSe16);_8`*@{x!JXq+!O{OeOrYMzBT4XadIR7h?`T0rK z5*TKD)K~&}1BPVzIM-62dpS(!%q@7ITK-yi?Jv*(B#{4U{^f}J-vxFV$$Yhi8*v(`1?vt_n zmkXn^vkMCO!@@J7BL9lV3lLeSvu`Q*Z3}3^&(L3fa^q21#&^BOuh!0)@qVKNZ>A|D ztW&SGlzlqd)cHq(^>o0B;>X{D8P-F2DJ|^Rs+hWO|8P7du8dC1`S)73q60Rn^BPQs zd-($18A)gU!|V1yuD5~DpnQ>4|G4C8ovZSH*-LA8RW9T zM1Lf99_(lMNO^XpR3{7VHqG-qRf~ly)AIr!=svKY0$wgn;y54}0$z4G@G~4DF30?j zdwPKEbMfP_EAKDxiDoeqMDcJPb+S_>{NFB&MT5kgB*1!?`w-bxD!_}S_LZ3{%0dFdUI0{vtYAEL?T-yGKU$<;sY!Stgk90mL^Be161>m$_f{Qu~$iy zy<`mCo=+EvwF5lm(+g#)ENp2Q&QW~Wc*!dP$-6)xNL`Jdm-+y3-sp?&%K3%sJ!Z{z z`9@5a{wjkN^p*};h~9d!-`De$A5Zn4$U40M-12sA)z;H4QZA_ED$MBB^8etF8rkzE zofPyVPyx2Qo#~3n*VMQ&LIl0OpC0lxr3F&s|F$X%&~X50>ADzf*%C#iX|XQ;FNtUXTqw<;t%iJUk(pmI z+`hq0^gH9k3?3yZ7Z*Ldi5Mne#Fg~_txL%TmaJ!CF`aeqW2EoUP&?+=@X*GY@}|ay zWdrGHZfX92(xV?>>^H~SFU`7Jh%;Gv9AC-YHJ|BQcpyB}amn_t)cB$g6h8^R-MR>& zEKMexMXeKF9c1^{a*)3!R6@#MIix)<&0r)p{G%u7&oq*QI`4}(B@_n%Sa3NMDvgi} z`j+kQeNn0bFYa_>wk5x@D6!^?B)f$E1Hj1{`CIB%=5j>J;e&}X<_gS zGr_Gma;pj`J+R=;2<)W#OJDpP;bmU;X7VKi)~#)VlnMlO)#4%_MqOLHm|v5V45fdA zTE8}8ou|ze#~1*FhO+$1ken5AR;b04yE1e9(IDG;MfqwK-?v%^-ng-@m4S^~@?r|w zFWm>!uG?(cSStz3``Zx8&E!Y{ic%ov?kdVfXW*&Jv5G=XRTYnoVa-?R(8JU-xPc9> z`iuOgV+ymhnn`&9p<4NOZt4*PU`uzJ>bGY@S64$>uw>^PK!;?2}mR+6S zDO%7SSGn#zdyG7NwLO-a^M`_X&U8ag=gi~#9!9M~oMi*@33OK8YWH@HpRn#e3o6{m z@ZHm`+=gfanLvaNv`@-%W{uZvHKa^H<(-&PPp*#1zf|k1vuMufQn`4{pAh0}c=QG{ zn|tO?>9b6K%ArUa(W45{UP(3_4t?Yoe*Vnv$fgLlOBZ|p;&usUgfp12RBNnoeEZ|h z;jeEuC!Gv_!on@+_%l@0c}^_~6@H!_LT>K}I9J8K$ET>th#9l;Bg2hcIE{w8!`zT6 zK(u|Ode3X7x3BvsK8Gd?es&s2T#I{3(bZ+%(YF1uAiZIHd^|8kt8vroTk3SL*}KUdi{3Cj%rupsV9dX0~+iNrQoi2I7q2 z$Ui0}5UhRR=y#cfbVwrHNY0tx<&MHGGaInE4guz{NUs!gtyzo9dD0+Pd2uhJ?&2O$ zm_Y`W?HU9w4ICn-|F0U?s{r13cAvXW6w**B7tzwN0P9N=>JNa;+Uen8laD;tmNFX3 z2>d1`a?XZEcDk53^ovj z|Exhat)QE5FBWaeY$ZMg22xM0J2mxHb*=BJI|aN3;vsM5&Kf`bronq-L|~`)1g34l z8P)-KDClE)8qCG+cgvfMZS>7N<$QeUU|8*k2YmxNC#``o0Yo_uWjw^RYUN>bk?TrBzTfbPnUl+T<|<2 zTwYWdS_&qwKoy<`WHcG=fumY5GeTTc5~M?y0BHaL^E;lIRP<+AL>~+s>Iwj_R3^hLd~& zgP-$;p-nvx#qL6>)d2AMb<;Rzgs3E10w-k}>t^d@JYEB=HL&I|HsUP5eH~y_Rfs{q zwzF;-INTPf?QY8O)~;=Xi}(PU$%`&v@ixAlk4-{_ZR!%lR~Mv)860qMhY!U9u$np_ zHoX;U8GHIg+xgu&AT_k%*a2u+7@GbN6l?x;b94g`Xh1PDOyivfi5861-lH@XMwy`b zd3Vz1o>GBDOwh3$Q0!dZIi+9lAyOdes*Gi^M9W6c)0(+vTRy3F`U!k*zjhYkWQ4 zyGF7&Wd05hXeK>_#iOqEt%nmq-Su*I2YL8Bo%A(gp4LxqiC5i*-QL$vZ4a5+>+ibQ zv}afzDp&sc)ZaEP-LPxgWTqHUY1j>HLHV!|rJDr!Hamc3#^a9Q$AN;bQhMtZdcRbT z#a$e2Q#9@y*=>y;_}V2m1}fYAoB=jM2uCRac}-|CM4bY6y?2z3H@_}?O_cN!0wT^E zzV6KAyyn%jZQda2csverZJ52%Y~+36yJ0i|>I z#DNQM>_l#VZ4-z1!x6DYwiz*@WGu^#d8mKVIpe*iTQ6F8pLsaG_R%uZKnOkjnge7( z;tNxjlIhE7g*%SsS^XH9Q>Nz`HDoPpN_kt9I6pRyje5l;YUG)%vuVo8BX^zkFuR`A zgY8*=w8{4phXFXVDllsBV)iah$I%ZRF$#HC?ufrx(0?r5BAJz|x0by!Wlvq<2~m$f z*Z4g(^QN${aEY9p+}DGUbKg9&d+w>Gmnb zY87?Us(YG?)r^#*l8ph@m605i?xP&Bc-+vwZdvpC+6iYAx-h)wBIH2Gq5r`#I93rL zsekHg6^<{;&NmI@-5vAw&?3(i3vWmlb?g&wp&SQtS^@ad_S|w{kSNR-n9RHD%A>%P zZD|K~5(MhmEgg9X48A5%MxAJ~5phq*HSn>9yhM7VGeOhc7TnyNF87-EM5v*yyfC|)1b+*fa4fEHgnSn zqrM}`v%Hj+!xIUxC(|~+DHHahNv7Z4XAr%&m?7qrD!tb#VxjV~&mP#0^hYkVmJKiT zJTRGv*L%B~ksiZy+_}~WEYNuckGxUEjur;2%09XU4{B3 z!I2favA|*p75>cO=7I!Lz>*71+@Z-I$+6f95=@w1SV;OfH=DlR!t!i(J-Jz?12-!p z=J--JX8Gv1>WEpk)g-eheSKIo;8QRF@>MzWh&q0FA{q{qYQ~CP&mW9h<@X5hcRxI# zG^=YN?+=blI%m{HywxA}$A=g$P6uSRZVd1fZ@tCPG_iC(QEUB3^>!kGQ8T`cv&d)n zMos9L+5QZ2MTlL4+WgNflwSfM2XU)bq~CgJQ2I#&b-usjWPZp$W^r{3pYD|Tm*desc+{;M)MT0?XW_?&q>h4 zDe0Mq%VF{>>2j0wIxPM+a2QZnPZmHGUCu-y89veKM~r2NbV(jM>-vF{iyklI1TCw4 z*U!nL1O;(D6djB0$co3xRdnRFn>G_P}T*mN)>`ryspa&l*D z#l5f9zrBx-jjn#UmsJKhCo7ig`D6F=Qa!64zXncDo8!3A#18r6ns%bwKb?Z7NigFY zk3qntrFK=dR@okBphF6wJbM6KDA31E31Bu00-gOBfhRsb{=gZ%&et6-x;y*0d;5Ef zi3B_xw}l0q}kAKle-kY-g95o`I(RHGL3Vt>+er7)hlM zsP_{W=7PF9afJ+YRvY+~R`OEKDR56RmkjJW3hvJDIWoF&6SQQu28_)=7ut2TXmnxC#y+s0K08CIM<6{pT9H+PjHA+q}(1II7 z{m~uI!BEu_gaa})OCXZTbC2$UHBJZyfvdV~^O%Tc6Z+{S=S<E=-8%*C{o z6_B6NSjE&^(y7pcIpYicMFoUCi~-u@8cv*-UYiT97xYb40FpdQKhVI>7uy*}56v(^ z78XOf_lnZHdj%lHv-EYqo50Q-euQ9^a3rVZGVR3~1mX&m8)tn37B)-Qih^rbR)40i zc6)XzOV}MjmR#&@*(?`Q(Q?Wdfk+hg5x~r{t(k=u9vQo?{ z2xNj7nWH246M$R@aKZj?rEt9GhPIri7=&3fca#)Hy2F5@UsWFbZk7m8hCTCBhDS&! zTr@Hj1w9VKo})&axfF#hx7`9MmYIQ+BA!C1)H&1PcsdF=?#f9=8&q}RZj1%B0IxD! zgC1uDP0u#`5|5Qxm_q@*y(3z3haIOyj$_c|9UtRmZ-Bh-_7U!hv2u`G8RGR7g9y?> zXsfT`Zp;zG@kTJoQV4c3q4v8*o}nx>vxGym0&Y+ghJ|Jq0pt&6ek=;22a*3_oB#gB z{NMllKkw<7RjA=ZqK?d1GDbK8$D$4=VS6yz#%GU3sw1F8HA8#~i#o(y4Xz!o+_sNx z?jHB1$3ox;NI9)&_zTDtgC1(sM_szRcj?u#I#5JpqNsret+ac}t%j2vjG4#q_bV*; zUbMz??9-x4@2DPmxyD@HsnxRPD*}N#6F;3poYRpH8l?#q6JO=Z(M`1~UP^fM*+`N5 zDeaxdfpwN`FY`a>d)}_l`dlYApV0MO_<>CT)r-ad^hD`vnj;8_1c5|>ha_#hB9O*n zW`j(Lg&T1GD^LO?qO|zJNlead-p(afrIab2V3-CN+Y?iSwO6XJSFUhZDnAbmfd}9m zK_EC1M+CVprq6KCK;PhNi<$d+B9y`=&nwe`$&>{aV-{nKMt(tgX)nSoAjL$vC?XQa z(?PM%9s<1zHy#+QMO?wr;tfD_2HUz#qEL_&tQ_a!AeyqTHH4g^=GG?bKG`|(W2?ns@*spEXNWoY=IQd7lorb@AwXRTZ36s zn%flNNd+Z9zeBAR5D@r&7tQyH8X`k-_~Vu0Y$ZU#vq3s>Zs;We(FA1p68#eN1Po(= zm_hi69C(}5pa^QL0m&0cat{7F2+QhipDC^N1YdeZ_DAME2FnM?eV(Eevon7bi6y)FsnTLE547rYHf+j(?eIjmS?URq^6|YDVwbf~juzk?24OvF10IN$l z0NDVJe6g}Ac-05|W2gR&m0zpZKJ-DfvWq zxN|?z8(YOsCKN)+sVK6bQWSJh8aTT?Nv>2T(i+4Qa4$WLt@3inJ01uv1uYZw?f#ZZ zu`iZn4?*FMvTAJCdB;A7{v}b%-PB{1iMar_OFioc9j|7}PXAtLe*)b?g`2kHIFT%T zI2&KCJ*M_{V=Z<1W|)Dj*Q&Ip82mYWL=37-$%X_WL1CB9zWw(i?>$EZFJ6T`Pr_S3 zB4Qpwe|=E!DI$5W1jY#t5K%-jeBC5o2Y)XCPX)ai%E_fu9Yw2woF_W07XLPdy9pz0 zdu6h<^&Ob7j1CNry*w@ZDvOC*VOuI&Nddp4KeefKLd2mjnTfEn3?2&gaI!_*66v_2 zOyq+lGIQm6{IXbUDeMXzKC$`+y3*->*uP+bWuOfdfD#6=;T=FtG*Ent7$iciBpTbM zHOF0c32_OYjfC%OxpOfQ(c5o;r%FC$r(lml&4dy~z4BANAWxTS<%2_K{1B zy>t$cMSRaq`}gbFSkdq$2+*_hcr0Ek0_Y$Uz`J=!1vtj%Y-}~~G$I!_A*}mYv>T4O z!v-z|tH5#Nc!<(CQwKIIOE2X(UISuOmk?Ol>B088TvNa}Na9oxcxx<#9QF-3@URIXMf(UQ ziNA_va&WpS%#iOyL zqJv0~IRKP3Hw>ID{Z^DAG zymTNB$U`n@8*ZzUD2_A6(qp;nGtE^ER4t0mMwJG~gumGf3`z4xb1y_DB9m4hS^ztT zzXkDzsNm7iK!hrM4jBUHzb;^!36FtL_i==g*n>dlh<+b!p;v=n+>F>gwsV)W&+Xu4 zV}vr&+QCR6kv)Tx_*5JMuS0a;+4k@fku}g1@IwIL+k;5WdBh#)na6mSID3WdV~{D? zI#-aQN`6>4_B>G-$AS0gWyLZye>C=q0r+0C1I^Es$K}o?jm99iRL#|rRf_Ppv5WdH z2KC{ZNM1m?0~Z%U!Lb!qIMCxjgCm2Shr;5*+?9|&ZE5*0+h=2Ve!`j2)I2SrrZiAq z#2C<_BxtROo*sn_KiAhhVh@NE1Y+&QOhe-b94^D+adsLwKB7r4%@`Imi;oM3zw}YN zozJuQwF=)Uc8eft{_q;O2LwV4Xgaa{g2~{u@EZ6?oHS07C`qJ)m;hL_0)BirI?|?+ znG;OFa(iX6D`5490cR|({%LznpXQy)2V4` zb3A3VFQJKmmb(t2g3<>A(j*QU)yulCUaxlj!}-K?#269eGzJ0=++>4%?4`mXAjWtT zycWcmO#uTxLWvzAWw2IwDS)x9Q3h)Jst|-Vk*t^!i4Uf4n8DC1FM@ze1Db-29&>=b z%(qosD8v^HJSb+DD1fr6<{^w`oJs(&#ascmxgN%0+;8D1jEQ zFR@}-_$Ii^@(>{oAk-cR5(Yxx5TbYxmgF7pH|RqchXM8;^aCcvpF6$H+h%3FkH|ZL zN(aP%4KhwiG@7@S0-r!MS~`a_?1e8~7zD_f%HBXFm>ljmzCMSlSBEPvCiukKN7u(} zMf8#qDIk}j>Qp$AXkBS?CwRhH7v7=EHF>D7SDPp6_J1D!&X)s%^Xh+iL2&t2_4fW{ zGDrmu>%fb|JHUwgSoS3{90?=_M}gPzeJJPKv=#3QEqMSh0-gT|khTs?0GZGu8gZco z_L|6zV~N94a3fxCr5Zz6VO*RzjtjNIYf%ub+EBPtYK&@qkC4LL4-jxN*7I2vgAOQc=#?D zl`XA{WLZ>{aG=)T6%^5+OgJ?R`qpW*n(A;_f-dSCzNZn8W&iJs)WJT|nJ8~j|KK@M zx;+1cEN5sA1e)Wzg32PA+h2qjroo=A_p*xckf-Do*K0BJFw(N|(iXsAQ>v##1_&>d z93Bb{hT{uOdwJ~BrgS@tl9|=bF=+l^?gB&}1@sxfjW9@BUft98&%S;Bu&(*D=MNxW zbQzF}pVsxNw{^Km>AE+(VPaha?lu@M8D8-o5C#AN&5yo zfWX>Pt`B4X%-5!;N-GGxLK^~u0k|cNflMrseLAL-pzv9EaPT1& z1T11F*#dh)VU zIP8kB&!0RHj7clPnN{5(vBFp20_!EhaZdHoMUnRP2JGy#eqmU;3RO+hMW1vz$ayI^ zvvn<4U8IddK@I4vB-{pq7>MM7{TkLsrQvzEQ(RZ9?{*`ff! z&jL|_xZthuZg?&z1b!QxhxAcZfJc*ZY|t^`BZzGH{w3b}=&j^^)gSie{Kz&{+n&Zx zfOT<>=p`EGgI{9lMfoHfsBUSdxT|J_(`{je7aBGI=68mFK?CA|mK@pz4dDettJt80 zxbrd8&B{0`Q6;J{pqGf5A?%j!ydzO%QOqv{BciD<+zNBS6TcxQXbDhj1O`DqfKztF zB7Bs5V()tNgaLYwiykL}BqB3BX`jKulJH45BP`s3%>l7Q8iwVn$2-vOV~gSq-hVK^ zw3tmj;Q*l~1$iM90BOIEcIO&HA8`dEnUw*Z7b_ZpCEp5DVP1d7dmg6Wrg??O6M=#2 z_ab^}u_z?&`OXrZ|LbsI4pU2~h>WJjoSWmBr4!kTwa+k6*)o`#Q}+RE^k-YiSYMCC z8k{^%y_W>gzr3P&EY~4)0hkz&-|pg>c3b({i}(!RfgLUEoo(@w>Mql=ku z@$sVhW3(dB0w{!5<4Q0OIh;Ca5Qj3HBm9E;)AGSc!ij=JQoNcp)+g-Ka_!6T9My+= z0NQ{H-cXMd9j0Q{06D+onZ0z2QPi1y$P>v#Bq5C=oCQqn zZYE!hLiUo1@)xH~#_u|k%w#s?{56unbYPA%(81F1FK7S$y&wYvC~ody>M#J&q+DC< z%1H9aS~#%H<2BTBk&+3|ZwoKi^C43;6D^PZ%z&`QJrYX3rsgk*Zl_lwaabq5j;y1y zW$6Ch(0VE*N5(=1HFSs;KgWdVPxMjgzbg?BO^N5CzLkw7LtNBMhep~mTyD5U0i)&i zq?dMoAwxtw2H(Y!B*BVd+(&K13ADV83WHoKkTmRw^#q z;nora?lTUdc4cUlUg}df6g5~vt1r6a5k83usK}xo?5T(q^pU7a9~AG?&&jSJkwoK@ z?8yf&DuRn4KRoYe=hjTAH&}YCx(d0Zay}k97=dAN$C0CL8-3%TNCPY!YM7^-8NYRJ zI4j+~Hx@4I2YJ!ahQg`Bi+|u%G3fY5eaLw6^S{0!kXuB01<@Gtr1Lba3RmPdhf>Z% zF3GTa-n^r(DbDu8^8c{+-r;a{U%=?WV1($M=qW&3>+_}y-;s#JFs{04rWj0FQW8^!fB@gt z;x|3xl~K3{yN(D`@-1?7j@d6^9?qZMKk<2KmkBX;`Kh|6E02QE2pUIM_kLPwIUrX)k7D6){ z7^-r`L!}x?{Q?m2a?TgcPRy8$lDY5*pz;#}r0L zz_SdCl}c7JL}aFL%4QuC;Fai1R?A{aAA~!32r@s`{ScqX&04#;xj9a!%0|-@N6&yY zfx7Q&dE_+-VMI}j-+B^Lctx&DiFe=e4{G8Is*y4KV0Ne^`3qe#%$joZYz*=89zdfJ zmu-Tw`Tj@~6HsO_M^CCbp`x|RZl~H8*Pz16dw=_iwe-F|V?r!O*jqm!sjxUDRIv9r zM2(;g)vhu-9z>V$IB>7VgJ;#nzF&ott|zN_bkyNonBzuheMzhGGqHy4g2AH>&MZF14BV>CLs%iw)Gz-ylgufEqN6XK_oYdBJ*Sc zips^6qU(I~vE-Frk?5)I>JQ?g!N+&8rRZ2KWLh<2GP^)Jgl#`|&zWbfoj<3*mc z#!lXQn&MK^Wm4XK8T^-|?y%6YQqqA|iOe;cg|8%~Rtt~yyYJp!Duj?xkEXNT&iurP zjML^qZ&`Pv==j7C*RvMfJ<-UM+hYZ1JQ6ai-fVL8t>NV$yr6A$%edepl+NW*EVfbzBFuf00k#`_5F_a#9>R{=|VRbrz>Wt=n1LrVRm95A3UsW-;hyn1og-z~c3hs;yXFr;|$F5uHu7^ie4xKV2 zFG=u8*6ITpoO{Yf`vO`lXA}GFb>DgZVm|)9bweOGAVC{RC9z1ddoXZ|cXonk3#|z<-_6W=MhjhAXfhp02koOIR0$g@EO5tp3%(C@` z9UAX{dc`yNw>Z5yys!EgK|F`zaz?SiL@2tJK3okdPYAP3_UMWjEcc#~7T9%(c03ph z50hZ0wlwGe>c#{)_LX8K>VS5fxE}74Bz@59kjEnsluS z=bkleHj<{8%es*P^k^<+FesG8kP|-EP5hd&uJj#`TEcH&M6eDz?z8(cQzn_v)Gl5I zF+Zb#6Rf*66d5T>AUZre-;@ z;5><*;)~s2x6VOsF9lL^&RPfYjbz=H#|Kq$64HJX@Wxg2L+{0^G3_$=%N|~+UKLD# z(*??D9w}k(lue!$eNo66XZcLl16Cs;zF*h7f_MoFdQ$jVzg&u}m`g-mP#2oj;z&Lx zt|Fz8T|2d#G80Xb3`bYv96L4dK$wYfWRV^|(KsOV`tS5A!3T z+Md%7mJ6ZKLf9wwAz7iRjns5$MM!knkQ?1`6c1A4C-cQKo*!?uz=Z6uGVI>cpbms} z4k8w2CD(dk+0u2={S5a#ma@{)kmC9Gz22uc57LSH%C@1Z`Vm@Db4$;@J;;+_k)Y&K zX%?{m(xOip6cmX38U8FRyTu#u4!C26)P>Sm;Ph)B2jPRRv1w9{nwnlof$hAI81=Pv z^wL)<%S@tqs)KKpyXRGTN-hI2D=#w;69-voK06a-QOvPK3sw)YAT%CJ|PknX=6aIp`)dUM_Ba{o24uM7itB zK!0pX?n`w~D;`g{pLGW$p8CGK0LlP+J%;I10xJa0E_Xwr)p`a|PdZa$Lc=OAURJzB zmX>>sJlN1|ft6H?Np_1+JRO9KAE%lOK6f}lPp4KE>iF_=I*4#hlYX#sVJKi%Ch2qkHd#JT4TVWMn@!MGHA2W{!@hE1cXi9Oyi2 zj7Fa6vunMn-qR1Rk}1hR>}lVJ(ok)OsB`gB9l-RYd|9Oi!NZ@|_1wZ-A!)g4Vx~mP z#{Cwn4_|YG-mlHAD&^))TVt7xv>0`hdG62i`B$Kc->#}KYA9w0$?@;1$7K6UB)FUC ziQjzt>SrVLY1xw!v7ai0ukO@)FEj8+b3Dnh6GS*aaa z3B|+~(>?W0&*~0HUH@F%5Aoyd+>GE$-_tKo^)J)&QlLEg=%9{%Ygr*KFZ$?G9sPc$ zxg)CL>54dedjeU`Lb%z zi{JG8`q(*$NOKaBfA)3IsSfHE7q1;HxRsa+jf%KY%Z-=!VoXhk#+u*u?7pn&zCGTC zd=hYc5yB6l=i9znvL3eo!;eNLvWu^wiglRd_RM(2`MxlxZwlUvS<2TEI+*q8NQ=Ec z-v20QBN1!ScS8fq8J*yM{9@3wQy(7AKKd?D_sjejEQ@4~!gkPInME;rzEY#00o2s4 ztnG6R(y!rzDX*<(a7OMVG*WK1*e9!aGdDLI*oG^{7gT2e!`fay@+$Eh#JpcqRnKdC z#-Tc(SDG_c)2o$6W-7ibpOUy5};4GbSx@I%+5U1Xtjd|#o$VjJ)#Sxv;LwNOnDt_p6HL|2Y%hlFM+MOQ+sR91S)b?gK#P*cp})xE$%9ta;)2|{BMG6bPM z17$QVxGG;NpKfnYnY(uK{L^Q}9-L(O@0LHzF@DY*e{x|SuD4i9;dG;I-0n*a*1>QXQ`NZ5 zw&{KUmBNdk{zNVH>*PFMXejg5lmp|gHzm_f_RUDi*-VA-x)4NyzO$?>rAUP4Bz=?? zv!BqQp6U0J^Lkc+LZ?MMp1n;F0NI2XZid%#?!ai6zX)^ovblE}AsxHX!|Do}qux#% zaI$_rgNnQ?bJ14KWTEkUiX2JL)$}sYL~FEb&^6@p!^|y~vK6L3Y8fuBeTpK#x-25n z{T(U(`0Ymfp6GaVLR*oI;qB9p$H|;?3GEhE-PnD{zBj_9Wb&lad}0UfFY8f1xM_gRi5+|N)W zeOph1?JQm_S?KI@*Ch~h4xT#ap^GUZ&j$c8c^g&+{hSR@PrNCN$46tN@%V2 zbDxjpqD&7w_3sI^;KItk6V%k^ZLLf$>BzQKA?QqJ`L;PFtSVoOT%uuwhRw$trm(4) z`VEe6EvJ(llNLV;o#Bt$V5-8;si;~SUI)yoEq zIga5{ki1Ye*b*}z7txf;qQ6 z4fE7Z=JaggQsvKnjcj7)R;nbY8D(WH@*#&es*$Eb`354`Ye^;INGe)}Cz3jHX+GUw z*NIOgwZzkWJc|!uLd^zB?#wbJ58^4PCRAu;Q8Bk1`e#;f;o?`jcXDI;jBRMoev79n zhRU?)dUSuiyC9mA1AGcRGl9FCfoV(7f0@s6$}{8gXEkq=3x^T87jbM7-eXP+o=DhWSHgfG)aqkDFF-q9 z2I%+EL_)={1>bTikYJVM)9Q5DX__^Cy4QRkuj$zI$#?l$tSb}hSlgS@8uim`?e0rR zZFH$qMax{$r?N1ql18V8KQpMfpmcl`Su=oSeA2=mFO57it2&k7OTdacYq<%tB|Bp! zdB`bA-mb=+sN6MdZD)U62A3JJnS;bJRzJ5M{!6LgZEI8u<%UL^|zT}`@ZFaL(F**Ump=Z+J zkMVYyo$H+@2*q9gkWnacF6;jL+?}?V*mlvq#Si;47vBclw|pOc${c9~zBlG@lyJQM zIi0+nqUQ>Ur_^UbgwK4hx*vZWe1n(ax8XPNEGRK`P;uBN^$v~0A5{xiE|Zd5Ast$H ztfPamh1oP)#4|DFc;PG@pKe*I5mvnx>O{&)-A4o%ijW1M0Toa!>m_tgzp=elS4rM5 za^Qs9PANK5i9zi$Q9yNJF^#p%B`qT^p5rr=!EdNW$!)2=-AG9Zqy6nxNcb9|iawuP zh?~js@G9F(Zo?y_D?>cJ|94i64{oa??oN~TPlPkSoT2ol2>V?{!d1+uvWTD6Lj%6m zrOhsb#vi}2mJ=77`1LQgw&&R!@fvbdn^aurpx)*fS=Vy*0&Pz&!ndx3$YG0~`N*J7`+jUqkU zdUq$1Gg2l(Jl{J!^F1WJ>+*IGRzh)-sxK3Q?MzJr6ZF~Ko-s0mXIBcVPuFPMh#aUN z+;xs=;>^syJCM4Qni3-6oT*IZKw`~qQ6&}cKUp)X_(~P$a(iq2Ng>C^yFVYPWp>-n zVk%_8zCpum#h}u0Ip+5^aG@)yUxXfJz-RX5Vi;9Gl?;`&M8>|iX%TwE&&4KreIl)= zZR>j>yP*VqK8o@!%J!kGLqQ7Sr1$pncGId@Y|oB_UEV=z)Pnku7;v5g>xnO3 zjghJyV=OslNtmu(K$+1g+T#Obzc$~A&tMf{kYHhQbLZJ1+Mmc<5o$vA=Ik~)R1TKx zzE_i5k2#V1RL|vla_t*6sVBW>gD<(w4A^$Hq|qTSoW%vQPD7(c+-IkhhU&;1rQY3z z))!d5vRhrPMn{UKGfRO6LV)dy!uKvOJ1~?TXS?D$!v`KpboV1-8hy7BZ=t#18(Z^6 z*iI_O!X@_$zYsTthZ4uy`N4ya5&mr7aP6^EPm~^+h zUn{+46P(SwWoJ}bG-R{F^{p{8!+bJ!u?Ms^fA(_DEx5FCZm3vQEVU6@!FNA8P*tfK zRYp0BhH8vRCR8#a@!=A$XBP|O{Uu)UQtt1vv?{()LvwBF-%=nn^4isKj&uR-7DrC{ zlq>3DGHcE{O7lqzUKyD>9$^E`E%L-l@6w_^U{@$@y%JSSyj$Q)i>_SGQjN zlD8JQ)3`ER^9--FmIm_^{-Wk{M!X3;=Om=S<$dz-p>o(554L)8 z^ZLrryE2Udo@pF7sdn!v_*4gNr(s|Nr@SR=f%uo?XA}_Gcq)=)ZH$UvGd(>klu^sk zd5Ou7Jqp%HqLRO%yfoFX6oyfVYP8y(h0$G}cSPsa-7XHLFT5AE)+6xg1zBx|zX_jlW(CR@0>@C>) zs4kMVxL0>iZ5oS1+uHtq>g~Au2XuupN}AqGPKnrb2srHlJwStZOO{7UaUuNUS<<3e8`0_Y-scu@p725-&ASpoeec8D*yD ztn`ZV)Lm;P)Mz}L>S_?#J3YZOH<`5;qoqK6AwcaH6(BJBc(jRIRqw3CP+L47l7;OFubQ`O~r>dKH44>dR2;wUZB!v{3V=4Dz*;!hS3t zx)WTT&q(wIDDD(b5>RC z-1{8g7*?T2EDr{9<;L2Z4Jiwz5*dNp7dXWy3g)dzY4G z_9nk+eozgJhHlolzOgR0+C0v4tQ!c$VyLFN*POTcI`Z!rvS7+IB47gjxu|0BU9Ma1>M_ge5R|&Y{KNFj`{GtO(}5TMlFQt-)4cq zKbBocDcnPlClzD!1w97_`8hk6`){KJ!wR9YooC19R^$vMTQ%QUWO_aK2isFLG|)@TT$5$S z=>F8Id69?Tc*F1bzvd}}Rlh%Rnp9pE>%`z>YP#I& z_VKVBM%cB?P{t?u-qXlA zwvsFhggxBhem;F2xG;$ETp#f*Z=o6P=c z^hj`~I98}wL_yZQt%mpKvmVy5%~wQj9d7j!^0H=Y7doi>Vz&(w-ft5!o!~-m0tG7X zG!b7hGXz0W*u*b5P4)_?$t}F?^?pEXD-v#&Dv76K6Z6g=syj#=09SgbFmrzkUMLdM zVCMGrhGp|L*jGB?eoK6##{LZs=}OblF02_M5k-Ns5f)|HS#08u`rg1fp87+fVY`ja zEO6|l3?Qsmm5?4Fx7S^Cm?roJsYZbmnaUAUL3#B(K)MD6vYe7!Z7^g)_j0}gOGCpD z?Kl6pO9_Ldp(=Kb9w009`oIcg6jWZ^qoU=zri6_la0?ydYE2YTF;-Lzlz6NcrNJ$< zS5g+xOTfR1aXBNkdH97j<;#O`I$MRUpUlld!LMU?ce$9mdhj(leY{Y~+HWF`O-RaJ zU4@725iuLf_;u|u2aQx!rF?Pc6%ImLzaVd0%E~rUl*i4Z-5IL-&1NB9q%qERP?3J; zf?A(;Rdo!rLNojgaXxT6m24dAQk&g)W!*mt7Z=^RIIv8WRB5-b#;njn<3xgK#3WqZ z(o+~Ros!!5RY}lm#qosf&0~%%E}+dw)URx6xURyFx&7%$iVXW~&#gii-8Q66v2xrT zuQH0lR&z3_7DI!g;&T5b;n@A_+>6M|>*_yHW+kKuu1zm8$@Yu%6ol-EyK`O%G(y7j zeP&&27_xtf{r2~}#cryRW6;UpY%kKuv`=X3m z5B461u@EJpF5CtPXJZ!Xy5}kk@zjZZDQ=X3PAOixs&ixc$lUn0@BV9%9DScaJ%KxV=b%!^PXj`9BB4$>r_^jU3uqcj7}m&txSo|pYl##D{_-F!zc8095{-eHlY zpKQ##E30EVyX1OUb$Q4m#IPzom-^HJZy!_=>k8P(ntUw;&&|I&ha^gZYE%5|`sD|+ z3!Oji{@lOa?wnjWpwoR_f+UKOP%&&d!H}bMCy-c*--}V8zjsi9;AH^tD1a#+1!mj< z0HGt`|M~j&4PDv|ns7c#a5WkDKT070@V^-ve8B{Cwq9`% zqMZaN0UmH2G%rB!>K+oPfBwA15rap#N6&x1cE*9<0*=W2_xOLu{*Pbu*F8eqK_x-K z@PO+f?*1SQ0|072_rTy#0HFB>hHHd}27)jxKM1o2gA9VO;t}li2W)r*yZr&%|Hip= z;Vg)A#4Dq_x9fEfhJ&!I+dsm+{sI5N1Be0AG4Z(R5$xkGbfgPVvz|VF9={|0xcv{J z|AG1c2KxJjfinNT1i(8(i0?&n@F{g9yLYhZg+Jj(?yg1`L0Ak7{}32za1<^9!au@% zFYAM_G`QM{)ic-_tWQU2DYYWKFWG@GxY3XDx=*Otr9ZPco~a&t_?aB#1=6SL4h%j2Cl6FBH~p-R@&b8=FnWai zmJy^$wG!%m$@Gu35Vg?YOMj+?IC%OPoBfFo5A^$87eU@2PlCfP9PtLyhYY#~8<~JG zNC&d%ar5$#-awd|`?{;)k#6NdSO>7Ba0NVo0Kg5ry8}0YL$L8(089V_@EHgMgE5|f z58wxec!04UV2BUJaljW0`|o(?f8+d-=5GwI->FxQQiHktcbq?R`2HtO0E7#o2vG*V znh*w2eNP=H-AeR@OL~&=P!vto&)}=0U!j_z`vxE`=_3I;4R#L#R!c-nw>@% zdf6rp$H4m}_4MEAsi&x?!OtY150-%6Z;t#yu6%x%M95!wa{nen2Z$L8 zxPo^Kh!+6z`Y%rZtwcR<-r@Z_=13DBNme^nK)meVp^6iV>xyHFrHW4!*ZwV!zbXEk zmZ);68mQh=y`g$b^$8H7YNzU;YNP6=s-}AP7tQ}(_J2_MtL%TvdlYsg?NKTGE5Cp0 z+5_-oG+^Xo6lFAI6l4@?p?iP4l%5{%*dtK9tlj{i4Ve1I#UuKuOf|DM-T z3-AF)shi+E9K;O0I+r8_xMJ^Iq-K_C^-CT{{;K2!N0>C!T_K$1RR!C{tlA@`$Ucs0BBZo4-3Ba z2R(4$?FWDmPvuj;e^W3RfPK>}nY;z|SF||*aF|UdA3P?L56eLM(*V%!N5%l5Mlc^w z0I;+?>h-~G*boX{fEt7-z^@Jk-(RpXh1Ahb6EK_-0FrzF$e%bzef80G)W063`Qu6X zi1J?;6u={@f5AXIhyjqNfU`%|!~fECMC5;oz)@myJHP@3+9?1k3KoEpg@THOf{X?P zK}o3ppnb&d(M3T?1)-*)h0-0P2N4>W0ZIxgDoO|yH8liO1VuC$4?tL`S%pC}oz2FT zRwRi1R9to`RMeoRgX6*wPE6S?IG*kpCl@yluegMy)JbU-RW)^u(`U{a8X23Inw`6N z>9VaISiJ7nJv_aMMU04CL|^$r=;fO-o1A}FTbGhaoLln&z_gRcv)Ll z-_Y39{N^pH6W!I_^P%_S@W|-c_{5jVuNdsYx5cI9mG7(g&8=VCJG+Fv{Uf=KVsX>l(x+aw-nWZjfDC(?KVyd;!Pd7Cdx} zQ%nUTjz1FZw`Biwg2n%TlI$>Ko=m9q<}}1vBy9Y;Qu`ScUA#5 ztS!ZbsYSiK_X+HFcPrP>w!K?oME#73H3)k-`M3mnZiBGZej znYQkH<0)aU)uZ+CwSBVzhh!pp0XOQ4;k_;?9Idn@RlAe=+ zxaut?f)g2_L##Z3DUg9`^N$D0gXZPq2F`el&;Mwm6pLD0UG4CuZf1M|MbP7;?c z%4Pqg06iH%rCE@HZ-u%OH<`c;ABd8H&SEw)a6f5W3Nf&XAn=j_<#OC|I$RP<*bv7x zrKni5NR-G1&OPM2SU;-MBRjPB`srZfedD-i>0HU@xcV=6g% z5Gl+ux0?VxhY8ycFO4mf>gAKYBOw`!j8P#^rUSfu6HG6)i7jXbd>m;wn0hm8_ssr0 zg&sAy_5XkFAs{zT23QGRX83?^ZQTnKzvPr{1X*Mi#A{o}WM!*k`onO2m~Xe50{nxt zEHZNF&Y0YIQ5-K|>63}Fz@~+J1L{YA!QkO|vOeTK@ z@9^^rPi{n=DgGGr+~(Dlw;}1*XHJXvTLorVoV)wDq|xfLndTW4zaKL{er&IK!u=0C zV+Pymn>qth$v|Bn>GQ1M2uYa8^$xe(o#DQd8bI#|)9lhYT{8yPtRQlbfduhKFlDO= z;$_SO`m{EIwaB(~xD57Q^LQvBG$2VmMioD5w;xkAUnQ}_R7RTaMXUtfBLkRDIx^6g z@&2jq-X0V2IHCYAkbU4r20E;s6W-4Uq(t_hDz3C1TfOCAjU-y*Tsmj@akmQOAM(fO z;>keLwqQB~+@)%YXr6}_kQn?`O}Vyj-FZ-wEWkU|LV=m%iXfd#LWh$$$K_S)4nn}X zSlVp|relyK1M*Bh)})xTWPr+LDW;nAQCCpwGTwLI1gRB;A21lyVTD_aZM!6MM)t(Z zze-FB3U~qw!J4GCD9u;1^gZ%*=zd;72y2O$kLK%)(INxjdFrDLd}M$ri#3CHm9**0 z_2%w>h=l<{)*X$D? z4?N$@IH}&atn>xu34_~G$$xx8D&>Wp%O^So-NW0%JjlQ!yKa+s+?88ga%E=^JwKfy zat7ruYow|uT@G%M_ep%7`Ehf)xLD+#>9w^1d9-WI7vg7`wb~bHiS);1<@i-278-Ri z)^N!U+(>(RR2|{s*<0?@bq(2`?xS_ApMuTAa-Fk?XRVpe;B@Jl#`=W%#3h$cYAFW? zgiB1_TyLED%tT0r!|I*9x>&BVhkW{|BoRRYGBD)RrAvtULeBG$*DL-%{TDO6uft~S^R1bPik}qoonokv8Zsy1dR$i) z6z!)a%yZoW^IIe&ihN!1_D+_(Y-P!vSgFq(-V;wxk5pI%y`VdH$}<1623}O53;UXz zB)!1TsY#t&jqIMU0pHvuc43rYH)_jLP}tYo6{to*mZU1W;cDYbVcUE5=Qu=pjGiJ$ z?7OIdeTf)Ka7ZyX0EZObmH&H5Ki4H1>S%-G%t$H%cUV9MwoEf{QJ9-dlSC?v|CxaK zmZAEzt4ub?ohW~66Y~=W<9ZQSY2NpT%x>&MW^hi z8s6w|wp^?dH?@i4-OF%iT18Y3@0$DTFGV*MKd;P(IF&GUosMBlbiA@KZd1J2YQ_~bu5y=KuX@`rS2!zns`rMxtwgcdDKzgX{(~<9 zTv+}AdWKuHQr%d^FzHLrt=V`jZ7MEgNmuY*mRR6@_290%O-HYR^?l28EBKlsqwGaO zfvZx%GuA|D=7e+k5trUO1Xg_d{_%-$zjVxyu@(QSyp7YxwTnz7UYYrqu7eS!>#+K`^$ zT@Io6Ho|dTlD*(s_;E5YxB!lJan@k>!9?(`j@SKVLj-FP;%3_(Z`Oa%Zzlte%>kq& zZfoK(1Tl8vuq=kQyK)0B)0v!H`Ex_{dVbOxNb&aE;@9iw! z#UEIW)*pPhfF0iN-WfOZf3+_EC|jbbIo?d9Q1XiCEn5h2R+K3jWmlEZWmA!e#;ktM z6lHQQ`fgk5aJNYMLdChq>EB0@Bk35Gr#upc7Q5wkWhrImY>8FYEJ@W?9OV;b8e>l# z?wP(oJ(a!_oM37tcTPDiD97j7h{Cu;=|AiwimhP+y)_|wK`?ngE2Y8GV<4&JqATVq z>x5PDXVljoqb8gkvPJ(}?uoSNnE|yLthVz{$Fz4TMfAz*7#4j<(8RJ#5^mbE2rnKwaocGr`?_~(hyiVLt$eLN0fGMCENFQ{O8t%}@&rERJ% z)Ia;SCoLUhHYxQoba@2So5WN=v@F~Pzq_#fWBWjx=v7aU#AY!Ny~i4!59)fgv9Hcb z4{htxAW*`k-Y)fC>-=qXF36|vxV|1%r#H|aN_Hu(Itxwst0>T{HsWBBA4NHcg%5vm zidK+>XN^Exw$7R;n?werWLE3j+Q8~jS2#)r{IduWOZUos_Wj5JpN{y9dHE#4_dHjj z2}r(-|FhqNq9Z`el8=AQVOf(R(@*^x7j zaC?)<_8(F)y&NWy0TRtX6pk^zm=3?3)*|@q#+iq+agqr{QEa)ts+s@IC$;0M+SXl# z@@3*x)3*0_b-muz;&yVJ$FYvduEn!vRmkHZAxqyoC*i^JLZ46hNl0=y%HO|y*ArKk zc2BytG^5L{4$dfX=_M-TOzYDh>z!Y!fqJITQRaP`)Gc( zx-9Zzx6URrd4Q$uXoJGS&*HV}9K9pE2GG{& z0yG3f(6c$`sb2Q40aLOqmLbO*%bytyZwSntFZ{a67a=EkaQn%xxx_ic0M*TgP&3MT1D5}sDHC6RbwAw9*~xN4;8M)KERc5ihaN~FwN z3Zi)%OUhwwc3J1~TuDC!EpdmfrIC4We`ehnOxe~HD_M6uH{s*r`~Fa~MA-A^@Xe|3 zQIW+DE%fyS?+ey%^h5=u>uBP2f2db|zXONX;gg6$Y7@GgItoO+;Z}jBG`|g!GR#{4 zwmw1OvBURPvDbvW3gWqV(@+J9?{+#Taf=(ts%bL;oo5;|Twi*J7hc}oOiJN*&BUvx zhE$h5<l5A2|>eMD=+hSE7?#&Y{Sf7tC2P@nYsDMGa?8Ol9G-ki?I5MFWXS zU*IqBt^S!k*T*zm7Ymlu>C6RIJg!uWJG_yDmvLlX`ONrUq6b&D09y7jsxaLhH=M#c z57_-8=xkAI3!Di-T(`B<{oUtvZVurzoH%dMb95t*4sEsJis2;v>mFpa5MhIoB1&8=6q2%pKtY)pnxxt zg>Vmn7euKG;_mwFyk$aHL)N%rs0me=C^PXWf7+f%S+&~P*1|0k3Bf>kVEKNS=rRB9 zds}olOc(8NVg}U}F4x~8#2p>rIB9#k>cXf;V3=Hk#$gJ()s$za{t zH7%J>LS2=fvu$h~eYNiOX5`susK29S>b_W%*ZbiHKGnMe?jigxA^D3utsdDpe|Veh zr;uapwOTQpPyINV*wUVwvoT6zWess#508b3TD5qC7UtqPOUnyro0ki{wyb$Q*OaxI z6h6ahGj$c)=PNFM4zw=}1rJ^0zHv`+6H}Rp1U)J*4K9{Re~J8c+5S1LZNiNkPNPfr zt=C!b8&)_naHPutXTnK5J*K+>pJzzW#H-s8%*(Pk2qqWLG@)nII~-;1^UFW~sKJLca&%Zmh$NC}r!zV3;ZTA$!O7Va$ZX}BgEQL&x0sCO4eSzy_fDqDw z*xbT*Vwu)!$N;r`?L@0`byEFY!cMF35L^!HSb{93$GzW;B?%ElC%h5`zcQ?HHO+Cs zjRJ53=%&csB)Jw{9OoA1XMud&W8IAHISz2X(uRwvd**aQKpdAssti&%WSd+j@dl9r z;%C7%Mtw4H_EX7`Uq^xD9R2;^RLme5;9elC;WgU@>lM%?l)kexLpr>0rLh*7g(~H4 z0je~VTFj}I!BCq8Yr4iapp&Q*15UkJw2Z>5oqYGd#i--pYO}0$gJrci+a}OoGLX`u zSS(3sMpW>FGcLoO2(Tp-AwXA9(thV1#NZa_2IwpXr*nBFF@ouBP(X}$ncxRNa^NAD zSb#srY)pgdg+vypH5cN@z0iVzCed8mnVZ_M9%2k5}7P z@n%~}_FlM)xlmN)V_=i>)~9&JMJih8pPnZ8K>2r)?kL0|aYY z2?yb#c|#liJT5$8sqny}c3g*%Xx5rKLSp&ea@tGggu8XT`I=@^k_oavp@FHd#y&;_ zyt~hv8cRT#mtuCP*80f%Li9(b#`Mada`c%;9`T z#~Z8?zoqRxhgp;ro#n~dC#?6Zy=cB(=p4WGEzojH=H0=2mps@AX0}bDG@=r2Sc1u2 zecM`sF@JY>u^TKj>92{;pTc?Y*GrhSm_j0=Ud4R$#O_)XE-pL_cHx8B`aHcq)jlgb zE{2!5^VPY!T=hrK4k88dOBq2xfO99(J>g!^ST9K<12iLGWoKJfV1%--XO)sGH+{K0grmc`NY(>rbnP{~Q;A;giu;-?0FX^>-d>QNp`mZ8O3i zb@0EIq{~G*{v7lPNDd1^ zTLodc1~`v~iFV(%BwmxwIriCESncO!jASZ_;R;M0?T}dcA&(^1P|`sLYM(?(RE3v6 zurGTvhVf0g+1k$^?4%J#Su#li9Swv1pe+XaugJjur6dV;Qj7wT51dZqTZLeG30MU_ zxHir%nRsO(nhHI~tRn%}#m%K?nPCF>e9R)Ea5F7z_+|7N=cK2;0=zh`&NubufuwSR;H>w;yj#~zAS>0bVYy3rUD0V-q_1VX37;QJ8TX!n5#G%+Vt_S0Bw~y^X z51m2QXfPvR0`ISynol>}IGkFm%utOdD*a8n&Ubz{vbf|i%ZBSHmsE;Z~bBEa=+fvU#2i%+Mlrx3fPCEbH!kC%iw9^VP*& zvYwpivRM^;y}VvhN|?iXp>zonAPWa4iC1s|ooxa{cY^9dzj=?2JpOq?j3!ZGOv?td z!MSR)GD|nws<0YEPk2X@=HoTrMmQJhO=5)=uU#Y*>(-NiLuBEy3&X2X{;LnH)@P#k z4+pNc+DbcRVKXytnAMl$ZZ}LgzYEAa&?3zuxOBZ;=t-Y+`C7oaB(-$on9gYu*pW7= z-wr)M5F~XwOOg;2I-=7suAPf`lOF3@xB)?XK}JqyezpL=Yc{6C0%ydvrII9J4|Zzt z6)<U?Ow>IHC5^i9#~fdoYXtNC+GjmX25wvx-6_DuB$OjM1bDFdB4~rDq=8Frh*QH~) zh#CY<%trhiC6Nu!w%~&9ZPCV(0q82}STmvX73iawRVMU+r^iL=rfV@Fz?P5I&C=2u zUOXwKT9JDGrO}g+f;K%PwFY5)1e|> z$4UN3IJibsAdDRt5ibsfB5phQ%~HQ5bmCtsq(wd}Er;cH*u^m6KbPW-quvd0fBoLZ zcQ7 z-bAwxetLkYRGN#c3@#Qy&-;2_89il>X?|R#)uh_Ftid4eH%Fa}>QU-+RT{16qt{xd zE5PEK{W`gBce<5hY#B4ze!Xn7&{aML5N_{ur@UGscs*&Ded^7T ziqC9-bNmA*Qg4hPUf@ocoWRc>o5TT!!EL#-W}_Fr{$vYzK0E#OL-)xiwuGW^Vo?ky z*ilMmA-1D1Z+5s9_JlNYNqvli})V2oTJqn z#gDa>>if>mvG3k%UZ~5yBiEl;>Koz_P6v~(T8cLl4QSNS>L#GGa9%x;UhCq|DoijZ zD?{g~NJDDpUu+^Ul&PB-q743qY1zT<9JImz+!l#drs`b@CMg+yIqKHL1(-?aPED-8 zvkP30khFkEb_h?Di(&QImjushKa0C-M^eERH!S$OJHH!kVZyiwI;}GIK8NL^#tU`s zL3C8=M&xAm$DTDe*SsHn@-ANUgTKf@q+)L^{JA*V-8bk2+$tQ|Qay|xhiF4lL zpHTdGayX|dzGt+{uBi5HbLzdeNzAdZ7d9EEKNhW;FRYIC*EtQSm)?GUXQ*?LyHd?% zU0I7pQVETf9_tG{{q$VQaQ8LP@PIC{JYckP(d4e`1LX-7k>8*7?Do*Y z`GMFQM)UDkvPF9HF(bhEBcj1X)e($n0>uBG?#ck4RDm0wkZCR2KSAnF<$-)w_0#C*8v|T+u^IjR@(&=5?KFWd zsy}y=4h|$`l5K50f#W#afDcQmSf;jPYWf^XyKbi*bx;vmaM#1wvncqJS&6r!Uef%& z4t~XUkv`P4DJOq1WTQFvir99yU!a4ct2TPQ}F%K5$& zDSR+6zAis+_{h!hjyVg)i~c>%H9xcR~63er*vD$;E9D<*2&^1JJC9e z^G*7eY~;^4H=CW#!dwB|GR z0Ve>00S?+y)W;gEv0)QY(_8~Y1I$Bw?VPEJGTs8C{lxfTJPF)SwW)dd91Woz8%5ww11#Aml?KGM znc+Z``!0M7Q-mg2FSW0&&+*|Yv6g^C_{2upSF#A?DPF8qTDDDtD9)h^USQVrZgsq{ z+&-JF3u+GRXPw*;G~+9`@YbkUd`8Q(FwPR@rP_}~3*x*Y6qFCLF(NmCwed=u6qXM- z0Kb{6pL_p3z)Le>@Kf6~_L#&b=u_5%g+#zpq>i7%&NPpBPKyke9f;j3OM(P{B`ZtF zrp-n;5<24>@gP|#m;M`n_XED($?Gy^Gv;!vu-zt5aUhPVt*e%iq5P~ zT4w5cuwO3PKIvoLS`=(Noo=7GggmVXw%ae*enTZ9qk%(&O3_^V>`HaQ(P3Q*cs2ts zm*G=%)Z`;AS*d->VOVzSCcYj_w=Fg{r**IyEXks90jD%Koy8;seZA~6z5;meNvso- z***4!ephh%fk_*My){#|(`4AUMMvIt%(W@9BhPYnVzWutx4x2DLR+8*h7E#6Vc0#A zS`neD3Xna2^~fR8X3A(2zmgqk!I$E;Fo?C8xpgY^Lj=K;_yBK!L56V3;Y(+G0vTnH z%zjiEM3aM*0Aa%j5PiUai=QY?<_U?(@A?qr;U<}%`fwc^8XDFhIj}Qjf<}bUOl1dq zAdZ=hZbE9_~4H)$%Xx zmaKZtyx&~wvYtcG5pR_qq&6HiCTifE(z8~kh47({*qBB-*ka3gVb~mq#!sow144(d z5Cat=3+z}`V~8w3CItJkS4~2?n_D&>)tttPlgfNB^ zGjz6T^!<7|xX@^i2}i-vm72lfq@r+zE4%uhpEdmzJo_k={S~GXHj&9xm9Fu8C(@dkGO&Z3|Jk2kga=VU{ zuDrk&C4Z-+yuRYu%Y|UWTd6~Yy<_>~>s#_C?<=w$l!`fSSK=)TW>_ryiI?Xcy+*nEsmU#vF!(uWkK?Dn0~Gp1Dv-z#HhuHuNv1!6lO(4;zfABfgZ7b_D< z^!K0D6hnKKprPz54Pcz4^fVvN;AtIO?hQqN!3`=VyywuY4G!m)S=Co=_imB>2y8WK?~ zk6O?;-~n%pM*1-#)Rp4d#*sPm+d>0*Jt}q{dAcw7S)FqrAJ&yfl;m$$OJV2C8DJ52 zaQ9)fTaC|c^~XorwNJL%`_A@+n4PP^$vkdgwWqT&FR2JmB+>LiJ$hKjCOeuTO!zoe z+*h)2NhBkz$gDE7c?KJ0xuXc!M(GG3O9yiaNV?g+>9|uU1bpK~^UYIo5%6EQqc`ER zPXkU57U&M#!W~QZI0*`*%YV8Fwt2;8W}4R~96saW0$-xfs|5g`la z2eb)NQ2aUT5UDQy7CEgPOw4K1c1$W%XQX@?@NuMaL>?)()4MQ?h~4nf;8_Y2egi_BJ%%7@cMhSQxt`fCRPL$Yp#|LvQOw_tY>S9 zXA5?x%61g-+-6Ya1$potP{)Yny_lC}Kk8GqYJlo1_bE#k&`q`NzGGK&D?RLrw zMej>hJoB5 zhMJL=MCg@<-l-{z-EG#WSKR#ob!@3vSZUiB>DnrI7^O%-j(A`s3T++ro4eHUK2kY= zD=RWXRiYhzala~3M2j80PuHpwB3i&=fa<8=tUqd&lnSxGRxS#)Rdj{gz-TK?>hs{>CbIzLIr4L>K}_QO`aEFAXL>+YASnRT3FY?%=w1MotHG?8yk)c`H2wJ zn{sVLu!zX4dXROLPwypGbi3UK&)S*RX#Z&|!9LxX`2C3>vi6jQGZ+hf`D_hc)txyf&&&o zQ!$Y85;N?0ZVs?FPb+faJ2Z?G!~pyEB%muPXGP>TV37AjJ#_n!qk_iV)Rj?9IsaPq zINj3lg|;v2ROLgNUit>Qs;rX}bt#t=tr8cAMk$uA`JSgGng-Bo5tIrKDd;s=o*2G+ zsBqO7W*v^|$U6QsTcw<}TtG0oK+fY`w@akmfNPRll===YrHae#oNR$|fi1To&jka6 zQq8<6Q**a=q`g=ut9fVx-2@PoGHC1)YbD8J5pAHcp4NS_5F#a-hI682{5@WKHwbTu z5z!j&-tW`|WsOI1-$W+r4~ue&$lvJaZW!D#N*{1^%F-^E1HtgT*x@~NWzc*~OHxz= z635nNT)!9{Ac)T$zr-C1#KcF=RcNYf97&d#z`I>3DI4(Pp6yc9eb5gWXX_N2&oh&T zjk3tb{_p*X6uVUi2*~Uk*6ej|!u^1LWGQ@Y2**ErC%Xmtc&2Q#2^mx44gm+S5$|EO z*Hh6TNt#YBi&sIclb>4Bu>x)g*`1ud=vgH|CqI8uT&u=zX~M%j0Txk3f!S>p8F2>daNI~U znA*?Y-`5Rig6R%JBf`_T@b=hTO=IwBAYG0M>PMfm45!(ilDUN)t0)uUNsX_c;3;pY zT(GYl?yQ{V!Hh4s)Fr$6m}m!^S0wuHZ#c`z1R?FrL(EH45fQ@fF?fL;L^CuRUM}`% z8$Qm2Muvz6NZ=Rez$oz87K%hMQqEy=7k|_m2WnLmJ;=#V$0Ozrly3AlNcm~h4=A33 zRo)5J7~H7i!n&c`!d$X?Tnl)?mDarOMQ_&P{KhNu`VZ(fnfS4$%44-g9~vqKl;01J z3{|@IHk>9Z9%OPS8Xu&tNx~-*o6Sr1BH{KxAKLdWuI@p=B8rkQ=hbY0WpfXw9FI*` zC_@+6vxALLP~DL8#dN*o^Iqc&Bhd*rvVN6tS{ug)pD;l~*AFnraW9N$IYAw7jseV? z7Whe04-=wPEZC11=VgR54^jldSXXt-p9BctbzWzMHur#R%*3!2G5+q;{5Xb?>_S*H zp~dWMUpA%mJlod!iZ4aJuB&gfRwnFc3Z~kHc!gZ6j9kaNwrul!XAEj5-Y#y}=6ogl zV1_j~h=YfN_v46MMb8eK#d?R#Vi)srvCuj-403D}(;n&vPB()gT3L&NMIFl^AVWtHCf&cfR^ z-%l4Gl&?Kk6h3{n^c0&05I9{)7_OKZW0mg;YY$dncr#{eb^_~g`sgbK3G}+OeXFC^ z;;pI_3P6;PU))2HXt6Qt_PA&QIur#BOB2UJT4sVdnSgYnR`9XxXh{S$%-S3aZxoT& zt4*7*8CoZvM{~`^oPq7#?l1FKQmstV$(x=u9lN}~@EYkG*;D#4nHx>5sGaiATa#Kv zExPUgd8?Oe`oA%!+^x!f>ioV1!~G;r&7crFdQ%!aacA+}JBy`$-P_C8gfPXgq;-<5 z74Dcwc6=sw7f{a}4Nlh+Z$jfr(?eotJ{i6UeT|b`sgVpQ32zy3&-vU01VHn&Jb3wW z2Ej;2WRO_yQUeH=O*}o<~JG9>9`DCyN3))3QT>gW$ic?@6MF!&DN1C?JXo2(r<3wkt~aHgFQT`-}X5 zDnv9$YtS)Le=I1}*eMU4V{i+b+7m*wv_+>{qsE7Zkl_jxn0omZPu7qkOblK%Wkq#= zwat86A16ZsmztC8K|9*P@TFG(>4_3nGsKU+X^#nZekXB|sInq5Je)*{vcPb7=>}dK zumKKt$h%~yj66_JYcndgC@e+2+&eNO`C}jUW$`TEx zU-F3#q9oPe5)T;aGy&^%4RB{9p$_!W=KFjwAW}{}<^_byIgo3ngsXl62k-pc>}QKu z0ssq%vVmPJoCukl;eg5OYE!_Vcb?$&n)fS%C6h0M^~*U=dbj0fw49o>R}>sM9;hJV z?<*1->PLS(V#fr`09X@p@WMJP>GUdL(}FynMwN;sh@zYlm%XgSw%&PG(A$sJf)k zP?k!PtK(^?!M!1ZQj3q^wn^)Th5%&H#TkzcKi=p3wRc-F~LT}|M~dQpyS*6k?%GDGL0 zP%8N4h0W{*?}s1?l@P~Q^V{N8-k(O>4FwFxr={ zg%HeUEzjGkR#ZLFdcONSzt%;cYdZDwd=p;&Vh^5U`P+NO3A5R2r8qszNHFO#9^4+l zf;YjoH=3VRuyw?#HqS6AioiAvaiZzCw~**(#LL(~qRha#GUPz{COs^4*9{*wTYrvO zK{;QsbWYO?4GEQeDpn2#Pb#4i+6P*{0~r%QK&>S%4Dw~od??2gL82)D&T)WP&GF}F z*0Q{Dv=hyW?09?JVp{yuwj=u#;V_)>f zY#G5>CxkI&BGIkOv<=tn1r|w)*!A2th2E{k7KXrc#=xH!X7I5t{9nl~2dxa&0%7lC z!+>`-bOc_?zfMJvCJp;!ESppL$rG*^)gzmGPWqWQ)Z@BFTEWMchs{pm_M#QJVQh`& z%W{cP9|kw;tlY5KZR4b{gJ8~rw*Ws%ylsNNTk-K9&alj$1h06i600joJSl3xUf>?! zfCO>~n#z%1EOuf-B~74|MD5x>N&7A@0$2|#?9MtQ$Gf6p7e7j{YA~sa zyK_IyILHWV)dpSCdAB@tn_r6|-nOPVB}Xs*A^q*uD&@|E+trg+m%7}}zuOY^R?D`w zcHC}gFBuu<;JU(TfZZoes3375RM$0|^_?jRQye7Bz0>Gvw5D})ng9++A$TfW9wlXd z?DNRYs$mmUO&+Rxty}}NT^25XplE`8G`nU>UCNY#eJGkK@NkrU;&P9;q@db0Zv@DC zY+6FLdBKoDNI{dD#-ZCt+CtE;A7xn_v3fG)!pln-#kmOa@=|tDz1AvY*MbB~*SbXh zwvo3f=tS#kQSIQ4l1l*>^71eHIkMMWYB(lgCmYEqv`6dKj6o|632pX-{`-XCmxx*I zH7mjeQWxN(30E+|nxOeY(O_nL|B?5A+;b`i)5DN$;}x$sI;K_MXv~4xRuy@0lAN5; zxN|izsNtl7hNp?*CR!E0Y1pt{(us8HAKKV~ZaTitx}@Rd>z6p|W0vT}6du4kW$$C} zpP_=)4wZ^IUXl4IS>qe`8}xdJxHh*rE7bPjRngeOM8|hMR0`7jFNpirFQH`z>QvC6 z#{0I5L^pHE#?A?=6p`44yVAHmO>~L(u-hvu*~t;gCk0M7wRbNof*W<(hO*B0XGOQ& zY1}%19*xRUU3VE2eBj5XD$-VD^%5rvO~n1y^r0xJn7!&NqxaMKRkTh?$v@^ z1#PM_Yq>Mb7&dL5cOUCv@AJYRha(3FjS&lkQ!D6Ugf+* zzqz}Tuz#aUQ-+{T0O<{63|g0juh{$A*N!gMhWEBVER8Tc8xDEh8zDs8;N>Ms({?JH{C} zxwO5kTV(daPm9$9t@KJ~cSgTJP5*^#_pK)@Kq#qPO7upXkQj+&3oUj)l@v;1RFnbK zW^@f?M3Eaf?y~~HJ9HqwJOz}^@9-tsA`-iV7|8*Ix9)j@+!nP1;|=jMfG(0d^zV=% zg;3HXKp&$~fQnuKwy7b0c)r5t@vQ12+t0pEd*d+s8a0JtpXQ}O>gK+HF3-}ftJl7j^Kt2Sh^bo*%)D@b$R3rKv zUC({9SCU4qN3~DVgw0e!t$!QOT~RWyO%TwfGSM)B1-74|yB5Z7lR>WP7H19#Z@up_ znuPyo ztt3^j1r8Yh&(i%eD(MS8_{9+aBihIzGk z?VG;M5Jixem(^Ck*H0K(FBw0v&bh*zp5$xqYgou?RbKg-!5PR@=fyRvih8WU|XB24=9PgZoZ)fw1_1pTTyBCYtPfXw|$8J@}8 z`T5BvX5;4X4XQubA;|qW3c4=0mFM7#463T3pvxck-7hgxGQGA2(%A&Q6+KWz{IEZp$C_XzLEtQbycoqVg0*b znyaREKb73+i%`wD(9fjCdCK&>d$YUSF8N!rM+zq-akleRT(d=#R8V0URE5Ao%0rPt zCv^ZbrVgOyIZhNQ4KQb#@<*_UwM8tUQM$`&)<|me=vdu(huyT($WrWlsY!c|-Tp_< z^6ytpuTI=vttI{R>Z^*FJmBI=yt)|yGRm^^&7lb zV~qje2JNyH+c~f|tS_nTpU}l|mV4z-PApgKoi-JTN*rfavOZF&SKm7F{FIv4Ig{j9 zye1lVLQ6${7k}j>SRp4HiQLK{~s#e(x zh&^z$Jznrk2IVC)*En^Bfw(vw&03+g!j1LXnFpTb8?3=(Zqr=YqEMn9O`Y6EGQ+Bo z`UtE4xQ2^W&T=AcE$5v2P(EMzkYsHb_rYW$tN(mi5B-JGcwX(O6f8*_F_57x-8j&y zAfl$+xL*bK!oi>bb}}1QkJ{2eG{nwEhx!n;rigAi5>S`YV}~JN(@x)dQL;KzJ}R zvBS5ofL9yr0r}7kSne%MLGUkaU~HZ{XrI>a2C%+Ma1wx!seuf#XOKcBp+J06?PJmEr4Q>Y?&>i33 z1ojHOr9nWZ?$Oy9l1nI2aEgKygg6DkuK58`*M-8Eo#O%kY$cE(h-sdSAw8uy@alpu z88rb3xPe&U?y@KngVSR`67__E@t%r&@GS$?{h)Yw?*t&&a277@z!rp@RJ(xO76yW3 z#H%pi?kV@d!HSIWXX+Yo!&y#~YSuYKEqoN*LT*nZj}39=gRK|+Qm?6!B#5XJOHP3$ zoPC#aLAF7-T_>?Uq#ZZHdLR43z;L8_xFyJAnTG?mY?%v9(PmPMI z)2~PZzR}I|kHHAtU1=Qy2_-*a;Lw zIS14Sp$EQkc6Jx@w6*g3UQ|sK=I9Ww*Q7NkPFK&p4l!&{>W>d`8az`_7D&~9j(*q4 zK}O2ep>r-ip=hS$^y@3nMggb8W|yzT?uzS-?fW>+cqysW)cN=usDfK>3zq%eJZdtJ z{3a1-YyUtKbZTjSzx_kU9eG}a)8(tbQ845!OCK??V!;-yF{c>u(@Z<&ZyGlCR=&cn zQHIH_^Rz0?)0 z!M3V9-?R1J@aFA@h}uW`*Hmbf^a8S5>FC8jO6`sd(Gw!kh)~rJ6t7=qzCv<6mJk^c z(r-$e?T#R(oVwoqIg@@MG)(d&t4rZ~v+|B-{+im0RNLNHoG*#JQ4*G48Qc~4a_pLW zTKAE3S=Y(vot}8vi2ZP*OSIMkEU}$d>gQ(I)Og??sXqQM!`6fJ7hpHcYtnkMZz6l{ zBPn}iEhLF=HikqP;dW4mXT87s``nxxZ@7JC5mFKgTK+mD$(7z3>bl6>j<_K!ihI*C zbAwXV0Oc||=L7@%nm{p|uM}iIQ-1UyDkdNJO9gP9{x8bATikcB(sTEAuyXrGd+LvB zw1MKxSJ3rgUN$6u5hWd-GtFm(yjI8sC8Fra+u`Rn-e3Ht$VkS$$Mcdmg?~K7}?^~N>=VKXeZr7eVs-{<6 zerdF{zVlFL(y^L4(**B3@Pg;@B1ae|?$}^hT9Zs};Mq52joF>^Pi=2d-1U)cbGbb{ zRGo7mC>(I*J>+i(*MXsMbp_bE7pMaCFSd3DiW~i#t;?QwIyH-*xxV*eAM|{$&GXc6 z*N?>0JrgX~Wm-R86-JSO2`%i($lc%cIPZT}+F@m=Tt!0BOCc3}8@zr**4F*;=%Y6` zmfFg6i>S7VWzCjnF7cHPzNb=00Te~T1b zdKDY9kbAEjML5AZSjzVCCW<1L|3Vgv&RskA&nT&Y0gw0e<+c@qWPZVqmST9ExC;nc zr6ZXKQ*+d|j0p}tut)0-9d5^06O}=I(R)XY3*I}^Rnx_~#PY4_okc!OjtD|}ktD=# z_Ax$qJe`o?P?D0#+iml{@w|rRUCjiBZo7m?0jsh|)lC7IVNzwk6#KY*>&X2vb#u2K z?Wm()?rZR}iFdmP^fD_qtehKOJ8H-s6LrBS_n?aQGWqc;w>CKo-Y(3k7{0kv*=h<+ zR(D3KayxM1o%iJ)Y=`Q&`%MtIEgk3K=wLJC1ohlZkMEPQ<9|yaA9)9flK^ozfFe$G zWGBe~UB?lqq4k{Vbd=Ay z2pkR5^zmFb8qOW5a7cVY+V3tbEslSu>noHkBN6ijCU5COxNHCZI5=Kv%RzzN>PTd< z?yD&UUxAI|BP^89**=s@iTBXby*Jt2rI~`QHmV+deDCDx1tW%x@;wGHC(J-gM&`h1boOS&^mw#F5PY@V7{;Av?SDM;i<7 zk>K3Nn$SWONyylC-p<8h+^3KQ%6{!`TVB|8wNZ6SXpjiEkxTl`vh;Iogd+i#eQ&%G z5lL4Xo5tbOm2RcwEJx7f)MNU)VRgwL3#SK&4Ckhtd%V(W1&d=wEqXFd3V2>8FNi%2 zD52-Lq47xcMf^RpH%p48%Xa0x9pyyY{(@OnMuAg8)wGXtVrXlQOba)L2!WZW+Q&Gr zm!%!qIc;z+_BmAH3irCggj-Qnn1G9thDt;^RbT0EUgU0;!eb(91N(-WqgA|T@!S{Y z?Xr1;!&#fnIl86c`?>TydcbGRI79Y+z(7@?vuNE~pUo++H%GIJ1J0Sg> zWW3G4KT~CGOnN)rJRF@&5e^*0dGUpl^RC4v?1>XcPpZ3#3+NOgS~S45m)Ggdh-R#E zYZvW<_G)U$%7d3?@(N$jC*bQeUJVP9wO&yNz$*Ex^tPO=<$(eMuI#&j`(gc9LS3!? zcLDt=Fd}2Sv{2%7Pd0DVDSh%?A?BPF(&T;T^G269@XDmH?}Rar=L0cK!mg|>o9=95 z->b2n(z#DtN~TABi?vuTbK`i&@wSru_&YuOE2c`BYMYnh zjKjl{_jDdpDX7WwC9#ZgNk{7Pd){)B!O^a_MwLjZ!pls?opDW-SKR#6kIqz|p=Qv(m9I(V=@{R3&#~!C3%mc=B@Xsf1H)Mx z2OZZ*T!9$3q4S8ZsQL)3m7|b2=Wyot&^hfbsFIAOMN!R&NWXCQTq&{w`pI49_r}fN zwW99Ek8Hc>h^jrm?!u_z!mQoNW3|kok+CN_IpkNlwXEbHjR)P2eWBCbAFn+26h?l= zAG7*3AOE*psxpa6wFfNAdH(O!PQP21&aSpj?pCgPR_^Y$PS$Q>hkm~xdf(P*(x}U6 zPMXeh?;%79l)K58Dj5}ZZB^M0+Dq15SnPRn`+@kWIXmu%!0R#|2oH11O%C;Q%6gDh z&BxdKxt;kuNPmN@3M1zMEztM&diEJ zGE>2omzI}5wD`p@_i})lx#iz*g^dCa-t>5ZN|1O$H`b5>56Bto9?RDys0Q7gmD`t;$xM_f!_&<$EXR2 z8^Q^31RXhu-utGrcV4z~{nqo@I?j!X7vx7_Kecf5IiA`3i1R&Xd~J|Yn2uk2Fa-rI zrbO*lKKq(d-7+n8($&vrQ>3u$MDhop$jMT}Re4p^=vY~zo-`*dmLXUKspD)UKiy~{ z5ImBogPHqFqnH$WH9P9&Ej~1quLpOvcjss*&T`Pt#cwb8;_tqd@J=#F@)-JTePLa9 zOH{cuGQ>WA_JkGXaBMM8)<-=EsYIB!%k{-Y)*ho9o$vN9`u~=GF9|Ovwe({OQ#pI`IuELg~DgHS%UXslT@ zFYaT5$!!FNcV7x^>0`I~4)whHK3Glz0@Qn7U=RFk~OH+W3b9#~vZCxIGL zY+7F8va~Xyq7riX8#g>c#XC)}%9Jco_1wFe$|?cw4J%7mqze%(eyFPC@xn#D%Bfjd zcQGkHz}af%%GA@n`Oi1`xL@H$6+)i~izyHGDat=lH{wgqD0&4W>q+nb?b$gKM!uC{ zffYggErW8c@Z6l2=C^Ne6Wld}-!Q7zJS}ZvTXG5DaDUxi{kl8gxPQ{%ec7VCXSxta zuah%2R?oN3pyE*-$-m#qTAUI*Qv(W*`+Rlg)ffG#xL~%&*NsBsHr1KbYPy63o?jvG zEqKwf`Z#Xde?I1urRG{1bbo(qzBRMt zs^EFUx!0D*Gw(5|Di>&WJk1zT)e;_>RWn}DHILdUh3x~6Z|s21+zbHrL;s~#$$t|8 z93B7K5I?C9$fW{=nKHej+X+-;#wzXbdBKy7G#)itUA0h$%n3wbY1!|1PQ3l z`vWKZ$x(+P9yz}oAOcJnFLxMXiRZ5n-wA&h0(F_KG6$gdSHKkbc_2(8e}(wYiH9NR zYCSj80EkWQ!w_2%e}(u?mBSE2eX+O(U>d)z3ZR7g53d$rX#bvzn-<}{(A~u z`bYB&u;dS~?JNHT`GWXAg8rH94uEz2-*;N}m&lS`)!jhBWU_W(b^eTeROts~O$#@` z=KhJH|M=>kF~`r-;dK26;C@N*Uu)IM zlDF4afpHuEW!&L+{|5PoasRCpKhpF$*av{K1ytbA(^zKlpW*&iHQlobzBdl|A!XSQ z!#O_u&v1XMZ_(!Mg{J|yi+|}|h{Jz|`!1UfQ{|&4L#sXjhx!ZLsLOwb`z|#O!$}`S zJ){OW+8W@SpXbie>p#PN*HDMyPByJmKmfQJz()BQuFB^>!+lq!hvCkR?y@oglr5k> zyndwv{xjSk;^q%Lz=-_*;v(C9c#B!G_&2g|7voRsH!AQCJV&bswiaSG51ehF?$C>( zUJslPW7LI5sbBhfg6!M%vk|v*k>dNJ{R6|+(Zbs5qNuZz_2E&)opkg#4b1l<$6+(@ z-bL!~2<|pkj#j`kjDYv=V)Jkxp8KB4TrMIb`*!`@hpbC~ApFpW3xD?E&zZoiOAMw; zk&%77ex8ZO%o{Ym0$3H>P4m95<Tv;~U0y9C!33dJ3Q6iN$$7AX`f1TAg>ihFPlBj z#>l{|g_Y$;AAxrI_k$M<-*;vo^RCOw#FeuWF6_W7^a8_W2yU@~bGVex6}iX>Yy#&{ zzZ$d+Vjov%KM&mQq2%H}z&BcHh1duf^q61V49P9aZ7FP7E@&uOIW^`m8$mNGtMkWr zGtx^LJ{9Q3|EZsRi91=j1A3A+G(scNMSnTEx55@rG<1-5cn3o9bbd(qJ08ca_sfl* zEtvU=?A7q3GyEl8Cn5UEsfpn48Q^$A8V{!u=W}o#jsJMRfD(vHg*X}cc#r-EQ5%6` z+pN84leHBt6C!=Z$c^cj(e1n>Z0HK ziUk6gVB;5jdszq`*%@C4n)+{yVMoSS4YT0wv@(Q&(?9EfT`z(wvaNDFjW?qfhw9&E z599Ep*mjnVtcMYXsWkj(E5jf8BQGQIh2iw&8)vuba@G0j9Me~%81ZZc%M`>T*Vc^R zpE!mnenN_whZtV;jqmV>{;>bxKs`T;-&(*ppIW&1XWxf_DPUHmOjdfGLm75T&wQPJH))?(axe`s751LRWH`lAx-7~7wG zdG%ePzs93;0A`|MFo%81VN<{Vl+}UuTdmA&?mp4WF8MABd=f8LdHTl_!GafOZF;_j z4DulT(_3J$AoSJf+!4#oNXlJIPVGyfa~?gUn55YOEhizZqp!>#xPTEsf}# zJ?ANfnCER|#{0_`#0xx+J4(>&>0gz=X)0*Dvb^H2Ey2CGOQ(G*FaOU~SceZGv6?UM zY5eS*#3vUyVi7{HOz}m#5;844NdIQ8rlRH%anNA1xW$xKEd7Wi{n&<}v|n@k?}V?s z9g*D0+p0_Gj%ScXGS@>hjoAC&3VX(mW@WU&2UHiGEb}qPprB2OFA0PfKigNgzCK?k zNHdVHT}HF*yj)%MX&UzryEGaT&`{uzVY#oCVNtN+zGoP>J5w>m^7MCM6{3CEHi$i* zn|fnmG1C0^!FDM8^RTM`v9vW*4gInA^9i%)r>^^sgza{UW}kH>)0<5?8oEdZc3bKT zXO)d#$%wu0DU0KW(CSkQp)9|=d)B)|^{OX6-r`%g$o>*Kbh*_#v);kMZDC>a5Un)U zS~@zMz5G{hBe%s5ES60K4g0_2{}A{;1pW_!|3l#aR|o)wxc)VMJezci2b$89wS?4M zwDo*+T@`c3mGrO>&D<`423UaOG|+V}wJdx%6xd@4PZE3E@DX>^IqYX`PE(dMZ`#ri z3-=6-UgK#LA@JV2F|{SX;aHYtPjIC=`v}&dOcHz6LG(%)z|UuigK7PomC}J}H4zq5 zS_v>v5S}^kb>GG$d<}a4K9HAKIM%oZf2E!YO{_M<@9c{AxHn*&oY5^l^rTwzxzU#& zk?A*WVFH>lwgIB&TR3c`$SwUM`z?p2IE~+xt=3~~d$bo?d^RvukJsmeV+DCr4nb05Er!Gc< zIC50SHkMEFtZTZmJ*|8djx61;qO81UbxU%q!s6Z08TZj1h9#^FMV4m!-oD$Fiic>m z{XM2K_EmuCblxu_+k6~Xvh2pa@6bZrfw#=z6(n+21zPS_N{`p`_9wOzd+d;V5PR%Z z=XZtcv-MbLk!d-)qMawpcB>tc3p0r<9ySLTk;*?3X4;7a`aI-B-i{gt3hLop1vPbj zL&==!n^T(g==WWU<}IF8%&Xl$C_taspq%qovFDR! z`|5XTjmkI~t8HcHLVj|fV;8|eE55QQZ^VwbaUkYjQDeOCzHqVuMf#eWoWJW<$fa;rLrFzi0bs^l#s6sj zhIs;f(lgRLBkicm2-j-wtvVawOgMd_GM=e0)**qP9hr_=AX3#uZ!Ji)K)U2L*XyE!jPP-+sN9 ztHsEZ6MxLVPr3duccnI)l%w>Jh@*_Vu*RjJw!>E54e7^p;a;3!HL5EYE1;`e$V-1% z<1t;eXa{#YJ;0YOGAH)7z5RP*D>x!BrjPd#PcaBB zI?Zh1o8qr{oe@Jm-tQhhrdKb=#x~`@uoaaPO-fnDCgrGc@o4R+h7;=JG4w*cs3~-| zl-klfhkv_lL!-!a%K(%#^ySI67P!8?tfqonUmqtyi*nbhz5(S1h+4X_kD*^CJmy(u zuY8X-iKQ*P{bq`92L);n^A-TiEzWd<0!0gC@o4ANk#aKEk2(IZon({`ozPd@#k~q- zKgd5-xmYBh`T4qUO)$iZM@DY*=qUbUF$^L=L1zlRqHc% z{FOfpTWp982W{hOdQUG|9KAU^;;a+hZGEEO7ja;8APqqWjuP9X&}C~hGl_V;QsL{{ ze{W2fS5Q=pC4WO`qOAT>N{Vl$pphZbn*!jG``V<nj88LI)_CzwZ)q+U-xd;c>q3-PNH?E&q*grXgq z=^i_Gf7!3q;0`h4W^mq;rqe68dhTz;=*M(2dFGb=hg+W*uZ>F&RudHd;&1I`cH_x+ zft5y^po1slJ!!FR?eE)vYR8F167CWz39Srj-2k|y!%BA!L^*La#YYx`g zsS7q`=e}i;>XZk1x?S;qO5#z>4RCSaUtsUdRL==$s9}k)50wi&AoNri-I3EPz_EM3 zsGqh+cNp7waLn*&CwIgA&O;vTjqd5+An6FE z(Xgf1h&-D81+p_~=!Cp#4BEWM+Z5MRr4CB_kFb#@ku+$+$pU)yeD7Pe`Yk0=0?E1k zb{h|Y!9W$#{KR`ebJF#gA;e$W4_GYk-T?CwP%pVUPw)S-P`}t83ue{)S$~&m#(GqKXK z^6Gg(plI=Ile6aNJb+)kKZ9|;NLe(Q0 zeV$Y^uUh7fXH)lL4{#yJVy7{xHD-2Im+={puP%F5e|5e;<9vZ9djjr%mK5azF8y`O z$R$$E>>%)zeARZ&rT>@>nl7|3jM^7ojxaega|E1INs@}AnUb2Foq4)H749;;-I@6D zA^0{3Vs8aJ<2;OHW1W~REOJTAFLxpwE8IE-NG^|U;rXO-bP^Xk0|bXr_0)w#FrHvq z@dene5H!C9rZZ-(t6Yok!TEQ{h8OgKO(-&{d}x*YcNZWp_TfHbusG?x`W}DS{bOG`<*%eT%3sG$ zJF7RI_a7DtfI0F=&n&-Bq@DG+VRMBs4o_S*VTCpdf$hHnId$1PF429(FFeB;87{t-*Kf9IrKWei=J5e9jX}@tq z%QiW1AP!mz(>Z4dI3t5)_k^P?!~6ls#GB24iDuA1Z*s5ZW{zj5mD+uzKW5luK>Che z98S+211pyp8&p^@G!(>n#g`g)_WN%b*z;rFFf&*{23LIJ5O2`uaY@XYTUG#df|w+2e_`Kpt|@Eu)^Dc}|nxJ}}c4PD*V>&qA3k zuO+vkQ=$<2=Jr6Y$fchgz#8AcOedS#4B{{S;F;bCCU7;D`0#7h9v4*>{^lRCscBpMKJA>;iz!B7bV>N7KvTLYbnMEAKiC!2h z_DKgP`<1wd;GVFkjHH70Ic_EQJXQzKJboyNZ&yj9S9nkPwjXUf2o<8g;`TSHfsz$g z-WhOBNEhJtr!#WGC)Puwnw3z`-g}u#yhjq4(2e>XvHpGel_oCDNLD7B=o5Z8pA6Yw zuaj+T6}%v0_hDE#bm~qbk74& zyD&qsgIn}HL@vJ(WwKQ*vF&5RAr9x~-fz{l>btIWT}*w7xw?c-T)VL@XbKQCIdpbX z*yir2IB=$~MZ21Do(T20c1G_*c(SK&ieh$R=inB3Pv9CkYfP7V0==kI=Y+Jb)BB(J zFA{*Ch;4V<{KeLJTTC{SR4tAsVG8sRcGYRN?9E4utsr~|i~aIkM}Rd%s&Bd9JUz`0 zac0jti(N%i_e3FZViX2q10|dGQOF?HhIZRI>w}S48M^>D9Ih0nKnlxEbx(%9eV+ft z;jF*%xUbj8uc(i9lQdz8iA^7m8yM!!-8CokeNIW@!@uR1lea-S$t~~f?>|-IN*i%# z3%7uh<(Q=~{OX`ux$BKD%S>nsgDswPr|3}lpu2h=xZ2f$$GYGURtWi#n!e`j`E&x6 zOWibEk5dTz%%fl|=REm)-)TDf~pCViiA1m;H}=)l0ZT#_72fszN)>>d|?an9xHc2O97 zBpD3Imr;)>I-xvyZ#@e z`L5Phvdpgg+wr;D>s2A1`Xz<^$tN1ybWqw!&fGYi4{x0IdF#a>P(sx_&gFcYZpt5Z zE-BWoIm?a*RV|Wv01ol#TTP~k`B4(Toh))P3lB7D0(YtE=ImimVEbV}27uDbF zeH@Rx{#H5(5oCGV<%Eass>HM{QqQNa{YaD6OT3G?+6z%qc#!xPFp0j@r%8=2i5P9I z(8x&Y`2(}~bM;hDz@=KAt54F}-xaEbI>h5PY|jo;)di}$epUFHIm54l@Z{)C;6pV) zY~aAOYCmlK5Hus-E=YPD#3t%4skUZ^vBY^^qtGY)XzptOCpw3Xw9B=&P$;s-upnj)&v)Je{5vqK$L)^Em1*}Km zi59oRorbn?*ZKGL zom{ybKBf(eP8Irk{u{mPvU)L21c9Hs5zJ}WCWo_A3RY>d3si(gkST~iNaLPLM4mV< z08SLDlGBq@5-~W8Vwx_wP7rDFL~Lfc=Z1IhUnT8Ix9dp|M{{%Hj1c=jaQP11VFjl9 z(X?RaKUX|a7jZY^e0LR7ypsG?HI%u4ddjsg&H5CxLAuE*YOEaL5yJ%@3+Z5ayq`C$ zd6B807|ylz^mMmTq2#8=bY5OfAK^6V@s#z8h5!WFr$F(muvaABT!#XU5M^75Z z6~_WQ)%%U~-Vf_*;0>k%(bRhFTSi9tjxyx=S}8fRYNHokjkO)w=(X;a6bzgDzgYe( z==0)D7%O;r2u)arex*_=c0~*WbE34;S-o>LOJsDVwLSBSecg#ZhR*aXQ-s_|MFE6< zpC? zyQzumL!&NXyyGbR30#r&C;1239Nb_^B`or=!NFDEi~EMq3%2_0UKnI5Hb7u;wwY6? zlAuzITVE4zJ|*k81VAmCEW&V0WaGsdWx57&2|Jo z#sN)fkMGeVvaM-Z0&ErvAI5a|+k{so{!B`p1+`Mv$vo;&gxKw2q2B%)92Fe&eNhpT z2ztvxC7lyo;1iD=rz+`ZX?lO(!6~u%@7lfHC;SNq;F%-g>`DtiE zoHn#7QsDDH9Mg!Ro=hhATzz4WNha*DPOHSE+N+DyC0&T6i4)B<&OaS`0KJoR@cis9 zCN&Z#pTt2mvbd28WIJb?5|M~YG+vdIe)gtlrg(@`UONQWlV)TO1+WdYPZR!eqE&wE zo2Cj8dN?O26dX4%5-;@rw@u07&DS6gyo3?M6Lq#u+|>7#20yX}n4Ksx-Mq|+2wgh( z`wPFx%1DUWXA}*1I;?wl0i?z3@206-+hdAO+=~VJC0J7E*u^lXIc0yu+TLD&noORf zO~3EKh9uPfY-zjsR+{@)6w@1K7kMe*G;c{r4hBV}r1zJG!`dvI9sGl-;> zV@*0br+-qZ6iSxF*}#ZM@M}F6V|~*aAcS!H^|qO_Lq63qEekGeG(=z8o+Hvd z|C@O3LVWq-3LU(PC{8fWj$6sp52ZPo;taMMW5PY3TA@ub<%Ri~3S&jV_m+X)Ln0ak zy z-*|^}(S{?ajx`l;X#tbEo0?bpl)8V#Z8HEMn-&accK5G!m(MG~k*7O@pU zQnLXZiC2;O^5DytB7mkpx`{2K-mXld=mD|2?&s(n(=!TdaMDUt%~^7&ONX`)U3eLl z<8twuZ=+PgJ!P=s(HT>xo0*wGDBhPhwgD98S*7AA!iF)Hi1lT)G4KI+&KbLsIB9&1 z8ob2Z8V`bCpLQjKJ3wnmB z_P`rW=YT4UM{ncsuJF_{nZw^3F7Q2@ioC7+PE=UGJ7wYtDYAy^nqZ&KWg}-jZJkAJ za3^ALU%L#~I3jrt=0S+3{TR_z6z_a>Yok%k4~u{O2KnltofL%yQYWM6YyMhhe75dM zA^&FE6}`aKs4LCqf3V7`+h=wd(v1aixKrh@$5@$D0^(q!41_k=Z%72}MAE^a{o&Ot zPn1z;%wd$Q_C_;sXbL;`VEsxKkP!Sqc~~cTrhl|~d#gvBHkvILj4jZg$8?1AgUEtn zTz1;SE3Z6w_sxEK7eUFW;-nPVh9Ebigyb$^3ajdvMMd<=dO;&r`d~5en`F|&t7n`q zah7VeHvesQEH9C{(@S}d&e=U$4J;8{AhX*qb>xu38|b{w>d%oA_CtgWN_R|2EsPZz zNDntBH&d(zD+*V=&b+qzaz_)&TIac7e{^WVYZ-YME*7HZ7l>ps7#uk1ziaVaZExkEB$*ZH#7l}D{U1u8xTrEZ zPt??qyrU@xaouy!1l#Nf==L!M$y%a7A8ws5dp;MKH06Z=L!0v_Dmdl zsg=)v8Phn@3$4F5$Fl%$Vr*Zdx6kk{M0amd72)!SLhki z8%%Y`R7ai9-+yiA^RbQfwcZ?eDz82tg(>yFBrVGC?Y}l{5AmVGb1f(3xvp(HM<)_j zFJ^R8PyA7;w?2--wu+@t>3X>k3Wbd`E_u%BvompGkm~pHkls?NI@*;E$9?2s^l$lv zCVhMPC-PMOE@v&)2;wz7L>}!I*v3^q%y8?t#OibY%`+s)G(0hV+)*fHya+67M3Qx$ z*W^L7G=Z;}19^f&uZLCB9U7Z{i&P%h2o4Tau=pmMlD)Uy%tv98%+c^vpfS71EkWKI zRFMwb4804hV&j4*(Y^;ih*RkUuc2#m-&2`$sa$OUZ|2c*fTO|X z)wnwdkEaa_*o8A*D;XGDV8OqlDTM*>XU0{`_euo`akDx{4yLG?do-QNtOp${JG!d` z%l&r8$VLVYgXajR(P%{?E_6#i7d*D_E*8vm5VEb0IM>=Qj8VOha1>P?698XdOVG4l zcP&qm6OBdds4QZia3TGn&Q$aCRBVb3aY!;Kgh&z~zSW~xO|7ZECxOj_cG-6^EI4vM zru+T12p*CXyujJ)dts^_t&QV(n@{GsqUXLU36+_bK*l3&wu!b$ z5sgA=Vhdx6cq?=&7{1??#T;C2toEXB@wa&H9{Ut$d=?o@28(VBlqvL#IxzG^<8&8O zrJN|Qvsk_9=o?#yE28|6^~f5e0&*JZio~UIRYH(G9w58b_NCY={wpg3(#%uz&nu@| z(9u-fBtp#g@xR`us;To!BU zQ^WH+p@_a}Q#?doa()o(BPZZ`1Ejp(-?9+!E$8pw4-5b`Tolg~h3H)Mb)=?mgrc2L z%Q82f1hmD>R7q=A$^!ipwVlo_;8}L0fxakz5D&VQ3zX&5M&QQ}w!0O$_I)(AfN--h zGRjbjnSU0a0OTb)?$2Iv2wHTj+Ul)8SZk5pTD_!(dLvUfM|&w_9P?r=GZUYn(^CTW zU+*8%hkj<|{3h{^yXP(iPPM97fU$Z5#f&O$D?tz1m{+f!(yr#UvJZYfk&RW|uavv& zV0w$?nXD&$9|@0kYy#dt?_;^EWkajGsLVuxIpGiD@ZCk=HZK%{@1rN4dClP#Dk;gj zOSVYisr&n)&wN`9N*NU}yjWbGs)P5MCiRS)uYf zSPkl=_{lI&XTwq8o(pC38Vw@tX$dlOt>Bc5U#Hb$v3NhCZBt{>wOK=f+qvjLi zVZI4>P~9J^Z`7*AUO+w75Me7C;j~maJo0p8+zx)ukK;t_@8n$e+ZT9D2$f+{zqG}w!Z&$}I8ig}+78@{hfu28(wfr37nyO6u|U`MjuD(IKE{=2Rwy$BBp zn=OX%3{Jn!?|wf!Cr_ndeppC5URRg%Dw0sZ=0ZQd zRUo45T8~4v{Rg9rK7S`=Fk=q1FVtkkf$0Gr=1jyyA)X;abz*3}>iVB43s}QPo~;^h z2SL+cpq%pzJ4jve=O8RJTfoYz>^#Gqliy=6I;Kvncu_I(IXY2!fRqT4uuWj!2kz5^ z!gs79()b{MtUr`D0Sa6}bB`Rn^tQdAYq3h9|7`CdP;>z{{v1Ezmeq%Ia{KmK8~dv4 zhewhWgHy?UF`=;^6cqk3iLq z*B5a*M-E?bvhO)Vlb2Y^nEE;bbfIg*Y7bqsy-&4wl+Ti;*~C!A&Om@n32>j|%x+zc ze^1?3OT<1%&5$2whqyu4>X{S{k%tZX1u%r))Q4&P=ab7Zin8y01AvSlu(b^{Uc;Bd zQ*uGEYzB7D{v$A<5Wd#&TL=xbnQ)VXdF=qP7H_%Ko475(6%?lWV;wjUqSiLa$=Uu zHzcd;S?TMBeV$-J!?J;sgISqIfQFVfBh)pQVva+IH#hqL@4d0fe&Wr|hb`|Kv69&t zV80Mqctw^>>(X0w0h)p{)3M!ViC4LUeWzk68!TZI>4x@sbw0xk3$p5V%UX8MKJW=^ zRr=qE=wNX^+VDIgL_iv?wCiLJaSxan6wgYYoamE|>iZf0;E{`>edqy_+7LVE@AS$? z&xpLx7D-g4GEKKlRVf9*6DxaR{+UyD&c08JHc{Gy0; zG%%({#rSEYFG-M_K~T(R`fXX3CQ>}(R{H;bAyjMISi)-Vk787)$yhU*%;o$|cCGc68SPHdh`kViHm3;Tu5qZ7con?&(XEviw3oi0R+Ln>>(uRBS zr2@O{(G`zoG%GB)skm@hc({FFlZOAHDEJ1adZx*IAzQcASZ!nEK^am$!4Tcdrtmo0 z+=kFvZHd7F+{0gkr>J;4D~F<|ZJ>H73aYqV(;I3Bw1SAM$!d-Uu5*M8@bQ`1UfqJ24gwvu#TgQQM0yB7^?q5!Y^qoPNFkeE@l*~gQ4^;|d;)42 z2I0+fca!_;x!};>pi#`yT2mTD%-F3e`H`>xGb;oKzJY?sQI!o8NMocul94J@eaAr% zF^p;yyzQ!~75{y}m8|u*08ENr<6LVVISEGz(M^`tC%Ue~9GBI6_5I2SZS!K;AGGZ? zxl{9cDfvfoAs$sLOauR!6zZ6d#F?8G!SyL`DZdzGct?qHC6|(YR;&9>gJgPT(vi{O z*Q#P)IMneO^KTP5O@*$$!ov~2|`>}GL zw?h6fr}VeTjiq(I>N#8ctC$XUsHgZX!kVV$69mV>Chj54G!ZTg?okM2o|~uaW*;o}0pc>MHHhY7=k+_1&jvpGr#( z`(LAx!*Dl$&pJ&=C`k39=wz38-CL)C{6u!2Cqnr1iAcKV0w96bBiR8^xp-!mLt3m} zR983u3YW6!C^BapSFS6$&MA?o;0^P- zXBUSpICbDAMSW-Uluduj+!1@7JrXn4$u+HQmuJ;U(6S(bA<=N~&0>pXhJ#dn0%~o72YHFH23Pq@mk`j z>mRaw-kP~*@^QpJW5|CSUT^em1V?FCV2Jfv)zR->qlD+1pSPT&0(47`Y@T_ZBnNl= zp{cwh;Vyg|FROx3?fY=4wy%-o`5F_W%?Th{#LtetFNM}iY~#A_@A*cRs>%SXJr}xf zb>Jt#&~z0DNiOjGij8bs4kpr*ER2ZZJad8O?hv2QL27sQ0h#$Ch%H3SqMOB9JVdHqLGYINdoIi zL*yRc4=jgmsW7kl*ONC0Xq56XN1Il!u`P^YSVpbaP|0Q80oVfh4dqC(GNlIWN!GW- zKM8j!7KsK<^?+cFyKMNT5_@F2!*WiTWw>$#JPIBGiIqK?CBMNU5l68-U<6K@^A13D zxvR0FqZ6p=+|6)KnD%AHB4+zv?WdS4urSN0n&%=r!kQWWeTeG+zP4&wrqTmu1~2!( z54IeJwGd#@C|OYLvN9tJ5qWq>Oyb5*id7UYCn}@uO+beWZ9gvD&!~)15?dbkCxKVe zfpus{o7M3nwE}kzD4^WXxiB-CZ#MV^IP@OS@Y8BfE9ywqS$$8P5_kl(p8g1nDx?hA z{FC%%-C^^OH`SOgCRW$(6_*DU%V2V%{DhOF0AJgj&h-FDPGz_xQKrNhoZ5BzK_v)} zOX*X;+8forpIoQ7JwKP#_f1^ZbbnLw3^{XxUbwFP9&G>%ujU`9^~{AQ#_HsM&GUjl zOA@(MZue7lwgwJV!gSc+;X5IzVoN>Cs#V=*cCmck|M3le;MKKQ;Un6+ChernxQiSI zBiqrhvO?Wa#Y*F42wJxt?PvQVq~5M`R`vH%a4v2MPJ_{oMfhIoQ#&#_rMCj0I5 zxw7xkL;DNJJ!uZ-^=&;=f6EuDng99}Z8V$9$inkm#pvPAMRY$%zg7;a7`CcBT5rpt z)28Cb2awbV^_wK7Mv$2r|HFeah;a$3~@6FdrZOtJfW$w0-{qqy0Wx@gIp z?mpXSdr&WgvL2QD42yDo?jTx>lhWm^7Xv>?#M`njAt#%u72;g_1LIxvZ;bW5g+U!! z@4R!&uC*^WlXscVy0ySsp1R`jeM$j`Ew%H8lelB|V)Mi*%SehS_DHwr(Xd1ed0IxX zY>)PMdaCPr+Z}}stK6%0oVp}h-FcmdioL*ip+n22IRo~U-tTMMb@D^|XIA@9Gp2XI zq?@CFQla(oN1Gm%%8*`tTa8gk84(`!tT<;nEz}U@^nB&rdP?LrekaW?&N$PlWgzY< z=iu0BBr+TMSYLjDh<-GZA84gU%84Qc)D}i)stu`@yHJrFh0Vg9iw~(>t+v^qTRQ#A z91pIb%Q+{ivD_^mg`U7S4CFYX#o7Jp^;Mf7^;>O*BI-r_M=sz-UR zS7H*wi6~Fk_}?whj_UyuQ_m>Cc_}J*i`x$8YR#=24)@)SBnQmfCQwQ)S2QC{$>`Ib zfP%hR$h;m>YGAfb1@N-j0x9o^zwW;OrX8nPDN_usw9TQ9^Chy0!`AHOjPm-kAzxvq zS^3)|5kc|2?|W1N>I;?{HlYgLaqdYz#r+@EQesCRJyV&Jz9~&r#1(OL6jH+!Z*eX# zaKhMoQf1y%L-?etC}*3=PeYEjCY(;ZfNb_7v6|{_rkByi5wqh+ky!TV?JiqFW?P9g zIm%rEU-F87Tb^l`8o+Bhp(CfBQZpyo{P)~Mfo7i1o^e9M6p%0q0enW)!(T&nh7fU* zOW5PT(f)+n6lIjQ3)s)~^Bj@R7`gSg9JYz!!|T7EY=!BPN8AzRlV@w=f6;ZpdktA& z2j_BZ&VXVBB<`V57Vhd# z_ysdhW!p}%8u{mK84C+eQZ$1qeB4xm#Oo}ed)uQjT(;A z4@EQ{rM}vRMIC&gTQ!;gbHM?5b=?BID(o5>^N}8IB@ofs)N#R}T?*VRw4OED#nF<-n_9Jrfi5A#? zeGv%)tYx3rpAiRqjAMXHvU9%rt~LN@Ds7tgT#@ub8%BL}@|g>5DKjOfI=9ICCu;H4 z9f#wDGqv;*(=gIB=u^fIJgxA33_)b6H5$4&pA%AU=AJ_g+OY1KsZi;L&;YmN0S=QdJ#Jb^q)wV*+1(W2jv z5eif+wi#*l!uJnLBxzS6_T^EEi^2U%7&b>%(DrBdv@e#k<{dSiYM|fbH{@GgNXQB!kwZz@mEm(!vA&OSvJkHR z?o@*WH^_Ig>6%rVTaKPM5;pO`8@1G+)_>Yjmul`$zv45T`+RP#SD=Du8uG*0AM1KO zhNyo~fu zD544H6W5m~L$6v&Jh7LlztFz3Lu4(6=C&CYn`-%Je%Ddqfh^B|^hJ6A()V~#Y0ki) zFtu^(6P$CRb1X^1x{-$LfX`QTL*1(`m%M_7VC`Ahu$VY=9avFvi)QDk z%WL}H^i^k>$l??Ic3&LxTW{+#`JN^gul$B%e(CgA8o5mFDD&aPL-$!?f$k<%bHGW^ zbj)`1J1tof5@+0amZW?~`Ip}+i@c~2VOT0!0;;No0?OF`CPrk67>k!xTV@SiCOLMo zT!|J5TOg9+@^aZ6oJt&D&Y~{I-8rWf2<5SNNj;b0Fp#uy!r*>ja#VHHVfY_Y`p1cp z`*9RaTv{lrI!7w#*X*Ef?l)+zkr?;TrY*xjwIHD|UsR;a(D#wQ zOD>;lU_EZ>tTO$M113g^uy4q<;vv32JMc8O;IlqGAj1^yJUPqy(BFT7To@W#MNjBv zZ$}f#i)__Joge3k2qc&EL)w`D!L&pjaP6)N}@?=jsIl0(ABl`@#;iX1FKZ}2boUf8k;~rAeOwliE1nOeV+k}=VkH41C#on+Iale z8?eTZibFOk_sm0ZX)T*2-$kN$iHeP5XZZX{l>c~9VyqUX?8u&$$OR1a__)yeplb~VC5U2rOjwAXY_z}S_Y zCp|i)QTx=2Hvh<>)&iHal~&UCnn2S}rRxFV!RTL1lD6`aEc1fTzEY?&A9Y%A1^y$M zw-pn=j80tpJz4&29kT6}z7o49x5EdL7rfR5+Lv4&7uG&u)R>zcEei^-$IfTq$yekP zD#Q|a=EESM2Flpz>ky}o@)TNHif~wo?2)4hK8387mz+Z9Ca)7uo^H2s=YQTU*EIxHJz@F4BT2ma`w_xY zt0Y?(cH3mkw^Y{W58kw~vf-)MUllSgM|lemT18$(`5Qptw6^f;2WJ8Kh!=Q&R!6Cz z=>gKXUoRcW@*}%BcF4&P8M-3>vY5%o3chAK(m}UO6nSqSaU{75TkiBn;^e;KzYIny zfBGzkokU%3>Xi6=B=&oxf#FUv>FY^Sp;cTamMs!9esEXl2cAH)PAH~Wtb@ye zeUMBt8=DJ#w^sy1KJB~(tJuyRhA0aDGoxxt=~K72=A;T1d_L^uyY!V>XJDAz5BV53;u-q7jdhd|gM zXRviyV5$sb%X)x53G1ldtT>6QLrM&vq;4%WdzU<^$aP5)=2Pg%dgeOo^s2-iJBeVW3>HwA$JQELzS^W|J>v`S}MvuO>P>PGQLLh?p8?2C8 zY;D>a>L-S8>`%9f`SGwXEO;-t^nb*k-NX)!^|_l%H&sz!Hn$b1@>lLtmd zza4-2l#p_ZG_o0Yxo+bf+#rkX0soaYNzJHwF+K%u8aNUVCtmH`Y|_R$I4zrEMFP|7 zpd&Hkfw?WzXR{V0y>LFVVX9&=9>Qv<9}Ui&Aq)}wln7qj!-cl| z@sGax<28nicT`Yv#F^{KF4SO z?-~r>1u*@%R}+cIWrKi!UJNP)>vk!SV_`{G|MxC{%4J{yB_rS7l@sl`);fvG3A37r zZQ{x1N|Lq$kxgu^#3aFBpXQfS$~yuXPDMuXd`gwPHnBeS%_%;(1GPpVsW=<1fMHwO zaHDlIpCtA?oj5!%PLM8KocGt*8JKFhu9>$e7y#TaEx9;ZL>T!c5RyK3aB|ek&rF;i6 zrd%ym2XjeSt2bny)IVPf_E+u^b5IgAP{5}zy~!w4Yo@g2kG|FMRvUv!A|B|-ch;um zbIM_S97Yx)6LRakL`}1R#P>SBVRW+PVqfImEq#9ACElLi>>7R8sXN|RF*B}6E~+HT z8-4-s940$vcjhK{KRh+qOjKngEVzFW`AX;4Z0z6chjzC2qc6+X18C|$#IBoXE=Nzd zt*8$8wy$lgtXWY;lA{)ukvC#1tTR&PZ*CX#?xD!Ls=vEiXC`x1k^Eoo$e@}b-CTi~ z?z_CL0qJq}{~{q-LwKf<((liMg0fIr?^NdT(aMQRO@8U~$xq5!B3Z}f8iEsPwn{IhN@Fl+hleAPMdSceu@S*LvSSalg!(S*yFM>zsXdovzxark|!381`>>%o_6J#tQ9qcc(YcdO*4duyyt3||)!kZ{T^?s=S*k9Oyj_1Z|3G*u9;`x2?Be&yOv^8^N}czDi0YBT z{Oaw2pCDsHwCk+_RSkJ}7EC=|^r(<>L%)0+omeXPiW17YVMYn z768cA4C&Apw!fFD^Z7;Qqp|D16o7iF-v*%Q({+^!1QIj&!T$3itZi#EdOw$gS<3KN z>qR(=wAT(xZ%lW1I(n7NAI}rS2EtnO9-JM-aVOXn^&GZTADwma`^s#>F+O2j!lt6; zmp^dog82i4W%$%AV}bqqd;kAcIc(jeveGVLnJU~;^bBrQjr)M3GrOe*Qy#-4Z}4HX zqi@bWc$}#U+naWtva8Uu-Y-U+t?XLlljL7zz#njL8QtETGij@&MFwWP`rNr6*I+2w zUd@vHqTin!CPJl_c`KcsH`OQ85lCT4)7gl+ZFTc9EP+`crwDm1LG&m&p@z#WV~Ses zTa<;!mb0|P3$MOa1c?r^W5Jje9IOyQ>`8PW=3h4~)IWl6#swK+THn@r?=tMD>My(o zJ`0mMf7nH}jBS%*6=&FaJpgk_y*N8 z)H?FaR`y-9t}#kGc5LZ}tI7spZ{5Lq!E-OtWbB>D-PmiHdtSCU9EgNUc}r2sEImbx zdx4`j&8ROQj%CWpL!%65r4p)^-NAPb!X7PB4^%O4-HOJgdg_Kh#F03G9cshFs+`(h z(sbC*iWg;Wr0?r>9r9MWYV3-J?MwL@3$8emUtsm@KTw(fZZE%it^6)pSO1CRlqBTd z|9yn>=@q3l-!z7)RX6EB#2q`PBxg_qtu|H}Ru%pRO1gVMg*i>2gsVm<`M?PnUWqHK zeoPd1qC&Iyd!G3L!?dtZts1Aty=v;?wpCO{q!pgdz$Nmg!TWFI7R|!;R?Whf;)G7i zNcBCtXS`!$sw}*L6-L{tBDmn=@Ky<# z6F3WP^#Aj9Xt2Z~-EA0M0eI8Aw0|R?XL-pNF&8j@Y>!;kk&c||i!x!^C;okC+EGEy zR>&H^2%|^bLs%Opzs5x4FSrP+mZHb=VQ!pJ11oXpF;qIj=hYmTRYsJ5`vXQcmq9>) z;hdCK)uBd_$TTU9L1s6BHFx5ui_u-m!^HA6NY<%M3 zNO8u~z<@~~2{iYY7%piBv!lX3C_fB{`s>IrxtmV3wDFD!+qv_T;yQk;)bkSG`K3e+ z+rl+xu<9%FRI9s(Y3t61BZ3IEj8OLvB|uiw;Qy{AR3wU)YkK zZIt2|`3A)E8V5N{$9MVJFZ(t$NjxUM$BkI4q6Ys2**v+ z;~;!hB4Wk*gC}?gYB`R^1zP)a&+mqE?y<89HhJkwVT-fi&WTrZ5Jhm}mmL+;sX0z( z&9|`_Jy1!GpOAr`5!a5Y-#fNF^`k#K_ra|S5jzDEJW)p)mp#^?EN6qu#D#!k!Wuru zMj_!o>1>1nDVnYKj>c^=at1z}r*vrIG9_C}%zWCeuCwPLjRv^~E`3FaeeRTb zaR&6d7@Wm(_I}`s`sxtNoN(q^cG9P$`qe21hb^lc7a#>d28GXGx_sPt=!S9Ac;vmN zb+IaBm!rah29XilpeET>wV*Q1xdXe}WJH(PuRIhhA6|r_C@XKs^q<&PIHQ;iwJIsE4J6`NeHhj1Bgb$9t8B5 z)(Chv+%{?;Bcq-GiitV^jYr6<{z5F5ZW_^HT==JhAS6WoS zLv~pxgUOrF6E20H!IRJmil>Fa)=zBySd7Pvr^RvmQaXQstC!t^ zBjE7fA*%Vy5+Ccg;Z>?RDE0QsUF`y&=&7~2pG+Tw@Zu0@vvfBt4^+%#ximdgK2I$v z0aNa^_3iKDKus21Bo}%r6#4QEr8@HVEoOYEHMns%wcD|W6CvYc!|YjW@?yojr6RXq zkLyVhwEKjzw2!a8`^

    (6s9^dUuvIo7YXtTGd)E3_ElTHkN&(A?!^+cv;1AvQNH* zQ$|~h(X(2bg58E;af&ft^!;8nrX6)I_}Uu}au;~_2S=G?ABy_4-bEIM9YwVt@Voq( zE;P-Y(sudpRpU0PE(h%qV<+}XFGCP~)-P23_?o)I(B3zW9oo(8HSPpqsQ)RjioJHC z!QGCfkt+HpQQecoT90gy#0o-1>aF@t@n4RWXMxZ;EMAG8yjIq8U9K7NGims^uj3gHzjma`05)Xt)HNBTcN!fjH-Il}sw676N4Ftod zM%#*KvyU&L4L~OrB@l%DfU(R<17@-|v=QRWan6_?;sb1`h^W~6d?6J`2p0%5M*Bs@ zX9v+J09T%Nn7bG!KD~K|!Al3U83NN*{m*$+tk1C@tehkVc#^6bXocxmd9FVFhsXX| zzkO@1?;z{uG(%lJ1eH#-LW?c_w!b$TaedH(BZl3Wr=sd)){mOR#jQi+75^(H8W0Uw z2qe(vb$=Qz_r~wUH2i{Q?%EPd?SAilUDM^YQGeTNDJqFsmKcP{&AZ#wxYSO=Q~MNe za1`!c;a!--N!k4HKJw6g^{R{6Xlr&P(`K7cEHlhQ#Y1Ji^Xq9wq-mt>HpkEQgN`^% zVPM`GGtq&i0A3eI#caFnro~5d;=E^*`XYX*+w4R4-OG5!^(uYkN`CC@hpKh#<5+EG zWHR03foByuG2FDH{-mV5=`Pl%u(37N_+mmY$_}OZrdO$de}6Gg}Ay z`JuDsqWA1{AIXTx;U0F?jQdzoqpIkMK#YcALW79lLOjtUumc$0Ii+q72JCtV<<93UyC0}_&sNGJ$oNCd$m(BQi<>x=KT6* zlBHT-VioKBPLpH%_V(;*Y+bjphx_>t>b!N}iOr`6FL}+fp8na+j?Cw-rUI0+%xLuC zm|+`>=SGwSCBzqz*6R1722wRck%y;`f1{qr>>taKD!u$9}$k z&HmLmX-CiZ>E5)>!l9iG=h*q9w1TXu!bJt;p?{>bHY0*udYT>3_*c48tce%ozs4q& zmRbJ_*r9u2)t&vnxCT3eNK0oWW^3%S6f=6KEBdVtTVdVqXX1Bqd!knN=ay=tk%Y}< zYApx_`Pk->wM$L2g}FXiWClGy{nDtt02hH#kcnC#UJ_`+;604@GJQI-=9JcCd?b6IK_zt< z){n~XQ<#t9&Q6T#Z=W9-&pH@83fic$Ek)+UGt*wwBA|U#@YuXm5x2+)qJO60lfT2B znvgAF(^PO+BVwS$@NY(4$m_)L6SOA=1j1wa6;W%nbBuEl{%`AnnbmjTMii9IIY_h2J^CO$P@W+R>q4zHMd`C?Ok~XiXKdapnGvWwd?6_R zw#WpcX8>&C%;BF-)cdzIH&F;0Cd9>$tajBAz7!zZ?(m7!#Dg5?5V;KJM8aU;f3?98 zim)VMu2(NkN(pZ3!jdIJ@t#GuIbgtb|59#{bb%E31!!5goNRx>^J0FD9+Kdf3LF`y zx?WRqOSRo?(L^8ZK=S$ghrg)Ez7}g0?iwxCqoTP0Yu3aF>`Bk_K6@;!^qi{aW>xt* zjdWFNTgH|8@p^HUN?1pb`2ofJ7-dj?-+!JP+;KUHv&JtWt>q&Y7T2$8B^rxJ)$T04 zjp+wV#7=X9v_b#9w&o`=|FqrJK#d*h9(*g~9Cq&rh-kh`_wh?@xP^6yb*-QAo?^R+ zoWCZp6v_R=RD{ygV3`@*=m+mwoFhrP-ct25v0rTgk6p1aEn8)a?O}$x`wx^6@loC) z{Xl5y^I1KxWMO}vmmFvep-UU(UBcJNHxmUK*W#Rkk$ynte{ZBJrW_hHb-c ziSJGeD2~*i0=a#(uhL1LXPwG;6#u?M9Lq?_B(4jSX^2=J@|d#D(Chzn%aj4n}-ChPA3ETW!<0P7s8jbWF=)lkE?y4_WEX6oPIZ=>NkWQ9zlW&|w zAu)q3FM}jTe6-S0pKygqn{i#(cMN@H^A)nO(uY{7M|vNr$J@uHcOWK*;MaFpG}F%D zE6VyE349BFh5DH<#z=L?2Giceiv-mUSakCo!mgL0meNvv>-R)!ri1*xz1CtP-4SE* zq6ea-wh=(;iG&-*xX0CQNOE^HhqJuajs$Z z-Lu&~f)WbGBBQ--TPziR(cMJcjm}?JjG!mR6GBT$ZGTpyYEvPsH>L>f2Nqaui*Uri z9mujolM_y`Ue0;Zn&H(p8Gz&JiQovms@0P-%cOM<{lN=@)*`}uD?x_9*S?^oOS~P& zgug+$G~`>2pGz40v;x!!JgSao&AhnIkvD`n^em%He%+wRhK{ag!_H*gqnreyg6qv_ z)aCoT4Kzwz7hZ4T1e3)&m58D?#YD#KMK6%!^2QYRsmKArGl|a?6Y1oedZ6R@+3>)Z z@z~}A7nJGBlii_(`dfwb)PZ_7kXs?3jXR%Yovik)oyaES(vcHcIYM+2ROnr3sJ7+Q z=4&M;TZKP|V+5@~?fZVo7TGgGan^J? zu#)BQzpn4KiCY(oAdhOzpaN3FP(ZTajN-;DTNrRRi$IP!C%JpTS=8xXz*~QD?Ur=! zB3?C|oDoRQp8RX{dQ0KS-^+u#A|dICaLvy@#-Ad@mKwfAeIj zh;Zm25eO>W^RP4z~vRXpx{-iuei758?QS+oedbk?BR@_b#?YZ9?Na0`}IVnULI!XlJiTfO_7IQP+L8TVel$A@Z_DbFVR$7Z1uE(gA zYqrA_WkF!#;S6Nt%UPhI#UnO$wXA7zM5)larNH z1$K74GXeDD^=D&o4iN3%huC$zz#$;Git5j!Mcv`qIRpCyLVRb~wIW@zl9l0D$-r&Helng=IXdD1*cgIo`{v-q7NAJLx42ezK)%$4(JT1yI{9cp=r`0Ja{2&LcF_-m}>M3{hQs4 z`R?jOeo}M@SF_Z96q`&|c?n-p zokHK{q2?}a*X13`zT0u;ed$gJqzUHI0H#!!Hapas2O*EKMPd<>;i%fM^{%*$pN|dF z4N~4RL{e_njqYSTu82WMb9hTtwG}v2W__yLFC#=sR!mKgSn2-ZGk#C*??Yr^C z7Fq&RK9=vC+O-CK%mSP&$4Nf5cXhe=e%Zjbrm20&hga?JEkonke(C;XL?iP{q3H%c zHn%uwhkT5i>l5Bl_l?|7%w@{LlJMi!bKEHXOD4(n6<$HtaEm_n2V-$Vkvi5o8`wCi zFzyA3O5sQwM8d2It3MQHLgq5MF5-Q0ZW*<$`-5F~1{mxnTpr~k93WqU+g!v zHnSF_Gm!r{Y%!5oRiPn_iGJIxGK8i4Ua(_pTMy2EG**&W@+OsBAU@1WXQJf2Ne3Ul z2W|&70l9(Ru+#VV<%7Q-nDI{IM|WyaTX13(9dk$ zJ=&~H>fO~(c#V>6|1JwqjftEzS*mt7?%{4~+234E&itmY@g3>5yxq=zxDH2UpmCGHAaw#Yz`7?CdZK0w+Qc$;*XehuS*`*#CKa!LZ8III%EctT^mhg*k*BX57e@ zdOw7^T0W1PBeTQ0!@FZ+&DT@-J-*6nwS$Gn!QrippV7ZB2amc>)8C9_E#V3)f&yEf z`DwKk9gAvJWphGw^qfK*@79>Ve44&%1qdy_{gtQKzM|QW$r7(Nx=UJlpH{tV zOvn5L3(Xm4k$G1&y93*cXKLTN81ijumS}$v;Y79243?;4o(Zl9TIVQUKmHVK@KS{1 znlHQ!GQQD=j5m$nVWTU#{&qm>!Ev5g?|H%EwQyZ3Um{TlIm`FdAz4jt+N%BQc6 zwLfvaTejaJrY#4csT)$v`!VYJCW)0nVMmILY7{sr z^U48=p*l*!sWvfrxsMM|_9<-L|#*VRH4oTc{ z#IIJ^_CKsB8di?WGnmF7^Zv+4BU;4K(aAdY4A=W|5oNheS%oRYF|;25B>%>9GG&8^ zP;?K&I51JVAuQHkJY*&0$o~=hfpl$7E;DpdrhYlHhfM_Wq#}dw4$0TYKPDcYZ3X-O znljsXS2)`%oKz z3@V?p6)^8W9|^hUw7WsZe)9RtIGzj6P`*!3%C9?FOyBS{&R03zT1y@K(CyK(&q~C9 zYJ6JK`t#r9Z<+?S2pd700=mTpA=U^70f+AZJ1LSr6238hn=55=_02oD=*shkOu)5J z58L2!&x^KQ=91|)Hh*(G{Z-wsvpsHiF?f0N8KKmjlwWMcuMlDW0Dk6GQBHmo{2|`s zn}_DrL?_y*29=n|^QZ`;+|qXb$u`ww&R5f83%T=Pw^nO#XY7j%s0T`Do~;AxXTyKz zLd8`MtaL@%mk8*wI7M6to+v^$%kc$fLG_i?)+eiWm7(~si&C)@tk@^LT^JJ_5Kr)? zch=VMsLQ3RfjN4-^=~3LXg{;(+>^(RBwM@*pRk!BS-Z%-ggzpj9A<<9B}AWEV!cVQ z^cmxc2i+AGMV-t=XV5yK&J06ir5mn?&D}6Lj7)FySZy+NqmanY`ZV$LA~Vh#jf!%G z9~PPivfq*1rJfYC)WS;fZd)PIY3!YPx2ngK&Bz_yb(BZy$6W;`er!JL)%L$$esuzm zVzg=#*N&Mz zq6&0KFAW?Q z%a6V{?Lsa+kJ^{{;G0`byY`EYb0c$&Hpg1dz&kbpklZLD6kQNu(?6J3>OX{aQB@2gqG)%0G!XghmV7uU98^6%&z0Ys> zP;wBv>+MG^$n6_NdweFO@Gj+t447z1XY(iCY9vR!c}N(n;w?72^kSg#3k)b9-W%u` z&_3^`#XVKUgkPsIx67CW_;VZF-R{_eU{nl3iBv+ZLW;vr+N) zehz!{pTzrAz5Slg3JU_qtkXQiAHu6L=s)L!5tX~Z0VS>e;tH~Kz%IOsg?{@7G zSTxw*9IcC)G#x~$A&4jCbVaE}YWMMLq!N?krV_(1w2%pTh1?mw{Lb#$I|@d3HyK;S zByr+*k#5)Qs-OD%i7jC)sQ9M_5=#h>;?OrGetOW;FzecTl{1DR@_o5nWiRD+Vfqc6 zYr~zLMBvcp`F-ajka=_kX!dD}*8wtpI;ylhKYNrT(uMaah#JowUOCYTcdmsyyju5o)a^NNO}R6k&rFs3K*q z#j6#YK7N9?JP`|(+`ag7b_tQd#G-Q~kW^CCVByO5%Pa00lgDDI!V0I&$8to^WN_ab1(80#^zYgA+%=#yK?Y$PipUzkIM;qG>8J2wzenlQ#L0|vY zlKf+u`I&!T0NS7X3%=goKK<{qsKw;#rZG!79bC&%9DMauoHzvDL4?X&a)OAy?0s4F z{IbXXg?=0n1R@d}N2@6fu%WF9s@9LiAaGUveyH$2TJ5Th-B@&w<57q7)h?G$zm{ybgljCkw&=tus zo@sKC+UUoBbR2m{;w(XZ#MtNKxdfMrrfhX_!fEoQK5|4tC3e=FyYfG7ZN5zR!r#g9 z@024tvAUTIAo}l-(A{W1Pbdm8$Xqdn+2Vdxg z$1`w=GVW3gdroTMqA$JfM4U3COAalWSB7W03vJ8mv9wO|si;0{#v1cEfd>fG-+NA`MxG;>Zf#q=1N<64O&JsloeSQot8MXKH?_# z`~a#WP;9y-r;IKlQ=h5UWND*ALgLt)iVh&U*kyggj^W1qd7@l;w2Wx@efSe@%+C!A zRB%dir}=2o*gG}3iyHn4t2$h$5QZB&aGj0XZoW&jYl$z%&~P5w^jj+AGM$cf*GqDf zLTtmFFNBRny8Y)FS9JLT>+NfD#B;jvQ<>8n2)9LUl~mBCb863|3-W+!44 zf|)UW&ul(uF75bCr(Db1Xl+ql8-0$IZyts^BuUyIIAmZPpyDD(fB#AP@pbe0GG19> zr`&_E&c7UApV`$nM=pPIq9wknc$F-naToY3d_8&a_zpZ5IHg6>mXKAXz63HW{CyBl z&l*~e!U3r7g`2J&Rg!5nUWu{fhLuH1L}h zCX^sijK-LK+Dm@SPkXUz)^gRS9d9-C#d@>PbF-BX0pv;)_V*-dOmlP>?&|l-;JH(d z(?$^tRBa84iuqB~7OAd_!Km)C~KUOfC6Q4de;$?e8C4 zTG3i4nm7^q$(Bf6`5Dxo<+ew8DgDQ^S+1!vHnlHK4;_S`8~b3I&Sx*z#4aNvGjrwn zpP}i-g-@m#kK2x-_G2ffyccuXsJ=QULd71s&`L$j&aS(};QNpQ$Um2aDRsO#89h6o zb|(}G@P1UC@%6~zQ3h}7c*h_EQ%4Fxj)5n=E zN3}O*ixt)wG63Nd|B^wTQ?z10ZWBUOta%`K`hAwFlJDi@dl8cXx#o(=W^KbP%0*Ez z;o@qQ5J?=2sE4n|{bs(0;hVt0*^vHZsb{Pu`BUoGm{#LKNs!*XW>4Nq*HyEBxXpha zFj5Q~*N0khtq-h(Pu$wAX1e)6Gg)YCq}KM#0z#ME$JXK(7wU-sWY3!=qnh<7e(kPu z&hZw=iSfCNQ0OMGihjCA+)sV;J3rKQhBr{bOc)z29F!z>uddvU zg*hK>9?hHAI1ALZ^;YD6NOqvHt=4YaIs4{!ur!FMxi#|3v-y+&o`lUIosv@u|CMxH zCO@9rJ*(|`Yt12ZY@$bDYl74$Hd_;j}9DuD%0lNmaubd`$wC^ zLjpp=M(-ipfo{#?9EW?3Tj?skbG{lVKxx+pMn1j`q8$#Yh=i@2S%h3mT`!!J{q%dr z4@?*7G?_!RT!_1#v3*^gV~$zgXi2p7(_F%TzDNBn2jGuGf0mvrP;#;IuH#+21jQ3m z&&kGcLnECYZ3DxT7sTztLd${z4IGv_=6qVe6?^4NKk9mtU9CVi{dhMpKG5fq3Q&z) zJpa-aB>r`BpH<$QP2BBv#WF+tRf%S=ZtYYBP#aa8g2eszt;n*_HUAx>&D$RC$v_$1 zELY_wl^-tvq9P32?FD8owjfE@;U8)Ga{F7Su62m7g$Ns>N(Fsg^&4EPTUDOTyCK5q zbvJ(v_0CzgN`g~J4EcV09c@C&Lh~OJvOMDU=k^mxY<-dwHCH zCP2Ak$e{j_`(1}>k!TqggoRO3v{8qpeS!&D0MlvlqD-dYo%Ej_^bH46lzv9P&qntj&J?&y z9E(nEnI9_k_}x}cv7Y|5DK%jtfRMJRslIaK@TGwT(&aGTaQjh|enAGS2&fW5a!OiJe={iF!F7!&|hFDml(rm-Z zZ|l?4TjAi1eU7+e!?qluc#atABVAbo7A@I=#aGZszsO=5O8)oeNRWv0 z7aj&tUBpLACFD%8TBZjo(Y0pR(=`-)8F^ZYj~D10A{>zYYv?S!Gh2-~h^TPn9<45L@z))d}UEY#m>R3U>|3qwslsg+vT4RT04#$gl0u|3c&eCNxh zLjB?sL(FVH?nkjS!6p77wDWJ0EZAhc3rhXH0}+>Z5R2B;v1sOZ$BtRGmz5VP(VVfE zSPn|MD@4a%1OTtla{1oL9ov$pv@(j@6;e3fp_=ztu}QqXOX(+-^Yx@mFr(z<;__{D zNW@QhmGYbU&1qFa*(~XLiS03){>`@8g7>=jW1QwIEqJXu8>zv=$-q#J1p8&d!pkcv%0b$nK62>w|8?U8r?Vc#I86u z-EB#sy?6s2M&dl;mj}@&W~W-*lTPMU#&i4Nln+!suCRf$kaEvIC#lJ-^nerh@xiTM zeSGT~xLBbN9;IURI%5d-YEhq>uGW? z?!~>*AQ9m?s{Y2st9rs(wA#M6YBelj;)kxuu1xytq5MTxTwe5?ya%!^W(jNo<2d*0`EdT%j literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index debdb33108676..7fea73024a8a0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -75,7 +75,7 @@ For this version of Spark (0.8.1) Hadoop 2.2.x (or newer) users will have to bui * [Spark Programming Guide](scala-programming-guide.html): an overview of Spark concepts, and details on the Scala API * [Java Programming Guide](java-programming-guide.html): using Spark from Java * [Python Programming Guide](python-programming-guide.html): using Spark from Python -* [Spark Streaming](streaming-programming-guide.html): using the alpha release of Spark Streaming +* [Spark Streaming](streaming-programming-guide.html): Spark's API for processing data streams * [MLlib (Machine Learning)](mllib-guide.html): Spark's built-in machine learning library * [Bagel (Pregel on Spark)](bagel-programming-guide.html): simple graph processing model * [GraphX (Graphs on Spark)](graphx-programming-guide.html): Spark's new API for graphs diff --git a/docs/js/main.js b/docs/js/main.js index 8b137891791fe..102699789a71a 100755 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -1 +1,107 @@ +// From docs.scala-lang.org +function styleCode() { + if (typeof disableStyleCode != "undefined") { + return; + } + $(".codetabs pre code").parent().each(function() { + if (!$(this).hasClass("prettyprint")) { + var lang = $(this).parent().data("lang"); + if (lang == "python") { + lang = "py" + } + if (lang == "bash") { + lang = "bsh" + } + $(this).addClass("prettyprint lang-"+lang+" linenums"); + } + }); + console.log("runningPrettyPrint()") + prettyPrint(); +} + + +function codeTabs() { + var counter = 0; + var langImages = { + "scala": "img/scala-sm.png", + "python": "img/python-sm.png", + "java": "img/java-sm.png" + }; + $("div.codetabs").each(function() { + $(this).addClass("tab-content"); + + // Insert the tab bar + var tabBar = $('

    '); + $(this).before(tabBar); + + // Add each code sample to the tab bar: + var codeSamples = $(this).children("div"); + codeSamples.each(function() { + $(this).addClass("tab-pane"); + var lang = $(this).data("lang"); + var image = $(this).data("image"); + var notabs = $(this).data("notabs"); + var capitalizedLang = lang.substr(0, 1).toUpperCase() + lang.substr(1); + var id = "tab_" + lang + "_" + counter; + $(this).attr("id", id); + if (image != null && langImages[lang]) { + var buttonLabel = "" + capitalizedLang + ""; + } else if (notabs == null) { + var buttonLabel = "" + capitalizedLang + ""; + } else { + var buttonLabel = "" + } + tabBar.append( + '
  • ' + buttonLabel + '
  • ' + ); + }); + + codeSamples.first().addClass("active"); + tabBar.children("li").first().addClass("active"); + counter++; + }); + $("ul.nav-tabs a").click(function (e) { + // Toggling a tab should switch all tabs corresponding to the same language + // while retaining the scroll position + e.preventDefault(); + var scrollOffset = $(this).offset().top - $(document).scrollTop(); + $("." + $(this).attr('class')).tab('show'); + $(document).scrollTop($(this).offset().top - scrollOffset); + }); +} + +function makeCollapsable(elt, accordionClass, accordionBodyId, title) { + $(elt).addClass("accordion-inner"); + $(elt).wrap('
    ') + $(elt).wrap('
    ') + $(elt).wrap('
    ') + $(elt).parent().before( + '
    ' + + '' + + title + + '' + + '
    ' + ); +} + +function viewSolution() { + var counter = 0 + $("div.solution").each(function() { + var id = "solution_" + counter + makeCollapsable(this, "", id, + '' + + '' + "View Solution"); + counter++; + }); +} + + +$(document).ready(function() { + codeTabs(); + viewSolution(); + $('#chapter-toc').toc({exclude: '', context: '.container'}); + $('#chapter-toc').prepend('

    In This Chapter

    '); + makeCollapsable($('#global-toc'), "", "global-toc", "Show Table of Contents"); + //styleCode(); +}); diff --git a/docs/spark-standalone.md b/docs/spark-standalone.md index 2a186261b754a..3388c14ec4d48 100644 --- a/docs/spark-standalone.md +++ b/docs/spark-standalone.md @@ -151,7 +151,7 @@ You can also pass an option `-c ` to control the number of cores that You may also run your application entirely inside of the cluster by submitting your application driver using the submission client. The syntax for submitting applications is as follows: - ./spark-class org.apache.spark.deploy.Client launch + ./bin/spark-class org.apache.spark.deploy.Client launch [client-options] \ \ [application-options] @@ -176,7 +176,7 @@ Once you submit a driver program, it will appear in the cluster management UI at be assigned an identifier. If you'd like to prematurely terminate the program, you can do so using the same client: - ./spark-class org.apache.spark.deploy.client.DriverClient kill + ./bin/spark-class org.apache.spark.deploy.Client kill # Resource Scheduling diff --git a/docs/streaming-programming-guide.md b/docs/streaming-programming-guide.md index 07c4c55633929..ccc1c8bf2c541 100644 --- a/docs/streaming-programming-guide.md +++ b/docs/streaming-programming-guide.md @@ -7,74 +7,457 @@ title: Spark Streaming Programming Guide {:toc} # Overview -A Spark Streaming application is very similar to a Spark application; it consists of a *driver program* that runs the user's `main` function and continuous executes various *parallel operations* on input streams of data. The main abstraction Spark Streaming provides is a *discretized stream* (DStream), which is a continuous sequence of RDDs (distributed collections of elements) representing a continuous stream of data. DStreams can be created from live incoming data (such as data from a socket, Kafka, etc.) or can be generated by transforming existing DStreams using parallel operators like `map`, `reduce`, and `window`. The basic processing model is as follows: -(i) While a Spark Streaming driver program is running, the system receives data from various sources and and divides it into batches. Each batch of data is treated as an RDD, that is, an immutable parallel collection of data. These input RDDs are saved in memory and replicated to two nodes for fault-tolerance. This sequence of RDDs is collectively called an InputDStream. -(ii) Data received by InputDStreams are processed using DStream operations. Since all data is represented as RDDs and all DStream operations as RDD operations, data is automatically recovered in the event of node failures. +Spark Streaming is an extension of the core Spark API that allows enables high-throughput, +fault-tolerant stream processing of live data streams. Data can be ingested from many sources +like Kafka, Flume, Twitter, ZeroMQ or plain old TCP sockets and be processed using complex +algorithms expressed with high-level functions like `map`, `reduce`, `join` and `window`. +Finally, processed data can be pushed out to filesystems, databases, +and live dashboards. In fact, you can apply Spark's in-built +[machine learning](mllib-guide.html) algorithms, and +[graph processing](graphx-programming-guide.html) algorithms on data streams. + +

    + Spark Streaming +

    + +Internally, it works as follows. Spark Streaming receives live input data streams and divides +the data into batches, which are then processed by the Spark engine to generate the final +stream of results in batches. + +

    + Spark Streaming +

    + +Spark Streaming provides a high-level abstraction called *discretized stream* or *DStream*, +which represents a continuous stream of data. DStreams can be created either from input data +stream from sources such as Kafka and Flume, or by applying high-level +operations on other DStreams. Internally, a DStream is represented as a sequence of +[RDDs](api/core/index.html#org.apache.spark.rdd.RDD). + +This guide shows you how to start writing Spark Streaming programs with DStreams. You can +write Spark Streaming programs in Scala or Java, both of which are presented in this guide. You +will find tabs throughout this guide that let you choose between Scala and Java +code snippets. + +*************************************************************************************************** + +# A Quick Example +Before we go into the details of how to write your own Spark Streaming program, +let's take a quick look at what a simple Spark Streaming program looks like. Let's say we want to +count the number of words in text data received from a data server listening on a TCP +socket. All you need to +do is as follows. + +
    +
    + +First, we create a +[StreamingContext](api/streaming/index.html#org.apache.spark.streaming.StreamingContext) object, +which is the main entry point for all streaming +functionality. Besides Spark's configuration, we specify that any DStream will be processed +in 1 second batches. -This guide shows some how to start programming with DStreams. +{% highlight scala %} +// Create a StreamingContext with a SparkConf configuration +val ssc = new StreamingContext(sparkConf, Seconds(1)) +{% endhighlight %} -# Linking with Spark Streaming +Using this context, we then create a new DStream +by specifying the IP address and port of the data server. -Add the following SBT or Maven dependency to your project to use Spark Streaming: +{% highlight scala %} +// Create a DStream that will connect to serverIP:serverPort +val lines = ssc.socketTextStream(serverIP, serverPort) +{% endhighlight %} - groupId = org.apache.spark - artifactId = spark-streaming_{{site.SCALA_VERSION}} - version = {{site.SPARK_VERSION}} +This `lines` DStream represents the stream of data that will be received from the data +server. Each record in this DStream is a line of text. Next, we want to split the lines by +space into words. -For ingesting data from sources like Kafka and Flume, add the corresponding artifact `spark-streaming-xyz_{{site.SCALA_VERSION}}` to the dependencies. For example, `spark-streaming-kafka_{{site.SCALA_VERSION}}` for Kafka, `spark-streaming-flume_{{site.SCALA_VERSION}}`, etc. Please refer to the [Apache repository](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.spark%22%20AND%20v%3A%22{{site.SPARK_VERSION}}%22) for the full list of supported sources / artifacts. +{% highlight scala %} +// Split each line into words +val words = lines.flatMap(_.split(" ")) +{% endhighlight %} -# Initializing Spark Streaming -The first thing a Spark Streaming program must do is create a `StreamingContext` object, which tells Spark how to access a cluster. A `StreamingContext` can be created by using +`flatMap` is a one-to-many DStream operation that creates a new DStream by +generating multiple new records from each record int the source DStream. In this case, +each line will be split into multiple words and the stream of words is represented as the +`words` DStream. Next, we want to count these words. {% highlight scala %} -new StreamingContext(master, appName, batchDuration, [sparkHome], [jars]) +// Count each word in each batch +val pairs = words.map(word => (word, 1)) +val wordCounts = pairs.reduceByKey(_ + _) + +// Print a few of the counts to the console +wordCount.print() {% endhighlight %} -The `master` parameter is a standard [Spark cluster URL](scala-programming-guide.html#master-urls) and can be "local" for local testing. The `appName` is a name of your program, which will be shown on your cluster's web UI. The `batchDuration` is the size of the batches (as explained earlier). This must be set carefully such that the cluster can keep up with the processing of the data streams. Start with something conservative like 5 seconds. See the [Performance Tuning](#setting-the-right-batch-size) section for a detailed discussion. Finally, `sparkHome` and `jars` are optional parameters, which need to be set when running on a cluster to specify the location of your code, as described in the [Spark programming guide](scala-programming-guide.html#deploying-code-on-a-cluster). +The `words` DStream is further mapped (one-to-one transformation) to a DStream of `(word, +1)` pairs, which is then reduced to get the frequency of words in each batch of data. +Finally, `wordCounts.print()` will print a few of the counts generated every second. + +Note that when these lines are executed, Spark Streaming only sets up the computation it +will perform when it is started, and no real processing has started yet. To start the processing +after all the transformations have been setup, we finally call {% highlight scala %} -new SparkConf(conf, batchDuration) +ssc.start() // Start the computation +ssc.awaitTermination() // Wait for the computation to terminate +{% endhighlight %} + +The complete code can be found in the Spark Streaming example +[NetworkWordCount]({{site.SPARK_GITHUB_URL}}/blob/master/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala). +
    + +
    +
    + +First, we create a +[JavaStreamingContext](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaStreamingContext) object, +which is the main entry point for all streaming +functionality. Besides Spark's configuration, we specify that any DStream would be processed +in 1 second batches. + +{% highlight java %} +// Create a StreamingContext with a SparkConf configuration +JavaStreamingContext jssc = StreamingContext(sparkConf, new Duration(1000)) +{% endhighlight %} + +Using this context, we then create a new DStream +by specifying the IP address and port of the data server. + +{% highlight java %} +// Create a DStream that will connect to serverIP:serverPort +JavaDStream lines = jssc.socketTextStream(serverIP, serverPort); +{% endhighlight %} + +This `lines` DStream represents the stream of data that will be received from the data +server. Each record in this stream is a line of text. Then, we want to split the the lines by +space into words. + +{% highlight java %} +// Split each line into words +JavaDStream words = lines.flatMap( + new FlatMapFunction() { + @Override public Iterable call(String x) { + return Lists.newArrayList(x.split(" ")); + } + }); +{% endhighlight %} + +`flatMap` is a DStream operation that creates a new DStream by +generating multiple new records from each record in the source DStream. In this case, +each line will be split into multiple words and the stream of words is represented as the +`words` DStream. Note that we defined the transformation using a +[FlatMapFunction](api/core/index.html#org.apache.spark.api.java.function.FlatMapFunction) object. +As we will discover along the way, there are a number of such convenience classes in the Java API +that help define DStream transformations. + +Next, we want to count these words. + +{% highlight java %} +// Count each word in each batch +JavaPairDStream pairs = words.map( + new PairFunction() { + @Override public Tuple2 call(String s) throws Exception { + return new Tuple2(s, 1); + } + }); +JavaPairDStream wordCounts = pairs.reduceByKey( + new Function2() { + @Override public Integer call(Integer i1, Integer i2) throws Exception { + return i1 + i2; + } + }); +wordCount.print(); // Print a few of the counts to the console +{% endhighlight %} + +The `words` DStream is further mapped (one-to-one transformation) to a DStream of `(word, +1)` pairs, using a [PairFunction](api/core/index.html#org.apache.spark.api.java.function.PairFunction) +object. Then, it is reduced to get the frequency of words in each batch of data, +using a [Function2](api/core/index.html#org.apache.spark.api.java.function.Function2) object. +Finally, `wordCounts.print()` will print a few of the counts generated every second. + +Note that when these lines are executed, Spark Streaming only sets up the computation it +will perform when it is started, and no real processing has started yet. To start the processing +after all the transformations have been setup, we finally call + +{% highlight java %} +jssc.start(); // Start the computation +jssc.awaitTermination(); // Wait for the computation to terminate +{% endhighlight %} + +The complete code can be found in the Spark Streaming example +[JavaNetworkWordCount]({{site.SPARK_GITHUB_URL}}/blob/master/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java). +
    + +
    +
    + +If you have already [downloaded](index.html#downloading) and [built](index.html#building) Spark, +you can run this example as follows. You will first need to run Netcat +(a small utility found in most Unix-like systems) as a data server by using + +{% highlight bash %} +$ nc -lk 9999 +{% endhighlight %} + +Then, in a different terminal, you can start the example by using + +
    +
    +{% highlight bash %} +$ ./bin/run-example org.apache.spark.streaming.examples.NetworkWordCount local[2] localhost 9999 +{% endhighlight %} +
    +
    +{% highlight bash %} +$ ./bin/run-example org.apache.spark.streaming.examples.JavaNetworkWordCount local[2] localhost 9999 +{% endhighlight %} +
    +
    + + +Then, any lines typed in the terminal running the netcat server will be counted and printed on +screen every second. It will look something like this. + + + + + +
    +{% highlight bash %} +# TERMINAL 1: +# Running Netcat + +$ nc -lk 9999 + +hello world + + + +... {% endhighlight %} + +{% highlight bash %} +# TERMINAL 2: RUNNING NetworkWordCount or JavaNetworkWordCount -where `conf` is a [SparkConf](api/core/index.html#org.apache.spark.SparkConf) -object used for more advanced configuration. In both cases, a [SparkContext](api/core/index.html#org.apache.spark.SparkContext) is created as well which can be accessed with `streamingContext.sparkContext`. +$ ./bin/run-example org.apache.spark.streaming.examples.NetworkWordCount local[2] localhost 9999 +... +------------------------------------------- +Time: 1357008430000 ms +------------------------------------------- +(hello,1) +(world,1) +... +{% endhighlight %} +
    + +*************************************************************************************************** -# Attaching Input Sources -The StreamingContext is used to creating input streams from data sources: +# Basics + +Next, we move beyond the simple example and elaborate on the basics of Spark Streaming that you +need to know to write your streaming applications. + +## Linking + +To write your own Spark Streaming program, you will have to add the following dependency to your + SBT or Maven project: + + groupId = org.apache.spark + artifactId = spark-streaming_{{site.SCALA_VERSION}} + version = {{site.SPARK_VERSION}} + +For ingesting data from sources like Kafka and Flume that are not present in the Spark +Streaming core + API, you will have to add the corresponding +artifact `spark-streaming-xyz_{{site.SCALA_VERSION}}` to the dependencies. For example, +some of the common ones are as follows. + + + + + + + + + + +
    SourceArtifact
    Kafka spark-streaming-kafka_{{site.SCALA_VERSION}}
    Flume spark-streaming-flume_{{site.SCALA_VERSION}}
    Twitter spark-streaming-twitter_{{site.SCALA_VERSION}}
    ZeroMQ spark-streaming-zeromq_{{site.SCALA_VERSION}}
    MQTT spark-streaming-mqtt_{{site.SCALA_VERSION}}
    + +For an up-to-date list, please refer to the +[Apache repository](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.spark%22%20AND%20v%3A%22{{site.SPARK_VERSION}}%22) +for the full list of supported sources and artifacts. + +## Initializing + +
    +
    + +To initialize a Spark Streaming program in Scala, a +[`StreamingContext`](api/streaming/index.html#org.apache.spark.streaming.StreamingContext) +object has to be created, which is the main entry point of all Spark Streaming functionality. +A `StreamingContext` object can be created by using {% highlight scala %} -// Assuming ssc is the StreamingContext -ssc.textFileStream(directory) // Creates a stream that monitors and processes new files in a HDFS directory -ssc.socketStream(hostname, port) // Creates a stream that uses a TCP socket to read data from hostname:port +new StreamingContext(master, appName, batchDuration, [sparkHome], [jars]) {% endhighlight %} +
    +
    + +To initialize a Spark Streaming program in Java, a +[`JavaStreamingContext`](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaStreamingContext) +object has to be created, which is the main entry point of all Spark Streaming functionality. +A `JavaStreamingContext` object can be created by using -The core Spark Streaming API provides input streams for files, sockets, and Akka actors. Additional functionality for Kafka, Flume, ZeroMQ, Twitter, etc. can be imported by adding the right dependencies as explained in the [linking](#linking-with-spark-streaming) section. +{% highlight scala %} +new JavaStreamingContext(master, appName, batchInterval, [sparkHome], [jars]) +{% endhighlight %} +
    +
    + +The `master` parameter is a standard [Spark cluster URL](scala-programming-guide.html#master-urls) +and can be "local" for local testing. The `appName` is a name of your program, +which will be shown on your cluster's web UI. The `batchInterval` is the size of the batches, +as explained earlier. Finally, the last two parameters are needed to deploy your code to a cluster + if running in distributed mode, as described in the + [Spark programming guide](scala-programming-guide.html#deploying-code-on-a-cluster). + Additionally, the underlying SparkContext can be accessed as +`streamingContext.sparkContext`. + +The batch interval must be set based on the latency requirements of your application +and available cluster resources. See the [Performance Tuning](#setting-the-right-batch-size) +section for more details. + +## DStreams +*Discretized Stream* or *DStream* is the basic abstraction provided by Spark Streaming. +It represents a continuous stream of data, either the input data stream received from source, +or the processed data stream generated by transforming the input stream. Internally, +it is represented by a continuous sequence of RDDs, which is Spark's abstraction of an immutable, +distributed dataset. Each RDD in a DStream contains data from a certain interval, +as shown in the following figure. + +

    + Spark Streaming +

    + +Any operation applied on a DStream translates to operations on the underlying RDDs. For example, +in the [earlier example](#a-quick-example) of converting a stream of lines to words, +the `flatmap` operation is applied on each RDD in the `lines` DStream to generate the RDDs of the + `words` DStream. This is shown the following figure. + +

    + Spark Streaming +

    + + +These underlying RDD transformations are computed by the Spark engine. The DStream operations +hide most of these details and provides the developer with higher-level API for convenience. +These operations are discussed in detail in later sections. + +## Input Sources + +We have already taken a look at the `streamingContext.socketTextStream(...)` in the [quick +example](#a-quick-example) which creates a DStream from text +data received over a TCP socket connection. Besides sockets, the core Spark Streaming API provides +methods for creating DStreams from files and Akka actors as input sources. + +Specifically, for files, the DStream can be created as + +
    +
    +{% highlight scala %} +streamingContext.fileStream(dataDirectory) +{% endhighlight %} +
    +
    +{% highlight java %} +javaStreamingContext.fileStream(dataDirectory); +{% endhighlight %} +
    +
    + +Spark Streaming will monitor the directory `dataDirectory` for any Hadoop-compatible filesystem +and process any files created in that directory. Note that + + * The files must have the same data format. + * The files must be created in the `dataDirectory` by atomically *moving* or *renaming* them into + the data directory. + * Once moved the files must not be changed. + +For more details on streams from files, Akka actors and sockets, +see the API documentations of the relevant functions in +[StreamingContext](api/streaming/index.html#org.apache.spark.streaming.StreamingContext) for +Scala and [JavaStreamingContext](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaStreamingContext) + for Java. + +Additional functionality for creating DStreams from sources such as Kafka, Flume, and Twitter +can be imported by adding the right dependencies as explained in an +[earlier](#linking) section. To take the +case of Kafka, after adding the artifact `spark-streaming-kafka_{{site.SCALA_VERSION}}` to the +project dependencies, you can create a DStream from Kafka as + +
    +
    +{% highlight scala %} +import org.apache.spark.streaming.kafka._ +KafkaUtils.createStream(streamingContext, kafkaParams, ...) +{% endhighlight %} +
    +
    +{% highlight java %} +import org.apache.spark.streaming.kafka.* +KafkaUtils.createStream(javaStreamingContext, kafkaParams, ...); +{% endhighlight %} +
    +
    -# DStream Operations -Data received from the input streams can be processed using _DStream operations_. There are two kinds of operations - _transformations_ and _output operations_. Similar to RDD transformations, DStream transformations operate on one or more DStreams to create new DStreams with transformed data. After applying a sequence of transformations to the input streams, output operations need to called, which write data out to an external data sink like a file system or a database. +For more details on these additional sources, see the corresponding [API documentation] +(#where-to-go-from-here). Furthermore, you can also implement your own custom receiver +for your sources. See the [Custom Receiver Guide](streaming-custom-receivers.html). -## Transformations +## Operations +There are two kinds of DStream operations - _transformations_ and _output operations_. Similar to +RDD transformations, DStream transformations operate on one or more DStreams to create new DStreams +with transformed data. After applying a sequence of transformations to the input streams, output +operations need to called, which write data out to an external data sink, such as a filesystem or a +database. -DStreams support many of the transformations available on normal Spark RDD's: +### Transformations +DStreams support many of the transformations available on normal Spark RDD's. Some of the +common ones are as follows. - + - - - - - + - + - - + + @@ -82,329 +465,681 @@ DStreams support many of the transformations available on normal Spark RDD's: - + - + - + - - - - - + - + - + - + - + - - - -
    TransformationMeaning
    TransformationMeaning
    map(func) Returns a new DStream formed by passing each element of the source DStream through a function func.
    filter(func) Returns a new DStream formed by selecting those elements of the source DStream on which func returns true. Return a new DStream by passing each element of the source DStream through a + function func.
    flatMap(func) Similar to map, but each input item can be mapped to 0 or more output items (so func should return a Seq rather than a single item). Similar to map, but each input item can be mapped to 0 or more output items.
    mapPartitions(func) Similar to map, but runs separately on each partition (block) of the DStream, so func must be of type - Iterator[T] => Iterator[U] when running on an DStream of type T. filter(func) Return a new DStream by selecting only the records of the source DStream on which + func returns true.
    repartition(numPartitions)
    union(otherStream) Return a new DStream that contains the union of the elements in the source DStream and the argument DStream. Return a new DStream that contains the union of the elements in the source DStream and + otherDStream.
    count() Returns a new DStream of single-element RDDs by counting the number of elements in each RDD of the source DStream. Return a new DStream of single-element RDDs by counting the number of elements in each RDD + of the source DStream.
    reduce(func) Returns a new DStream of single-element RDDs by aggregating the elements in each RDD of the source DStream using a function func (which takes two arguments and returns one). The function should be associative so that it can be computed in parallel. Return a new DStream of single-element RDDs by aggregating the elements in each RDD of the + source DStream using a function func (which takes two arguments and returns one). + The function should be associative so that it can be computed in parallel.
    countByValue() When called on a DStream of elements of type K, returns a new DStream of (K, Long) pairs where the value of each key is its frequency in each RDD of the source DStream.
    groupByKey([numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, Seq[V]) pairs by grouping together all the values of each key in the RDDs of the source DStream.
    - Note: By default, this uses Spark's default number of parallel tasks (2 for local machine, 8 for a cluster) to do the grouping. You can pass an optional numTasks argument to set a different number of tasks. -
    When called on a DStream of elements of type K, return a new DStream of (K, Long) pairs + where the value of each key is its frequency in each RDD of the source DStream.
    reduceByKey(func, [numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, V) pairs where the values for each key are aggregated using the given reduce function. Like in groupByKey, the number of reduce tasks is configurable through an optional second argument. When called on a DStream of (K, V) pairs, return a new DStream of (K, V) pairs where the + values for each key are aggregated using the given reduce function. Note: By default, + this uses Spark's default number of parallel tasks (2 for local machine, 8 for a cluster) to + do the grouping. You can pass an optional numTasks argument to set a different + number of tasks.
    join(otherStream, [numTasks]) When called on two DStreams of (K, V) and (K, W) pairs, returns a new DStream of (K, (V, W)) pairs with all pairs of elements for each key. When called on two DStreams of (K, V) and (K, W) pairs, return a new DStream of (K, (V, W)) + pairs with all pairs of elements for each key.
    cogroup(otherStream, [numTasks]) When called on DStream of (K, V) and (K, W) pairs, returns a new DStream of (K, Seq[V], Seq[W]) tuples. When called on DStream of (K, V) and (K, W) pairs, return a new DStream of + (K, Seq[V], Seq[W]) tuples.
    transform(func) Returns a new DStream by applying func (a RDD-to-RDD function) to every RDD of the stream. This can be used to do arbitrary RDD operations on the DStream. Return a new DStream by applying a RDD-to-RDD function to every RDD of the source DStream. + This can be used to do arbitrary RDD operations on the DStream.
    updateStateByKey(func) Return a new "state" DStream where the state for each key is updated by applying the given function on the previous state of the key and the new values of each key. This can be used to track session state by using the session-id as the key and updating the session state as new data is received.
    - -Spark Streaming features windowed computations, which allow you to apply transformations over a sliding window of data. All window functions take a windowDuration, which represents the width of the window and a slideTime, which represents the frequency during which the window is calculated. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
    TransformationMeaning
    window(windowDuration, slideDuration) Return a new DStream which is computed based on windowed batches of the source DStream. windowDuration is the width of the window and slideTime is the frequency during which the window is calculated. Both times must be multiples of the batch interval. -
    countByWindow(windowDuration, slideDuration) Return a sliding count of elements in the stream. windowDuration and slideDuration are exactly as defined in window(). -
    reduceByWindow(func, windowDuration, slideDuration) Return a new single-element stream, created by aggregating elements in the stream over a sliding interval using func. The function should be associative so that it can be computed correctly in parallel. windowDuration and slideDuration are exactly as defined in window(). -
    groupByKeyAndWindow(windowDuration, slideDuration, [numTasks]) - When called on a DStream of (K, V) pairs, returns a new DStream of (K, Seq[V]) pairs by grouping together values of each key over batches in a sliding window.
    -Note: By default, this uses Spark's default number of parallel tasks (2 for local machine, 8 for a cluster) to do the grouping. You can pass an optional numTasks argument to set a different number of tasks.
    reduceByKeyAndWindow(func, windowDuration, slideDuration, [numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, V) pairs where the values for each key are aggregated using the given reduce function func over batches in a sliding window. Like in groupByKeyAndWindow, the number of reduce tasks is configurable through an optional second argument. - windowDuration and slideDuration are exactly as defined in window(). -
    reduceByKeyAndWindow(func, invFunc, windowDuration, slideDuration, [numTasks]) A more efficient version of the above reduceByKeyAndWindow() where the reduce value of each window is calculated - incrementally using the reduce values of the previous window. This is done by reducing the new data that enter the sliding window, and "inverse reducing" the old data that leave the window. An example would be that of "adding" and "subtracting" counts of keys as the window slides. However, it is applicable to only "invertible reduce functions", that is, those reduce functions which have a corresponding "inverse reduce" function (taken as parameter invFunc. Like in groupByKeyAndWindow, the number of reduce tasks is configurable through an optional second argument. - windowDuration and slideDuration are exactly as defined in window(). -
    countByValueAndWindow(windowDuration, slideDuration, [numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, Long) pairs where the value of each key is its frequency within a sliding window. Like in groupByKeyAndWindow, the number of reduce tasks is configurable through an optional second argument. - windowDuration and slideDuration are exactly as defined in window(). - Return a new "state" DStream where the state for each key is updated by applying the + given function on the previous state of the key and the new values for the key. This can be + used to maintain arbitrary state data for each ket.
    -A complete list of DStream operations is available in the API documentation of [DStream](api/streaming/index.html#org.apache.spark.streaming.dstream.DStream) and [PairDStreamFunctions](api/streaming/index.html#org.apache.spark.streaming.dstream.PairDStreamFunctions). +The last two transformations are worth highlighting again. -## Output Operations -When an output operator is called, it triggers the computation of a stream. Currently the following output operators are defined: +

    UpdateStateByKey Operation

    - - - - - - +The `updateStateByKey` operation allows +you to main arbitrary stateful computation, where you want to maintain some state data and +continuously update it with new information. To use this, you will have to do two steps. - - - - +1. Define the state - The state can be of arbitrary data type. +1. Define the state update function - Specify with a function how to update the state using the +previous state and the new values from input stream. - - - - +Let's illustrate this with an example. Say you want to maintain a running count of each word +seen in a text data stream. Here, the running count is the state and it is an integer. We +define the update function as - - - - +
    +
    -
    - - - +{% highlight scala %} +def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = { + val newCount = ... // add the new values with the previous running count to get the new count + Some(newCount) +} +{% endhighlight %} -
    OperatorMeaning
    foreachRDD(func) The fundamental output operator. Applies a function, func, to each RDD generated from the stream. This function should have side effects, such as printing output, saving the RDD to external files, or writing it over the network to an external system.
    print() Prints first ten elements of every batch of data in a DStream on the driver.
    saveAsObjectFiles(prefix, [suffix]) Save this DStream's contents as a SequenceFile of serialized objects. The file name at each batch interval is generated based on prefix and suffix: "prefix-TIME_IN_MS[.suffix]". -
    saveAsTextFiles(prefix, [suffix]) Save this DStream's contents as a text files. The file name at each batch interval is generated based on prefix and suffix: "prefix-TIME_IN_MS[.suffix]".
    saveAsHadoopFiles(prefix, [suffix]) Save this DStream's contents as a Hadoop file. The file name at each batch interval is generated based on prefix and suffix: "prefix-TIME_IN_MS[.suffix]".
    +This is applied on a DStream containing words (say, the `pairs` DStream containing `(word, +1)` pairs in the [earlier example](#a-quick-example)). -# Starting the Streaming computation -All the above DStream operations are completely lazy, that is, the operations will start executing only after the context is started by using {% highlight scala %} -ssc.start() +val runningCounts = pairs.updateStateByKey[Int](updateFunction _) {% endhighlight %} -Conversely, the computation can be stopped by using -{% highlight scala %} -ssc.stop() + +
    + +{% highlight java %} +Function2, Optional, Optional> updateFunction = + new Function2, Optional, Optional>() { + @Override public Optional call(List values, Optional state) { + Integer newSum = ... // add the new values with the previous running count to get the new count + return Optional.of(newSum) + } + } {% endhighlight %} -# Example -A simple example to start off is the [NetworkWordCount](https://github.com/apache/incubator-spark/tree/master/examples/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala). This example counts the words received from a network server every second. Given below is the relevant sections of the source code. You can find the full source code in `/streaming/src/main/scala/org/apache/spark/streaming/examples/NetworkWordCount.scala` . +This is applied on a DStream containing words (say, the `pairs` DStream containing `(word, +1)` pairs in the [quick example](#a-quick-example)). -{% highlight scala %} -import org.apache.spark.streaming.{Seconds, StreamingContext} -import StreamingContext._ -... +{% highlight java %} +JavaPairDStream runningCounts = pairs.updateStateByKey(updateFunction); +{% endhighlight %} -// Create the context and set up a network input stream to receive from a host:port -val ssc = new StreamingContext(args(0), "NetworkWordCount", Seconds(1)) -val lines = ssc.socketTextStream(args(1), args(2).toInt) +
    + -// Split the lines into words, count them, and print some of the counts on the master -val words = lines.flatMap(_.split(" ")) -val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _) -wordCounts.print() +The update function will be called for each word, with `newValues` having a sequence of 1's (from +the `(word, 1)` pairs) and the `runningCount` having the previous count. For the complete +Scala code, take a look at the example +[StatefulNetworkWordCount]({{site.SPARK_GITHUB_URL}}/blob/master/examples/src/main/scala/org/apache/spark/streaming/examples/StatefulNetworkWordCount.scala). -// Start the computation -ssc.start() -{% endhighlight %} +

    Transform Operation

    -The `socketTextStream` returns a DStream of text data received from a TCP server socket. The `lines` DStream is _transformed_ into a DStream using the `flatMap` operation, where each line is split into words. This `words` DStream is then mapped to a DStream of `(word, 1)` pairs, which is finally reduced to get the word counts. `wordCounts.print()` will print 10 of the counts generated every second. +The `transform` operation (along with its variations like `transformWith`) allows +arbitrary RDD-to-RDD functions to be applied on a DStream. It can be used to apply any RDD +operation that is not exposed in the DStream API. +For example, the functionality of joining every batch in a data stream +with another dataset is not directly exposed in the DStream API. However, +you can easily use `transform` to do this. This enables very powerful possibilities. For example, +if you want to do real-time data cleaning by joining the input data stream with precomputed +spam information (maybe generated with Spark as well) and then filtering based on it. -To run this example on your local machine, you need to first run a Netcat server by using +
    +
    -{% highlight bash %} -$ nc -lk 9999 +{% highlight scala %} +val spamInfoRDD = sparkContext.hadoopFile(...) // RDD containing spam information + +val cleanedDStream = inputDStream.transform(rdd => { + rdd.join(spamInfoRDD).filter(...) // join data stream with spam information to do data cleaning + ... +}) {% endhighlight %} -Then, in a different terminal, you can start NetworkWordCount by using +
    +
    -{% highlight bash %} -$ ./bin/run-example org.apache.spark.streaming.examples.NetworkWordCount local[2] localhost 9999 +{% highlight java %} +// RDD containing spam information +JavaPairRDD spamInfoRDD = javaSparkContext.hadoopFile(...); + +JavaPairDStream cleanedDStream = inputDStream.transform( + new Function, JavaPairRDD>() { + @Override public JavaPairRDD call(JavaPairRDD rdd) throws Exception { + rdd.join(spamInfoRDD).filter(...) // join data stream with spam information to do data cleaning + ... + } + }); {% endhighlight %} -This will make NetworkWordCount connect to the netcat server. Any lines typed in the terminal running the netcat server will be counted and printed on screen. +
    +
    - - - -
    -{% highlight bash %} -# TERMINAL 1 -# RUNNING NETCAT +In fact, you can also use [machine learning](mllib-guide.html) and +[graph computation](graphx-programming-guide.html) algorithms in the `transform` method. -$ nc -lk 9999 -hello world +

    Window Operations

    +Finally, Spark Streaming also provides *windowed computations*, which allow you to apply +transformations over a sliding window of data. This following figure illustrates this sliding +window. +

    + Spark Streaming +

    +As shown in the figure, every time the window *slides* over a source DStream, +the source RDDs that fall within the window are combined and operated upon to produce the +RDDs of the windowed DStream. In this specific case, the operation is applied over last 3 time +units of data, and slides by 2 time units. This shows that any window-based operation needs to +specify two parameters. + * window length - The duration of the window (3 in the figure) + * slide interval - The interval at which the window-based operation is performed (2 in + the figure). -... +These two parameters must be multiples of the batch interval of the source DStream (1 in the +figure). + +Let's illustrate the window operations with an example. Say, you want to extend the +[earlier example](#a-quick-example) by generating word counts over last 30 seconds of data, +every 10 seconds. To do this, we have to apply the `reduceByKey` operation on the `pairs` DStream of +`(word, 1)` pairs over the last 30 seconds of data. This is done using the +operation `reduceByKeyAndWindow`. + +
    +
    + +{% highlight scala %} +// Reduce last 30 seconds of data, every 10 seconds +val windowedWordCounts = pairs.reduceByKeyAndWindow(_ + _, Seconds(30), Seconds(10)) {% endhighlight %} -
    -{% highlight bash %} -# TERMINAL 2: RUNNING NetworkWordCount -... -------------------------------------------- -Time: 1357008430000 ms -------------------------------------------- -(hello,1) -(world,1) -... + +
    + +{% highlight java %} +// Reduce function adding two integers, defined separately for clarity +Function2 reduceFunc = new Function2() { + @Override public Integer call(Integer i1, Integer i2) throws Exception { + return i1 + i2; + } +}; + +// Reduce last 30 seconds of data, every 10 seconds +JavaPairDStream windowedWordCounts = pair.reduceByKeyAndWindow(reduceFunc, new Duration(30000), new Duration(10000)); {% endhighlight %} -
    -You can find more examples in `/streaming/src/main/scala/org/apache/spark/streaming/examples/`. They can be run in the similar manner using `./bin/run-example org.apache.spark.streaming.examples....` . Executing without any parameter would give the required parameter list. Further explanation to run them can be found in comments in the files. + + -# DStream Persistence -Similar to RDDs, DStreams also allow developers to persist the stream's data in memory. That is, using `persist()` method on a DStream would automatically persist every RDD of that DStream in memory. This is useful if the data in the DStream will be computed multiple times (e.g., multiple operations on the same data). For window-based operations like `reduceByWindow` and `reduceByKeyAndWindow` and state-based operations like `updateStateByKey`, this is implicitly true. Hence, DStreams generated by window-based operations are automatically persisted in memory, without the developer calling `persist()`. +Some of the common window-based operations are as follows. All of these operations take the +said two parameters - windowLength and slideInterval. -For input streams that receive data from the network (that is, subclasses of NetworkInputDStream like FlumeInputDStream and KafkaInputDStream), the default persistence level is set to replicate the data to two nodes for fault-tolerance. + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TransformationMeaning
    window(windowLength, slideInterval) Return a new DStream which is computed based on windowed batches of the source DStream. +
    countByWindow(windowLength, slideInterval) Return a sliding window count of elements in the stream. +
    reduceByWindow(func, windowLength, slideInterval) Return a new single-element stream, created by aggregating elements in the stream over a + sliding interval using func. The function should be associative so that it can be computed + correctly in parallel. +
    reduceByKeyAndWindow(func, windowLength, slideInterval, + [numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, V) + pairs where the values for each key are aggregated using the given reduce function func + over batches in a sliding window. Note: By default, this uses Spark's default number of + parallel tasks (2 for local machine, 8 for a cluster) to do the grouping. You can pass an optional + numTasks argument to set a different number of tasks. +
    reduceByKeyAndWindow(func, invFunc, windowLength, + slideInterval, [numTasks]) A more efficient version of the above reduceByKeyAndWindow() where the reduce + value of each window is calculated incrementally using the reduce values of the previous window. + This is done by reducing the new data that enter the sliding window, and "inverse reducing" the + old data that leave the window. An example would be that of "adding" and "subtracting" counts + of keys as the window slides. However, it is applicable to only "invertible reduce functions", + that is, those reduce functions which have a corresponding "inverse reduce" function (taken as + parameter invFunc. Like in reduceByKeyAndWindow, the number of reduce tasks + is configurable through an optional argument. +
    countByValueAndWindow(windowLength, + slideInterval, [numTasks]) When called on a DStream of (K, V) pairs, returns a new DStream of (K, Long) pairs where the + value of each key is its frequency within a sliding window. Like in + reduceByKeyAndWindow, the number of reduce tasks is configurable through an + optional argument. +
    -Note that, unlike RDDs, the default persistence level of DStreams keeps the data serialized in memory. This is further discussed in the [Performance Tuning](#memory-tuning) section. More information on different persistence levels can be found in [Spark Programming Guide](scala-programming-guide.html#rdd-persistence). +### Output Operations +When an output operator is called, it triggers the computation of a stream. Currently the following +output operators are defined: -# RDD Checkpointing within DStreams -A _stateful operation_ is one which operates over multiple batches of data. This includes all window-based operations and the `updateStateByKey` operation. + + + + + + + + + + + + + + + + + + + + + + + +
    Output OperationMeaning
    print() Prints first ten elements of every batch of data in a DStream on the driver.
    foreachRDD(func) The fundamental output operator. Applies a function, func, to each RDD generated from + the stream. This function should have side effects, such as printing output, saving the RDD to + external files, or writing it over the network to an external system.
    saveAsObjectFiles(prefix, [suffix]) Save this DStream's contents as a SequenceFile of serialized objects. The file + name at each batch interval is generated based on prefix and + suffix: "prefix-TIME_IN_MS[.suffix]". +
    saveAsTextFiles(prefix, [suffix]) Save this DStream's contents as a text files. The file name at each batch interval is + generated based on prefix and suffix: "prefix-TIME_IN_MS[.suffix]".
    saveAsHadoopFiles(prefix, [suffix]) Save this DStream's contents as a Hadoop file. The file name at each batch interval is + generated based on prefix and suffix: "prefix-TIME_IN_MS[.suffix]".
    -Because stateful operations have a dependency on previous batches of data, they continuously accumulate metadata over time. To clear this metadata, streaming supports periodic _checkpointing_ by saving intermediate data to HDFS. Note that checkpointing also incurs the cost of saving to HDFS which may cause the corresponding batch to take longer to process. Hence, the interval of checkpointing needs to be set carefully. At small batch sizes (say 1 second), checkpointing every batch may significantly reduce operation throughput. Conversely, checkpointing too slowly causes the lineage and task sizes to grow which may have detrimental effects. Typically, a checkpoint interval of 5 - 10 times of sliding interval of a DStream is good setting to try. -To enable checkpointing, the developer has to provide the HDFS path to which RDD will be saved. This is done by using +The complete list of DStream operations is available in the API documentation. For the Scala API, +see [DStream](api/streaming/index.html#org.apache.spark.streaming.dstream.DStream) +and [PairDStreamFunctions](api/streaming/index.html#org.apache.spark.streaming.dstream.PairDStreamFunctions). +For the Java API, see [JavaDStream](api/streaming/index.html#org.apache.spark.streaming.api.java.dstream.DStream) +and [JavaPairDStream](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaPairDStream). +Specifically for the Java API, see [Spark's Java programming guide](java-programming-guide.html) +for more information. + +## Persistence +Similar to RDDs, DStreams also allow developers to persist the stream's data in memory. That is, +using `persist()` method on a DStream would automatically persist every RDD of that DStream in +memory. This is useful if the data in the DStream will be computed multiple times (e.g., multiple +operations on the same data). For window-based operations like `reduceByWindow` and +`reduceByKeyAndWindow` and state-based operations like `updateStateByKey`, this is implicitly true. +Hence, DStreams generated by window-based operations are automatically persisted in memory, without +the developer calling `persist()`. + +For input streams that receive data over the network (such as, Kafka, Flume, sockets, etc.), the +default persistence level is set to replicate the data to two nodes for fault-tolerance. + +Note that, unlike RDDs, the default persistence level of DStreams keeps the data serialized in +memory. This is further discussed in the [Performance Tuning](#memory-tuning) section. More +information on different persistence levels can be found in +[Spark Programming Guide](scala-programming-guide.html#rdd-persistence). + +## RDD Checkpointing +A _stateful operation_ is one which operates over multiple batches of data. This includes all +window-based operations and the `updateStateByKey` operation. Since stateful operations have a +dependency on previous batches of data, they continuously accumulate metadata over time. +To clear this metadata, streaming supports periodic _checkpointing_ by saving intermediate data +to HDFS. Note that checkpointing also incurs the cost of saving to HDFS which may cause the +corresponding batch to take longer to process. Hence, the interval of checkpointing needs to be +set carefully. At small batch sizes (say 1 second), checkpointing every batch may significantly +reduce operation throughput. Conversely, checkpointing too slowly causes the lineage and task +sizes to grow which may have detrimental effects. Typically, a checkpoint interval of 5 - 10 +times of sliding interval of a DStream is good setting to try. + +To enable checkpointing, the developer has to provide the HDFS path to which RDD will be saved. +This is done by using {% highlight scala %} -ssc.checkpoint(hdfsPath) // assuming ssc is the StreamingContext +ssc.checkpoint(hdfsPath) // assuming ssc is the StreamingContext or JavaStreamingContext {% endhighlight %} The interval of checkpointing of a DStream can be set by using {% highlight scala %} -dstream.checkpoint(checkpointInterval) // checkpointInterval must be a multiple of slide duration of dstream +dstream.checkpoint(checkpointInterval) {% endhighlight %} -For DStreams that must be checkpointed (that is, DStreams created by `updateStateByKey` and `reduceByKeyAndWindow` with inverse function), the checkpoint interval of the DStream is by default set to a multiple of the DStream's sliding interval such that its at least 10 seconds. - +For DStreams that must be checkpointed (that is, DStreams created by `updateStateByKey` and +`reduceByKeyAndWindow` with inverse function), the checkpoint interval of the DStream is by +default set to a multiple of the DStream's sliding interval such that its at least 10 seconds. -## Custom Receivers -Spark comes with a built in support for most common usage scenarios where input stream source can be either a network socket stream to support for a few message queues. Apart from that it is also possible to supply your own custom receiver via a convenient API. Find more details at [Custom Receiver Guide](streaming-custom-receivers.html). +*************************************************************************************************** # Performance Tuning -Getting the best performance of a Spark Streaming application on a cluster requires a bit of tuning. This section explains a number of the parameters and configurations that can tuned to improve the performance of you application. At a high level, you need to consider two things: +Getting the best performance of a Spark Streaming application on a cluster requires a bit of +tuning. This section explains a number of the parameters and configurations that can tuned to +improve the performance of you application. At a high level, you need to consider two things: +
      -
    1. Reducing the processing time of each batch of data by efficiently using cluster resources.
    2. -
    3. Setting the right batch size such that the data processing can keep up with the data ingestion.
    4. +
    5. + Reducing the processing time of each batch of data by efficiently using cluster resources. +
    6. +
    7. + Setting the right batch size such that the data processing can keep up with the data ingestion. +
    ## Reducing the Processing Time of each Batch -There are a number of optimizations that can be done in Spark to minimize the processing time of each batch. These have been discussed in detail in [Tuning Guide](tuning.html). This section highlights some of the most important ones. +There are a number of optimizations that can be done in Spark to minimize the processing time of +each batch. These have been discussed in detail in [Tuning Guide](tuning.html). This section +highlights some of the most important ones. ### Level of Parallelism -Cluster resources maybe under-utilized if the number of parallel tasks used in any stage of the computation is not high enough. For example, for distributed reduce operations like `reduceByKey` and `reduceByKeyAndWindow`, the default number of parallel tasks is 8. You can pass the level of parallelism as an argument (see the [`PairDStreamFunctions`](api/streaming/index.html#org.apache.spark.PairDStreamFunctions) documentation), or set the [config property](configuration.html#spark-properties) `spark.default.parallelism` to change the default. +Cluster resources maybe under-utilized if the number of parallel tasks used in any stage of the +computation is not high enough. For example, for distributed reduce operations like `reduceByKey` +and `reduceByKeyAndWindow`, the default number of parallel tasks is 8. You can pass the level of +parallelism as an argument (see the +[`PairDStreamFunctions`](api/streaming/index.html#org.apache.spark.streaming.dstream.PairDStreamFunctions) +documentation), or set the [config property](configuration.html#spark-properties) +`spark.default.parallelism` to change the default. ### Data Serialization -The overhead of data serialization can be significant, especially when sub-second batch sizes are to be achieved. There are two aspects to it. +The overhead of data serialization can be significant, especially when sub-second batch sizes are + to be achieved. There are two aspects to it. -* **Serialization of RDD data in Spark**: Please refer to the detailed discussion on data serialization in the [Tuning Guide](tuning.html). However, note that unlike Spark, by default RDDs are persisted as serialized byte arrays to minimize pauses related to GC. +* **Serialization of RDD data in Spark**: Please refer to the detailed discussion on data + serialization in the [Tuning Guide](tuning.html). However, note that unlike Spark, by default + RDDs are persisted as serialized byte arrays to minimize pauses related to GC. -* **Serialization of input data**: To ingest external data into Spark, data received as bytes (say, from the network) needs to deserialized from bytes and re-serialized into Spark's serialization format. Hence, the deserialization overhead of input data may be a bottleneck. +* **Serialization of input data**: To ingest external data into Spark, data received as bytes + (say, from the network) needs to deserialized from bytes and re-serialized into Spark's + serialization format. Hence, the deserialization overhead of input data may be a bottleneck. ### Task Launching Overheads -If the number of tasks launched per second is high (say, 50 or more per second), then the overhead of sending out tasks to the slaves maybe significant and will make it hard to achieve sub-second latencies. The overhead can be reduced by the following changes: +If the number of tasks launched per second is high (say, 50 or more per second), then the overhead +of sending out tasks to the slaves maybe significant and will make it hard to achieve sub-second +latencies. The overhead can be reduced by the following changes: -* **Task Serialization**: Using Kryo serialization for serializing tasks can reduced the task sizes, and therefore reduce the time taken to send them to the slaves. +* **Task Serialization**: Using Kryo serialization for serializing tasks can reduced the task + sizes, and therefore reduce the time taken to send them to the slaves. -* **Execution mode**: Running Spark in Standalone mode or coarse-grained Mesos mode leads to better task launch times than the fine-grained Mesos mode. Please refer to the [Running on Mesos guide](running-on-mesos.html) for more details. -These changes may reduce batch processing time by 100s of milliseconds, thus allowing sub-second batch size to be viable. +* **Execution mode**: Running Spark in Standalone mode or coarse-grained Mesos mode leads to + better task launch times than the fine-grained Mesos mode. Please refer to the + [Running on Mesos guide](running-on-mesos.html) for more details. -## Setting the Right Batch Size -For a Spark Streaming application running on a cluster to be stable, the processing of the data streams must keep up with the rate of ingestion of the data streams. Depending on the type of computation, the batch size used may have significant impact on the rate of ingestion that can be sustained by the Spark Streaming application on a fixed cluster resources. For example, let us consider the earlier WordCountNetwork example. For a particular data rate, the system may be able to keep up with reporting word counts every 2 seconds (i.e., batch size of 2 seconds), but not every 500 milliseconds. +These changes may reduce batch processing time by 100s of milliseconds, +thus allowing sub-second batch size to be viable. -A good approach to figure out the right batch size for your application is to test it with a conservative batch size (say, 5-10 seconds) and a low data rate. To verify whether the system is able to keep up with data rate, you can check the value of the end-to-end delay experienced by each processed batch (in the Spark master logs, find the line having the phrase "Total delay"). If the delay is maintained to be less than the batch size, then system is stable. Otherwise, if the delay is continuously increasing, it means that the system is unable to keep up and it therefore unstable. Once you have an idea of a stable configuration, you can try increasing the data rate and/or reducing the batch size. Note that momentary increase in the delay due to temporary data rate increases maybe fine as long as the delay reduces back to a low value (i.e., less than batch size). +## Setting the Right Batch Size +For a Spark Streaming application running on a cluster to be stable, the processing of the data +streams must keep up with the rate of ingestion of the data streams. Depending on the type of +computation, the batch size used may have significant impact on the rate of ingestion that can be +sustained by the Spark Streaming application on a fixed cluster resources. For example, let us +consider the earlier WordCountNetwork example. For a particular data rate, the system may be able +to keep up with reporting word counts every 2 seconds (i.e., batch size of 2 seconds), but not +every 500 milliseconds. + +A good approach to figure out the right batch size for your application is to test it with a +conservative batch size (say, 5-10 seconds) and a low data rate. To verify whether the system +is able to keep up with data rate, you can check the value of the end-to-end delay experienced +by each processed batch (either look for "Total delay" in Spark driver log4j logs, or use the +[StreamingListener](api/streaming/index.html#org.apache.spark.streaming.scheduler.StreamingListener) +interface). +If the delay is maintained to be comparable to the batch size, then system is stable. Otherwise, +if the delay is continuously increasing, it means that the system is unable to keep up and it +therefore unstable. Once you have an idea of a stable configuration, you can try increasing the +data rate and/or reducing the batch size. Note that momentary increase in the delay due to +temporary data rate increases maybe fine as long as the delay reduces back to a low value +(i.e., less than batch size). ## 24/7 Operation -By default, Spark does not forget any of the metadata (RDDs generated, stages processed, etc.). But for a Spark Streaming application to operate 24/7, it is necessary for Spark to do periodic cleanup of it metadata. This can be enabled by setting the [config property](configuration.html#spark-properties) `spark.cleaner.ttl` to the number of seconds you want any metadata to persist. For example, setting `spark.cleaner.ttl` to 600 would cause Spark periodically cleanup all metadata and persisted RDDs that are older than 10 minutes. Note, that this property needs to be set before the SparkContext is created. - -This value is closely tied with any window operation that is being used. Any window operation would require the input data to be persisted in memory for at least the duration of the window. Hence it is necessary to set the delay to at least the value of the largest window operation used in the Spark Streaming application. If this delay is set too low, the application will throw an exception saying so. +By default, Spark does not forget any of the metadata (RDDs generated, stages processed, etc.). +But for a Spark Streaming application to operate 24/7, it is necessary for Spark to do periodic +cleanup of it metadata. This can be enabled by setting the +[configuration property](configuration.html#spark-properties) `spark.cleaner.ttl` to the number of +seconds you want any metadata to persist. For example, setting `spark.cleaner.ttl` to 600 would +cause Spark periodically cleanup all metadata and persisted RDDs that are older than 10 minutes. +Note, that this property needs to be set before the SparkContext is created. + +This value is closely tied with any window operation that is being used. Any window operation +would require the input data to be persisted in memory for at least the duration of the window. +Hence it is necessary to set the delay to at least the value of the largest window operation used +in the Spark Streaming application. If this delay is set too low, the application will throw an +exception saying so. + +## Monitoring +Besides Spark's in-built [monitoring capabilities](monitoring.html), +the progress of a Spark Streaming program can also be monitored using the [StreamingListener] +(streaming/index.html#org.apache.spark.scheduler.StreamingListener) interface, +which allows you to get statistics of batch processing times, queueing delays, +and total end-to-end delays. Note that this is still an experimental API and it is likely to be +improved upon (i.e., more information reported) in the future. ## Memory Tuning -Tuning the memory usage and GC behavior of Spark applications have been discussed in great detail in the [Tuning Guide](tuning.html). It is recommended that you read that. In this section, we highlight a few customizations that are strongly recommended to minimize GC related pauses in Spark Streaming applications and achieving more consistent batch processing times. - -* **Default persistence level of DStreams**: Unlike RDDs, the default persistence level of DStreams serializes the data in memory (that is, [StorageLevel.MEMORY_ONLY_SER](api/core/index.html#org.apache.spark.storage.StorageLevel$) for DStream compared to [StorageLevel.MEMORY_ONLY](api/core/index.html#org.apache.spark.storage.StorageLevel$) for RDDs). Even though keeping the data serialized incurs a higher serialization overheads, it significantly reduces GC pauses. - -* **Concurrent garbage collector**: Using the concurrent mark-and-sweep GC further minimizes the variability of GC pauses. Even though concurrent GC is known to reduce the overall processing throughput of the system, its use is still recommended to achieve more consistent batch processing times. +Tuning the memory usage and GC behavior of Spark applications have been discussed in great detail +in the [Tuning Guide](tuning.html). It is recommended that you read that. In this section, +we highlight a few customizations that are strongly recommended to minimize GC related pauses +in Spark Streaming applications and achieving more consistent batch processing times. + +* **Default persistence level of DStreams**: Unlike RDDs, the default persistence level of DStreams +serializes the data in memory (that is, +[StorageLevel.MEMORY_ONLY_SER](api/core/index.html#org.apache.spark.storage.StorageLevel$) for +DStream compared to +[StorageLevel.MEMORY_ONLY](api/core/index.html#org.apache.spark.storage.StorageLevel$) for RDDs). +Even though keeping the data serialized incurs higher serialization/deserialization overheads, +it significantly reduces GC pauses. + +* **Clearing persistent RDDs**: By default, all persistent RDDs generated by Spark Streaming will + be cleared from memory based on Spark's in-built policy (LRU). If `spark.cleaner.ttl` is set, + then persistent RDDs that are older than that value are periodically cleared. As mentioned + [earlier](#operation), this needs to be careful set based on operations used in the Spark + Streaming program. However, a smarter unpersisting of RDDs can be enabled by setting the + [configuration property](configuration.html#spark-properties) `spark.streaming.unpersist` to + `true`. This makes the system to figure out which RDDs are not necessary to be kept around and + unpersists them. This is likely to reduce + the RDD memory usage of Spark, potentially improving GC behavior as well. + +* **Concurrent garbage collector**: Using the concurrent mark-and-sweep GC further +minimizes the variability of GC pauses. Even though concurrent GC is known to reduce the +overall processing throughput of the system, its use is still recommended to achieve more +consistent batch processing times. + +*************************************************************************************************** # Fault-tolerance Properties -In this section, we are going to discuss the behavior of Spark Streaming application in the event of a node failure. To understand this, let us remember the basic fault-tolerance properties of Spark's RDDs. +In this section, we are going to discuss the behavior of Spark Streaming application in the event +of a node failure. To understand this, let us remember the basic fault-tolerance properties of +Spark's RDDs. - 1. An RDD is an immutable, and deterministically re-computable, distributed dataset. Each RDD remembers the lineage of deterministic operations that were used on a fault-tolerant input dataset to create it. - 1. If any partition of an RDD is lost due to a worker node failure, then that partition can be re-computed from the original fault-tolerant dataset using the lineage of operations. + 1. An RDD is an immutable, deterministically re-computable, distributed dataset. Each RDD + remembers the lineage of deterministic operations that were used on a fault-tolerant input + dataset to create it. + 1. If any partition of an RDD is lost due to a worker node failure, then that partition can be + re-computed from the original fault-tolerant dataset using the lineage of operations. -Since all data transformations in Spark Streaming are based on RDD operations, as long as the input dataset is present, all intermediate data can recomputed. Keeping these properties in mind, we are going to discuss the failure semantics in more detail. +Since all data transformations in Spark Streaming are based on RDD operations, as long as the input +dataset is present, all intermediate data can recomputed. Keeping these properties in mind, we are +going to discuss the failure semantics in more detail. ## Failure of a Worker Node - There are two failure behaviors based on which input sources are used. -1. _Using HDFS files as input source_ - Since the data is reliably stored on HDFS, all data can re-computed and therefore no data will be lost due to any failure. -1. _Using any input source that receives data through a network_ - For network-based data sources like Kafka and Flume, the received input data is replicated in memory between nodes of the cluster (default replication factor is 2). So if a worker node fails, then the system can recompute the lost from the the left over copy of the input data. However, if the worker node where a network receiver was running fails, then a tiny bit of data may be lost, that is, the data received by the system but not yet replicated to other node(s). The receiver will be started on a different node and it will continue to receive data. - -Since all data is modeled as RDDs with their lineage of deterministic operations, any recomputation always leads to the same result. As a result, all DStream transformations are guaranteed to have _exactly-once_ semantics. That is, the final transformed result will be same even if there were was a worker node failure. However, output operations (like `foreachRDD`) have _at-least once_ semantics, that is, the transformed data may get written to an external entity more than once in the event of a worker failure. While this is acceptable for saving to HDFS using the `saveAs*Files` operations (as the file will simply get over-written by the same data), additional transactions-like mechanisms may be necessary to achieve exactly-once semantics for output operations. +1. _Using HDFS files as input source_ - Since the data is reliably stored on HDFS, all data can +re-computed and therefore no data will be lost due to any failure. +1. _Using any input source that receives data through a network_ - For network-based data sources +like Kafka and Flume, the received input data is replicated in memory between nodes of the cluster +(default replication factor is 2). So if a worker node fails, then the system can recompute the +lost from the the left over copy of the input data. However, if the worker node where a network +receiver was running fails, then a tiny bit of data may be lost, that is, the data received by +the system but not yet replicated to other node(s). The receiver will be started on a different +node and it will continue to receive data. + +Since all data is modeled as RDDs with their lineage of deterministic operations, any recomputation + always leads to the same result. As a result, all DStream transformations are guaranteed to have + _exactly-once_ semantics. That is, the final transformed result will be same even if there were + was a worker node failure. However, output operations (like `foreachRDD`) have _at-least once_ + semantics, that is, the transformed data may get written to an external entity more than once in + the event of a worker failure. While this is acceptable for saving to HDFS using the + `saveAs*Files` operations (as the file will simply get over-written by the same data), + additional transactions-like mechanisms may be necessary to achieve exactly-once semantics + for output operations. ## Failure of the Driver Node -A system that is required to operate 24/7 needs to be able tolerate the failure of the driver node as well. Spark Streaming does this by saving the state of the DStream computation periodically to a HDFS file, that can be used to restart the streaming computation in the event of a failure of the driver node. This checkpointing is enabled by setting a HDFS directory for checkpointing using `ssc.checkpoint()` as described [earlier](#rdd-checkpointing-within-dstreams). To elaborate, the following state is periodically saved to a file. +To allows a streaming application to operate 24/7, Spark Streaming allows a streaming computation +to be resumed even after the failure of the driver node. Spark Streaming periodically writes the +metadata information of the DStreams setup through the `StreamingContext` to a +HDFS directory (can be any Hadoop-compatible filesystem). This periodic +*checkpointing* can be enabled by setting a the checkpoint +directory using `ssc.checkpoint()` as described +[earlier](#rdd-checkpointing). On failure of the driver node, +the lost `StreamingContext` can be recovered from this information, and restarted. + +To allow a Spark Streaming program to be recoverable, it must be written in a way such that +it has the following behavior: -1. The DStream operator graph (input streams, output streams, etc.) -1. The configuration of each DStream (checkpoint interval, etc.) -1. The RDD checkpoint files of each DStream +1. When the program is being started for the first time, it will create a new StreamingContext, + set up all the streams and then call start(). +1. When the program is being restarted after failure, it will re-create a StreamingContext + from the checkpoint data in the checkpoint directory. -All this is periodically saved in the checkpoint directory. To recover, a new `StreamingContext` can be created with this directory by using +
    +
    + +This behavior is made simple by using `StreamingContext.getOrCreate`. This is used as follows. {% highlight scala %} -val ssc = new StreamingContext(checkpointDirectory) +// Function to create and setup a new StreamingContext +def functionToCreateContext(): StreamingContext = { + val ssc = new StreamingContext(...) // new context + val lines = ssc.socketTextStream(...) // create DStreams + ... + ssc.checkpoint(checkpointDirectory) // set checkpoint directory + ssc +} + +// Get StreaminContext from checkpoint data or create a new one +val context = StreamingContext.getOrCreate(checkpointDirectory, functionToCreateContext _) + +// Do additional setup on context that needs to be done, +// irrespective of whether it is being started or restarted +context. ... + +// Start the context +context.start() +context.awaitTermination() {% endhighlight %} -On calling `ssc.start()` on this new context, the following steps are taken by the system +If the `checkpointDirectory` exists, then the context will be recreated from the checkpoint data. +If the directory does not exist (i.e., running for the first time), +then the function `functionToCreateContext` will be called to create a new +context and set up the DStreams. See the Scala example +[RecoverableNetworkWordCount]({{site.SPARK_GITHUB_URL}}/tree/master/examples/src/main/scala/org/apache/spark/streaming/examples/RecoverableNetworkWordCount.scala). +This example appends the word counts of network data into a file. -1. Schedule the transformations and output operations for all the time steps between the time when the driver failed and when it last checkpointed. This is also done for those time steps that were previously scheduled but not processed due to the failure. This will make the system recompute all the intermediate data from the checkpointed RDD files, etc. -1. Restart the network receivers, if any, and continue receiving new data. +You can also explicitly create a `StreamingContext` from the checkpoint data and start the + computation by using `new StreamingContext(checkpointDirectory)`. -There are two different failure behaviors based on which input sources are used. +
    +
    + +This behavior is made simple by using `JavaStreamingContext.getOrCreate`. This is used as follows. + +{% highlight java %} +// Create a factory object that can create a and setup a new JavaStreamingContext +JavaStreamingContextFactory contextFactory = new JavaStreamingContextFactory() { + JavaStreamingContextFactory create() { + JavaStreamingContext jssc = new JavaStreamingContext(...); // new context + JavaDStream lines = jssc.socketTextStream(...); // create DStreams + ... + jssc.checkpoint(checkpointDirectory); // set checkpoint directory + return jssc; + } +}; + +// Get JavaStreamingContext from checkpoint data or create a new one +JavaStreamingContext context = JavaStreamingContext.getOrCreate(checkpointDirectory, contextFactory); + +// Do additional setup on context that needs to be done, +// irrespective of whether it is being started or restarted +context. ... + +// Start the context +context.start(); +context.awaitTermination(); +{% endhighlight %} -1. _Using HDFS files as input source_ - Since the data is reliably stored on HDFS, all data can re-computed and therefore no data will be lost due to any failure. -1. _Using any input source that receives data through a network_ - The received input data is replicated in memory to multiple nodes. Since, all the data in the Spark worker's memory is lost when the Spark driver fails, the past input data will not be accessible and driver recovers. Hence, if stateful and window-based operations are used (like `updateStateByKey`, `window`, `countByValueAndWindow`, etc.), then the intermediate state will not be recovered completely. +If the `checkpointDirectory` exists, then the context will be recreated from the checkpoint data. +If the directory does not exist (i.e., running for the first time), +then the function `contextFactory` will be called to create a new +context and set up the DStreams. See the Scala example +[JavaRecoverableWordCount]({{site.SPARK_GITHUB_URL}}/tree/master/examples/src/main/scala/org/apache/spark/streaming/examples/JavaRecoverableWordCount.scala) +(note that this example is missing in the 0.9 release, so you can test it using the master branch). +This example appends the word counts of network data into a file. + +You can also explicitly create a `JavaStreamingContext` from the checkpoint data and start +the computation by using `new JavaStreamingContext(checkpointDirectory)`. + +
    +
    + +**Note**: If Spark Streaming and/or the Spark Streaming program is recompiled, +you *must* create a new `StreamingContext` or `JavaStreamingContext`, +not recreate from checkpoint data. This is because trying to load a +context from checkpoint data may fail if the data was generated before recompilation of the +classes. So, if you are using `getOrCreate`, then make sure that the checkpoint directory is +explicitly deleted every time recompiled code needs to be launched. + +This failure recovery can be done automatically using Spark's +[standalone cluster mode](spark-standalone.html), which allows any Spark +application's driver to be as well as, ensures automatic restart of the driver on failure (see +[supervise mode](spark-standalone.html#launching-applications-inside-the-cluster)). This can be +tested locally by launching the above example using the supervise mode in a +local standalone cluster and killing the java process running the driver (will be shown as +*DriverWrapper* when `jps` is run to show all active Java processes). The driver should be +automatically restarted, and the word counts will cont + +For other deployment environments like Mesos and Yarn, you have to restart the driver through other +mechanisms. + +

    Recovery Semantics

    -In future releases, we will support full recoverability for all input sources. Note that for non-stateful transformations like `map`, `count`, and `reduceByKey`, with _all_ input streams, the system, upon restarting, will continue to receive and process new data. +There are two different failure behaviors based on which input sources are used. -To better understand the behavior of the system under driver failure with a HDFS source, lets consider what will happen with a file input stream Specifically, in the case of the file input stream, it will correctly identify new files that were created while the driver was down and process them in the same way as it would have if the driver had not failed. To explain further in the case of file input stream, we shall use an example. Lets say, files are being generated every second, and a Spark Streaming program reads every new file and output the number of lines in the file. This is what the sequence of outputs would be with and without a driver failure. +1. _Using HDFS files as input source_ - Since the data is reliably stored on HDFS, all data can +re-computed and therefore no data will be lost due to any failure. +1. _Using any input source that receives data through a network_ - The received input data is +replicated in memory to multiple nodes. Since, all the data in the Spark worker's memory is lost +when the Spark driver fails, the past input data will not be accessible and driver recovers. +Hence, if stateful and window-based operations are used +(like `updateStateByKey`, `window`, `countByValueAndWindow`, etc.), then the intermediate state +will not be recovered completely. + +In future releases, we will support full recoverability for all input sources. Note that for +non-stateful transformations like `map`, `count`, and `reduceByKey`, with _all_ input streams, +the system, upon restarting, will continue to receive and process new data. + +To better understand the behavior of the system under driver failure with a HDFS source, lets +consider what will happen with a file input stream. Specifically, in the case of the file input +stream, it will correctly identify new files that were created while the driver was down and +process them in the same way as it would have if the driver had not failed. To explain further +in the case of file input stream, we shall use an example. Lets say, files are being generated +every second, and a Spark Streaming program reads every new file and output the number of lines +in the file. This is what the sequence of outputs would be with and without a driver failure. @@ -476,58 +1211,21 @@ To better understand the behavior of the system under driver failure with a HDFS
    -If the driver had crashed in the middle of the processing of time 3, then it will process time 3 and output 30 after recovery. - -# Java API - -Similar to [Spark's Java API](java-programming-guide.html), we also provide a Java API for Spark Streaming which allows all its features to be accessible from a Java program. This is defined in [org.apache.spark.streaming.api.java] (api/streaming/index.html#org.apache.spark.streaming.api.java.package) package and includes [JavaStreamingContext](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaStreamingContext) and [JavaDStream](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaDStream) classes that provide the same methods as their Scala counterparts, but take Java functions (that is, Function, and Function2) and return Java data and collection types. Some of the key points to note are: - -1. Functions for transformations must be implemented as subclasses of [Function](api/core/index.html#org.apache.spark.api.java.function.Function) and [Function2](api/core/index.html#org.apache.spark.api.java.function.Function2) -1. Unlike the Scala API, the Java API handles DStreams for key-value pairs using a separate [JavaPairDStream](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaPairDStream) class(similar to [JavaRDD and JavaPairRDD](java-programming-guide.html#rdd-classes). DStream functions like `map` and `filter` are implemented separately by JavaDStreams and JavaPairDStream to return DStreams of appropriate types. - -Spark's [Java Programming Guide](java-programming-guide.html) gives more ideas about using the Java API. To extends the ideas presented for the RDDs to DStreams, we present parts of the Java version of the same NetworkWordCount example presented above. The full source code is given at `/examples/src/main/java/org/apache/spark/streaming/examples/JavaNetworkWordCount.java` - -The streaming context and the socket stream from input source is started by using a `JavaStreamingContext`, that has the same parameters and provides the same input streams as its Scala counterpart. - -{% highlight java %} -JavaStreamingContext ssc = new JavaStreamingContext(mesosUrl, "NetworkWordCount", Seconds(1)); -JavaDStream lines = ssc.socketTextStream(ip, port); -{% endhighlight %} - - -Then the `lines` are split into words by using the `flatMap` function and [FlatMapFunction](api/core/index.html#org.apache.spark.api.java.function.FlatMapFunction). - -{% highlight java %} -JavaDStream words = lines.flatMap( - new FlatMapFunction() { - @Override - public Iterable call(String x) { - return Lists.newArrayList(x.split(" ")); - } - }); -{% endhighlight %} - -The `words` is then mapped to a [JavaPairDStream](api/streaming/index.html#org.apache.spark.streaming.api.java.JavaPairDStream) of `(word, 1)` pairs using `map` and [PairFunction](api/core/index.html#org.apache.spark.api.java.function.PairFunction). This is reduced by using `reduceByKey` and [Function2](api/core/index.html#org.apache.spark.api.java.function.Function2). - -{% highlight java %} -JavaPairDStream wordCounts = words.map( - new PairFunction() { - @Override - public Tuple2 call(String s) throws Exception { - return new Tuple2(s, 1); - } - }).reduceByKey( - new Function2() { - @Override - public Integer call(Integer i1, Integer i2) throws Exception { - return i1 + i2; - } - }); -{% endhighlight %} - +If the driver had crashed in the middle of the processing of time 3, then it will process time 3 +and output 30 after recovery. # Where to Go from Here -* API docs - [Scala](api/streaming/index.html#org.apache.spark.streaming.package) and [Java](api/streaming/index.html#org.apache.spark.streaming.api.java.package) -* More examples - [Scala](https://github.com/apache/incubator-spark/tree/master/examples/src/main/scala/org/apache/spark/streaming/examples) and [Java](https://github.com/apache/incubator-spark/tree/master/examples/src/main/java/org/apache/spark/streaming/examples) -* [Paper describing Spark Streaming](http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-259.pdf) +* API documentation + - Main docs of StreamingContext and DStreams in [Scala](api/streaming/index.html#org.apache.spark.streaming.package) + and [Java](api/streaming/index.html#org.apache.spark.streaming.api.java.package) + - Additional docs for + [Kafka](api/external/kafka/index.html#org.apache.spark.streaming.kafka.KafkaUtils$), + [Flume](api/external/flume/index.html#org.apache.spark.streaming.flume.FlumeUtils$), + [Twitter](api/external/twitter/index.html#org.apache.spark.streaming.twitter.TwitterUtils$), + [ZeroMQ](api/external/zeromq/index.html#org.apache.spark.streaming.zeromq.ZeroMQUtils$), and + [MQTT](api/external/mqtt/index.html#org.apache.spark.streaming.mqtt.MQTTUtils$) + +* More examples in [Scala]({{site.SPARK_GITHUB_URL}}/tree/master/examples/src/main/scala/org/apache/spark/streaming/examples) + and [Java]({{site.SPARK_GITHUB_URL}}/tree/master/examples/src/main/java/org/apache/spark/streaming/examples) +* [Paper](http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-259.pdf) describing Spark Streaming From a41a83cd690124e5d65ea75304912da08b0a6e14 Mon Sep 17 00:00:00 2001 From: Ankur Dave Date: Fri, 31 Jan 2014 16:52:02 -0800 Subject: [PATCH 077/133] Merge pull request #527 from ankurdave/graphx-assembly-pom Add GraphX to assembly/pom.xml Author: Ankur Dave == Merge branch commits == commit bb0b33ef9eb1b3d4a4fc283d9abb2ece4abcac23 Author: Ankur Dave Date: Fri Jan 31 15:24:52 2014 -0800 Add GraphX to assembly/pom.xml (cherry picked from commit a8cf3ec157fc9a512421b319cfffc5e4f07cf1f3) Signed-off-by: Patrick Wendell --- assembly/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assembly/pom.xml b/assembly/pom.xml index a99e3d2a02569..3303d326449a1 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -71,6 +71,11 @@ spark-streaming_${scala.binary.version} ${project.version} + + org.apache.spark + spark-graphx_${scala.binary.version} + ${project.version} + net.sf.py4j py4j From a414071f25d21dbdaa0b477ac29f45ec677ffc38 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Thu, 30 Jan 2014 09:33:18 -0800 Subject: [PATCH 078/133] Merge pull request #524 from rxin/doc Added spark.shuffle.file.buffer.kb to configuration doc. Author: Reynold Xin == Merge branch commits == commit 0eea1d761ff772ff89be234e1e28035d54e5a7de Author: Reynold Xin Date: Wed Jan 29 14:40:48 2014 -0800 Added spark.shuffle.file.buffer.kb to configuration doc. (cherry picked from commit ac712e48af3068672e629cec7766caae3cd77c37) Signed-off-by: Patrick Wendell --- docs/configuration.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index 0cf9d231ab896..7fb4f262c57cb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -398,6 +398,14 @@ Apart from these, the following properties are also available, and may be useful If set to "true", consolidates intermediate files created during a shuffle. Creating fewer files can improve filesystem performance for shuffles with large numbers of reduce tasks. It is recommended to set this to "true" when using ext4 or xfs filesystems. On ext3, this option might degrade performance on machines with many (>8) cores due to filesystem limitations. + + spark.shuffle.file.buffer.kb + 100 + + Size of the in-memory buffer for each shuffle file output stream, in kilobytes. These buffers + reduce the number of disk seeks and system calls made in creating intermediate shuffle files. + + spark.shuffle.spill true From 18520f55f9468cb221435a632697054251a7704b Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Mon, 27 Jan 2014 14:24:06 -0800 Subject: [PATCH 079/133] Merge pull request #490 from hsaputra/modify_checkoption_with_isdefined Replace the check for None Option with isDefined and isEmpty in Scala code Propose to replace the Scala check for Option "!= None" with Option.isDefined and "=== None" with Option.isEmpty. I think this, using method call if possible then operator function plus argument, will make the Scala code easier to read and understand. Pass compile and tests. (cherry picked from commit f16c21e22f706b268419fefce44e9905db3ee485) Signed-off-by: Patrick Wendell --- .../scala/org/apache/spark/Partitioner.scala | 2 +- .../deploy/master/ui/ApplicationPage.scala | 2 +- .../apache/spark/metrics/MetricsConfig.scala | 2 +- .../partial/ApproximateActionListener.scala | 2 +- .../apache/spark/partial/PartialResult.scala | 16 +-- .../main/scala/org/apache/spark/rdd/RDD.scala | 2 +- .../apache/spark/scheduler/DAGScheduler.scala | 2 +- .../org/apache/spark/scheduler/Stage.scala | 2 +- .../spark/scheduler/TaskSchedulerImpl.scala | 4 +- .../spark/storage/BlockManagerWorker.scala | 2 +- .../apache/spark/storage/MemoryStore.scala | 2 +- .../scala/org/apache/spark/util/Utils.scala | 2 +- .../spark/scheduler/TaskSetManagerSuite.scala | 2 +- .../spark/storage/BlockManagerSuite.scala | 126 +++++++++--------- 14 files changed, 84 insertions(+), 84 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Partitioner.scala b/core/src/main/scala/org/apache/spark/Partitioner.scala index fc0a7498820b5..3081f927cc3cb 100644 --- a/core/src/main/scala/org/apache/spark/Partitioner.scala +++ b/core/src/main/scala/org/apache/spark/Partitioner.scala @@ -49,7 +49,7 @@ object Partitioner { */ def defaultPartitioner(rdd: RDD[_], others: RDD[_]*): Partitioner = { val bySize = (Seq(rdd) ++ others).sortBy(_.partitions.size).reverse - for (r <- bySize if r.partitioner != None) { + for (r <- bySize if r.partitioner.isDefined) { return r.partitioner.get } if (rdd.context.conf.contains("spark.default.parallelism")) { diff --git a/core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala b/core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala index 9485bfd89eb57..f29a6ad2e7b92 100644 --- a/core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala +++ b/core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala @@ -67,7 +67,7 @@ private[spark] class ApplicationPage(parent: MasterWebUI) {
  • User: {app.desc.user}
  • Cores: { - if (app.desc.maxCores == None) { + if (app.desc.maxCores.isEmpty) { "Unlimited (%s granted)".format(app.coresGranted) } else { "%s (%s granted, %s left)".format( diff --git a/core/src/main/scala/org/apache/spark/metrics/MetricsConfig.scala b/core/src/main/scala/org/apache/spark/metrics/MetricsConfig.scala index 6f9f29969eaec..e54ac0b332093 100644 --- a/core/src/main/scala/org/apache/spark/metrics/MetricsConfig.scala +++ b/core/src/main/scala/org/apache/spark/metrics/MetricsConfig.scala @@ -80,7 +80,7 @@ private[spark] class MetricsConfig(val configFile: Option[String]) extends Loggi val subProperties = new mutable.HashMap[String, Properties] import scala.collection.JavaConversions._ prop.foreach { kv => - if (regex.findPrefixOf(kv._1) != None) { + if (regex.findPrefixOf(kv._1).isDefined) { val regex(prefix, suffix) = kv._1 subProperties.getOrElseUpdate(prefix, new Properties).setProperty(suffix, kv._2) } diff --git a/core/src/main/scala/org/apache/spark/partial/ApproximateActionListener.scala b/core/src/main/scala/org/apache/spark/partial/ApproximateActionListener.scala index d71069444a73f..423ff67a5fd43 100644 --- a/core/src/main/scala/org/apache/spark/partial/ApproximateActionListener.scala +++ b/core/src/main/scala/org/apache/spark/partial/ApproximateActionListener.scala @@ -71,7 +71,7 @@ private[spark] class ApproximateActionListener[T, U, R]( val finishTime = startTime + timeout while (true) { val time = System.currentTimeMillis() - if (failure != None) { + if (failure.isDefined) { throw failure.get } else if (finishedTasks == totalTasks) { return new PartialResult(evaluator.currentResult(), true) diff --git a/core/src/main/scala/org/apache/spark/partial/PartialResult.scala b/core/src/main/scala/org/apache/spark/partial/PartialResult.scala index 5ce49b8100ee6..812368e04ac0d 100644 --- a/core/src/main/scala/org/apache/spark/partial/PartialResult.scala +++ b/core/src/main/scala/org/apache/spark/partial/PartialResult.scala @@ -31,10 +31,10 @@ class PartialResult[R](initialVal: R, isFinal: Boolean) { * Blocking method to wait for and return the final value. */ def getFinalValue(): R = synchronized { - while (finalValue == None && failure == None) { + while (finalValue.isEmpty && failure.isEmpty) { this.wait() } - if (finalValue != None) { + if (finalValue.isDefined) { return finalValue.get } else { throw failure.get @@ -46,11 +46,11 @@ class PartialResult[R](initialVal: R, isFinal: Boolean) { * is supported per PartialResult. */ def onComplete(handler: R => Unit): PartialResult[R] = synchronized { - if (completionHandler != None) { + if (completionHandler.isDefined) { throw new UnsupportedOperationException("onComplete cannot be called twice") } completionHandler = Some(handler) - if (finalValue != None) { + if (finalValue.isDefined) { // We already have a final value, so let's call the handler handler(finalValue.get) } @@ -63,11 +63,11 @@ class PartialResult[R](initialVal: R, isFinal: Boolean) { */ def onFail(handler: Exception => Unit) { synchronized { - if (failureHandler != None) { + if (failureHandler.isDefined) { throw new UnsupportedOperationException("onFail cannot be called twice") } failureHandler = Some(handler) - if (failure != None) { + if (failure.isDefined) { // We already have a failure, so let's call the handler handler(failure.get) } @@ -102,7 +102,7 @@ class PartialResult[R](initialVal: R, isFinal: Boolean) { private[spark] def setFinalValue(value: R) { synchronized { - if (finalValue != None) { + if (finalValue.isDefined) { throw new UnsupportedOperationException("setFinalValue called twice on a PartialResult") } finalValue = Some(value) @@ -117,7 +117,7 @@ class PartialResult[R](initialVal: R, isFinal: Boolean) { private[spark] def setFailure(exception: Exception) { synchronized { - if (failure != None) { + if (failure.isDefined) { throw new UnsupportedOperationException("setFailure called twice on a PartialResult") } failure = Some(exception) diff --git a/core/src/main/scala/org/apache/spark/rdd/RDD.scala b/core/src/main/scala/org/apache/spark/rdd/RDD.scala index cd90a1561a975..1472c92b6031d 100644 --- a/core/src/main/scala/org/apache/spark/rdd/RDD.scala +++ b/core/src/main/scala/org/apache/spark/rdd/RDD.scala @@ -666,7 +666,7 @@ abstract class RDD[T: ClassTag]( } var jobResult: Option[T] = None val mergeResult = (index: Int, taskResult: Option[T]) => { - if (taskResult != None) { + if (taskResult.isDefined) { jobResult = jobResult match { case Some(value) => Some(f(value, taskResult.get)) case None => taskResult diff --git a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala index 7046c06d2057d..237cbf4c0c942 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala @@ -877,7 +877,7 @@ class DAGScheduler( logInfo("running: " + running) logInfo("waiting: " + waiting) logInfo("failed: " + failed) - if (stage.shuffleDep != None) { + if (stage.shuffleDep.isDefined) { // We supply true to increment the epoch number here in case this is a // recomputation of the map outputs. In that case, some nodes may have cached // locations with holes (from when we detected the error) and will need the diff --git a/core/src/main/scala/org/apache/spark/scheduler/Stage.scala b/core/src/main/scala/org/apache/spark/scheduler/Stage.scala index c60e9896dee4f..520c0b29e3536 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/Stage.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/Stage.scala @@ -46,7 +46,7 @@ private[spark] class Stage( callSite: Option[String]) extends Logging { - val isShuffleMap = shuffleDep != None + val isShuffleMap = shuffleDep.isDefined val numPartitions = rdd.partitions.size val outputLocs = Array.fill[List[MapStatus]](numPartitions)(Nil) var numAvailableOutputs = 0 diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala index 6cc608ea5bc69..83ba5840155fb 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala @@ -293,7 +293,7 @@ private[spark] class TaskSchedulerImpl( } } // Update the DAGScheduler without holding a lock on this, since that can deadlock - if (failedExecutor != None) { + if (failedExecutor.isDefined) { dagScheduler.executorLost(failedExecutor.get) backend.reviveOffers() } @@ -387,7 +387,7 @@ private[spark] class TaskSchedulerImpl( } } // Call dagScheduler.executorLost without holding the lock on this to prevent deadlock - if (failedExecutor != None) { + if (failedExecutor.isDefined) { dagScheduler.executorLost(failedExecutor.get) backend.reviveOffers() } diff --git a/core/src/main/scala/org/apache/spark/storage/BlockManagerWorker.scala b/core/src/main/scala/org/apache/spark/storage/BlockManagerWorker.scala index 42f52d7b26a04..3efe738a08f66 100644 --- a/core/src/main/scala/org/apache/spark/storage/BlockManagerWorker.scala +++ b/core/src/main/scala/org/apache/spark/storage/BlockManagerWorker.scala @@ -111,7 +111,7 @@ private[spark] object BlockManagerWorker extends Logging { val blockMessageArray = new BlockMessageArray(blockMessage) val resultMessage = connectionManager.sendMessageReliablySync( toConnManagerId, blockMessageArray.toBufferMessage) - resultMessage != None + resultMessage.isDefined } def syncGetBlock(msg: GetBlock, toConnManagerId: ConnectionManagerId): ByteBuffer = { diff --git a/core/src/main/scala/org/apache/spark/storage/MemoryStore.scala b/core/src/main/scala/org/apache/spark/storage/MemoryStore.scala index 27f057b9f22f4..eb5a18521683e 100644 --- a/core/src/main/scala/org/apache/spark/storage/MemoryStore.scala +++ b/core/src/main/scala/org/apache/spark/storage/MemoryStore.scala @@ -214,7 +214,7 @@ private class MemoryStore(blockManager: BlockManager, maxMemory: Long) while (maxMemory - (currentMemory - selectedMemory) < space && iterator.hasNext) { val pair = iterator.next() val blockId = pair.getKey - if (rddToAdd != None && rddToAdd == getRddId(blockId)) { + if (rddToAdd.isDefined && rddToAdd == getRddId(blockId)) { logInfo("Will not store " + blockIdToAdd + " as it would require dropping another " + "block from the same RDD") return false diff --git a/core/src/main/scala/org/apache/spark/util/Utils.scala b/core/src/main/scala/org/apache/spark/util/Utils.scala index 64acfbd3526f3..8447773343d25 100644 --- a/core/src/main/scala/org/apache/spark/util/Utils.scala +++ b/core/src/main/scala/org/apache/spark/util/Utils.scala @@ -652,7 +652,7 @@ private[spark] object Utils extends Logging { for (el <- trace) { if (!finished) { - if (SPARK_CLASS_REGEX.findFirstIn(el.getClassName) != None) { + if (SPARK_CLASS_REGEX.findFirstIn(el.getClassName).isDefined) { lastSparkMethod = if (el.getMethodName == "") { // Spark method is a constructor; get its class name el.getClassName.substring(el.getClassName.lastIndexOf('.') + 1) diff --git a/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala b/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala index c9f6cc5d079b5..ecac2f79a25e2 100644 --- a/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala +++ b/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala @@ -287,7 +287,7 @@ class TaskSetManagerSuite extends FunSuite with LocalSparkContext with Logging { // after the last failure. (1 to manager.maxTaskFailures).foreach { index => val offerResult = manager.resourceOffer("exec1", "host1", 1, ANY) - assert(offerResult != None, + assert(offerResult.isDefined, "Expect resource offer on iteration %s to return a task".format(index)) assert(offerResult.get.index === 0) manager.handleFailedTask(offerResult.get.taskId, TaskState.FINISHED, Some(TaskResultLost)) diff --git a/core/src/test/scala/org/apache/spark/storage/BlockManagerSuite.scala b/core/src/test/scala/org/apache/spark/storage/BlockManagerSuite.scala index 18aa587662d24..85011c6451777 100644 --- a/core/src/test/scala/org/apache/spark/storage/BlockManagerSuite.scala +++ b/core/src/test/scala/org/apache/spark/storage/BlockManagerSuite.scala @@ -137,9 +137,9 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a3", a3, StorageLevel.MEMORY_ONLY, tellMaster = false) // Checking whether blocks are in memory - assert(store.getSingle("a1") != None, "a1 was not in store") - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") // Checking whether master knows about the blocks or not assert(master.getLocations("a1").size > 0, "master was not told about a1") @@ -186,9 +186,9 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT val memStatus = master.getMemoryStatus.head._2 assert(memStatus._1 == 2000L, "total memory " + memStatus._1 + " should equal 2000") assert(memStatus._2 <= 1200L, "remaining memory " + memStatus._2 + " should <= 1200") - assert(store.getSingle("a1-to-remove") != None, "a1 was not in store") - assert(store.getSingle("a2-to-remove") != None, "a2 was not in store") - assert(store.getSingle("a3-to-remove") != None, "a3 was not in store") + assert(store.getSingle("a1-to-remove").isDefined, "a1 was not in store") + assert(store.getSingle("a2-to-remove").isDefined, "a2 was not in store") + assert(store.getSingle("a3-to-remove").isDefined, "a3 was not in store") // Checking whether master knows about the blocks or not assert(master.getLocations("a1-to-remove").size > 0, "master was not told about a1") @@ -259,7 +259,7 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_ONLY) - assert(store.getSingle("a1") != None, "a1 was not in store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") assert(master.getLocations("a1").size > 0, "master was not told about a1") master.removeExecutor(store.blockManagerId.executorId) @@ -333,14 +333,14 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_ONLY) store.putSingle("a2", a2, StorageLevel.MEMORY_ONLY) store.putSingle("a3", a3, StorageLevel.MEMORY_ONLY) - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") assert(store.getSingle("a1") === None, "a1 was in store") - assert(store.getSingle("a2") != None, "a2 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") // At this point a2 was gotten last, so LRU will getSingle rid of a3 store.putSingle("a1", a1, StorageLevel.MEMORY_ONLY) - assert(store.getSingle("a1") != None, "a1 was not in store") - assert(store.getSingle("a2") != None, "a2 was not in store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") assert(store.getSingle("a3") === None, "a3 was in store") } @@ -352,14 +352,14 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_ONLY_SER) store.putSingle("a2", a2, StorageLevel.MEMORY_ONLY_SER) store.putSingle("a3", a3, StorageLevel.MEMORY_ONLY_SER) - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") assert(store.getSingle("a1") === None, "a1 was in store") - assert(store.getSingle("a2") != None, "a2 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") // At this point a2 was gotten last, so LRU will getSingle rid of a3 store.putSingle("a1", a1, StorageLevel.MEMORY_ONLY_SER) - assert(store.getSingle("a1") != None, "a1 was not in store") - assert(store.getSingle("a2") != None, "a2 was not in store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") assert(store.getSingle("a3") === None, "a3 was in store") } @@ -374,8 +374,8 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT // Even though we accessed rdd_0_3 last, it should not have replaced partitions 1 and 2 // from the same RDD assert(store.getSingle(rdd(0, 3)) === None, "rdd_0_3 was in store") - assert(store.getSingle(rdd(0, 2)) != None, "rdd_0_2 was not in store") - assert(store.getSingle(rdd(0, 1)) != None, "rdd_0_1 was not in store") + assert(store.getSingle(rdd(0, 2)).isDefined, "rdd_0_2 was not in store") + assert(store.getSingle(rdd(0, 1)).isDefined, "rdd_0_1 was not in store") // Check that rdd_0_3 doesn't replace them even after further accesses assert(store.getSingle(rdd(0, 3)) === None, "rdd_0_3 was in store") assert(store.getSingle(rdd(0, 3)) === None, "rdd_0_3 was in store") @@ -392,7 +392,7 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT assert(!store.memoryStore.contains(rdd(0, 1)), "rdd_0_1 was in store") assert(store.memoryStore.contains(rdd(0, 2)), "rdd_0_2 was not in store") // Do a get() on rdd_0_2 so that it is the most recently used item - assert(store.getSingle(rdd(0, 2)) != None, "rdd_0_2 was not in store") + assert(store.getSingle(rdd(0, 2)).isDefined, "rdd_0_2 was not in store") // Put in more partitions from RDD 0; they should replace rdd_1_1 store.putSingle(rdd(0, 3), new Array[Byte](400), StorageLevel.MEMORY_ONLY) store.putSingle(rdd(0, 4), new Array[Byte](400), StorageLevel.MEMORY_ONLY) @@ -413,9 +413,9 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.DISK_ONLY) store.putSingle("a2", a2, StorageLevel.DISK_ONLY) store.putSingle("a3", a3, StorageLevel.DISK_ONLY) - assert(store.getSingle("a2") != None, "a2 was in store") - assert(store.getSingle("a3") != None, "a3 was in store") - assert(store.getSingle("a1") != None, "a1 was in store") + assert(store.getSingle("a2").isDefined, "a2 was in store") + assert(store.getSingle("a3").isDefined, "a3 was in store") + assert(store.getSingle("a1").isDefined, "a1 was in store") } test("disk and memory storage") { @@ -426,11 +426,11 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_AND_DISK) store.putSingle("a2", a2, StorageLevel.MEMORY_AND_DISK) store.putSingle("a3", a3, StorageLevel.MEMORY_AND_DISK) - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") assert(store.memoryStore.getValues("a1") == None, "a1 was in memory store") - assert(store.getSingle("a1") != None, "a1 was not in store") - assert(store.memoryStore.getValues("a1") != None, "a1 was not in memory store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") + assert(store.memoryStore.getValues("a1").isDefined, "a1 was not in memory store") } test("disk and memory storage with getLocalBytes") { @@ -441,11 +441,11 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_AND_DISK) store.putSingle("a2", a2, StorageLevel.MEMORY_AND_DISK) store.putSingle("a3", a3, StorageLevel.MEMORY_AND_DISK) - assert(store.getLocalBytes("a2") != None, "a2 was not in store") - assert(store.getLocalBytes("a3") != None, "a3 was not in store") + assert(store.getLocalBytes("a2").isDefined, "a2 was not in store") + assert(store.getLocalBytes("a3").isDefined, "a3 was not in store") assert(store.memoryStore.getValues("a1") == None, "a1 was in memory store") - assert(store.getLocalBytes("a1") != None, "a1 was not in store") - assert(store.memoryStore.getValues("a1") != None, "a1 was not in memory store") + assert(store.getLocalBytes("a1").isDefined, "a1 was not in store") + assert(store.memoryStore.getValues("a1").isDefined, "a1 was not in memory store") } test("disk and memory storage with serialization") { @@ -456,11 +456,11 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_AND_DISK_SER) store.putSingle("a2", a2, StorageLevel.MEMORY_AND_DISK_SER) store.putSingle("a3", a3, StorageLevel.MEMORY_AND_DISK_SER) - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") assert(store.memoryStore.getValues("a1") == None, "a1 was in memory store") - assert(store.getSingle("a1") != None, "a1 was not in store") - assert(store.memoryStore.getValues("a1") != None, "a1 was not in memory store") + assert(store.getSingle("a1").isDefined, "a1 was not in store") + assert(store.memoryStore.getValues("a1").isDefined, "a1 was not in memory store") } test("disk and memory storage with serialization and getLocalBytes") { @@ -471,11 +471,11 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a1", a1, StorageLevel.MEMORY_AND_DISK_SER) store.putSingle("a2", a2, StorageLevel.MEMORY_AND_DISK_SER) store.putSingle("a3", a3, StorageLevel.MEMORY_AND_DISK_SER) - assert(store.getLocalBytes("a2") != None, "a2 was not in store") - assert(store.getLocalBytes("a3") != None, "a3 was not in store") + assert(store.getLocalBytes("a2").isDefined, "a2 was not in store") + assert(store.getLocalBytes("a3").isDefined, "a3 was not in store") assert(store.memoryStore.getValues("a1") == None, "a1 was in memory store") - assert(store.getLocalBytes("a1") != None, "a1 was not in store") - assert(store.memoryStore.getValues("a1") != None, "a1 was not in memory store") + assert(store.getLocalBytes("a1").isDefined, "a1 was not in store") + assert(store.memoryStore.getValues("a1").isDefined, "a1 was not in memory store") } test("LRU with mixed storage levels") { @@ -489,18 +489,18 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.putSingle("a2", a2, StorageLevel.MEMORY_ONLY_SER) store.putSingle("a3", a3, StorageLevel.DISK_ONLY) // At this point LRU should not kick in because a3 is only on disk - assert(store.getSingle("a1") != None, "a2 was not in store") - assert(store.getSingle("a2") != None, "a3 was not in store") - assert(store.getSingle("a3") != None, "a1 was not in store") - assert(store.getSingle("a1") != None, "a2 was not in store") - assert(store.getSingle("a2") != None, "a3 was not in store") - assert(store.getSingle("a3") != None, "a1 was not in store") + assert(store.getSingle("a1").isDefined, "a2 was not in store") + assert(store.getSingle("a2").isDefined, "a3 was not in store") + assert(store.getSingle("a3").isDefined, "a1 was not in store") + assert(store.getSingle("a1").isDefined, "a2 was not in store") + assert(store.getSingle("a2").isDefined, "a3 was not in store") + assert(store.getSingle("a3").isDefined, "a1 was not in store") // Now let's add in a4, which uses both disk and memory; a1 should drop out store.putSingle("a4", a4, StorageLevel.MEMORY_AND_DISK_SER) assert(store.getSingle("a1") == None, "a1 was in store") - assert(store.getSingle("a2") != None, "a2 was not in store") - assert(store.getSingle("a3") != None, "a3 was not in store") - assert(store.getSingle("a4") != None, "a4 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") + assert(store.getSingle("a3").isDefined, "a3 was not in store") + assert(store.getSingle("a4").isDefined, "a4 was not in store") } test("in-memory LRU with streams") { @@ -511,18 +511,18 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.put("list1", list1.iterator, StorageLevel.MEMORY_ONLY, tellMaster = true) store.put("list2", list2.iterator, StorageLevel.MEMORY_ONLY, tellMaster = true) store.put("list3", list3.iterator, StorageLevel.MEMORY_ONLY, tellMaster = true) - assert(store.get("list2") != None, "list2 was not in store") + assert(store.get("list2").isDefined, "list2 was not in store") assert(store.get("list2").get.size == 2) - assert(store.get("list3") != None, "list3 was not in store") + assert(store.get("list3").isDefined, "list3 was not in store") assert(store.get("list3").get.size == 2) assert(store.get("list1") === None, "list1 was in store") - assert(store.get("list2") != None, "list2 was not in store") + assert(store.get("list2").isDefined, "list2 was not in store") assert(store.get("list2").get.size == 2) // At this point list2 was gotten last, so LRU will getSingle rid of list3 store.put("list1", list1.iterator, StorageLevel.MEMORY_ONLY, tellMaster = true) - assert(store.get("list1") != None, "list1 was not in store") + assert(store.get("list1").isDefined, "list1 was not in store") assert(store.get("list1").get.size == 2) - assert(store.get("list2") != None, "list2 was not in store") + assert(store.get("list2").isDefined, "list2 was not in store") assert(store.get("list2").get.size == 2) assert(store.get("list3") === None, "list1 was in store") } @@ -538,26 +538,26 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT store.put("list2", list2.iterator, StorageLevel.MEMORY_ONLY_SER, tellMaster = true) store.put("list3", list3.iterator, StorageLevel.DISK_ONLY, tellMaster = true) // At this point LRU should not kick in because list3 is only on disk - assert(store.get("list1") != None, "list2 was not in store") + assert(store.get("list1").isDefined, "list2 was not in store") assert(store.get("list1").get.size === 2) - assert(store.get("list2") != None, "list3 was not in store") + assert(store.get("list2").isDefined, "list3 was not in store") assert(store.get("list2").get.size === 2) - assert(store.get("list3") != None, "list1 was not in store") + assert(store.get("list3").isDefined, "list1 was not in store") assert(store.get("list3").get.size === 2) - assert(store.get("list1") != None, "list2 was not in store") + assert(store.get("list1").isDefined, "list2 was not in store") assert(store.get("list1").get.size === 2) - assert(store.get("list2") != None, "list3 was not in store") + assert(store.get("list2").isDefined, "list3 was not in store") assert(store.get("list2").get.size === 2) - assert(store.get("list3") != None, "list1 was not in store") + assert(store.get("list3").isDefined, "list1 was not in store") assert(store.get("list3").get.size === 2) // Now let's add in list4, which uses both disk and memory; list1 should drop out store.put("list4", list4.iterator, StorageLevel.MEMORY_AND_DISK_SER, tellMaster = true) assert(store.get("list1") === None, "list1 was in store") - assert(store.get("list2") != None, "list3 was not in store") + assert(store.get("list2").isDefined, "list3 was not in store") assert(store.get("list2").get.size === 2) - assert(store.get("list3") != None, "list1 was not in store") + assert(store.get("list3").isDefined, "list1 was not in store") assert(store.get("list3").get.size === 2) - assert(store.get("list4") != None, "list4 was not in store") + assert(store.get("list4").isDefined, "list4 was not in store") assert(store.get("list4").get.size === 2) } @@ -579,7 +579,7 @@ class BlockManagerSuite extends FunSuite with BeforeAndAfter with PrivateMethodT assert(store.getSingle("a1") === None, "a1 was in store") store.putSingle("a2", new Array[Byte](1000), StorageLevel.MEMORY_AND_DISK) assert(store.memoryStore.getValues("a2") === None, "a2 was in memory store") - assert(store.getSingle("a2") != None, "a2 was not in store") + assert(store.getSingle("a2").isDefined, "a2 was not in store") } test("block compression") { From b10f6074047ae60642e29405432369ce143f2cf1 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Mon, 27 Jan 2014 16:27:01 -0800 Subject: [PATCH 080/133] Merge pull request #516 from sarutak/master modified SparkPluginBuild.scala to use https protocol for accessing gith... We cannot build Spark behind a proxy although we execute sbt with -Dhttp(s).proxyHost -Dhttp(s).proxyPort -Dhttp(s).proxyUser -Dhttp(s).proxyPassword options. It's because of using git protocol to clone junit_xml_listener.git. I could build after modifying SparkPluginBuild.scala. I reported this issue to JIRA. https://spark-project.atlassian.net/browse/SPARK-1046 (cherry picked from commit 3d5c03e2305777b8a32f2e196e3b73ab221b3e79) Signed-off-by: Patrick Wendell --- project/project/SparkPluginBuild.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/project/SparkPluginBuild.scala b/project/project/SparkPluginBuild.scala index 6a66bd1d06b23..4853be2617684 100644 --- a/project/project/SparkPluginBuild.scala +++ b/project/project/SparkPluginBuild.scala @@ -20,5 +20,5 @@ import sbt._ object SparkPluginDef extends Build { lazy val root = Project("plugins", file(".")) dependsOn(junitXmlListener) /* This is not published in a Maven repository, so we get it from GitHub directly */ - lazy val junitXmlListener = uri("git://github.com/ijuma/junit_xml_listener.git#fe434773255b451a38e8d889536ebc260f4225ce") + lazy val junitXmlListener = uri("https://github.com/ijuma/junit_xml_listener.git#fe434773255b451a38e8d889536ebc260f4225ce") } From 2c6c9b9d33570ea563900902f9b3d37beef51c06 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Sat, 25 Jan 2014 22:41:30 -0800 Subject: [PATCH 081/133] Merge pull request #504 from JoshRosen/SPARK-1025 Fix PySpark hang when input files are deleted (SPARK-1025) This pull request addresses [SPARK-1025](https://spark-project.atlassian.net/browse/SPARK-1025), an issue where PySpark could hang if its input files were deleted. (cherry picked from commit c40619d4873f36ffb96a2e6292b32d5b64eab153) Signed-off-by: Patrick Wendell --- .../scala/org/apache/spark/api/python/PythonRDD.scala | 9 +++++++++ python/pyspark/tests.py | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala index 46d53e3e66f7c..9cbd26b607b24 100644 --- a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala +++ b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala @@ -52,6 +52,8 @@ private[spark] class PythonRDD[T: ClassTag]( val env = SparkEnv.get val worker = env.createPythonWorker(pythonExec, envVars.toMap) + @volatile var readerException: Exception = null + // Start a thread to feed the process input from our parent's iterator new Thread("stdin writer for " + pythonExec) { override def run() { @@ -84,6 +86,10 @@ private[spark] class PythonRDD[T: ClassTag]( dataOut.flush() worker.shutdownOutput() } catch { + case e: java.io.FileNotFoundException => + readerException = e + // Kill the Python worker process: + worker.shutdownOutput() case e: IOException => // This can happen for legitimate reasons if the Python code stops returning data before we are done // passing elements through, e.g., for take(). Just log a message to say it happened. @@ -108,6 +114,9 @@ private[spark] class PythonRDD[T: ClassTag]( } private def read(): Array[Byte] = { + if (readerException != null) { + throw readerException + } try { stream.readInt() match { case length if length > 0 => diff --git a/python/pyspark/tests.py b/python/pyspark/tests.py index acd1ca5676209..527104587fd31 100644 --- a/python/pyspark/tests.py +++ b/python/pyspark/tests.py @@ -168,6 +168,17 @@ def test_cartesian_on_textfile(self): self.assertEqual("Hello World!", x.strip()) self.assertEqual("Hello World!", y.strip()) + def test_deleting_input_files(self): + # Regression test for SPARK-1025 + tempFile = NamedTemporaryFile(delete=False) + tempFile.write("Hello World!") + tempFile.close() + data = self.sc.textFile(tempFile.name) + filtered_data = data.filter(lambda x: True) + self.assertEqual(1, filtered_data.count()) + os.unlink(tempFile.name) + self.assertRaises(Exception, lambda: filtered_data.count()) + class TestIO(PySparkTestCase): From 1280e8afddac3f01ef5d44ab1bf9df4a672329a0 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Sat, 25 Jan 2014 22:36:07 -0800 Subject: [PATCH 082/133] Merge pull request #511 from JoshRosen/SPARK-1040 Fix ClassCastException in JavaPairRDD.collectAsMap() (SPARK-1040) This fixes [SPARK-1040](https://spark-project.atlassian.net/browse/SPARK-1040), an issue where JavaPairRDD.collectAsMap() could sometimes fail with ClassCastException. I applied the same fix to the Spark Streaming Java APIs. The commit message describes the fix in more detail. I also increased the verbosity of JUnit test output under SBT to make it easier to verify that the Java tests are actually running. (cherry picked from commit c66a2ef1c2dc9c218069b3ce8c39a49e5b92fc16) Signed-off-by: Patrick Wendell --- .../org/apache/spark/api/java/JavaRDDLike.scala | 4 ++-- .../scala/org/apache/spark/JavaAPISuite.java | 17 +++++++++++++++++ pom.xml | 2 +- project/SparkBuild.scala | 3 ++- .../streaming/api/java/JavaDStreamLike.scala | 4 ++-- .../streaming/api/java/JavaPairDStream.scala | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/api/java/JavaRDDLike.scala b/core/src/main/scala/org/apache/spark/api/java/JavaRDDLike.scala index ebbbbd88061a1..0818ee4dbc801 100644 --- a/core/src/main/scala/org/apache/spark/api/java/JavaRDDLike.scala +++ b/core/src/main/scala/org/apache/spark/api/java/JavaRDDLike.scala @@ -88,7 +88,7 @@ trait JavaRDDLike[T, This <: JavaRDDLike[T, This]] extends Serializable { * Return a new RDD by applying a function to all elements of this RDD. */ def map[K2, V2](f: PairFunction[T, K2, V2]): JavaPairRDD[K2, V2] = { - def cm = implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] + def cm = implicitly[ClassTag[Tuple2[_, _]]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] new JavaPairRDD(rdd.map(f)(cm))(f.keyType(), f.valueType()) } @@ -119,7 +119,7 @@ trait JavaRDDLike[T, This <: JavaRDDLike[T, This]] extends Serializable { def flatMap[K2, V2](f: PairFlatMapFunction[T, K2, V2]): JavaPairRDD[K2, V2] = { import scala.collection.JavaConverters._ def fn = (x: T) => f.apply(x).asScala - def cm = implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] + def cm = implicitly[ClassTag[Tuple2[_, _]]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] JavaPairRDD.fromRDD(rdd.flatMap(fn)(cm))(f.keyType(), f.valueType()) } diff --git a/core/src/test/scala/org/apache/spark/JavaAPISuite.java b/core/src/test/scala/org/apache/spark/JavaAPISuite.java index 23ec6c3b311f0..8c573ac0d65e0 100644 --- a/core/src/test/scala/org/apache/spark/JavaAPISuite.java +++ b/core/src/test/scala/org/apache/spark/JavaAPISuite.java @@ -387,18 +387,21 @@ public Double call(Integer x) { return 1.0 * x; } }).cache(); + doubles.collect(); JavaPairRDD pairs = rdd.map(new PairFunction() { @Override public Tuple2 call(Integer x) { return new Tuple2(x, x); } }).cache(); + pairs.collect(); JavaRDD strings = rdd.map(new Function() { @Override public String call(Integer x) { return x.toString(); } }).cache(); + strings.collect(); } @Test @@ -962,4 +965,18 @@ public void countApproxDistinctByKey() { } } + + @Test + public void collectAsMapWithIntArrayValues() { + // Regression test for SPARK-1040 + JavaRDD rdd = sc.parallelize(Arrays.asList(new Integer[] { 1 })); + JavaPairRDD pairRDD = rdd.map(new PairFunction() { + @Override + public Tuple2 call(Integer x) throws Exception { + return new Tuple2(x, new int[] { x }); + } + }); + pairRDD.collect(); // Works fine + Map map = pairRDD.collectAsMap(); // Used to crash with ClassCastException + } } diff --git a/pom.xml b/pom.xml index 150dba8d636d8..2a3f8fcc30b98 100644 --- a/pom.xml +++ b/pom.xml @@ -389,7 +389,7 @@ com.novocode junit-interface - 0.9 + 0.10 test diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index b891ffab3259b..788ef120d04ef 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -212,12 +212,13 @@ object SparkBuild extends Build { "org.eclipse.jetty.orbit" % "javax.servlet" % "2.5.0.v201103041518" artifacts Artifact("javax.servlet", "jar", "jar"), "org.scalatest" %% "scalatest" % "1.9.1" % "test", "org.scalacheck" %% "scalacheck" % "1.10.0" % "test", - "com.novocode" % "junit-interface" % "0.9" % "test", + "com.novocode" % "junit-interface" % "0.10" % "test", "org.easymock" % "easymock" % "3.1" % "test", "org.mockito" % "mockito-all" % "1.8.5" % "test", "commons-io" % "commons-io" % "2.4" % "test" ), + testOptions += Tests.Argument(TestFrameworks.JUnit, "-v", "-a"), parallelExecution := true, /* Workaround for issue #206 (fixed after SBT 0.11.0) */ watchTransitiveSources <<= Defaults.inDependencies[Task[Seq[File]]](watchSources.task, diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStreamLike.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStreamLike.scala index a493a8279f942..64fe204cdf7a5 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStreamLike.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaDStreamLike.scala @@ -138,7 +138,7 @@ trait JavaDStreamLike[T, This <: JavaDStreamLike[T, This, R], R <: JavaRDDLike[T /** Return a new DStream by applying a function to all elements of this DStream. */ def map[K2, V2](f: PairFunction[T, K2, V2]): JavaPairDStream[K2, V2] = { - def cm = implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] + def cm = implicitly[ClassTag[Tuple2[_, _]]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] new JavaPairDStream(dstream.map(f)(cm))(f.keyType(), f.valueType()) } @@ -159,7 +159,7 @@ trait JavaDStreamLike[T, This <: JavaDStreamLike[T, This, R], R <: JavaRDDLike[T def flatMap[K2, V2](f: PairFlatMapFunction[T, K2, V2]): JavaPairDStream[K2, V2] = { import scala.collection.JavaConverters._ def fn = (x: T) => f.apply(x).asScala - def cm = implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] + def cm = implicitly[ClassTag[Tuple2[_, _]]].asInstanceOf[ClassTag[Tuple2[K2, V2]]] new JavaPairDStream(dstream.flatMap(fn)(cm))(f.keyType(), f.valueType()) } diff --git a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala index 79fa6a623d290..62cfa0a229db1 100644 --- a/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala +++ b/streaming/src/main/scala/org/apache/spark/streaming/api/java/JavaPairDStream.scala @@ -745,7 +745,7 @@ class JavaPairDStream[K, V](val dstream: DStream[(K, V)])( } override val classTag: ClassTag[(K, V)] = - implicitly[ClassTag[AnyRef]].asInstanceOf[ClassTag[Tuple2[K, V]]] + implicitly[ClassTag[Tuple2[_, _]]].asInstanceOf[ClassTag[Tuple2[K, V]]] } object JavaPairDStream { From 574741f2829255c5be8b2945e01e07cf849aa8f2 Mon Sep 17 00:00:00 2001 From: Matei Zaharia Date: Wed, 22 Jan 2014 14:05:48 -0800 Subject: [PATCH 083/133] Merge pull request #493 from kayousterhout/double_add Fixed bug where task set managers are added to queue twice @mateiz can you verify that this is a bug and wasn't intentional? (https://github.com/apache/incubator-spark/commit/90a04dab8d9a2a9a372cea7cdf46cc0fd0f2f76c#diff-7fa4f84a961750c374f2120ca70e96edR551) This bug leads to a small performance hit because task set managers will get offered each rejected resource offer twice, but doesn't lead to any incorrect functionality. Thanks to @hdc1112 for pointing this out. (cherry picked from commit 5bcfd798117e8617e604c1dd3b5c9b67e83100bb) Signed-off-by: Patrick Wendell --- .../main/scala/org/apache/spark/scheduler/TaskSetManager.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala index 73d6972bb4204..ccd7f6f8f8d92 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala @@ -592,7 +592,7 @@ private[spark] class TaskSetManager( override def removeSchedulable(schedulable: Schedulable) {} override def getSortedTaskSetQueue(): ArrayBuffer[TaskSetManager] = { - var sortedTaskSetQueue = ArrayBuffer[TaskSetManager](this) + var sortedTaskSetQueue = new ArrayBuffer[TaskSetManager]() sortedTaskSetQueue += this sortedTaskSetQueue } From dc8adf158e78b6501b4672e0389c18c3034f30b9 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Tue, 21 Jan 2014 14:53:49 -0800 Subject: [PATCH 084/133] Merge pull request #489 from ash211/patch-6 Clarify spark.default.parallelism It's the task count across the cluster, not per worker, per machine, per core, or anything else. (cherry picked from commit 749f842827c7e7766a342b6b0a437803044a9f90) Signed-off-by: Patrick Wendell --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 7fb4f262c57cb..07d1eb0931a17 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -98,7 +98,7 @@ Apart from these, the following properties are also available, and may be useful spark.default.parallelism 8 - Default number of tasks to use for distributed shuffle operations (groupByKey, + Default number of tasks to use across the cluster for distributed shuffle operations (groupByKey, reduceByKey, etc) when not set by user. From 0021ef9645cdd84e9f375afdc262cf8919fa2ab9 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Wed, 15 Jan 2014 23:47:25 -0800 Subject: [PATCH 085/133] Merge pull request #445 from kayousterhout/exec_lost Fail rather than hanging if a task crashes the JVM. Prior to this commit, if a task crashes the JVM, the task (and all other tasks running on that executor) is marked at KILLED rather than FAILED. As a result, the TaskSetManager will retry the task indefinitely rather than failing the job after maxFailures. Eventually, this makes the job hang, because the Standalone Scheduler removes the application after 10 works have failed, and then the app is left in a state where it's disconnected from the master and waiting to reconnect. This commit fixes that problem by marking tasks as FAILED rather than killed when an executor is lost. The downside of this commit is that if task A fails because another task running on the same executor caused the VM to crash, the failure will incorrectly be counted as a failure of task A. This should not be an issue because we typically set maxFailures to 3, and it is unlikely that a task will be co-located with a JVM-crashing task multiple times. (cherry picked from commit c06a307ca22901839df00d25fe623f6faa6af17e) Signed-off-by: Patrick Wendell --- .../apache/spark/scheduler/TaskSetManager.scala | 2 +- .../org/apache/spark/DistributedSuite.scala | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala index ccd7f6f8f8d92..e91470800c82f 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala @@ -629,7 +629,7 @@ private[spark] class TaskSetManager( } // Also re-enqueue any tasks that were running on the node for ((tid, info) <- taskInfos if info.running && info.executorId == execId) { - handleFailedTask(tid, TaskState.KILLED, None) + handleFailedTask(tid, TaskState.FAILED, None) } } diff --git a/core/src/test/scala/org/apache/spark/DistributedSuite.scala b/core/src/test/scala/org/apache/spark/DistributedSuite.scala index d9cb7fead5b88..8de7a328d1cf5 100644 --- a/core/src/test/scala/org/apache/spark/DistributedSuite.scala +++ b/core/src/test/scala/org/apache/spark/DistributedSuite.scala @@ -125,6 +125,23 @@ class DistributedSuite extends FunSuite with ShouldMatchers with BeforeAndAfter assert(thrown.getMessage.contains("failed 4 times")) } + test("repeatedly failing task that crashes JVM") { + // Ensures that if a task fails in a way that crashes the JVM, the job eventually fails rather + // than hanging due to retrying the failed task infinitely many times (eventually the + // standalone scheduler will remove the application, causing the job to hang waiting to + // reconnect to the master). + sc = new SparkContext(clusterUrl, "test") + failAfter(Span(100000, Millis)) { + val thrown = intercept[SparkException] { + // One of the tasks always fails. + sc.parallelize(1 to 10, 2).foreach { x => if (x == 1) System.exit(42) } + } + assert(thrown.getClass === classOf[SparkException]) + System.out.println(thrown.getMessage) + assert(thrown.getMessage.contains("failed 4 times")) + } + } + test("caching") { sc = new SparkContext(clusterUrl, "test") val data = sc.parallelize(1 to 1000, 10).cache() From 6e4d0895588e860ceec0e3a4327455e2858a6d24 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Wed, 15 Jan 2014 20:15:29 -0800 Subject: [PATCH 086/133] Merge pull request #414 from soulmachine/code-style Code clean up for mllib * Removed unnecessary parentheses * Removed unused imports * Simplified `filter...size()` to `count ...` * Removed obsoleted parameters' comments (cherry picked from commit 84595ea3e25d2f9578b3de34704da14eb02330fa) Signed-off-by: Patrick Wendell --- .../spark/mllib/api/python/PythonMLLibAPI.scala | 4 +--- .../apache/spark/mllib/classification/SVM.scala | 2 -- .../spark/mllib/clustering/KMeansModel.scala | 4 +--- .../mllib/regression/LinearRegression.scala | 2 +- .../mllib/regression/RidgeRegression.scala | 6 +++--- .../spark/mllib/util/LinearDataGenerator.scala | 4 +--- .../spark/mllib/util/MFDataGenerator.scala | 17 ++++++++--------- .../org/apache/spark/mllib/util/MLUtils.scala | 2 +- .../spark/mllib/util/SVMDataGenerator.scala | 2 +- .../LogisticRegressionSuite.scala | 6 +++--- .../spark/mllib/classification/SVMSuite.scala | 9 ++++----- .../spark/mllib/clustering/KMeansSuite.scala | 3 --- .../spark/mllib/recommendation/ALSSuite.scala | 1 - .../spark/mllib/regression/LassoSuite.scala | 6 ++---- .../regression/LinearRegressionSuite.scala | 5 ++--- .../mllib/regression/RidgeRegressionSuite.scala | 3 --- 16 files changed, 28 insertions(+), 48 deletions(-) diff --git a/mllib/src/main/scala/org/apache/spark/mllib/api/python/PythonMLLibAPI.scala b/mllib/src/main/scala/org/apache/spark/mllib/api/python/PythonMLLibAPI.scala index 3fec1a909dfb9..efc0eb935376b 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/api/python/PythonMLLibAPI.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/api/python/PythonMLLibAPI.scala @@ -24,7 +24,6 @@ import org.apache.spark.mllib.recommendation._ import org.apache.spark.rdd.RDD import java.nio.ByteBuffer import java.nio.ByteOrder -import java.nio.DoubleBuffer /** * The Java stubs necessary for the Python mllib bindings. @@ -81,7 +80,6 @@ class PythonMLLibAPI extends Serializable { } val db = bb.asDoubleBuffer() val ans = new Array[Array[Double]](rows.toInt) - var i = 0 for (i <- 0 until rows.toInt) { ans(i) = new Array[Double](cols.toInt) db.get(ans(i)) @@ -236,7 +234,7 @@ class PythonMLLibAPI extends Serializable { * Serialize a Rating object into an array of bytes. * It can be deserialized using RatingDeserializer(). * - * @param rate + * @param rate the Rating object to serialize * @return */ private[spark] def serializeRating(rate: Rating): Array[Byte] = { diff --git a/mllib/src/main/scala/org/apache/spark/mllib/classification/SVM.scala b/mllib/src/main/scala/org/apache/spark/mllib/classification/SVM.scala index f2964ea446ec8..6dff29dfb45cc 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/classification/SVM.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/classification/SVM.scala @@ -17,8 +17,6 @@ package org.apache.spark.mllib.classification -import scala.math.signum - import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apache.spark.mllib.optimization._ diff --git a/mllib/src/main/scala/org/apache/spark/mllib/clustering/KMeansModel.scala b/mllib/src/main/scala/org/apache/spark/mllib/clustering/KMeansModel.scala index cfc81c985aa64..980be931576dc 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/clustering/KMeansModel.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/clustering/KMeansModel.scala @@ -19,8 +19,6 @@ package org.apache.spark.mllib.clustering import org.apache.spark.rdd.RDD import org.apache.spark.SparkContext._ -import org.apache.spark.mllib.util.MLUtils - /** * A clustering model for K-means. Each point belongs to the cluster with the closest center. @@ -39,6 +37,6 @@ class KMeansModel(val clusterCenters: Array[Array[Double]]) extends Serializable * model on the given data. */ def computeCost(data: RDD[Array[Double]]): Double = { - data.map(p => KMeans.pointCost(clusterCenters, p)).sum + data.map(p => KMeans.pointCost(clusterCenters, p)).sum() } } diff --git a/mllib/src/main/scala/org/apache/spark/mllib/regression/LinearRegression.scala b/mllib/src/main/scala/org/apache/spark/mllib/regression/LinearRegression.scala index fe5cce064bac7..df599fde76a86 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/regression/LinearRegression.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/regression/LinearRegression.scala @@ -17,7 +17,7 @@ package org.apache.spark.mllib.regression -import org.apache.spark.{Logging, SparkContext} +import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apache.spark.mllib.optimization._ import org.apache.spark.mllib.util.MLUtils diff --git a/mllib/src/main/scala/org/apache/spark/mllib/regression/RidgeRegression.scala b/mllib/src/main/scala/org/apache/spark/mllib/regression/RidgeRegression.scala index c125c6797ada3..0c0e67fb7b123 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/regression/RidgeRegression.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/regression/RidgeRegression.scala @@ -17,7 +17,7 @@ package org.apache.spark.mllib.regression -import org.apache.spark.{Logging, SparkContext} +import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apache.spark.mllib.optimization._ import org.apache.spark.mllib.util.MLUtils @@ -76,7 +76,7 @@ class RidgeRegressionWithSGD private ( def createModel(weights: Array[Double], intercept: Double) = { val weightsMat = new DoubleMatrix(weights.length + 1, 1, (Array(intercept) ++ weights):_*) val weightsScaled = weightsMat.div(xColSd) - val interceptScaled = yMean - (weightsMat.transpose().mmul(xColMean.div(xColSd)).get(0)) + val interceptScaled = yMean - weightsMat.transpose().mmul(xColMean.div(xColSd)).get(0) new RidgeRegressionModel(weightsScaled.data, interceptScaled) } @@ -86,7 +86,7 @@ class RidgeRegressionWithSGD private ( initialWeights: Array[Double]) : RidgeRegressionModel = { - val nfeatures: Int = input.first.features.length + val nfeatures: Int = input.first().features.length val nexamples: Long = input.count() // To avoid penalizing the intercept, we center and scale the data. diff --git a/mllib/src/main/scala/org/apache/spark/mllib/util/LinearDataGenerator.scala b/mllib/src/main/scala/org/apache/spark/mllib/util/LinearDataGenerator.scala index bc5045fb05d3b..2e03684e62861 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/util/LinearDataGenerator.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/util/LinearDataGenerator.scala @@ -25,7 +25,6 @@ import org.jblas.DoubleMatrix import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apache.spark.mllib.regression.LabeledPoint -import org.apache.spark.mllib.regression.LabeledPoint /** * Generate sample data used for Linear Data. This class generates @@ -73,7 +72,7 @@ object LinearDataGenerator { val x = Array.fill[Array[Double]](nPoints)( Array.fill[Double](weights.length)(2 * rnd.nextDouble - 1.0)) val y = x.map { xi => - (new DoubleMatrix(1, xi.length, xi:_*)).dot(weightsMat) + intercept + eps * rnd.nextGaussian() + new DoubleMatrix(1, xi.length, xi: _*).dot(weightsMat) + intercept + eps * rnd.nextGaussian() } y.zip(x).map(p => LabeledPoint(p._1, p._2)) } @@ -86,7 +85,6 @@ object LinearDataGenerator { * @param nexamples Number of examples that will be contained in the RDD. * @param nfeatures Number of features to generate for each example. * @param eps Epsilon factor by which examples are scaled. - * @param weights Weights associated with the first weights.length features. * @param nparts Number of partitions in the RDD. Default value is 2. * * @return RDD of LabeledPoint containing sample data. diff --git a/mllib/src/main/scala/org/apache/spark/mllib/util/MFDataGenerator.scala b/mllib/src/main/scala/org/apache/spark/mllib/util/MFDataGenerator.scala index d5f3f6b8dbeea..348aba1dea5b6 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/util/MFDataGenerator.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/util/MFDataGenerator.scala @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.spark.mllib.recommendation +package org.apache.spark.mllib.util import scala.util.Random @@ -23,7 +23,6 @@ import org.jblas.DoubleMatrix import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD -import org.apache.spark.mllib.util.MLUtils /** * Generate RDD(s) containing data for Matrix Factorization. @@ -31,9 +30,9 @@ import org.apache.spark.mllib.util.MLUtils * This method samples training entries according to the oversampling factor * 'trainSampFact', which is a multiplicative factor of the number of * degrees of freedom of the matrix: rank*(m+n-rank). -* -* It optionally samples entries for a testing matrix using -* 'testSampFact', the percentage of the number of training entries +* +* It optionally samples entries for a testing matrix using +* 'testSampFact', the percentage of the number of training entries * to use for testing. * * This method takes the following inputs: @@ -73,7 +72,7 @@ object MFDataGenerator{ val A = DoubleMatrix.randn(m, rank) val B = DoubleMatrix.randn(rank, n) - val z = 1 / (scala.math.sqrt(scala.math.sqrt(rank))) + val z = 1 / scala.math.sqrt(scala.math.sqrt(rank)) A.mmuli(z) B.mmuli(z) val fullData = A.mmul(B) @@ -91,7 +90,7 @@ object MFDataGenerator{ .map(x => (fullData.indexRows(x - 1), fullData.indexColumns(x - 1), fullData.get(x - 1))) // optionally add gaussian noise - if (noise) { + if (noise) { trainData.map(x => (x._1, x._2, x._3 + rand.nextGaussian * sigma)) } @@ -107,8 +106,8 @@ object MFDataGenerator{ .map(x => (fullData.indexRows(x - 1), fullData.indexColumns(x - 1), fullData.get(x - 1))) testData.map(x => x._1 + "," + x._2 + "," + x._3).saveAsTextFile(outputPath) } - + sc.stop() - + } } diff --git a/mllib/src/main/scala/org/apache/spark/mllib/util/MLUtils.scala b/mllib/src/main/scala/org/apache/spark/mllib/util/MLUtils.scala index d91b74c3ac2b3..64c6136a8b89d 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/util/MLUtils.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/util/MLUtils.scala @@ -97,7 +97,7 @@ object MLUtils { while (col < nfeatures) { xColMean.put(col, xColSumsMap(col)._1 / nexamples) val variance = - (xColSumsMap(col)._2 - (math.pow(xColSumsMap(col)._1, 2) / nexamples)) / (nexamples) + (xColSumsMap(col)._2 - (math.pow(xColSumsMap(col)._1, 2) / nexamples)) / nexamples xColSd.put(col, math.sqrt(variance)) col += 1 } diff --git a/mllib/src/main/scala/org/apache/spark/mllib/util/SVMDataGenerator.scala b/mllib/src/main/scala/org/apache/spark/mllib/util/SVMDataGenerator.scala index 07022093f300c..c96c94f70eef7 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/util/SVMDataGenerator.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/util/SVMDataGenerator.scala @@ -56,7 +56,7 @@ object SVMDataGenerator { val x = Array.fill[Double](nfeatures) { rnd.nextDouble() * 2.0 - 1.0 } - val yD = (new DoubleMatrix(1, x.length, x:_*)).dot(trueWeights) + rnd.nextGaussian() * 0.1 + val yD = new DoubleMatrix(1, x.length, x: _*).dot(trueWeights) + rnd.nextGaussian() * 0.1 val y = if (yD < 0) 0.0 else 1.0 LabeledPoint(y, x) } diff --git a/mllib/src/test/scala/org/apache/spark/mllib/classification/LogisticRegressionSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/classification/LogisticRegressionSuite.scala index 34c67294e9ac9..02ede711372d3 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/classification/LogisticRegressionSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/classification/LogisticRegressionSuite.scala @@ -80,9 +80,9 @@ class LogisticRegressionSuite extends FunSuite with BeforeAndAfterAll with Shoul } def validatePrediction(predictions: Seq[Double], input: Seq[LabeledPoint]) { - val numOffPredictions = predictions.zip(input).filter { case (prediction, expected) => - (prediction != expected.label) - }.size + val numOffPredictions = predictions.zip(input).count { case (prediction, expected) => + prediction != expected.label + } // At least 83% of the predictions should be on. ((input.length - numOffPredictions).toDouble / input.length) should be > 0.83 } diff --git a/mllib/src/test/scala/org/apache/spark/mllib/classification/SVMSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/classification/SVMSuite.scala index 6a957e3ddca71..3357b86f9b706 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/classification/SVMSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/classification/SVMSuite.scala @@ -18,7 +18,6 @@ package org.apache.spark.mllib.classification import scala.util.Random -import scala.math.signum import scala.collection.JavaConversions._ import org.scalatest.BeforeAndAfterAll @@ -50,7 +49,7 @@ object SVMSuite { val x = Array.fill[Array[Double]](nPoints)( Array.fill[Double](weights.length)(rnd.nextDouble() * 2.0 - 1.0)) val y = x.map { xi => - val yD = (new DoubleMatrix(1, xi.length, xi:_*)).dot(weightsMat) + + val yD = new DoubleMatrix(1, xi.length, xi: _*).dot(weightsMat) + intercept + 0.01 * rnd.nextGaussian() if (yD < 0) 0.0 else 1.0 } @@ -72,9 +71,9 @@ class SVMSuite extends FunSuite with BeforeAndAfterAll { } def validatePrediction(predictions: Seq[Double], input: Seq[LabeledPoint]) { - val numOffPredictions = predictions.zip(input).filter { case (prediction, expected) => - (prediction != expected.label) - }.size + val numOffPredictions = predictions.zip(input).count { case (prediction, expected) => + prediction != expected.label + } // At least 80% of the predictions should be on. assert(numOffPredictions < input.length / 5) } diff --git a/mllib/src/test/scala/org/apache/spark/mllib/clustering/KMeansSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/clustering/KMeansSuite.scala index 94245f6027b30..73657cac893ce 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/clustering/KMeansSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/clustering/KMeansSuite.scala @@ -17,15 +17,12 @@ package org.apache.spark.mllib.clustering -import scala.util.Random import org.scalatest.BeforeAndAfterAll import org.scalatest.FunSuite import org.apache.spark.SparkContext -import org.apache.spark.SparkContext._ -import org.jblas._ class KMeansSuite extends FunSuite with BeforeAndAfterAll { @transient private var sc: SparkContext = _ diff --git a/mllib/src/test/scala/org/apache/spark/mllib/recommendation/ALSSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/recommendation/ALSSuite.scala index e683a90f57aba..4e8dbde65801c 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/recommendation/ALSSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/recommendation/ALSSuite.scala @@ -24,7 +24,6 @@ import org.scalatest.BeforeAndAfterAll import org.scalatest.FunSuite import org.apache.spark.SparkContext -import org.apache.spark.SparkContext._ import org.jblas._ diff --git a/mllib/src/test/scala/org/apache/spark/mllib/regression/LassoSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/regression/LassoSuite.scala index db980c7bae64f..b2c8df97a82a7 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/regression/LassoSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/regression/LassoSuite.scala @@ -17,8 +17,6 @@ package org.apache.spark.mllib.regression -import scala.collection.JavaConversions._ -import scala.util.Random import org.scalatest.BeforeAndAfterAll import org.scalatest.FunSuite @@ -41,10 +39,10 @@ class LassoSuite extends FunSuite with BeforeAndAfterAll { } def validatePrediction(predictions: Seq[Double], input: Seq[LabeledPoint]) { - val numOffPredictions = predictions.zip(input).filter { case (prediction, expected) => + val numOffPredictions = predictions.zip(input).count { case (prediction, expected) => // A prediction is off if the prediction is more than 0.5 away from expected value. math.abs(prediction - expected.label) > 0.5 - }.size + } // At least 80% of the predictions should be on. assert(numOffPredictions < input.length / 5) } diff --git a/mllib/src/test/scala/org/apache/spark/mllib/regression/LinearRegressionSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/regression/LinearRegressionSuite.scala index ef500c704c8a9..406afbaa3e2c1 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/regression/LinearRegressionSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/regression/LinearRegressionSuite.scala @@ -21,7 +21,6 @@ import org.scalatest.BeforeAndAfterAll import org.scalatest.FunSuite import org.apache.spark.SparkContext -import org.apache.spark.SparkContext._ import org.apache.spark.mllib.util.LinearDataGenerator class LinearRegressionSuite extends FunSuite with BeforeAndAfterAll { @@ -37,10 +36,10 @@ class LinearRegressionSuite extends FunSuite with BeforeAndAfterAll { } def validatePrediction(predictions: Seq[Double], input: Seq[LabeledPoint]) { - val numOffPredictions = predictions.zip(input).filter { case (prediction, expected) => + val numOffPredictions = predictions.zip(input).count { case (prediction, expected) => // A prediction is off if the prediction is more than 0.5 away from expected value. math.abs(prediction - expected.label) > 0.5 - }.size + } // At least 80% of the predictions should be on. assert(numOffPredictions < input.length / 5) } diff --git a/mllib/src/test/scala/org/apache/spark/mllib/regression/RidgeRegressionSuite.scala b/mllib/src/test/scala/org/apache/spark/mllib/regression/RidgeRegressionSuite.scala index c18092d804fa3..1d6a10b66e892 100644 --- a/mllib/src/test/scala/org/apache/spark/mllib/regression/RidgeRegressionSuite.scala +++ b/mllib/src/test/scala/org/apache/spark/mllib/regression/RidgeRegressionSuite.scala @@ -17,15 +17,12 @@ package org.apache.spark.mllib.regression -import scala.collection.JavaConversions._ -import scala.util.Random import org.jblas.DoubleMatrix import org.scalatest.BeforeAndAfterAll import org.scalatest.FunSuite import org.apache.spark.SparkContext -import org.apache.spark.SparkContext._ import org.apache.spark.mllib.util.LinearDataGenerator class RidgeRegressionSuite extends FunSuite with BeforeAndAfterAll { From 5f63f32b748e52124ca3ac3f0de405f861438940 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Mon, 20 Jan 2014 22:35:45 -0800 Subject: [PATCH 087/133] Merge pull request #449 from CrazyJvm/master SPARK-1028 : fix "set MASTER automatically fails" bug. spark-shell intends to set MASTER automatically if we do not provide the option when we start the shell , but there's a problem. The condition is "if [[ "x" != "x$SPARK_MASTER_IP" && "y" != "y$SPARK_MASTER_PORT" ]];" we sure will set SPARK_MASTER_IP explicitly, the SPARK_MASTER_PORT option, however, we probably do not set just using spark default port 7077. So if we do not set SPARK_MASTER_PORT, the condition will never be true. We should just use default port if users do not set port explicitly I think. (cherry picked from commit 6b4eed779bd1889543ac2c058745bd0864f02b2a) Signed-off-by: Patrick Wendell --- bin/spark-shell | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/spark-shell b/bin/spark-shell index e6885b51ef567..05a46ee0caf55 100755 --- a/bin/spark-shell +++ b/bin/spark-shell @@ -45,13 +45,18 @@ for o in "$@"; do done # Set MASTER from spark-env if possible +DEFAULT_SPARK_MASTER_PORT=7077 if [ -z "$MASTER" ]; then if [ -e "$FWDIR/conf/spark-env.sh" ]; then . "$FWDIR/conf/spark-env.sh" fi - if [[ "x" != "x$SPARK_MASTER_IP" && "y" != "y$SPARK_MASTER_PORT" ]]; then - MASTER="spark://${SPARK_MASTER_IP}:${SPARK_MASTER_PORT}" - export MASTER + if [ "x" != "x$SPARK_MASTER_IP" ]; then + if [ "y" != "y$SPARK_MASTER_PORT" ]; then + SPARK_MASTER_PORT="${SPARK_MASTER_PORT}" + else + SPARK_MASTER_PORT=$DEFAULT_SPARK_MASTER_PORT + fi + export MASTER="spark://${SPARK_MASTER_IP}:${SPARK_MASTER_PORT}" fi fi From f3cba2d8190416712dc2b8d09b8fccff951aa464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stevo=20Slavi=C4=87?= Date: Tue, 4 Feb 2014 09:45:46 -0800 Subject: [PATCH 088/133] Merge pull request #535 from sslavic/patch-2. Closes #535. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed typo in scaladoc Author: Stevo Slavić == Merge branch commits == commit 0a77f789e281930f4168543cc0d3b3ffbf5b3764 Author: Stevo Slavić Date: Tue Feb 4 15:30:27 2014 +0100 Fixed typo in scaladoc (cherry picked from commit 0c05cd374dac309b5444980f10f8dcb820c752c2) Signed-off-by: Reynold Xin --- core/src/main/scala/org/apache/spark/Partitioner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/Partitioner.scala b/core/src/main/scala/org/apache/spark/Partitioner.scala index 3081f927cc3cb..cfba43dec3111 100644 --- a/core/src/main/scala/org/apache/spark/Partitioner.scala +++ b/core/src/main/scala/org/apache/spark/Partitioner.scala @@ -41,7 +41,7 @@ object Partitioner { * spark.default.parallelism is set, then we'll use the value from SparkContext * defaultParallelism, otherwise we'll use the max number of upstream partitions. * - * Unless spark.default.parallelism is set, He number of partitions will be the + * Unless spark.default.parallelism is set, the number of partitions will be the * same as the number of partitions in the largest upstream RDD, as this should * be least likely to cause out-of-memory errors. * From d815cfa68ffbf1a0af02e47b01a0d0e76b4da2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stevo=20Slavi=C4=87?= Date: Tue, 4 Feb 2014 09:47:11 -0800 Subject: [PATCH 089/133] Merge pull request #534 from sslavic/patch-1. Closes #534. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed wrong path to compute-classpath.cmd compute-classpath.cmd is in bin, not in sbin directory Author: Stevo Slavić == Merge branch commits == commit 23deca32b69e9429b33ad31d35b7e1bfc9459f59 Author: Stevo Slavić Date: Tue Feb 4 15:01:47 2014 +0100 Fixed wrong path to compute-classpath.cmd compute-classpath.cmd is in bin, not in sbin directory (cherry picked from commit 92092879c3b8001a456fefc2efc0df16585515a8) Signed-off-by: Reynold Xin --- bin/run-example2.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/run-example2.cmd b/bin/run-example2.cmd index 6861334cb07e5..40abb9af74246 100644 --- a/bin/run-example2.cmd +++ b/bin/run-example2.cmd @@ -49,7 +49,7 @@ if "x%SPARK_EXAMPLES_JAR%"=="x" ( rem Compute Spark classpath using external script set DONT_PRINT_CLASSPATH=1 -call "%FWDIR%sbin\compute-classpath.cmd" +call "%FWDIR%bin\compute-classpath.cmd" set DONT_PRINT_CLASSPATH=0 set CLASSPATH=%SPARK_EXAMPLES_JAR%;%CLASSPATH% From b044b0b4fa07ec92fd2c80589247d59a5925df96 Mon Sep 17 00:00:00 2001 From: Thomas Graves Date: Wed, 5 Feb 2014 23:37:07 -0800 Subject: [PATCH 090/133] Merge pull request #526 from tgravescs/yarn_client_stop_am_fix. Closes #526. spark on yarn - yarn-client mode doesn't always exit immediately https://spark-project.atlassian.net/browse/SPARK-1049 If you run in the yarn-client mode but you don't get all the workers you requested right away and then you exit your application, the application master stays around until it gets the number of workers you initially requested. This is a waste of resources. The AM should exit immediately upon the client going away. This fix simply checks to see if the driver closed while its waiting for the initial # of workers. Author: Thomas Graves == Merge branch commits == commit 03f40a62584b6bdd094ba91670cd4aa6afe7cd81 Author: Thomas Graves Date: Fri Jan 31 11:23:10 2014 -0600 spark on yarn - yarn-client mode doesn't always exit immediately (cherry picked from commit 38020961d101e792393855fd00d8e42f40713754) Signed-off-by: Reynold Xin --- .../scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala | 2 +- .../scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn/alpha/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala b/yarn/alpha/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala index 9fe4d64a0fca0..138c27910b0b0 100644 --- a/yarn/alpha/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala +++ b/yarn/alpha/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala @@ -210,7 +210,7 @@ class WorkerLauncher(args: ApplicationMasterArguments, conf: Configuration, spar // Wait until all containers have finished // TODO: This is a bit ugly. Can we make it nicer? // TODO: Handle container failure - while(yarnAllocator.getNumWorkersRunning < args.numWorkers) { + while ((yarnAllocator.getNumWorkersRunning < args.numWorkers) && (!driverClosed)) { yarnAllocator.allocateContainers(math.max(args.numWorkers - yarnAllocator.getNumWorkersRunning, 0)) Thread.sleep(100) } diff --git a/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala b/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala index 78353224fa4b8..40600f38e5e73 100644 --- a/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala +++ b/yarn/stable/src/main/scala/org/apache/spark/deploy/yarn/WorkerLauncher.scala @@ -193,7 +193,7 @@ class WorkerLauncher(args: ApplicationMasterArguments, conf: Configuration, spar // TODO: Handle container failure yarnAllocator.addResourceRequests(args.numWorkers) - while (yarnAllocator.getNumWorkersRunning < args.numWorkers) { + while ((yarnAllocator.getNumWorkersRunning < args.numWorkers) && (!driverClosed)) { yarnAllocator.allocateResources() Thread.sleep(100) } From 44a2b03b6f6107dd4d0b13d94209079f8dad1aa7 Mon Sep 17 00:00:00 2001 From: Kay Ousterhout Date: Wed, 5 Feb 2014 23:38:12 -0800 Subject: [PATCH 091/133] Merge pull request #545 from kayousterhout/fix_progress. Closes #545. Fix off-by-one error with task progress info log. Author: Kay Ousterhout == Merge branch commits == commit 29798fc685c4e7e3eb3bf91c75df7fa8ec94a235 Author: Kay Ousterhout Date: Wed Feb 5 13:40:01 2014 -0800 Fix off-by-one error with task progress info log. (cherry picked from commit 79c95527a77af32bd83a968c1a56feb22e441b7d) Signed-off-by: Reynold Xin --- .../main/scala/org/apache/spark/scheduler/TaskSetManager.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala index e91470800c82f..777f31dc5e053 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala @@ -437,13 +437,13 @@ private[spark] class TaskSetManager( info.markSuccessful() removeRunningTask(tid) if (!successful(index)) { + tasksSuccessful += 1 logInfo("Finished TID %s in %d ms on %s (progress: %d/%d)".format( tid, info.duration, info.host, tasksSuccessful, numTasks)) sched.dagScheduler.taskEnded( tasks(index), Success, result.value, result.accumUpdates, info, result.metrics) // Mark successful and stop if all the tasks have succeeded. - tasksSuccessful += 1 successful(index) = true if (tasksSuccessful == numTasks) { sched.taskSetFinished(this) From 94896bbf03183674e052024930811c9b10b81a4b Mon Sep 17 00:00:00 2001 From: Kay Ousterhout Date: Thu, 6 Feb 2014 16:10:48 -0800 Subject: [PATCH 092/133] Merge pull request #321 from kayousterhout/ui_kill_fix. Closes #321. Inform DAG scheduler about all started/finished tasks. Previously, the DAG scheduler was not always informed when tasks started and finished. The simplest example here is for speculated tasks: the DAGScheduler was only told about the first attempt of a task, meaning that SparkListeners were also not told about multiple task attempts, so users can't see what's going on with speculation in the UI. The DAGScheduler also wasn't always told about finished tasks, so in the UI, some tasks will never be shown as finished (this occurs, for example, if a task set gets killed). The other problem is that the fairness accounting was wrong -- the number of running tasks in a pool was decreased when a task set was considered done, even if all of its tasks hadn't yet finished. Author: Kay Ousterhout == Merge branch commits == commit c8d547d0f7a17f5a193bef05f5872b9f475675c5 Author: Kay Ousterhout Date: Wed Jan 15 16:47:33 2014 -0800 Addressed Reynold's review comments. Always use a TaskEndReason (remove the option), and explicitly signal when we don't know the reason. Also, always tell DAGScheduler (and associated listeners) about started tasks, even when they're speculated. commit 3fee1e2e3c06b975ff7f95d595448f38cce97a04 Author: Kay Ousterhout Date: Wed Jan 8 22:58:13 2014 -0800 Fixed broken test and improved logging commit ff12fcaa2567c5d02b75a1d5db35687225bcd46f Author: Kay Ousterhout Date: Sun Dec 29 21:08:20 2013 -0800 Inform DAG scheduler about all finished tasks. Previously, the DAG scheduler was not always informed when tasks finished. For example, when a task set was aborted, the DAG scheduler was never told when the tasks in that task set finished. The DAG scheduler was also never told about the completion of speculated tasks. This led to confusion with SparkListeners because information about the completion of those tasks was never passed on to the listeners (so in the UI, for example, some tasks will never be shown as finished). The other problem is that the fairness accounting was wrong -- the number of running tasks in a pool was decreased when a task set was considered done, even if all of its tasks hadn't yet finished. (cherry picked from commit 18ad59e2c6b7bd009e8ba5ebf8fcf99630863029) Signed-off-by: Patrick Wendell --- .../org/apache/spark/TaskEndReason.scala | 13 ++ .../apache/spark/scheduler/DAGScheduler.scala | 4 +- .../apache/spark/scheduler/StageInfo.scala | 6 + .../spark/scheduler/TaskResultGetter.scala | 8 +- .../spark/scheduler/TaskSchedulerImpl.scala | 46 ++--- .../spark/scheduler/TaskSetManager.scala | 193 +++++++++--------- .../scheduler/ClusterSchedulerSuite.scala | 12 +- .../spark/scheduler/SparkListenerSuite.scala | 41 +++- .../spark/scheduler/TaskSetManagerSuite.scala | 4 +- 9 files changed, 183 insertions(+), 144 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/TaskEndReason.scala b/core/src/main/scala/org/apache/spark/TaskEndReason.scala index faf6dcd618623..3fd6f5eb472f4 100644 --- a/core/src/main/scala/org/apache/spark/TaskEndReason.scala +++ b/core/src/main/scala/org/apache/spark/TaskEndReason.scala @@ -53,3 +53,16 @@ private[spark] case class ExceptionFailure( private[spark] case object TaskResultLost extends TaskEndReason private[spark] case object TaskKilled extends TaskEndReason + +/** + * The task failed because the executor that it was running on was lost. This may happen because + * the task crashed the JVM. + */ +private[spark] case object ExecutorLostFailure extends TaskEndReason + +/** + * We don't know why the task ended -- for example, because of a ClassNotFound exception when + * deserializing the task result. + */ +private[spark] case object UnknownReason extends TaskEndReason + diff --git a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala index 237cbf4c0c942..821241508ea32 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala @@ -954,8 +954,8 @@ class DAGScheduler( // Do nothing here; the TaskScheduler handles these failures and resubmits the task. case other => - // Unrecognized failure - abort all jobs depending on this stage - abortStage(stageIdToStage(task.stageId), task + " failed: " + other) + // Unrecognized failure - also do nothing. If the task fails repeatedly, the TaskScheduler + // will abort the job. } } diff --git a/core/src/main/scala/org/apache/spark/scheduler/StageInfo.scala b/core/src/main/scala/org/apache/spark/scheduler/StageInfo.scala index e9f2198a007e5..c4d1ad5733b4c 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/StageInfo.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/StageInfo.scala @@ -21,6 +21,12 @@ import scala.collection._ import org.apache.spark.executor.TaskMetrics +/** + * Stores information about a stage to pass from the scheduler to SparkListeners. + * + * taskInfos stores the metrics for all tasks that have completed, including redundant, speculated + * tasks. + */ class StageInfo( stage: Stage, val taskInfos: mutable.Buffer[(TaskInfo, TaskMetrics)] = mutable.Buffer[(TaskInfo, TaskMetrics)]() diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskResultGetter.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskResultGetter.scala index 35e9544718eb2..bdec08e968a45 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskResultGetter.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskResultGetter.scala @@ -57,7 +57,7 @@ private[spark] class TaskResultGetter(sparkEnv: SparkEnv, scheduler: TaskSchedul * between when the task ended and when we tried to fetch the result, or if the * block manager had to flush the result. */ scheduler.handleFailedTask( - taskSetManager, tid, TaskState.FINISHED, Some(TaskResultLost)) + taskSetManager, tid, TaskState.FINISHED, TaskResultLost) return } val deserializedResult = serializer.get().deserialize[DirectTaskResult[_]]( @@ -80,13 +80,13 @@ private[spark] class TaskResultGetter(sparkEnv: SparkEnv, scheduler: TaskSchedul def enqueueFailedTask(taskSetManager: TaskSetManager, tid: Long, taskState: TaskState, serializedData: ByteBuffer) { - var reason: Option[TaskEndReason] = None + var reason : TaskEndReason = UnknownReason getTaskResultExecutor.execute(new Runnable { override def run() { try { if (serializedData != null && serializedData.limit() > 0) { - reason = Some(serializer.get().deserialize[TaskEndReason]( - serializedData, getClass.getClassLoader)) + reason = serializer.get().deserialize[TaskEndReason]( + serializedData, getClass.getClassLoader) } } catch { case cnd: ClassNotFoundException => diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala index 83ba5840155fb..5b525155e9f62 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSchedulerImpl.scala @@ -67,7 +67,6 @@ private[spark] class TaskSchedulerImpl( val taskIdToTaskSetId = new HashMap[Long, String] val taskIdToExecutorId = new HashMap[Long, String] - val taskSetTaskIds = new HashMap[String, HashSet[Long]] @volatile private var hasReceivedTask = false @volatile private var hasLaunchedTask = false @@ -142,7 +141,6 @@ private[spark] class TaskSchedulerImpl( val manager = new TaskSetManager(this, taskSet, maxTaskFailures) activeTaskSets(taskSet.id) = manager schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties) - taskSetTaskIds(taskSet.id) = new HashSet[Long]() if (!isLocal && !hasReceivedTask) { starvationTimer.scheduleAtFixedRate(new TimerTask() { @@ -171,31 +169,25 @@ private[spark] class TaskSchedulerImpl( // the stage. // 2. The task set manager has been created but no tasks has been scheduled. In this case, // simply abort the stage. - val taskIds = taskSetTaskIds(tsm.taskSet.id) - if (taskIds.size > 0) { - taskIds.foreach { tid => - val execId = taskIdToExecutorId(tid) - backend.killTask(tid, execId) - } + tsm.runningTasksSet.foreach { tid => + val execId = taskIdToExecutorId(tid) + backend.killTask(tid, execId) } + tsm.abort("Stage %s cancelled".format(stageId)) logInfo("Stage %d was cancelled".format(stageId)) - tsm.removeAllRunningTasks() - taskSetFinished(tsm) } } + /** + * Called to indicate that all task attempts (including speculated tasks) associated with the + * given TaskSetManager have completed, so state associated with the TaskSetManager should be + * cleaned up. + */ def taskSetFinished(manager: TaskSetManager): Unit = synchronized { - // Check to see if the given task set has been removed. This is possible in the case of - // multiple unrecoverable task failures (e.g. if the entire task set is killed when it has - // more than one running tasks). - if (activeTaskSets.contains(manager.taskSet.id)) { - activeTaskSets -= manager.taskSet.id - manager.parent.removeSchedulable(manager) - logInfo("Remove TaskSet %s from pool %s".format(manager.taskSet.id, manager.parent.name)) - taskIdToTaskSetId --= taskSetTaskIds(manager.taskSet.id) - taskIdToExecutorId --= taskSetTaskIds(manager.taskSet.id) - taskSetTaskIds.remove(manager.taskSet.id) - } + activeTaskSets -= manager.taskSet.id + manager.parent.removeSchedulable(manager) + logInfo("Removed TaskSet %s, whose tasks have all completed, from pool %s" + .format(manager.taskSet.id, manager.parent.name)) } /** @@ -237,7 +229,6 @@ private[spark] class TaskSchedulerImpl( tasks(i) += task val tid = task.taskId taskIdToTaskSetId(tid) = taskSet.taskSet.id - taskSetTaskIds(taskSet.taskSet.id) += tid taskIdToExecutorId(tid) = execId activeExecutorIds += execId executorsByHost(host) += execId @@ -270,9 +261,6 @@ private[spark] class TaskSchedulerImpl( case Some(taskSetId) => if (TaskState.isFinished(state)) { taskIdToTaskSetId.remove(tid) - if (taskSetTaskIds.contains(taskSetId)) { - taskSetTaskIds(taskSetId) -= tid - } taskIdToExecutorId.remove(tid) } activeTaskSets.get(taskSetId).foreach { taskSet => @@ -285,7 +273,9 @@ private[spark] class TaskSchedulerImpl( } } case None => - logInfo("Ignoring update with state %s from TID %s because its task set is gone" + logError( + ("Ignoring update with state %s for TID %s because its task set is gone (this is " + + "likely the result of receiving duplicate task finished status updates)") .format(state, tid)) } } catch { @@ -314,9 +304,9 @@ private[spark] class TaskSchedulerImpl( taskSetManager: TaskSetManager, tid: Long, taskState: TaskState, - reason: Option[TaskEndReason]) = synchronized { + reason: TaskEndReason) = synchronized { taskSetManager.handleFailedTask(tid, taskState, reason) - if (taskState != TaskState.KILLED) { + if (!taskSetManager.isZombie && taskState != TaskState.KILLED) { // Need to revive offers again now that the task set manager state has been updated to // reflect failed tasks that need to be re-run. backend.reviveOffers() diff --git a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala index 777f31dc5e053..3f0ee7a6d48cb 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/TaskSetManager.scala @@ -26,9 +26,10 @@ import scala.collection.mutable.HashSet import scala.math.max import scala.math.min -import org.apache.spark.{ExceptionFailure, FetchFailed, Logging, Resubmitted, SparkEnv, - Success, TaskEndReason, TaskKilled, TaskResultLost, TaskState} +import org.apache.spark.{ExceptionFailure, ExecutorLostFailure, FetchFailed, Logging, Resubmitted, + SparkEnv, Success, TaskEndReason, TaskKilled, TaskResultLost, TaskState} import org.apache.spark.TaskState.TaskState +import org.apache.spark.executor.TaskMetrics import org.apache.spark.util.{Clock, SystemClock} @@ -82,8 +83,16 @@ private[spark] class TaskSetManager( var name = "TaskSet_"+taskSet.stageId.toString var parent: Pool = null - var runningTasks = 0 - private val runningTasksSet = new HashSet[Long] + val runningTasksSet = new HashSet[Long] + override def runningTasks = runningTasksSet.size + + // True once no more tasks should be launched for this task set manager. TaskSetManagers enter + // the zombie state once at least one attempt of each task has completed successfully, or if the + // task set is aborted (for example, because it was killed). TaskSetManagers remain in the zombie + // state until all tasks have finished running; we keep TaskSetManagers that are in the zombie + // state in order to continue to track and account for the running tasks. + // TODO: We should kill any running task attempts when the task set manager becomes a zombie. + var isZombie = false // Set of pending tasks for each executor. These collections are actually // treated as stacks, in which new tasks are added to the end of the @@ -345,7 +354,7 @@ private[spark] class TaskSetManager( maxLocality: TaskLocality.TaskLocality) : Option[TaskDescription] = { - if (tasksSuccessful < numTasks && availableCpus >= CPUS_PER_TASK) { + if (!isZombie && availableCpus >= CPUS_PER_TASK) { val curTime = clock.getTime() var allowedLocality = getAllowedLocalityLevel(curTime) @@ -380,8 +389,7 @@ private[spark] class TaskSetManager( logInfo("Serialized task %s:%d as %d bytes in %d ms".format( taskSet.id, index, serializedTask.limit, timeTaken)) val taskName = "task %s:%d".format(taskSet.id, index) - if (taskAttempts(index).size == 1) - taskStarted(task,info) + sched.dagScheduler.taskStarted(task, info) return Some(new TaskDescription(taskId, execId, taskName, index, serializedTask)) } case _ => @@ -390,6 +398,12 @@ private[spark] class TaskSetManager( None } + private def maybeFinishTaskSet() { + if (isZombie && runningTasks == 0) { + sched.taskSetFinished(this) + } + } + /** * Get the level we can launch tasks according to delay scheduling, based on current wait time. */ @@ -418,10 +432,6 @@ private[spark] class TaskSetManager( index } - private def taskStarted(task: Task[_], info: TaskInfo) { - sched.dagScheduler.taskStarted(task, info) - } - def handleTaskGettingResult(tid: Long) = { val info = taskInfos(tid) info.markGettingResult() @@ -436,123 +446,116 @@ private[spark] class TaskSetManager( val index = info.index info.markSuccessful() removeRunningTask(tid) + sched.dagScheduler.taskEnded( + tasks(index), Success, result.value, result.accumUpdates, info, result.metrics) if (!successful(index)) { tasksSuccessful += 1 logInfo("Finished TID %s in %d ms on %s (progress: %d/%d)".format( tid, info.duration, info.host, tasksSuccessful, numTasks)) - sched.dagScheduler.taskEnded( - tasks(index), Success, result.value, result.accumUpdates, info, result.metrics) - // Mark successful and stop if all the tasks have succeeded. successful(index) = true if (tasksSuccessful == numTasks) { - sched.taskSetFinished(this) + isZombie = true } } else { logInfo("Ignorning task-finished event for TID " + tid + " because task " + index + " has already completed successfully") } + maybeFinishTaskSet() } /** * Marks the task as failed, re-adds it to the list of pending tasks, and notifies the * DAG Scheduler. */ - def handleFailedTask(tid: Long, state: TaskState, reason: Option[TaskEndReason]) { + def handleFailedTask(tid: Long, state: TaskState, reason: TaskEndReason) { val info = taskInfos(tid) if (info.failed) { return } removeRunningTask(tid) - val index = info.index info.markFailed() - var failureReason = "unknown" - if (!successful(index)) { + val index = info.index + copiesRunning(index) -= 1 + if (!isZombie) { logWarning("Lost TID %s (task %s:%d)".format(tid, taskSet.id, index)) - copiesRunning(index) -= 1 - // Check if the problem is a map output fetch failure. In that case, this - // task will never succeed on any node, so tell the scheduler about it. - reason.foreach { - case fetchFailed: FetchFailed => - logWarning("Loss was due to fetch failure from " + fetchFailed.bmAddress) - sched.dagScheduler.taskEnded(tasks(index), fetchFailed, null, null, info, null) + } + var taskMetrics : TaskMetrics = null + var failureReason = "unknown" + reason match { + case fetchFailed: FetchFailed => + logWarning("Loss was due to fetch failure from " + fetchFailed.bmAddress) + if (!successful(index)) { successful(index) = true tasksSuccessful += 1 - sched.taskSetFinished(this) - removeAllRunningTasks() - return - - case TaskKilled => - logWarning("Task %d was killed.".format(tid)) - sched.dagScheduler.taskEnded(tasks(index), reason.get, null, null, info, null) + } + isZombie = true + + case TaskKilled => + logWarning("Task %d was killed.".format(tid)) + + case ef: ExceptionFailure => + taskMetrics = ef.metrics.getOrElse(null) + if (ef.className == classOf[NotSerializableException].getName()) { + // If the task result wasn't serializable, there's no point in trying to re-execute it. + logError("Task %s:%s had a not serializable result: %s; not retrying".format( + taskSet.id, index, ef.description)) + abort("Task %s:%s had a not serializable result: %s".format( + taskSet.id, index, ef.description)) return - - case ef: ExceptionFailure => - sched.dagScheduler.taskEnded( - tasks(index), ef, null, null, info, ef.metrics.getOrElse(null)) - if (ef.className == classOf[NotSerializableException].getName()) { - // If the task result wasn't rerializable, there's no point in trying to re-execute it. - logError("Task %s:%s had a not serializable result: %s; not retrying".format( - taskSet.id, index, ef.description)) - abort("Task %s:%s had a not serializable result: %s".format( - taskSet.id, index, ef.description)) - return - } - val key = ef.description - failureReason = "Exception failure: %s".format(ef.description) - val now = clock.getTime() - val (printFull, dupCount) = { - if (recentExceptions.contains(key)) { - val (dupCount, printTime) = recentExceptions(key) - if (now - printTime > EXCEPTION_PRINT_INTERVAL) { - recentExceptions(key) = (0, now) - (true, 0) - } else { - recentExceptions(key) = (dupCount + 1, printTime) - (false, dupCount + 1) - } - } else { + } + val key = ef.description + failureReason = "Exception failure: %s".format(ef.description) + val now = clock.getTime() + val (printFull, dupCount) = { + if (recentExceptions.contains(key)) { + val (dupCount, printTime) = recentExceptions(key) + if (now - printTime > EXCEPTION_PRINT_INTERVAL) { recentExceptions(key) = (0, now) (true, 0) + } else { + recentExceptions(key) = (dupCount + 1, printTime) + (false, dupCount + 1) } - } - if (printFull) { - val locs = ef.stackTrace.map(loc => "\tat %s".format(loc.toString)) - logWarning("Loss was due to %s\n%s\n%s".format( - ef.className, ef.description, locs.mkString("\n"))) } else { - logInfo("Loss was due to %s [duplicate %d]".format(ef.description, dupCount)) + recentExceptions(key) = (0, now) + (true, 0) } + } + if (printFull) { + val locs = ef.stackTrace.map(loc => "\tat %s".format(loc.toString)) + logWarning("Loss was due to %s\n%s\n%s".format( + ef.className, ef.description, locs.mkString("\n"))) + } else { + logInfo("Loss was due to %s [duplicate %d]".format(ef.description, dupCount)) + } - case TaskResultLost => - failureReason = "Lost result for TID %s on host %s".format(tid, info.host) - logWarning(failureReason) - sched.dagScheduler.taskEnded(tasks(index), TaskResultLost, null, null, info, null) + case TaskResultLost => + failureReason = "Lost result for TID %s on host %s".format(tid, info.host) + logWarning(failureReason) - case _ => {} - } - // On non-fetch failures, re-enqueue the task as pending for a max number of retries - addPendingTask(index) - if (state != TaskState.KILLED) { - numFailures(index) += 1 - if (numFailures(index) >= maxTaskFailures) { - logError("Task %s:%d failed %d times; aborting job".format( - taskSet.id, index, maxTaskFailures)) - abort("Task %s:%d failed %d times (most recent failure: %s)".format( - taskSet.id, index, maxTaskFailures, failureReason)) - } + case _ => {} + } + sched.dagScheduler.taskEnded(tasks(index), reason, null, null, info, taskMetrics) + addPendingTask(index) + if (!isZombie && state != TaskState.KILLED) { + numFailures(index) += 1 + if (numFailures(index) >= maxTaskFailures) { + logError("Task %s:%d failed %d times; aborting job".format( + taskSet.id, index, maxTaskFailures)) + abort("Task %s:%d failed %d times (most recent failure: %s)".format( + taskSet.id, index, maxTaskFailures, failureReason)) + return } - } else { - logInfo("Ignoring task-lost event for TID " + tid + - " because task " + index + " is already finished") } + maybeFinishTaskSet() } def abort(message: String) { // TODO: Kill running tasks if we were not terminated due to a Mesos error sched.dagScheduler.taskSetFailed(taskSet, message) - removeAllRunningTasks() - sched.taskSetFinished(this) + isZombie = true + maybeFinishTaskSet() } /** If the given task ID is not in the set of running tasks, adds it. @@ -563,7 +566,6 @@ private[spark] class TaskSetManager( if (runningTasksSet.add(tid) && parent != null) { parent.increaseRunningTasks(1) } - runningTasks = runningTasksSet.size } /** If the given task ID is in the set of running tasks, removes it. */ @@ -571,16 +573,6 @@ private[spark] class TaskSetManager( if (runningTasksSet.remove(tid) && parent != null) { parent.decreaseRunningTasks(1) } - runningTasks = runningTasksSet.size - } - - private[scheduler] def removeAllRunningTasks() { - val numRunningTasks = runningTasksSet.size - runningTasksSet.clear() - if (parent != null) { - parent.decreaseRunningTasks(numRunningTasks) - } - runningTasks = 0 } override def getSchedulableByName(name: String): Schedulable = { @@ -629,7 +621,7 @@ private[spark] class TaskSetManager( } // Also re-enqueue any tasks that were running on the node for ((tid, info) <- taskInfos if info.running && info.executorId == execId) { - handleFailedTask(tid, TaskState.FAILED, None) + handleFailedTask(tid, TaskState.FAILED, ExecutorLostFailure) } } @@ -641,8 +633,9 @@ private[spark] class TaskSetManager( * we don't scan the whole task set. It might also help to make this sorted by launch time. */ override def checkSpeculatableTasks(): Boolean = { - // Can't speculate if we only have one task, or if all tasks have finished. - if (numTasks == 1 || tasksSuccessful == numTasks) { + // Can't speculate if we only have one task, and no need to speculate if the task set is a + // zombie. + if (isZombie || numTasks == 1) { return false } var foundTasks = false diff --git a/core/src/test/scala/org/apache/spark/scheduler/ClusterSchedulerSuite.scala b/core/src/test/scala/org/apache/spark/scheduler/ClusterSchedulerSuite.scala index 235d31709af2b..98ea4cb5612ec 100644 --- a/core/src/test/scala/org/apache/spark/scheduler/ClusterSchedulerSuite.scala +++ b/core/src/test/scala/org/apache/spark/scheduler/ClusterSchedulerSuite.scala @@ -36,22 +36,24 @@ class FakeTaskSetManager( parent = null weight = 1 minShare = 2 - runningTasks = 0 priority = initPriority stageId = initStageId name = "TaskSet_"+stageId override val numTasks = initNumTasks tasksSuccessful = 0 + var numRunningTasks = 0 + override def runningTasks = numRunningTasks + def increaseRunningTasks(taskNum: Int) { - runningTasks += taskNum + numRunningTasks += taskNum if (parent != null) { parent.increaseRunningTasks(taskNum) } } def decreaseRunningTasks(taskNum: Int) { - runningTasks -= taskNum + numRunningTasks -= taskNum if (parent != null) { parent.decreaseRunningTasks(taskNum) } @@ -77,7 +79,7 @@ class FakeTaskSetManager( maxLocality: TaskLocality.TaskLocality) : Option[TaskDescription] = { - if (tasksSuccessful + runningTasks < numTasks) { + if (tasksSuccessful + numRunningTasks < numTasks) { increaseRunningTasks(1) Some(new TaskDescription(0, execId, "task 0:0", 0, null)) } else { @@ -98,7 +100,7 @@ class FakeTaskSetManager( } def abort() { - decreaseRunningTasks(runningTasks) + decreaseRunningTasks(numRunningTasks) parent.removeSchedulable(this) } } diff --git a/core/src/test/scala/org/apache/spark/scheduler/SparkListenerSuite.scala b/core/src/test/scala/org/apache/spark/scheduler/SparkListenerSuite.scala index 1a16e438c43d8..368c5154ea3b9 100644 --- a/core/src/test/scala/org/apache/spark/scheduler/SparkListenerSuite.scala +++ b/core/src/test/scala/org/apache/spark/scheduler/SparkListenerSuite.scala @@ -168,6 +168,39 @@ class SparkListenerSuite extends FunSuite with LocalSparkContext with ShouldMatc assert(listener.endedTasks.contains(TASK_INDEX)) } + test("onTaskEnd() should be called for all started tasks, even after job has been killed") { + val WAIT_TIMEOUT_MILLIS = 10000 + val listener = new SaveTaskEvents + sc.addSparkListener(listener) + + val numTasks = 10 + val f = sc.parallelize(1 to 10000, numTasks).map { i => Thread.sleep(10); i }.countAsync() + // Wait until one task has started (because we want to make sure that any tasks that are started + // have corresponding end events sent to the listener). + var finishTime = System.currentTimeMillis + WAIT_TIMEOUT_MILLIS + listener.synchronized { + var remainingWait = finishTime - System.currentTimeMillis + while (listener.startedTasks.isEmpty && remainingWait > 0) { + listener.wait(remainingWait) + remainingWait = finishTime - System.currentTimeMillis + } + assert(!listener.startedTasks.isEmpty) + } + + f.cancel() + + // Ensure that onTaskEnd is called for all started tasks. + finishTime = System.currentTimeMillis + WAIT_TIMEOUT_MILLIS + listener.synchronized { + var remainingWait = finishTime - System.currentTimeMillis + while (listener.endedTasks.size < listener.startedTasks.size && remainingWait > 0) { + listener.wait(finishTime - System.currentTimeMillis) + remainingWait = finishTime - System.currentTimeMillis + } + assert(listener.endedTasks.size === listener.startedTasks.size) + } + } + def checkNonZeroAvg(m: Traversable[Long], msg: String) { assert(m.sum / m.size.toDouble > 0.0, msg) } @@ -184,12 +217,14 @@ class SparkListenerSuite extends FunSuite with LocalSparkContext with ShouldMatc val startedGettingResultTasks = new HashSet[Int]() val endedTasks = new HashSet[Int]() - override def onTaskStart(taskStart: SparkListenerTaskStart) { + override def onTaskStart(taskStart: SparkListenerTaskStart) = synchronized { startedTasks += taskStart.taskInfo.index + notify() } - override def onTaskEnd(taskEnd: SparkListenerTaskEnd) { - endedTasks += taskEnd.taskInfo.index + override def onTaskEnd(taskEnd: SparkListenerTaskEnd) = synchronized { + endedTasks += taskEnd.taskInfo.index + notify() } override def onTaskGettingResult(taskGettingResult: SparkListenerTaskGettingResult) { diff --git a/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala b/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala index ecac2f79a25e2..de321c45b547c 100644 --- a/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala +++ b/core/src/test/scala/org/apache/spark/scheduler/TaskSetManagerSuite.scala @@ -269,7 +269,7 @@ class TaskSetManagerSuite extends FunSuite with LocalSparkContext with Logging { assert(manager.resourceOffer("exec1", "host1", 1, ANY).get.index === 0) // Tell it the task has finished but the result was lost. - manager.handleFailedTask(0, TaskState.FINISHED, Some(TaskResultLost)) + manager.handleFailedTask(0, TaskState.FINISHED, TaskResultLost) assert(sched.endedTasks(0) === TaskResultLost) // Re-offer the host -- now we should get task 0 again. @@ -290,7 +290,7 @@ class TaskSetManagerSuite extends FunSuite with LocalSparkContext with Logging { assert(offerResult.isDefined, "Expect resource offer on iteration %s to return a task".format(index)) assert(offerResult.get.index === 0) - manager.handleFailedTask(offerResult.get.taskId, TaskState.FINISHED, Some(TaskResultLost)) + manager.handleFailedTask(offerResult.get.taskId, TaskState.FINISHED, TaskResultLost) if (index < MAX_TASK_FAILURES) { assert(!sched.taskSetsFailed.contains(taskSet.id)) } else { From 24e5298d24b607bc04293ac83f95873c39db2969 Mon Sep 17 00:00:00 2001 From: Kay Ousterhout Date: Thu, 6 Feb 2014 16:15:24 -0800 Subject: [PATCH 093/133] Merge pull request #450 from kayousterhout/fetch_failures. Closes #450. Only run ResubmitFailedStages event after a fetch fails Previously, the ResubmitFailedStages event was called every 200 milliseconds, leading to a lot of unnecessary event processing and clogged DAGScheduler logs. Author: Kay Ousterhout == Merge branch commits == commit e603784b3a562980e6f1863845097effe2129d3b Author: Kay Ousterhout Date: Wed Feb 5 11:34:41 2014 -0800 Re-add check for empty set of failed stages commit d258f0ef50caff4bbb19fb95a6b82186db1935bf Author: Kay Ousterhout Date: Wed Jan 15 23:35:41 2014 -0800 Only run ResubmitFailedStages event after a fetch fails Previously, the ResubmitFailedStages event was called every 200 milliseconds, leading to a lot of unnecessary event processing and clogged DAGScheduler logs. (cherry picked from commit 0b448df6ac520a7977b1eb51e8c55e33f3fd2da8) Signed-off-by: Patrick Wendell --- .../apache/spark/scheduler/DAGScheduler.scala | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala index 821241508ea32..21d16fabefaa5 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala @@ -155,7 +155,6 @@ class DAGScheduler( val failed = new HashSet[Stage] // Stages that must be resubmitted due to fetch failures // Missing tasks from each stage val pendingTasks = new TimeStampedHashMap[Stage, HashSet[Task[_]]] - var lastFetchFailureTime: Long = 0 // Used to wait a bit to avoid repeated resubmits val activeJobs = new HashSet[ActiveJob] val resultStageToJob = new HashMap[Stage, ActiveJob] @@ -176,22 +175,6 @@ class DAGScheduler( */ def start() { eventProcessActor = env.actorSystem.actorOf(Props(new Actor { - /** - * A handle to the periodical task, used to cancel the task when the actor is stopped. - */ - var resubmissionTask: Cancellable = _ - - override def preStart() { - import context.dispatcher - /** - * A message is sent to the actor itself periodically to remind the actor to resubmit failed - * stages. In this way, stage resubmission can be done within the same thread context of - * other event processing logic to avoid unnecessary synchronization overhead. - */ - resubmissionTask = context.system.scheduler.schedule( - RESUBMIT_TIMEOUT, RESUBMIT_TIMEOUT, self, ResubmitFailedStages) - } - /** * The main event loop of the DAG scheduler. */ @@ -207,7 +190,6 @@ class DAGScheduler( if (!processEvent(event)) { submitWaitingStages() } else { - resubmissionTask.cancel() context.stop(self) } } @@ -620,6 +602,8 @@ class DAGScheduler( case ResubmitFailedStages => if (failed.size > 0) { + // Failed stages may be removed by job cancellation, so failed might be empty even if + // the ResubmitFailedStages event has been scheduled. resubmitFailedStages() } @@ -926,7 +910,6 @@ class DAGScheduler( // Mark the stage that the reducer was in as unrunnable val failedStage = stageIdToStage(task.stageId) running -= failedStage - failed += failedStage // TODO: Cancel running tasks in the stage logInfo("Marking " + failedStage + " (" + failedStage.name + ") for resubmision due to a fetch failure") @@ -938,10 +921,16 @@ class DAGScheduler( } logInfo("The failed fetch was from " + mapStage + " (" + mapStage.name + "); marking it for resubmission") + if (failed.isEmpty && eventProcessActor != null) { + // Don't schedule an event to resubmit failed stages if failed isn't empty, because + // in that case the event will already have been scheduled. eventProcessActor may be + // null during unit tests. + import env.actorSystem.dispatcher + env.actorSystem.scheduler.scheduleOnce( + RESUBMIT_TIMEOUT, eventProcessActor, ResubmitFailedStages) + } + failed += failedStage failed += mapStage - // Remember that a fetch failed now; this is used to resubmit the broken - // stages later, after a small wait (to give other tasks the chance to fail) - lastFetchFailureTime = System.currentTimeMillis() // TODO: Use pluggable clock // TODO: mark the executor as failed only if there were lots of fetch failures on it if (bmAddress != null) { handleExecutorLost(bmAddress.executorId, Some(task.epoch)) From ce179f6b62673ad6e0b7469f77d95e31fc354e2b Mon Sep 17 00:00:00 2001 From: Andrew Or Date: Thu, 6 Feb 2014 22:05:53 -0800 Subject: [PATCH 094/133] Merge pull request #533 from andrewor14/master. Closes #533. External spilling - generalize batching logic The existing implementation consists of a hack for Kryo specifically and only works for LZF compression. Introducing an intermediate batch-level stream takes care of pre-fetching and other arbitrary behavior of higher level streams in a more general way. Author: Andrew Or == Merge branch commits == commit 3ddeb7ef89a0af2b685fb5d071aa0f71c975cc82 Author: Andrew Or Date: Wed Feb 5 12:09:32 2014 -0800 Also privatize fields commit 090544a87a0767effd0c835a53952f72fc8d24f0 Author: Andrew Or Date: Wed Feb 5 10:58:23 2014 -0800 Privatize methods commit 13920c918efe22e66a1760b14beceb17a61fd8cc Author: Andrew Or Date: Tue Feb 4 16:34:15 2014 -0800 Update docs commit bd5a1d7350467ed3dc19c2de9b2c9f531f0e6aa3 Author: Andrew Or Date: Tue Feb 4 13:44:24 2014 -0800 Typo: phyiscal -> physical commit 287ef44e593ad72f7434b759be3170d9ee2723d2 Author: Andrew Or Date: Tue Feb 4 13:38:32 2014 -0800 Avoid reading the entire batch into memory; also simplify streaming logic Additionally, address formatting comments. commit 3df700509955f7074821e9aab1e74cb53c58b5a5 Merge: a531d2e 164489d Author: Andrew Or Date: Mon Feb 3 18:27:49 2014 -0800 Merge branch 'master' of github.com:andrewor14/incubator-spark commit a531d2e347acdcecf2d0ab72cd4f965ab5e145d8 Author: Andrew Or Date: Mon Feb 3 18:18:04 2014 -0800 Relax assumptions on compressors and serializers when batching This commit introduces an intermediate layer of an input stream on the batch level. This guards against interference from higher level streams (i.e. compression and deserialization streams), especially pre-fetching, without specifically targeting particular libraries (Kryo) and forcing shuffle spill compression to use LZF. commit 164489d6f176bdecfa9dabec2dfce5504d1ee8af Author: Andrew Or Date: Mon Feb 3 18:18:04 2014 -0800 Relax assumptions on compressors and serializers when batching This commit introduces an intermediate layer of an input stream on the batch level. This guards against interference from higher level streams (i.e. compression and deserialization streams), especially pre-fetching, without specifically targeting particular libraries (Kryo) and forcing shuffle spill compression to use LZF. (cherry picked from commit 1896c6e7c9f5c29284a045128b4aca0d5a6e7220) Signed-off-by: Patrick Wendell --- .../spark/storage/BlockObjectWriter.scala | 8 +- .../spark/storage/DiskBlockManager.scala | 2 +- .../collection/ExternalAppendOnlyMap.scala | 179 ++++++++---------- docs/configuration.md | 4 +- 4 files changed, 93 insertions(+), 100 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala b/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala index 530712b5df4a8..696b930a26b9e 100644 --- a/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala +++ b/core/src/main/scala/org/apache/spark/storage/BlockObjectWriter.scala @@ -66,6 +66,11 @@ private[spark] abstract class BlockObjectWriter(val blockId: BlockId) { * Cumulative time spent performing blocking writes, in ns. */ def timeWriting(): Long + + /** + * Number of bytes written so far + */ + def bytesWritten: Long } /** BlockObjectWriter which writes directly to a file on disk. Appends to the given file. */ @@ -183,7 +188,8 @@ private[spark] class DiskBlockObjectWriter( // Only valid if called after close() override def timeWriting() = _timeWriting - def bytesWritten: Long = { + // Only valid if called after commit() + override def bytesWritten: Long = { lastValidPosition - initialPosition } } diff --git a/core/src/main/scala/org/apache/spark/storage/DiskBlockManager.scala b/core/src/main/scala/org/apache/spark/storage/DiskBlockManager.scala index a8ef7fa8b63eb..f3e1c38744d78 100644 --- a/core/src/main/scala/org/apache/spark/storage/DiskBlockManager.scala +++ b/core/src/main/scala/org/apache/spark/storage/DiskBlockManager.scala @@ -50,7 +50,7 @@ private[spark] class DiskBlockManager(shuffleManager: ShuffleBlockManager, rootD addShutdownHook() /** - * Returns the phyiscal file segment in which the given BlockId is located. + * Returns the physical file segment in which the given BlockId is located. * If the BlockId has been mapped to a specific FileSegment, that will be returned. * Otherwise, we assume the Block is mapped to a whole file identified by the BlockId directly. */ diff --git a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala index 3d9b09ec33e2a..7eb300d46e6e2 100644 --- a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala +++ b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala @@ -24,11 +24,11 @@ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import it.unimi.dsi.fastutil.io.FastBufferedInputStream +import com.google.common.io.ByteStreams import org.apache.spark.{Logging, SparkEnv} -import org.apache.spark.io.LZFCompressionCodec -import org.apache.spark.serializer.{KryoDeserializationStream, Serializer} -import org.apache.spark.storage.{BlockId, BlockManager, DiskBlockObjectWriter} +import org.apache.spark.serializer.Serializer +import org.apache.spark.storage.{BlockId, BlockManager} /** * An append-only map that spills sorted content to disk when there is insufficient space for it @@ -84,12 +84,15 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( // Number of in-memory pairs inserted before tracking the map's shuffle memory usage private val trackMemoryThreshold = 1000 - // Size of object batches when reading/writing from serializers. Objects are written in - // batches, with each batch using its own serialization stream. This cuts down on the size - // of reference-tracking maps constructed when deserializing a stream. - // - // NOTE: Setting this too low can cause excess copying when serializing, since some serializers - // grow internal data structures by growing + copying every time the number of objects doubles. + /** + * Size of object batches when reading/writing from serializers. + * + * Objects are written in batches, with each batch using its own serialization stream. This + * cuts down on the size of reference-tracking maps constructed when deserializing a stream. + * + * NOTE: Setting this too low can cause excessive copying when serializing, since some serializers + * grow internal data structures by growing + copying every time the number of objects doubles. + */ private val serializerBatchSize = sparkConf.getLong("spark.shuffle.spill.batchSize", 10000) // How many times we have spilled so far @@ -100,7 +103,6 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( private var _diskBytesSpilled = 0L private val fileBufferSize = sparkConf.getInt("spark.shuffle.file.buffer.kb", 100) * 1024 - private val syncWrites = sparkConf.getBoolean("spark.shuffle.sync", false) private val comparator = new KCComparator[K, C] private val ser = serializer.newInstance() @@ -153,37 +155,21 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( logWarning("Spilling in-memory map of %d MB to disk (%d time%s so far)" .format(mapSize / (1024 * 1024), spillCount, if (spillCount > 1) "s" else "")) val (blockId, file) = diskBlockManager.createTempBlock() + var writer = blockManager.getDiskWriter(blockId, file, serializer, fileBufferSize) + var objectsWritten = 0 - /* IMPORTANT NOTE: To avoid having to keep large object graphs in memory, this approach - * closes and re-opens serialization and compression streams within each file. This makes some - * assumptions about the way that serialization and compression streams work, specifically: - * - * 1) The serializer input streams do not pre-fetch data from the underlying stream. - * - * 2) Several compression streams can be opened, written to, and flushed on the write path - * while only one compression input stream is created on the read path - * - * In practice (1) is only true for Java, so we add a special fix below to make it work for - * Kryo. (2) is only true for LZF and not Snappy, so we coerce this to use LZF. - * - * To avoid making these assumptions we should create an intermediate stream that batches - * objects and sends an EOF to the higher layer streams to make sure they never prefetch data. - * This is a bit tricky because, within each segment, you'd need to track the total number - * of bytes written and then re-wind and write it at the beginning of the segment. This will - * most likely require using the file channel API. - */ + // List of batch sizes (bytes) in the order they are written to disk + val batchSizes = new ArrayBuffer[Long] - val shouldCompress = blockManager.shouldCompress(blockId) - val compressionCodec = new LZFCompressionCodec(sparkConf) - def wrapForCompression(outputStream: OutputStream) = { - if (shouldCompress) compressionCodec.compressedOutputStream(outputStream) else outputStream + // Flush the disk writer's contents to disk, and update relevant variables + def flush() = { + writer.commit() + val bytesWritten = writer.bytesWritten + batchSizes.append(bytesWritten) + _diskBytesSpilled += bytesWritten + objectsWritten = 0 } - def getNewWriter = new DiskBlockObjectWriter(blockId, file, serializer, fileBufferSize, - wrapForCompression, syncWrites) - - var writer = getNewWriter - var objectsWritten = 0 try { val it = currentMap.destructiveSortedIterator(comparator) while (it.hasNext) { @@ -192,22 +178,21 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( objectsWritten += 1 if (objectsWritten == serializerBatchSize) { - writer.commit() + flush() writer.close() - _diskBytesSpilled += writer.bytesWritten - writer = getNewWriter - objectsWritten = 0 + writer = blockManager.getDiskWriter(blockId, file, serializer, fileBufferSize) } } - - if (objectsWritten > 0) writer.commit() + if (objectsWritten > 0) { + flush() + } } finally { // Partial failures cannot be tolerated; do not revert partial writes writer.close() - _diskBytesSpilled += writer.bytesWritten } + currentMap = new SizeTrackingAppendOnlyMap[K, C] - spilledMaps.append(new DiskMapIterator(file, blockId)) + spilledMaps.append(new DiskMapIterator(file, blockId, batchSizes)) // Reset the amount of shuffle memory used by this map in the global pool val shuffleMemoryMap = SparkEnv.get.shuffleMemoryMap @@ -239,12 +224,12 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( private class ExternalIterator extends Iterator[(K, C)] { // A fixed-size queue that maintains a buffer for each stream we are currently merging - val mergeHeap = new mutable.PriorityQueue[StreamBuffer] + private val mergeHeap = new mutable.PriorityQueue[StreamBuffer] // Input streams are derived both from the in-memory map and spilled maps on disk // The in-memory map is sorted in place, while the spilled maps are already in sorted order - val sortedMap = currentMap.destructiveSortedIterator(comparator) - val inputStreams = Seq(sortedMap) ++ spilledMaps + private val sortedMap = currentMap.destructiveSortedIterator(comparator) + private val inputStreams = Seq(sortedMap) ++ spilledMaps inputStreams.foreach { it => val kcPairs = getMorePairs(it) @@ -252,11 +237,12 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( } /** - * Fetch from the given iterator until a key of different hash is retrieved. In the - * event of key hash collisions, this ensures no pairs are hidden from being merged. + * Fetch from the given iterator until a key of different hash is retrieved. + * + * In the event of key hash collisions, this ensures no pairs are hidden from being merged. * Assume the given iterator is in sorted order. */ - def getMorePairs(it: Iterator[(K, C)]): ArrayBuffer[(K, C)] = { + private def getMorePairs(it: Iterator[(K, C)]): ArrayBuffer[(K, C)] = { val kcPairs = new ArrayBuffer[(K, C)] if (it.hasNext) { var kc = it.next() @@ -274,7 +260,7 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( * If the given buffer contains a value for the given key, merge that value into * baseCombiner and remove the corresponding (K, C) pair from the buffer */ - def mergeIfKeyExists(key: K, baseCombiner: C, buffer: StreamBuffer): C = { + private def mergeIfKeyExists(key: K, baseCombiner: C, buffer: StreamBuffer): C = { var i = 0 while (i < buffer.pairs.size) { val (k, c) = buffer.pairs(i) @@ -293,7 +279,8 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( override def hasNext: Boolean = mergeHeap.exists(!_.pairs.isEmpty) /** - * Select a key with the minimum hash, then combine all values with the same key from all input streams. + * Select a key with the minimum hash, then combine all values with the same key from all + * input streams */ override def next(): (K, C) = { // Select a key from the StreamBuffer that holds the lowest key hash @@ -333,7 +320,7 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( * * StreamBuffers are ordered by the minimum key hash found across all of their own pairs. */ - case class StreamBuffer(iterator: Iterator[(K, C)], pairs: ArrayBuffer[(K, C)]) + private case class StreamBuffer(iterator: Iterator[(K, C)], pairs: ArrayBuffer[(K, C)]) extends Comparable[StreamBuffer] { def minKeyHash: Int = { @@ -355,51 +342,53 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( /** * An iterator that returns (K, C) pairs in sorted order from an on-disk map */ - private class DiskMapIterator(file: File, blockId: BlockId) extends Iterator[(K, C)] { - val fileStream = new FileInputStream(file) - val bufferedStream = new FastBufferedInputStream(fileStream, fileBufferSize) - - val shouldCompress = blockManager.shouldCompress(blockId) - val compressionCodec = new LZFCompressionCodec(sparkConf) - val compressedStream = - if (shouldCompress) { - compressionCodec.compressedInputStream(bufferedStream) + private class DiskMapIterator(file: File, blockId: BlockId, batchSizes: ArrayBuffer[Long]) + extends Iterator[(K, C)] { + private val fileStream = new FileInputStream(file) + private val bufferedStream = new FastBufferedInputStream(fileStream, fileBufferSize) + + // An intermediate stream that reads from exactly one batch + // This guards against pre-fetching and other arbitrary behavior of higher level streams + private var batchStream = nextBatchStream() + private var compressedStream = blockManager.wrapForCompression(blockId, batchStream) + private var deserializeStream = ser.deserializeStream(compressedStream) + private var nextItem: (K, C) = null + private var objectsRead = 0 + + /** + * Construct a stream that reads only from the next batch + */ + private def nextBatchStream(): InputStream = { + if (batchSizes.length > 0) { + ByteStreams.limit(bufferedStream, batchSizes.remove(0)) } else { + // No more batches left bufferedStream } - var deserializeStream = ser.deserializeStream(compressedStream) - var objectsRead = 0 - - var nextItem: (K, C) = null - var eof = false - - def readNextItem(): (K, C) = { - if (!eof) { - try { - if (objectsRead == serializerBatchSize) { - val newInputStream = deserializeStream match { - case stream: KryoDeserializationStream => - // Kryo's serializer stores an internal buffer that pre-fetches from the underlying - // stream. We need to capture this buffer and feed it to the new serialization - // stream so that the bytes are not lost. - val kryoInput = stream.input - val remainingBytes = kryoInput.limit() - kryoInput.position() - val extraBuf = kryoInput.readBytes(remainingBytes) - new SequenceInputStream(new ByteArrayInputStream(extraBuf), compressedStream) - case _ => compressedStream - } - deserializeStream = ser.deserializeStream(newInputStream) - objectsRead = 0 - } - objectsRead += 1 - return deserializeStream.readObject().asInstanceOf[(K, C)] - } catch { - case e: EOFException => - eof = true - cleanup() + } + + /** + * Return the next (K, C) pair from the deserialization stream. + * + * If the current batch is drained, construct a stream for the next batch and read from it. + * If no more pairs are left, return null. + */ + private def readNextItem(): (K, C) = { + try { + val item = deserializeStream.readObject().asInstanceOf[(K, C)] + objectsRead += 1 + if (objectsRead == serializerBatchSize) { + batchStream = nextBatchStream() + compressedStream = blockManager.wrapForCompression(blockId, batchStream) + deserializeStream = ser.deserializeStream(compressedStream) + objectsRead = 0 } + item + } catch { + case e: EOFException => + cleanup() + null } - null } override def hasNext: Boolean = { @@ -419,7 +408,7 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( } // TODO: Ensure this gets called even if the iterator isn't drained. - def cleanup() { + private def cleanup() { deserializeStream.close() file.delete() } diff --git a/docs/configuration.md b/docs/configuration.md index 07d1eb0931a17..3f03d97e8054c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -158,9 +158,7 @@ Apart from these, the following properties are also available, and may be useful spark.shuffle.spill.compress true - Whether to compress data spilled during shuffles. If enabled, spill compression - always uses the `org.apache.spark.io.LZFCompressionCodec` codec, - regardless of the value of `spark.io.compression.codec`. + Whether to compress data spilled during shuffles. From 22e0a3b4bf50ac83629ffd2460609d7b6ca748b2 Mon Sep 17 00:00:00 2001 From: Qiuzhuang Lian Date: Sat, 8 Feb 2014 12:59:48 -0800 Subject: [PATCH 095/133] Merge pull request #561 from Qiuzhuang/master. Closes #561. Kill drivers in postStop() for Worker. JIRA SPARK-1068:https://spark-project.atlassian.net/browse/SPARK-1068 Author: Qiuzhuang Lian == Merge branch commits == commit 9c19ce63637eee9369edd235979288d3d9fc9105 Author: Qiuzhuang Lian Date: Sat Feb 8 16:07:39 2014 +0800 Kill drivers in postStop() for Worker. JIRA SPARK-1068:https://spark-project.atlassian.net/browse/SPARK-1068 (cherry picked from commit f0ce736fadbcb7642b6148ad740f4508cd7dcd4d) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala b/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala old mode 100644 new mode 100755 index 312560d7063a4..36bb28912fbda --- a/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala +++ b/core/src/main/scala/org/apache/spark/deploy/worker/Worker.scala @@ -314,6 +314,7 @@ private[spark] class Worker( override def postStop() { executors.values.foreach(_.kill()) + drivers.values.foreach(_.kill()) webUi.stop() metricsSystem.stop() } From 2e3d1c31db55c7f961e559e47bb497ae15cb74d7 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 8 Feb 2014 23:35:31 -0800 Subject: [PATCH 096/133] Merge pull request #560 from pwendell/logging. Closes #560. [WIP] SPARK-1067: Default log4j initialization causes errors for those not using log4j To fix this - we add a check when initializing log4j. Author: Patrick Wendell == Merge branch commits == commit ffdce513877f64b6eed6d36138c3e0003d392889 Author: Patrick Wendell Date: Fri Feb 7 15:22:29 2014 -0800 Logging fix (cherry picked from commit b6d40b782327188a25ded5b22790552121e5271f) Signed-off-by: Reynold Xin --- core/src/main/scala/org/apache/spark/Logging.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Logging.scala b/core/src/main/scala/org/apache/spark/Logging.scala index b749e5414dab6..7423082e34f47 100644 --- a/core/src/main/scala/org/apache/spark/Logging.scala +++ b/core/src/main/scala/org/apache/spark/Logging.scala @@ -19,6 +19,7 @@ package org.apache.spark import org.apache.log4j.{LogManager, PropertyConfigurator} import org.slf4j.{Logger, LoggerFactory} +import org.slf4j.impl.StaticLoggerBinder /** * Utility trait for classes that want to log data. Creates a SLF4J logger for the class and allows @@ -101,9 +102,11 @@ trait Logging { } private def initializeLogging() { - // If Log4j doesn't seem initialized, load a default properties file + // If Log4j is being used, but is not initialized, load a default properties file + val binder = StaticLoggerBinder.getSingleton + val usingLog4j = binder.getLoggerFactoryClassStr.endsWith("Log4jLoggerFactory") val log4jInitialized = LogManager.getRootLogger.getAllAppenders.hasMoreElements - if (!log4jInitialized) { + if (!log4jInitialized && usingLog4j) { val defaultLogProps = "org/apache/spark/log4j-defaults.properties" val classLoader = this.getClass.getClassLoader Option(classLoader.getResource(defaultLogProps)) match { From de22abc7f9a5000e9469922eaeceadbea8ae0b42 Mon Sep 17 00:00:00 2001 From: jyotiska Date: Sat, 8 Feb 2014 23:36:48 -0800 Subject: [PATCH 097/133] Merge pull request #562 from jyotiska/master. Closes #562. Added example Python code for sort I added an example Python code for sort. Right now, PySpark has limited examples for new people willing to use the project. This example code sorts integers stored in a file. I was able to sort 5 million, 10 million and 25 million integers with this code. Author: jyotiska == Merge branch commits == commit 8ad8faf6c8e02ae1cd68565d98524edf165f54df Author: jyotiska Date: Sun Feb 9 11:00:41 2014 +0530 Added comments in code on collect() method commit 6f98f1e313f4472a7c2207d36c4f0fbcebc95a8c Author: jyotiska Date: Sat Feb 8 13:12:37 2014 +0530 Updated python example code sort.py commit 945e39a5d68daa7e5bab0d96cbd35d7c4b04eafb Author: jyotiska Date: Sat Feb 8 12:59:09 2014 +0530 Added example python code for sort (cherry picked from commit 2ef37c93664d74de6d7f6144834883a4a4ef79b7) Signed-off-by: Reynold Xin --- python/examples/sort.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 python/examples/sort.py diff --git a/python/examples/sort.py b/python/examples/sort.py new file mode 100755 index 0000000000000..5de20a6d98f43 --- /dev/null +++ b/python/examples/sort.py @@ -0,0 +1,36 @@ +# +# 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. +# + +import sys + +from pyspark import SparkContext + + +if __name__ == "__main__": + if len(sys.argv) < 3: + print >> sys.stderr, "Usage: sort " + exit(-1) + sc = SparkContext(sys.argv[1], "PythonSort") + lines = sc.textFile(sys.argv[2], 1) + sortedCount = lines.flatMap(lambda x: x.split(' ')) \ + .map(lambda x: (int(x), 1)) \ + .sortByKey(lambda x: x) + # This is just a demo on how to bring all the sorted data back to a single node. + # In reality, we wouldn't want to collect all the data to the driver node. + output = sortedCount.collect() + for (num, unitcount) in output: + print num From e70690f2609f59851fa9c087f5ad28967ca5f973 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 9 Feb 2014 23:33:35 -0800 Subject: [PATCH 098/133] Revert "Merge pull request #560 from pwendell/logging. Closes #560." This reverts commit 2e3d1c31db55c7f961e559e47bb497ae15cb74d7. --- core/src/main/scala/org/apache/spark/Logging.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Logging.scala b/core/src/main/scala/org/apache/spark/Logging.scala index 7423082e34f47..b749e5414dab6 100644 --- a/core/src/main/scala/org/apache/spark/Logging.scala +++ b/core/src/main/scala/org/apache/spark/Logging.scala @@ -19,7 +19,6 @@ package org.apache.spark import org.apache.log4j.{LogManager, PropertyConfigurator} import org.slf4j.{Logger, LoggerFactory} -import org.slf4j.impl.StaticLoggerBinder /** * Utility trait for classes that want to log data. Creates a SLF4J logger for the class and allows @@ -102,11 +101,9 @@ trait Logging { } private def initializeLogging() { - // If Log4j is being used, but is not initialized, load a default properties file - val binder = StaticLoggerBinder.getSingleton - val usingLog4j = binder.getLoggerFactoryClassStr.endsWith("Log4jLoggerFactory") + // If Log4j doesn't seem initialized, load a default properties file val log4jInitialized = LogManager.getRootLogger.getAllAppenders.hasMoreElements - if (!log4jInitialized && usingLog4j) { + if (!log4jInitialized) { val defaultLogProps = "org/apache/spark/log4j-defaults.properties" val classLoader = this.getClass.getClassLoader Option(classLoader.getResource(defaultLogProps)) match { From 28f88c5fb5fc06d0919021fa2cfd80bb65f82792 Mon Sep 17 00:00:00 2001 From: Raymond Liu Date: Tue, 11 Feb 2014 22:39:48 -0800 Subject: [PATCH 099/133] Merge pull request #583 from colorant/zookeeper. Minor fix for ZooKeeperPersistenceEngine to use configured working dir Author: Raymond Liu Closes #583 and squashes the following commits: 91b0609 [Raymond Liu] Minor fix for ZooKeeperPersistenceEngine to use configured working dir (cherry picked from commit 68b2c0d02dbdca246ca686b871c06af53845d5b5) Signed-off-by: Aaron Davidson --- .../apache/spark/deploy/master/ZooKeeperPersistenceEngine.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/deploy/master/ZooKeeperPersistenceEngine.scala b/core/src/main/scala/org/apache/spark/deploy/master/ZooKeeperPersistenceEngine.scala index f24f49ea8ad9f..10816a1f43ff6 100644 --- a/core/src/main/scala/org/apache/spark/deploy/master/ZooKeeperPersistenceEngine.scala +++ b/core/src/main/scala/org/apache/spark/deploy/master/ZooKeeperPersistenceEngine.scala @@ -87,7 +87,7 @@ class ZooKeeperPersistenceEngine(serialization: Serialization, conf: SparkConf) } def deserializeFromFile[T](filename: String)(implicit m: Manifest[T]): T = { - val fileData = zk.getData("/spark/master_status/" + filename) + val fileData = zk.getData(WORKING_DIR + "/" + filename) val clazz = m.runtimeClass.asInstanceOf[Class[T]] val serializer = serialization.serializerFor(clazz) serializer.fromBinary(fileData).asInstanceOf[T] From 754bc183d9aeea2d3eaed0e5216b3e5aa49c2935 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Wed, 12 Feb 2014 14:26:39 -0800 Subject: [PATCH 100/133] Merge pull request #590 from rxin/scalastyle. SPARK-1085: Fix Jenkins pull request builder for branch-0.9 (scalastyle command not found) Added a dummy scalastyle task to sbt. https://spark-project.atlassian.net/browse/SPARK-1085 Author: Reynold Xin Closes #590 and squashes the following commits: d0889bd [Reynold Xin] SPARK-1085: Fix Jenkins pull request builder for branch-0.9 (scalastyle command not found) --- project/SparkBuild.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index 788ef120d04ef..6294d7d6cd5ee 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -65,6 +65,12 @@ object SparkBuild extends Build { lazy val assembleDeps = TaskKey[Unit]("assemble-deps", "Build assembly of dependencies and packages Spark projects") + // A dummy command so we can run the Jenkins pull request builder for older versions of Spark. + lazy val scalastyle = TaskKey[Unit]("scalastyle", "Dummy scalastyle check") + val scalastyleTask = scalastyle := { + println("scalastyle is not configured for this version of Spark project.") + } + // A configuration to set an alternative publishLocalConfiguration lazy val MavenCompile = config("m2r") extend(Compile) lazy val publishLocalBoth = TaskKey[Unit]("publish-local", "publish local for m2 and ivy") @@ -381,6 +387,7 @@ object SparkBuild extends Build { def assemblyProjSettings = sharedSettings ++ Seq( libraryDependencies += "net.sf.py4j" % "py4j" % "0.8.1", name := "spark-assembly", + scalastyleTask, assembleDeps in Compile <<= (packageProjects.map(packageBin in Compile in _) ++ Seq(packageDependency in Compile)).dependOn, jarName in assembly <<= version map { v => "spark-assembly-" + v + "-hadoop" + hadoopVersion + ".jar" }, jarName in packageDependency <<= version map { v => "spark-assembly-" + v + "-hadoop" + hadoopVersion + "-deps.jar" } From 8093de1bb319e86dcf0d6d8d97b043a2bc1aa8f2 Mon Sep 17 00:00:00 2001 From: Bijay Bisht Date: Wed, 12 Feb 2014 23:42:10 -0800 Subject: [PATCH 101/133] Ported hadoopClient jar for < 1.0.1 fix #522 got messed after i rewrote the branch hadoop_jar_name. So created a new one. Author: Bijay Bisht Closes #584 from bijaybisht/hadoop_jar_name_on_0.9.0 and squashes the following commits: 1b6fb3c [Bijay Bisht] Ported hadoopClient jar for < 1.0.1 fix --- project/SparkBuild.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index 6294d7d6cd5ee..b8f901d71a56a 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -90,6 +90,7 @@ object SparkBuild extends Build { case None => DEFAULT_YARN case Some(v) => v.toBoolean } + lazy val hadoopClient = if (hadoopVersion.startsWith("0.20.") || hadoopVersion == "1.0.0") "hadoop-core" else "hadoop-client" // Conditionally include the yarn sub-project lazy val yarnAlpha = Project("yarn-alpha", file("yarn/alpha"), settings = yarnAlphaSettings) dependsOn(core) @@ -273,7 +274,7 @@ object SparkBuild extends Build { "org.apache.mesos" % "mesos" % "0.13.0", "net.java.dev.jets3t" % "jets3t" % "0.7.1", "org.apache.derby" % "derby" % "10.4.2.0" % "test", - "org.apache.hadoop" % "hadoop-client" % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), + "org.apache.hadoop" % hadoopClient % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), "org.apache.avro" % "avro" % "1.7.4", "org.apache.avro" % "avro-ipc" % "1.7.4" excludeAll(excludeNetty), "org.apache.zookeeper" % "zookeeper" % "3.4.5" excludeAll(excludeNetty), @@ -377,7 +378,7 @@ object SparkBuild extends Build { def yarnEnabledSettings = Seq( libraryDependencies ++= Seq( // Exclude rule required for all ? - "org.apache.hadoop" % "hadoop-client" % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), + "org.apache.hadoop" % hadoopClient % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), "org.apache.hadoop" % "hadoop-yarn-api" % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), "org.apache.hadoop" % "hadoop-yarn-common" % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib), "org.apache.hadoop" % "hadoop-yarn-client" % hadoopVersion excludeAll(excludeJackson, excludeNetty, excludeAsm, excludeCglib) From e5b86b1b7524f947c7ef88763b94218e0e3666c3 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Wed, 12 Feb 2014 23:42:58 -0800 Subject: [PATCH 102/133] SPARK-1088: Create a script for running tests so we can have version specific testing on Jenkins (branch-0.9) This is for branch-0.9. #592 is for master branch (1.0). Author: Reynold Xin Closes #593 from rxin/test-0.9 and squashes the following commits: 85a3aa0 [Reynold Xin] SPARK-1088: Create a script for running tests so we can have version specific testing on Jenkins. --- dev/README.md | 5 +++++ dev/run-tests | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 dev/README.md create mode 100644 dev/run-tests diff --git a/dev/README.md b/dev/README.md new file mode 100644 index 0000000000000..2b0f3d8ee8924 --- /dev/null +++ b/dev/README.md @@ -0,0 +1,5 @@ +# Spark Developer Scripts +This directory contains scripts useful to developers when packaging, +testing, or committing to Spark. + +Many of these scripts require Apache credentials to work correctly. diff --git a/dev/run-tests b/dev/run-tests new file mode 100644 index 0000000000000..a5dcacb4fd0c1 --- /dev/null +++ b/dev/run-tests @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# +# 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. +# + +# Go to the Spark project root directory +FWDIR="$(cd `dirname $0`/..; pwd)" +cd $FWDIR + +# Remove work directory +rm -rf ./work + +# Fail fast +set -e + +echo "=========================================================================" +echo "Running Spark unit tests" +echo "=========================================================================" +sbt/sbt assembly test + +echo "=========================================================================" +echo "Running PySpark tests" +echo "=========================================================================" +if [ -z "$PYSPARK_PYTHON" ]; then + export PYSPARK_PYTHON=/usr/local/bin/python2.7 +fi +./python/run-tests From 19b4bb2b444f1dbc4592bf3d58b17652e0ae6d6b Mon Sep 17 00:00:00 2001 From: Christian Lundgren Date: Thu, 13 Feb 2014 12:44:21 -0800 Subject: [PATCH 103/133] Add c3 instance types to Spark EC2 The number of disks for the c3 instance types taken from here: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html#StorageOnInstanceTypes Author: Christian Lundgren Closes #595 from chrisavl/branch-0.9 and squashes the following commits: c8af5f9 [Christian Lundgren] Add c3 instance types to Spark EC2 --- ec2/spark_ec2.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ec2/spark_ec2.py b/ec2/spark_ec2.py index e46e1f5e56442..e88f80aa62627 100755 --- a/ec2/spark_ec2.py +++ b/ec2/spark_ec2.py @@ -189,7 +189,12 @@ def get_spark_ami(opts): "i2.xlarge": "hvm", "i2.2xlarge": "hvm", "i2.4xlarge": "hvm", - "i2.8xlarge": "hvm" + "i2.8xlarge": "hvm", + "c3.large": "pvm", + "c3.xlarge": "pvm", + "c3.2xlarge": "pvm", + "c3.4xlarge": "pvm", + "c3.8xlarge": "pvm" } if opts.instance_type in instance_types: instance_type = instance_types[opts.instance_type] @@ -486,7 +491,12 @@ def get_num_disks(instance_type): "i2.xlarge": 1, "i2.2xlarge": 2, "i2.4xlarge": 4, - "i2.8xlarge": 8 + "i2.8xlarge": 8, + "c3.large": 2, + "c3.xlarge": 2, + "c3.2xlarge": 2, + "c3.4xlarge": 2, + "c3.8xlarge": 2 } if instance_type in disks_by_instance: return disks_by_instance[instance_type] From e797c1abd9692f1b7ec290e4c83d31fd106e6b05 Mon Sep 17 00:00:00 2001 From: Bijay Bisht Date: Sun, 16 Feb 2014 16:52:57 -0800 Subject: [PATCH 104/133] fix for https://spark-project.atlassian.net/browse/SPARK-1052 Author: Bijay Bisht Closes #568 from bijaybisht/SPARK-1052 and squashes the following commits: da70395 [Bijay Bisht] fix for https://spark-project.atlassian.net/browse/SPARK-1052 - comments incorporated fdb1d94 [Bijay Bisht] fix for https://spark-project.atlassian.net/browse/SPARK-1052 --- .../scheduler/cluster/mesos/MesosSchedulerBackend.scala | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackend.scala b/core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackend.scala index 49781485d9f96..fef291eea0257 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackend.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/cluster/mesos/MesosSchedulerBackend.scala @@ -130,13 +130,8 @@ private[spark] class MesosSchedulerBackend( private def createExecArg(): Array[Byte] = { if (execArgs == null) { val props = new HashMap[String, String] - val iterator = System.getProperties.entrySet.iterator - while (iterator.hasNext) { - val entry = iterator.next - val (key, value) = (entry.getKey.toString, entry.getValue.toString) - if (key.startsWith("spark.")) { - props(key) = value - } + for ((key,value) <- sc.conf.getAll) { + props(key) = value } // Serialize the map as an array of (String, String) pairs execArgs = Utils.serialize(props.toArray) From b0b5288aad408511ea26b97b1d6be693d588def1 Mon Sep 17 00:00:00 2001 From: Andrew Ash Date: Mon, 17 Feb 2014 09:51:55 -0800 Subject: [PATCH 105/133] Worker registration logging fix Author: Andrew Ash Closes #608 from ash211/patch-7 and squashes the following commits: bd85f2a [Andrew Ash] Worker registration logging fix (cherry picked from commit c0795cf481d47425ec92f4fd0780e2e0b3fdda85) Signed-off-by: Aaron Davidson --- core/src/main/scala/org/apache/spark/deploy/master/Master.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/deploy/master/Master.scala b/core/src/main/scala/org/apache/spark/deploy/master/Master.scala index 7be774980afa3..389715662beee 100644 --- a/core/src/main/scala/org/apache/spark/deploy/master/Master.scala +++ b/core/src/main/scala/org/apache/spark/deploy/master/Master.scala @@ -168,7 +168,7 @@ private[spark] class Master(host: String, port: Int, webUiPort: Int) extends Act case RegisterWorker(id, workerHost, workerPort, cores, memory, workerWebUiPort, publicAddress) => { logInfo("Registering worker %s:%d with %d cores, %s RAM".format( - host, workerPort, cores, Utils.megabytesToString(memory))) + workerHost, workerPort, cores, Utils.megabytesToString(memory))) if (state == RecoveryState.STANDBY) { // ignore, don't send response } else if (idToWorker.contains(id)) { From 0f0395cdae548a6b31961f2bf2c91120f719c6e5 Mon Sep 17 00:00:00 2001 From: CodingCat Date: Tue, 18 Feb 2014 16:29:23 -0800 Subject: [PATCH 106/133] [SPARK-1105] fix site scala version error in doc https://spark-project.atlassian.net/browse/SPARK-1105 fix site scala version error Author: CodingCat Closes #616 from CodingCat/doc_version and squashes the following commits: eafd99a [CodingCat] fix site scala version error in doc (cherry picked from commit d99773d5bba674cc1434c86435b6d9b3739314c8) Signed-off-by: Aaron Davidson Conflicts: docs/_config.yml --- docs/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index 97a2c4abf2998..ed94bc5d2551f 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,7 +5,7 @@ markdown: kramdown # of Spark, Scala, and Mesos. SPARK_VERSION: 0.9.0-incubating SPARK_VERSION_SHORT: 0.9.0 -SCALA_VERSION: "2.10" +SCALA_VERSION: "2.10.3" MESOS_VERSION: 0.13.0 SPARK_ISSUE_TRACKER_URL: https://spark-project.atlassian.net SPARK_GITHUB_URL: https://github.com/apache/incubator-spark From 7bde72ecf7fcb97864c2da4500eb88c904bf79fa Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 18 Feb 2014 17:47:34 -0800 Subject: [PATCH 107/133] Revert "[SPARK-1105] fix site scala version error in doc" This reverts commit 0f0395cdae548a6b31961f2bf2c91120f719c6e5. --- docs/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index ed94bc5d2551f..97a2c4abf2998 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,7 +5,7 @@ markdown: kramdown # of Spark, Scala, and Mesos. SPARK_VERSION: 0.9.0-incubating SPARK_VERSION_SHORT: 0.9.0 -SCALA_VERSION: "2.10.3" +SCALA_VERSION: "2.10" MESOS_VERSION: 0.13.0 SPARK_ISSUE_TRACKER_URL: https://spark-project.atlassian.net SPARK_GITHUB_URL: https://github.com/apache/incubator-spark From 289d76134d625a5ae322358800428563713af082 Mon Sep 17 00:00:00 2001 From: CodingCat Date: Wed, 19 Feb 2014 15:54:03 -0800 Subject: [PATCH 108/133] [SPARK-1105] fix site scala version error in docs https://spark-project.atlassian.net/browse/SPARK-1105 fix site scala version error Author: CodingCat Closes #618 from CodingCat/doc_version and squashes the following commits: 39bb8aa [CodingCat] more fixes 65bedb0 [CodingCat] fix site scala version error in doc (cherry picked from commit 7b012c93973201a1cbb4fc9a02e322152e5185a9) Conflicts: docs/_config.yml --- docs/_config.yml | 3 ++- docs/bagel-programming-guide.md | 2 +- docs/building-with-maven.md | 4 ++-- docs/index.md | 2 +- docs/quick-start.md | 4 ++-- docs/running-on-yarn.md | 16 ++++++++-------- docs/scala-programming-guide.md | 6 +++--- docs/streaming-programming-guide.md | 16 ++++++++-------- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 97a2c4abf2998..868fa2410fde2 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,7 +5,8 @@ markdown: kramdown # of Spark, Scala, and Mesos. SPARK_VERSION: 0.9.0-incubating SPARK_VERSION_SHORT: 0.9.0 -SCALA_VERSION: "2.10" +SCALA_BINARY_VERSION: "2.10" +SCALA_VERSION: "2.10.3" MESOS_VERSION: 0.13.0 SPARK_ISSUE_TRACKER_URL: https://spark-project.atlassian.net SPARK_GITHUB_URL: https://github.com/apache/incubator-spark diff --git a/docs/bagel-programming-guide.md b/docs/bagel-programming-guide.md index cffa55ee952b0..b070d8e73a38b 100644 --- a/docs/bagel-programming-guide.md +++ b/docs/bagel-programming-guide.md @@ -16,7 +16,7 @@ This guide shows the programming model and features of Bagel by walking through To use Bagel in your program, add the following SBT or Maven dependency: groupId = org.apache.spark - artifactId = spark-bagel_{{site.SCALA_VERSION}} + artifactId = spark-bagel_{{site.SCALA_BINARY_VERSION}} version = {{site.SPARK_VERSION}} # Programming Model diff --git a/docs/building-with-maven.md b/docs/building-with-maven.md index 6a9a8d681742f..ded12926885b9 100644 --- a/docs/building-with-maven.md +++ b/docs/building-with-maven.md @@ -17,10 +17,10 @@ You'll need to configure Maven to use more memory than usual by setting `MAVEN_O If you don't run this, you may see errors like the following: - [INFO] Compiling 203 Scala sources and 9 Java sources to /Users/me/Development/spark/core/target/scala-{{site.SCALA_VERSION}}/classes... + [INFO] Compiling 203 Scala sources and 9 Java sources to /Users/me/Development/spark/core/target/scala-{{site.SCALA_BINARY_VERSION}}/classes... [ERROR] PermGen space -> [Help 1] - [INFO] Compiling 203 Scala sources and 9 Java sources to /Users/me/Development/spark/core/target/scala-{{site.SCALA_VERSION}}/classes... + [INFO] Compiling 203 Scala sources and 9 Java sources to /Users/me/Development/spark/core/target/scala-{{site.SCALA_BINARY_VERSION}}/classes... [ERROR] Java heap space -> [Help 1] You can fix this by setting the `MAVEN_OPTS` variable as discussed before. diff --git a/docs/index.md b/docs/index.md index 7fea73024a8a0..aa9c8666e7d75 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,7 +19,7 @@ Spark uses [Simple Build Tool](http://www.scala-sbt.org), which is bundled with sbt/sbt assembly -For its Scala API, Spark {{site.SPARK_VERSION}} depends on Scala {{site.SCALA_VERSION}}. If you write applications in Scala, you will need to use this same version of Scala in your own program -- newer major versions may not work. You can get the right version of Scala from [scala-lang.org](http://www.scala-lang.org/download/). +For its Scala API, Spark {{site.SPARK_VERSION}} depends on Scala {{site.SCALA_BINARY_VERSION}}. If you write applications in Scala, you will need to use a compatible Scala version (e.g. {{site.SCALA_BINARY_VERSION}}.X) -- newer major versions may not work. You can get the right version of Scala from [scala-lang.org](http://www.scala-lang.org/download/). # Running the Examples and Shell diff --git a/docs/quick-start.md b/docs/quick-start.md index 153081bdaa286..13df6beea16e8 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -115,7 +115,7 @@ object SimpleApp { def main(args: Array[String]) { val logFile = "$YOUR_SPARK_HOME/README.md" // Should be some file on your system val sc = new SparkContext("local", "Simple App", "YOUR_SPARK_HOME", - List("target/scala-{{site.SCALA_VERSION}}/simple-project_{{site.SCALA_VERSION}}-1.0.jar")) + List("target/scala-{{site.SCALA_BINARY_VERSION}}/simple-project_{{site.SCALA_BINARY_VERSION}}-1.0.jar")) val logData = sc.textFile(logFile, 2).cache() val numAs = logData.filter(line => line.contains("a")).count() val numBs = logData.filter(line => line.contains("b")).count() @@ -214,7 +214,7 @@ To build the program, we also write a Maven `pom.xml` file that lists Spark as a org.apache.spark - spark-core_{{site.SCALA_VERSION}} + spark-core_{{site.SCALA_BINARY_VERSION}} {{site.SPARK_VERSION}} diff --git a/docs/running-on-yarn.md b/docs/running-on-yarn.md index 5dadd54492dca..cd4509ede735a 100644 --- a/docs/running-on-yarn.md +++ b/docs/running-on-yarn.md @@ -15,7 +15,7 @@ This can be built by setting the Hadoop version and `SPARK_YARN` environment var SPARK_HADOOP_VERSION=2.0.5-alpha SPARK_YARN=true sbt/sbt assembly The assembled JAR will be something like this: -`./assembly/target/scala-{{site.SCALA_VERSION}}/spark-assembly_{{site.SPARK_VERSION}}-hadoop2.0.5.jar`. +`./assembly/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-assembly_{{site.SPARK_VERSION}}-hadoop2.0.5.jar`. The build process now also supports new YARN versions (2.2.x). See below. @@ -25,7 +25,7 @@ The build process now also supports new YARN versions (2.2.x). See below. - The assembled jar can be installed into HDFS or used locally. - Your application code must be packaged into a separate JAR file. -If you want to test out the YARN deployment mode, you can use the current Spark examples. A `spark-examples_{{site.SCALA_VERSION}}-{{site.SPARK_VERSION}}` file can be generated by running `sbt/sbt assembly`. NOTE: since the documentation you're reading is for Spark version {{site.SPARK_VERSION}}, we are assuming here that you have downloaded Spark {{site.SPARK_VERSION}} or checked it out of source control. If you are using a different version of Spark, the version numbers in the jar generated by the sbt package command will obviously be different. +If you want to test out the YARN deployment mode, you can use the current Spark examples. A `spark-examples_{{site.SCALA_BINARY_VERSION}}-{{site.SPARK_VERSION}}` file can be generated by running `sbt/sbt assembly`. NOTE: since the documentation you're reading is for Spark version {{site.SPARK_VERSION}}, we are assuming here that you have downloaded Spark {{site.SPARK_VERSION}} or checked it out of source control. If you are using a different version of Spark, the version numbers in the jar generated by the sbt package command will obviously be different. # Configuration @@ -78,9 +78,9 @@ For example: $ cp conf/log4j.properties.template conf/log4j.properties # Submit Spark's ApplicationMaster to YARN's ResourceManager, and instruct Spark to run the SparkPi example - $ SPARK_JAR=./assembly/target/scala-{{site.SCALA_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ + $ SPARK_JAR=./assembly/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ ./bin/spark-class org.apache.spark.deploy.yarn.Client \ - --jar examples/target/scala-{{site.SCALA_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ + --jar examples/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ --class org.apache.spark.examples.SparkPi \ --args yarn-standalone \ --num-workers 3 \ @@ -117,13 +117,13 @@ In order to tune worker core/number/memory etc. You need to export environment v For example: - SPARK_JAR=./assembly/target/scala-{{site.SCALA_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ - SPARK_YARN_APP_JAR=examples/target/scala-{{site.SCALA_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ + SPARK_JAR=./assembly/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ + SPARK_YARN_APP_JAR=examples/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ ./bin/run-example org.apache.spark.examples.SparkPi yarn-client - SPARK_JAR=./assembly/target/scala-{{site.SCALA_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ - SPARK_YARN_APP_JAR=examples/target/scala-{{site.SCALA_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ + SPARK_JAR=./assembly/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop2.0.5-alpha.jar \ + SPARK_YARN_APP_JAR=examples/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-examples-assembly-{{site.SPARK_VERSION}}.jar \ MASTER=yarn-client ./bin/spark-shell diff --git a/docs/scala-programming-guide.md b/docs/scala-programming-guide.md index 7c0f67bc99e83..cd847e07f94ab 100644 --- a/docs/scala-programming-guide.md +++ b/docs/scala-programming-guide.md @@ -17,12 +17,12 @@ This guide shows each of these features and walks through some samples. It assum # Linking with Spark -Spark {{site.SPARK_VERSION}} uses Scala {{site.SCALA_VERSION}}. If you write applications in Scala, you'll need to use this same version of Scala in your program -- newer major versions may not work. +Spark {{site.SPARK_VERSION}} uses Scala {{site.SCALA_BINARY_VERSION}}. If you write applications in Scala, you will need to use a compatible Scala version (e.g. {{site.SCALA_BINARY_VERSION}}.X) -- newer major versions may not work. To write a Spark application, you need to add a dependency on Spark. If you use SBT or Maven, Spark is available through Maven Central at: groupId = org.apache.spark - artifactId = spark-core_{{site.SCALA_VERSION}} + artifactId = spark-core_{{site.SCALA_BINARY_VERSION}} version = {{site.SPARK_VERSION}} In addition, if you wish to access an HDFS cluster, you need to add a dependency on `hadoop-client` for your version of HDFS: @@ -31,7 +31,7 @@ In addition, if you wish to access an HDFS cluster, you need to add a dependency artifactId = hadoop-client version = -For other build systems, you can run `sbt/sbt assembly` to pack Spark and its dependencies into one JAR (`assembly/target/scala-{{site.SCALA_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop*.jar`), then add this to your CLASSPATH. Set the HDFS version as described [here](index.html#a-note-about-hadoop-versions). +For other build systems, you can run `sbt/sbt assembly` to pack Spark and its dependencies into one JAR (`assembly/target/scala-{{site.SCALA_BINARY_VERSION}}/spark-assembly-{{site.SPARK_VERSION}}-hadoop*.jar`), then add this to your CLASSPATH. Set the HDFS version as described [here](index.html#a-note-about-hadoop-versions). Finally, you need to import some Spark classes and implicit conversions into your program. Add the following lines: diff --git a/docs/streaming-programming-guide.md b/docs/streaming-programming-guide.md index ccc1c8bf2c541..4985c52a11ada 100644 --- a/docs/streaming-programming-guide.md +++ b/docs/streaming-programming-guide.md @@ -275,23 +275,23 @@ To write your own Spark Streaming program, you will have to add the following de SBT or Maven project: groupId = org.apache.spark - artifactId = spark-streaming_{{site.SCALA_VERSION}} + artifactId = spark-streaming_{{site.SCALA_BINARY_VERSION}} version = {{site.SPARK_VERSION}} For ingesting data from sources like Kafka and Flume that are not present in the Spark Streaming core API, you will have to add the corresponding -artifact `spark-streaming-xyz_{{site.SCALA_VERSION}}` to the dependencies. For example, +artifact `spark-streaming-xyz_{{site.SCALA_BINARY_VERSION}}` to the dependencies. For example, some of the common ones are as follows. - - - - - + + + + +
    SourceArtifact
    Kafka spark-streaming-kafka_{{site.SCALA_VERSION}}
    Flume spark-streaming-flume_{{site.SCALA_VERSION}}
    Twitter spark-streaming-twitter_{{site.SCALA_VERSION}}
    ZeroMQ spark-streaming-zeromq_{{site.SCALA_VERSION}}
    MQTT spark-streaming-mqtt_{{site.SCALA_VERSION}}
    Kafka spark-streaming-kafka_{{site.SCALA_BINARY_VERSION}}
    Flume spark-streaming-flume_{{site.SCALA_BINARY_VERSION}}
    Twitter spark-streaming-twitter_{{site.SCALA_BINARY_VERSION}}
    ZeroMQ spark-streaming-zeromq_{{site.SCALA_BINARY_VERSION}}
    MQTT spark-streaming-mqtt_{{site.SCALA_BINARY_VERSION}}
    @@ -410,7 +410,7 @@ Scala and [JavaStreamingContext](api/streaming/index.html#org.apache.spark.strea Additional functionality for creating DStreams from sources such as Kafka, Flume, and Twitter can be imported by adding the right dependencies as explained in an [earlier](#linking) section. To take the -case of Kafka, after adding the artifact `spark-streaming-kafka_{{site.SCALA_VERSION}}` to the +case of Kafka, after adding the artifact `spark-streaming-kafka_{{site.SCALA_BINARY_VERSION}}` to the project dependencies, you can create a DStream from Kafka as
    From 3c44ff482e5a8a37c28e478dfb59838aa79f18a3 Mon Sep 17 00:00:00 2001 From: Aaron Davidson Date: Thu, 20 Feb 2014 16:46:13 -0800 Subject: [PATCH 109/133] Super minor: Add require for mergeCombiners in combineByKey We changed the behavior in 0.9.0 from requiring that mergeCombiners be null when mapSideCombine was false to requiring that mergeCombiners *never* be null, for external sorting. This patch adds a require() to make this behavior change explicitly messaged rather than resulting in a NPE. Author: Aaron Davidson Closes #623 from aarondav/master and squashes the following commits: 520b80c [Aaron Davidson] Super minor: Add require for mergeCombiners in combineByKey (cherry picked from commit 3fede4831eeb7d36d4f8fa4aaa02ad0cc8b4b09e) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala b/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala index 4148581f527fe..9bafe41f0da58 100644 --- a/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala +++ b/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala @@ -77,6 +77,7 @@ class PairRDDFunctions[K: ClassTag, V: ClassTag](self: RDD[(K, V)]) partitioner: Partitioner, mapSideCombine: Boolean = true, serializerClass: String = null): RDD[(K, C)] = { + require(mergeCombiners != null, "mergeCombiners must be defined") // required as of Spark 0.9.0 if (getKeyClass().isArray) { if (mapSideCombine) { throw new SparkException("Cannot use map-side combining with array keys.") From b3fff962e4f527ed9faf706d705a38248f3d27d0 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Fri, 21 Feb 2014 11:11:55 -0800 Subject: [PATCH 110/133] SPARK-1111: URL Validation Throws Error for HDFS URL's Fixes an error where HDFS URL's cause an exception. Should be merged into master and 0.9. Author: Patrick Wendell Closes #625 from pwendell/url-validation and squashes the following commits: d14bfe3 [Patrick Wendell] SPARK-1111: URL Validation Throws Error for HDFS URL's (cherry picked from commit 45b15e27a84527abeaa8588b0eb1ade7e831e6ef) Signed-off-by: Aaron Davidson --- .../apache/spark/deploy/ClientArguments.scala | 17 +++++----- .../org/apache/spark/deploy/ClientSuite.scala | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 core/src/test/scala/org/apache/spark/deploy/ClientSuite.scala diff --git a/core/src/main/scala/org/apache/spark/deploy/ClientArguments.scala b/core/src/main/scala/org/apache/spark/deploy/ClientArguments.scala index db67c6d1bb55c..13a0f1fa9b767 100644 --- a/core/src/main/scala/org/apache/spark/deploy/ClientArguments.scala +++ b/core/src/main/scala/org/apache/spark/deploy/ClientArguments.scala @@ -17,8 +17,6 @@ package org.apache.spark.deploy -import java.net.URL - import scala.collection.mutable.ListBuffer import org.apache.log4j.Level @@ -71,13 +69,10 @@ private[spark] class ClientArguments(args: Array[String]) { case "launch" :: _master :: _jarUrl :: _mainClass :: tail => cmd = "launch" - try { - new URL(_jarUrl) - } catch { - case e: Exception => - println(s"Jar url '${_jarUrl}' is not a valid URL.") - println(s"Jar must be in URL format (e.g. hdfs://XX, file://XX)") - printUsageAndExit(-1) + if (!ClientArguments.isValidJarUrl(_jarUrl)) { + println(s"Jar url '${_jarUrl}' is not in valid format.") + println(s"Must be a jar file path in URL format (e.g. hdfs://XX.jar, file://XX.jar)") + printUsageAndExit(-1) } jarUrl = _jarUrl @@ -115,3 +110,7 @@ private[spark] class ClientArguments(args: Array[String]) { System.exit(exitCode) } } + +object ClientArguments { + def isValidJarUrl(s: String) = s.matches("(.+):(.+)jar") +} diff --git a/core/src/test/scala/org/apache/spark/deploy/ClientSuite.scala b/core/src/test/scala/org/apache/spark/deploy/ClientSuite.scala new file mode 100644 index 0000000000000..d6b93f5fedd3b --- /dev/null +++ b/core/src/test/scala/org/apache/spark/deploy/ClientSuite.scala @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.spark.deploy + +import org.scalatest.FunSuite +import org.scalatest.matchers.ShouldMatchers + +class ClientSuite extends FunSuite with ShouldMatchers { + test("correctly validates driver jar URL's") { + ClientArguments.isValidJarUrl("http://someHost:8080/foo.jar") should be (true) + ClientArguments.isValidJarUrl("file://some/path/to/a/jarFile.jar") should be (true) + ClientArguments.isValidJarUrl("hdfs://someHost:1234/foo.jar") should be (true) + + ClientArguments.isValidJarUrl("hdfs://someHost:1234/foo") should be (false) + ClientArguments.isValidJarUrl("/missing/a/protocol/jarfile.jar") should be (false) + ClientArguments.isValidJarUrl("not-even-a-path.jar") should be (false) + } + +} From 998abaecbc76f0a2b0317350d0ee589e78b0fbb0 Mon Sep 17 00:00:00 2001 From: Sean Owen Date: Fri, 21 Feb 2014 12:46:12 -0800 Subject: [PATCH 111/133] MLLIB-25: Implicit ALS runs out of memory for moderately large numbers of features There's a step in implicit ALS where the matrix `Yt * Y` is computed. It's computed as the sum of matrices; an f x f matrix is created for each of n user/item rows in a partition. In `ALS.scala:214`: ``` factors.flatMapValues{ case factorArray => factorArray.map{ vector => val x = new DoubleMatrix(vector) x.mmul(x.transpose()) } }.reduceByKeyLocally((a, b) => a.addi(b)) .values .reduce((a, b) => a.addi(b)) ``` Completely correct, but there's a subtle but quite large memory problem here. map() is going to create all of these matrices in memory at once, when they don't need to ever all exist at the same time. For example, if a partition has n = 100000 rows, and f = 200, then this intermediate product requires 32GB of heap. The computation will never work unless you can cough up workers with (more than) that much heap. Fortunately there's a trivial change that fixes it; just add `.view` in there. Author: Sean Owen Closes #629 from srowen/ALSMatrixAllocationOptimization and squashes the following commits: 062cda9 [Sean Owen] Update style per review comments e9a5d63 [Sean Owen] Avoid unnecessary out of memory situation by not simultaneously allocating lots of matrices (cherry picked from commit c8a4c9b1f6005815f5a4a331970624d1706b6b13) Signed-off-by: Reynold Xin --- .../scala/org/apache/spark/mllib/recommendation/ALS.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mllib/src/main/scala/org/apache/spark/mllib/recommendation/ALS.scala b/mllib/src/main/scala/org/apache/spark/mllib/recommendation/ALS.scala index 89ee07063dd89..3e93402adffaf 100644 --- a/mllib/src/main/scala/org/apache/spark/mllib/recommendation/ALS.scala +++ b/mllib/src/main/scala/org/apache/spark/mllib/recommendation/ALS.scala @@ -209,8 +209,8 @@ class ALS private (var numBlocks: Int, var rank: Int, var iterations: Int, var l def computeYtY(factors: RDD[(Int, Array[Array[Double]])]) = { if (implicitPrefs) { Option( - factors.flatMapValues{ case factorArray => - factorArray.map{ vector => + factors.flatMapValues { case factorArray => + factorArray.view.map { vector => val x = new DoubleMatrix(vector) x.mmul(x.transpose()) } From 84131fee752f0f6c441b325d85087e09f6bea0cc Mon Sep 17 00:00:00 2001 From: Andrew Or Date: Fri, 21 Feb 2014 20:05:39 -0800 Subject: [PATCH 112/133] [SPARK-1113] External spilling - fix Int.MaxValue hash code collision bug The original poster of this bug is @guojc, who opened a PR that preceded this one at https://github.com/apache/incubator-spark/pull/612. ExternalAppendOnlyMap uses key hash code to order the buffer streams from which spilled files are read back into memory. When a buffer stream is empty, the default hash code for that stream is equal to Int.MaxValue. This is, however, a perfectly legitimate candidate for a key hash code. When reading from a spilled map containing such a key, a hash collision may occur, in which case we attempt to read from an empty stream and throw NoSuchElementException. The fix is to maintain the invariant that empty buffer streams are never added back to the merge queue to be considered. This guarantees that we never read from an empty buffer stream, ever again. This PR also includes two new tests for hash collisions. Author: Andrew Or Closes #624 from andrewor14/spilling-bug and squashes the following commits: 9e7263d [Andrew Or] Slightly optimize next() 2037ae2 [Andrew Or] Move a few comments around... cf95942 [Andrew Or] Remove default value of Int.MaxValue for minKeyHash c11f03b [Andrew Or] Fix Int.MaxValue hash collision bug in ExternalAppendOnlyMap 21c1a39 [Andrew Or] Add hash collision tests to ExternalAppendOnlyMapSuite (cherry picked from commit fefd22f4c3e95d904cb6f4f3fd88b89050907ae9) Signed-off-by: Patrick Wendell --- .../collection/ExternalAppendOnlyMap.scala | 49 +++++----- .../ExternalAppendOnlyMapSuite.scala | 91 ++++++++++++++++--- 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala index 7eb300d46e6e2..6f368179bbfbd 100644 --- a/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala +++ b/core/src/main/scala/org/apache/spark/util/collection/ExternalAppendOnlyMap.scala @@ -148,7 +148,7 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( } /** - * Sort the existing contents of the in-memory map and spill them to a temporary file on disk + * Sort the existing contents of the in-memory map and spill them to a temporary file on disk. */ private def spill(mapSize: Long) { spillCount += 1 @@ -223,7 +223,8 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( */ private class ExternalIterator extends Iterator[(K, C)] { - // A fixed-size queue that maintains a buffer for each stream we are currently merging + // A queue that maintains a buffer for each stream we are currently merging + // This queue maintains the invariant that it only contains non-empty buffers private val mergeHeap = new mutable.PriorityQueue[StreamBuffer] // Input streams are derived both from the in-memory map and spilled maps on disk @@ -233,7 +234,9 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( inputStreams.foreach { it => val kcPairs = getMorePairs(it) - mergeHeap.enqueue(StreamBuffer(it, kcPairs)) + if (kcPairs.length > 0) { + mergeHeap.enqueue(new StreamBuffer(it, kcPairs)) + } } /** @@ -258,11 +261,11 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( /** * If the given buffer contains a value for the given key, merge that value into - * baseCombiner and remove the corresponding (K, C) pair from the buffer + * baseCombiner and remove the corresponding (K, C) pair from the buffer. */ private def mergeIfKeyExists(key: K, baseCombiner: C, buffer: StreamBuffer): C = { var i = 0 - while (i < buffer.pairs.size) { + while (i < buffer.pairs.length) { val (k, c) = buffer.pairs(i) if (k == key) { buffer.pairs.remove(i) @@ -274,40 +277,41 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( } /** - * Return true if there exists an input stream that still has unvisited pairs + * Return true if there exists an input stream that still has unvisited pairs. */ - override def hasNext: Boolean = mergeHeap.exists(!_.pairs.isEmpty) + override def hasNext: Boolean = mergeHeap.length > 0 /** * Select a key with the minimum hash, then combine all values with the same key from all * input streams */ override def next(): (K, C) = { + if (mergeHeap.length == 0) { + throw new NoSuchElementException + } // Select a key from the StreamBuffer that holds the lowest key hash val minBuffer = mergeHeap.dequeue() val (minPairs, minHash) = (minBuffer.pairs, minBuffer.minKeyHash) - if (minPairs.length == 0) { - // Should only happen when no other stream buffers have any pairs left - throw new NoSuchElementException - } var (minKey, minCombiner) = minPairs.remove(0) assert(minKey.hashCode() == minHash) // For all other streams that may have this key (i.e. have the same minimum key hash), // merge in the corresponding value (if any) from that stream val mergedBuffers = ArrayBuffer[StreamBuffer](minBuffer) - while (!mergeHeap.isEmpty && mergeHeap.head.minKeyHash == minHash) { + while (mergeHeap.length > 0 && mergeHeap.head.minKeyHash == minHash) { val newBuffer = mergeHeap.dequeue() minCombiner = mergeIfKeyExists(minKey, minCombiner, newBuffer) mergedBuffers += newBuffer } - // Repopulate each visited stream buffer and add it back to the merge heap + // Repopulate each visited stream buffer and add it back to the queue if it is non-empty mergedBuffers.foreach { buffer => - if (buffer.pairs.length == 0) { + if (buffer.isEmpty) { buffer.pairs ++= getMorePairs(buffer.iterator) } - mergeHeap.enqueue(buffer) + if (!buffer.isEmpty) { + mergeHeap.enqueue(buffer) + } } (minKey, minCombiner) @@ -323,13 +327,12 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( private case class StreamBuffer(iterator: Iterator[(K, C)], pairs: ArrayBuffer[(K, C)]) extends Comparable[StreamBuffer] { - def minKeyHash: Int = { - if (pairs.length > 0){ - // pairs are already sorted by key hash - pairs(0)._1.hashCode() - } else { - Int.MaxValue - } + def isEmpty = pairs.length == 0 + + // Invalid if there are no more pairs in this stream + def minKeyHash = { + assert(pairs.length > 0) + pairs.head._1.hashCode() } override def compareTo(other: StreamBuffer): Int = { @@ -356,7 +359,7 @@ private[spark] class ExternalAppendOnlyMap[K, V, C]( private var objectsRead = 0 /** - * Construct a stream that reads only from the next batch + * Construct a stream that reads only from the next batch. */ private def nextBatchStream(): InputStream = { if (batchSizes.length > 0) { diff --git a/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala b/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala index bb4dc0fcd31a3..fce1184d46364 100644 --- a/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala +++ b/core/src/test/scala/org/apache/spark/util/collection/ExternalAppendOnlyMapSuite.scala @@ -19,21 +19,16 @@ package org.apache.spark.util.collection import scala.collection.mutable.ArrayBuffer -import org.scalatest.{BeforeAndAfter, FunSuite} +import org.scalatest.FunSuite import org.apache.spark._ import org.apache.spark.SparkContext._ -class ExternalAppendOnlyMapSuite extends FunSuite with BeforeAndAfter with LocalSparkContext { +class ExternalAppendOnlyMapSuite extends FunSuite with LocalSparkContext { - private val createCombiner: (Int => ArrayBuffer[Int]) = i => ArrayBuffer[Int](i) - private val mergeValue: (ArrayBuffer[Int], Int) => ArrayBuffer[Int] = (buffer, i) => { - buffer += i - } - private val mergeCombiners: (ArrayBuffer[Int], ArrayBuffer[Int]) => ArrayBuffer[Int] = - (buf1, buf2) => { - buf1 ++= buf2 - } + private def createCombiner(i: Int) = ArrayBuffer[Int](i) + private def mergeValue(buffer: ArrayBuffer[Int], i: Int) = buffer += i + private def mergeCombiners(buf1: ArrayBuffer[Int], buf2: ArrayBuffer[Int]) = buf1 ++= buf2 test("simple insert") { val conf = new SparkConf(false) @@ -203,13 +198,13 @@ class ExternalAppendOnlyMapSuite extends FunSuite with BeforeAndAfter with Local } test("spilling") { - // TODO: Use SparkConf (which currently throws connection reset exception) - System.setProperty("spark.shuffle.memoryFraction", "0.001") - sc = new SparkContext("local-cluster[1,1,512]", "test") + val conf = new SparkConf(true) // Load defaults, otherwise SPARK_HOME is not found + conf.set("spark.shuffle.memoryFraction", "0.001") + sc = new SparkContext("local-cluster[1,1,512]", "test", conf) // reduceByKey - should spill ~8 times val rddA = sc.parallelize(0 until 100000).map(i => (i/2, i)) - val resultA = rddA.reduceByKey(math.max(_, _)).collect() + val resultA = rddA.reduceByKey(math.max).collect() assert(resultA.length == 50000) resultA.foreach { case(k, v) => k match { @@ -252,7 +247,73 @@ class ExternalAppendOnlyMapSuite extends FunSuite with BeforeAndAfter with Local case _ => } } + } + + test("spilling with hash collisions") { + val conf = new SparkConf(true) + conf.set("spark.shuffle.memoryFraction", "0.001") + sc = new SparkContext("local-cluster[1,1,512]", "test", conf) + + def createCombiner(i: String) = ArrayBuffer[String](i) + def mergeValue(buffer: ArrayBuffer[String], i: String) = buffer += i + def mergeCombiners(buffer1: ArrayBuffer[String], buffer2: ArrayBuffer[String]) = + buffer1 ++= buffer2 + + val map = new ExternalAppendOnlyMap[String, String, ArrayBuffer[String]]( + createCombiner, mergeValue, mergeCombiners) + + val collisionPairs = Seq( + ("Aa", "BB"), // 2112 + ("to", "v1"), // 3707 + ("variants", "gelato"), // -1249574770 + ("Teheran", "Siblings"), // 231609873 + ("misused", "horsemints"), // 1069518484 + ("isohel", "epistolaries"), // -1179291542 + ("righto", "buzzards"), // -931102253 + ("hierarch", "crinolines"), // -1732884796 + ("inwork", "hypercatalexes"), // -1183663690 + ("wainages", "presentencing"), // 240183619 + ("trichothecenes", "locular"), // 339006536 + ("pomatoes", "eructation") // 568647356 + ) + + (1 to 100000).map(_.toString).foreach { i => map.insert(i, i) } + collisionPairs.foreach { case (w1, w2) => + map.insert(w1, w2) + map.insert(w2, w1) + } + + // A map of collision pairs in both directions + val collisionPairsMap = (collisionPairs ++ collisionPairs.map(_.swap)).toMap + + // Avoid map.size or map.iterator.length because this destructively sorts the underlying map + var count = 0 + + val it = map.iterator + while (it.hasNext) { + val kv = it.next() + val expectedValue = ArrayBuffer[String](collisionPairsMap.getOrElse(kv._1, kv._1)) + assert(kv._2.equals(expectedValue)) + count += 1 + } + assert(count == 100000 + collisionPairs.size * 2) + } + + test("spilling with hash collisions using the Int.MaxValue key") { + val conf = new SparkConf(true) + conf.set("spark.shuffle.memoryFraction", "0.001") + sc = new SparkContext("local-cluster[1,1,512]", "test", conf) - System.clearProperty("spark.shuffle.memoryFraction") + val map = new ExternalAppendOnlyMap[Int, Int, ArrayBuffer[Int]](createCombiner, + mergeValue, mergeCombiners) + + (1 to 100000).foreach { i => map.insert(i, i) } + map.insert(Int.MaxValue, Int.MaxValue) + + val it = map.iterator + while (it.hasNext) { + // Should not throw NoSuchElementException + it.next() + } } } From ed5874276be13d97593db11de9768edc4fbfabd3 Mon Sep 17 00:00:00 2001 From: Xiangrui Meng Date: Fri, 21 Feb 2014 22:44:45 -0800 Subject: [PATCH 113/133] SPARK-1117: update accumulator docs The current doc hints spark doesn't support accumulators of type `Long`, which is wrong. JIRA: https://spark-project.atlassian.net/browse/SPARK-1117 Author: Xiangrui Meng Closes #631 from mengxr/acc and squashes the following commits: 45ecd25 [Xiangrui Meng] update accumulator docs (cherry picked from commit aaec7d4a80ed370847671e9e29ce2e92f1cff2c7) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/Accumulators.scala | 4 ++-- docs/scala-programming-guide.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Accumulators.scala b/core/src/main/scala/org/apache/spark/Accumulators.scala index df01b2e942180..de811eaf0d4bd 100644 --- a/core/src/main/scala/org/apache/spark/Accumulators.scala +++ b/core/src/main/scala/org/apache/spark/Accumulators.scala @@ -188,8 +188,8 @@ class GrowableAccumulableParam[R <% Growable[T] with TraversableOnce[T] with Ser * A simpler value of [[Accumulable]] where the result type being accumulated is the same * as the types of elements being merged, i.e. variables that are only "added" to through an * associative operation and can therefore be efficiently supported in parallel. They can be used - * to implement counters (as in MapReduce) or sums. Spark natively supports accumulators of type - * `Int` and `Double`, and programmers can add support for new types. + * to implement counters (as in MapReduce) or sums. Spark natively supports accumulators of numeric + * value types, and programmers can add support for new types. * * An accumulator is created from an initial value `v` by calling [[SparkContext#accumulator]]. * Tasks running on the cluster can then add to it using the [[Accumulable#+=]] operator. diff --git a/docs/scala-programming-guide.md b/docs/scala-programming-guide.md index cd847e07f94ab..506d3faa767f3 100644 --- a/docs/scala-programming-guide.md +++ b/docs/scala-programming-guide.md @@ -344,7 +344,7 @@ After the broadcast variable is created, it should be used instead of the value ## Accumulators -Accumulators are variables that are only "added" to through an associative operation and can therefore be efficiently supported in parallel. They can be used to implement counters (as in MapReduce) or sums. Spark natively supports accumulators of type Int and Double, and programmers can add support for new types. +Accumulators are variables that are only "added" to through an associative operation and can therefore be efficiently supported in parallel. They can be used to implement counters (as in MapReduce) or sums. Spark natively supports accumulators of numeric value types and standard mutable collections, and programmers can add support for new types. An accumulator is created from an initial value `v` by calling `SparkContext.accumulator(v)`. Tasks running on the cluster can then add to it using the `+=` operator. However, they cannot read its value. Only the driver program can read the accumulator's value, using its `value` method. From 00db30ccc85f686e15596ab277433407d505ddd7 Mon Sep 17 00:00:00 2001 From: CodingCat Date: Sat, 22 Feb 2014 15:39:25 -0800 Subject: [PATCH 114/133] [SPARK-1055] fix the SCALA_VERSION and SPARK_VERSION in docker file As reported in https://spark-project.atlassian.net/browse/SPARK-1055 "The used Spark version in the .../base/Dockerfile is stale on 0.8.1 and should be updated to 0.9.x to match the release." Author: CodingCat Author: Nan Zhu Closes #634 from CodingCat/SPARK-1055 and squashes the following commits: cb7330e [Nan Zhu] Update Dockerfile adf8259 [CodingCat] fix the SCALA_VERSION and SPARK_VERSION in docker file (cherry picked from commit 1aa4f8af7220bc311196ef0eef0a4814cd2757d3) Signed-off-by: Aaron Davidson --- docker/spark-test/base/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/spark-test/base/Dockerfile b/docker/spark-test/base/Dockerfile index 60962776dda57..e543db6143e4d 100644 --- a/docker/spark-test/base/Dockerfile +++ b/docker/spark-test/base/Dockerfile @@ -25,8 +25,7 @@ RUN apt-get update # install a few other useful packages plus Open Jdk 7 RUN apt-get install -y less openjdk-7-jre-headless net-tools vim-tiny sudo openssh-server -ENV SCALA_VERSION 2.9.3 -ENV SPARK_VERSION 0.8.1 +ENV SCALA_VERSION 2.10.3 ENV CDH_VERSION cdh4 ENV SCALA_HOME /opt/scala-$SCALA_VERSION ENV SPARK_HOME /opt/spark From 5e74b8eb0199a67bf17eb1b5e48f89571755b842 Mon Sep 17 00:00:00 2001 From: Matei Zaharia Date: Sun, 23 Feb 2014 23:45:48 -0800 Subject: [PATCH 115/133] SPARK-1124: Fix infinite retries of reduce stage when a map stage failed In the previous code, if you had a failing map stage and then tried to run reduce stages on it repeatedly, the first reduce stage would fail correctly, but the later ones would mistakenly believe that all map outputs are available and start failing infinitely with fetch failures from "null". --- .../apache/spark/scheduler/DAGScheduler.scala | 31 ++++++++++--------- .../scala/org/apache/spark/FailureSuite.scala | 13 ++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala index 21d16fabefaa5..21b7ccba51b40 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala @@ -272,8 +272,10 @@ class DAGScheduler( if (mapOutputTracker.has(shuffleDep.shuffleId)) { val serLocs = mapOutputTracker.getSerializedMapOutputStatuses(shuffleDep.shuffleId) val locs = MapOutputTracker.deserializeMapStatuses(serLocs) - for (i <- 0 until locs.size) stage.outputLocs(i) = List(locs(i)) - stage.numAvailableOutputs = locs.size + for (i <- 0 until locs.size) { + stage.outputLocs(i) = Option(locs(i)).toList // locs(i) will be null if missing + } + stage.numAvailableOutputs = locs.count(_ != null) } else { // Kind of ugly: need to register RDDs with the cache and map output tracker here // since we can't do it in the RDD constructor because # of partitions is unknown @@ -373,25 +375,26 @@ class DAGScheduler( } else { def removeStage(stageId: Int) { // data structures based on Stage - stageIdToStage.get(stageId).foreach { s => - if (running.contains(s)) { + for (stage <- stageIdToStage.get(stageId)) { + if (running.contains(stage)) { logDebug("Removing running stage %d".format(stageId)) - running -= s + running -= stage + } + stageToInfos -= stage + for (shuffleDep <- stage.shuffleDep) { + shuffleToMapStage.remove(shuffleDep.shuffleId) } - stageToInfos -= s - shuffleToMapStage.keys.filter(shuffleToMapStage(_) == s).foreach(shuffleId => - shuffleToMapStage.remove(shuffleId)) - if (pendingTasks.contains(s) && !pendingTasks(s).isEmpty) { + if (pendingTasks.contains(stage) && !pendingTasks(stage).isEmpty) { logDebug("Removing pending status for stage %d".format(stageId)) } - pendingTasks -= s - if (waiting.contains(s)) { + pendingTasks -= stage + if (waiting.contains(stage)) { logDebug("Removing stage %d from waiting set.".format(stageId)) - waiting -= s + waiting -= stage } - if (failed.contains(s)) { + if (failed.contains(stage)) { logDebug("Removing stage %d from failed set.".format(stageId)) - failed -= s + failed -= stage } } // data structures based on StageId diff --git a/core/src/test/scala/org/apache/spark/FailureSuite.scala b/core/src/test/scala/org/apache/spark/FailureSuite.scala index befdc1589f009..6465a80e4c8ba 100644 --- a/core/src/test/scala/org/apache/spark/FailureSuite.scala +++ b/core/src/test/scala/org/apache/spark/FailureSuite.scala @@ -81,6 +81,19 @@ class FailureSuite extends FunSuite with LocalSparkContext { FailureSuiteState.clear() } + // Run a map-reduce job in which the map stage always fails. + test("failure in a map stage") { + sc = new SparkContext("local", "test") + val data = sc.makeRDD(1 to 3).map(x => { throw new Exception; (x, x) }).groupByKey(3) + intercept[SparkException] { + data.collect() + } + // Make sure that running new jobs with the same map stage also fails + intercept[SparkException] { + data.collect() + } + } + test("failure because task results are not serializable") { sc = new SparkContext("local[1,1]", "test") val results = sc.makeRDD(1 to 3).map(x => new NonSerializable) From 0661cdcdfdc0b4fe165c95d951d74fa228c09a3b Mon Sep 17 00:00:00 2001 From: Matei Zaharia Date: Mon, 24 Feb 2014 13:14:56 -0800 Subject: [PATCH 116/133] Fix removal from shuffleToMapStage to search for a key-value pair with our stage instead of using our shuffleID. --- .../main/scala/org/apache/spark/scheduler/DAGScheduler.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala index 21b7ccba51b40..536d84f07e5ec 100644 --- a/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala +++ b/core/src/main/scala/org/apache/spark/scheduler/DAGScheduler.scala @@ -381,8 +381,8 @@ class DAGScheduler( running -= stage } stageToInfos -= stage - for (shuffleDep <- stage.shuffleDep) { - shuffleToMapStage.remove(shuffleDep.shuffleId) + for ((k, v) <- shuffleToMapStage.find(_._2 == stage)) { + shuffleToMapStage.remove(k) } if (pendingTasks.contains(stage) && !pendingTasks(stage).isEmpty) { logDebug("Removing pending status for stage %d".format(stageId)) From 6fe72dd389dac1b97a4277991a79ca973e1de823 Mon Sep 17 00:00:00 2001 From: Matei Zaharia Date: Wed, 26 Feb 2014 11:20:16 -0800 Subject: [PATCH 117/133] SPARK-1135: fix broken anchors in docs A recent PR that added Java vs Scala tabs for streaming also inadvertently added some bad code to a document.ready handler, breaking our other handler that manages scrolling to anchors correctly with the floating top bar. As a result the section title ended up always being hidden below the top bar. This removes the unnecessary JavaScript code. Author: Matei Zaharia Closes #3 from mateiz/doc-links and squashes the following commits: e2a3488 [Matei Zaharia] SPARK-1135: fix broken anchors in docs --- docs/js/main.js | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/docs/js/main.js b/docs/js/main.js index 102699789a71a..0bd2286cced19 100755 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -1,26 +1,3 @@ - -// From docs.scala-lang.org -function styleCode() { - if (typeof disableStyleCode != "undefined") { - return; - } - $(".codetabs pre code").parent().each(function() { - if (!$(this).hasClass("prettyprint")) { - var lang = $(this).parent().data("lang"); - if (lang == "python") { - lang = "py" - } - if (lang == "bash") { - lang = "bsh" - } - $(this).addClass("prettyprint lang-"+lang+" linenums"); - } - }); - console.log("runningPrettyPrint()") - prettyPrint(); -} - - function codeTabs() { var counter = 0; var langImages = { @@ -97,11 +74,7 @@ function viewSolution() { } -$(document).ready(function() { +$(function() { codeTabs(); viewSolution(); - $('#chapter-toc').toc({exclude: '', context: '.container'}); - $('#chapter-toc').prepend('

    In This Chapter

    '); - makeCollapsable($('#global-toc'), "", "global-toc", "Show Table of Contents"); - //styleCode(); }); From 886a466f32b06846a7f3f664c4a906fb6c0cb25d Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Wed, 26 Feb 2014 14:50:37 -0800 Subject: [PATCH 118/133] SPARK-1115: Catch depickling errors This surroungs the complete worker code in a try/except block so we catch any error that arrives. An example would be the depickling failing for some reason @JoshRosen Author: Bouke van der Bijl Closes #644 from bouk/catch-depickling-errors and squashes the following commits: f0f67cc [Bouke van der Bijl] Lol indentation 0e4d504 [Bouke van der Bijl] Surround the complete python worker with the try block (cherry picked from commit 12738c1aec136acd7f2e3e2f8f2b541db0890630) Signed-off-by: Josh Rosen --- python/pyspark/worker.py | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/python/pyspark/worker.py b/python/pyspark/worker.py index 4be4063dcf602..4e47d02965c4d 100644 --- a/python/pyspark/worker.py +++ b/python/pyspark/worker.py @@ -45,34 +45,34 @@ def report_times(outfile, boot, init, finish): def main(infile, outfile): - boot_time = time.time() - split_index = read_int(infile) - if split_index == -1: # for unit tests - return + try: + boot_time = time.time() + split_index = read_int(infile) + if split_index == -1: # for unit tests + return - # fetch name of workdir - spark_files_dir = utf8_deserializer.loads(infile) - SparkFiles._root_directory = spark_files_dir - SparkFiles._is_running_on_worker = True + # fetch name of workdir + spark_files_dir = utf8_deserializer.loads(infile) + SparkFiles._root_directory = spark_files_dir + SparkFiles._is_running_on_worker = True - # fetch names and values of broadcast variables - num_broadcast_variables = read_int(infile) - for _ in range(num_broadcast_variables): - bid = read_long(infile) - value = pickleSer._read_with_length(infile) - _broadcastRegistry[bid] = Broadcast(bid, value) + # fetch names and values of broadcast variables + num_broadcast_variables = read_int(infile) + for _ in range(num_broadcast_variables): + bid = read_long(infile) + value = pickleSer._read_with_length(infile) + _broadcastRegistry[bid] = Broadcast(bid, value) - # fetch names of includes (*.zip and *.egg files) and construct PYTHONPATH - sys.path.append(spark_files_dir) # *.py files that were added will be copied here - num_python_includes = read_int(infile) - for _ in range(num_python_includes): - filename = utf8_deserializer.loads(infile) - sys.path.append(os.path.join(spark_files_dir, filename)) + # fetch names of includes (*.zip and *.egg files) and construct PYTHONPATH + sys.path.append(spark_files_dir) # *.py files that were added will be copied here + num_python_includes = read_int(infile) + for _ in range(num_python_includes): + filename = utf8_deserializer.loads(infile) + sys.path.append(os.path.join(spark_files_dir, filename)) - command = pickleSer._read_with_length(infile) - (func, deserializer, serializer) = command - init_time = time.time() - try: + command = pickleSer._read_with_length(infile) + (func, deserializer, serializer) = command + init_time = time.time() iterator = deserializer.load_stream(infile) serializer.dump_stream(func(split_index, iterator), outfile) except Exception as e: From 349764d0c1f559257243ad34b8b055dd08bed7c2 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Wed, 26 Feb 2014 16:52:26 -0800 Subject: [PATCH 119/133] Removed reference to incubation in README.md. Author: Reynold Xin Closes #1 from rxin/readme and squashes the following commits: b3a77cd [Reynold Xin] Removed reference to incubation in README.md. (cherry picked from commit 84f7ca138165ca413897dada35c602676b0a614f) Signed-off-by: Patrick Wendell --- README.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c840a68f76b17..dc8135b9b8b51 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Apache Spark -Lightning-Fast Cluster Computing - +Lightning-Fast Cluster Computing - ## Online Documentation You can find the latest Spark documentation, including a programming -guide, on the project webpage at . +guide, on the project webpage at . This README file only contains basic setup instructions. @@ -92,21 +92,10 @@ If your project is built with Maven, add this to your POM file's ` ## Configuration -Please refer to the [Configuration guide](http://spark.incubator.apache.org/docs/latest/configuration.html) +Please refer to the [Configuration guide](http://spark.apache.org/docs/latest/configuration.html) in the online documentation for an overview on how to configure Spark. -## Apache Incubator Notice - -Apache Spark is an effort undergoing incubation at The Apache Software -Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of -all newly accepted projects until a further review indicates that the -infrastructure, communications, and decision making process have stabilized in -a manner consistent with other successful ASF projects. While incubation status -is not necessarily a reflection of the completeness or stability of the code, -it does indicate that the project has yet to be fully endorsed by the ASF. - - ## Contributing to Spark Contributions via GitHub pull requests are gladly accepted from their original From bc5e7d73409efdb42886cb5f2b7cd471a4fd2ce7 Mon Sep 17 00:00:00 2001 From: CodingCat Date: Wed, 26 Feb 2014 23:42:15 -0800 Subject: [PATCH 120/133] [SPARK-1089] fix the regression problem on ADD_JARS in 0.9 https://spark-project.atlassian.net/browse/SPARK-1089 copied from JIRA, reported by @ash211 "Using the ADD_JARS environment variable with spark-shell used to add the jar to both the shell and the various workers. Now it only adds to the workers and importing a custom class in the shell is broken. The workaround is to add custom jars to both ADD_JARS and SPARK_CLASSPATH. We should fix ADD_JARS so it works properly again. See various threads on the user list: https://mail-archives.apache.org/mod_mbox/incubator-spark-user/201402.mbox/%3CCAJbo4neMLiTrnm1XbyqomWmp0m+EUcg4yE-txuRGSVKOb5KLeA@mail.gmail.com%3E (another one that doesn't appear in the archives yet titled "ADD_JARS not working on 0.9")" The reason of this bug is two-folds in the current implementation of SparkILoop.scala, the settings.classpath is not set properly when the process() method is invoked the weird behaviour of Scala 2.10, (I personally thought it is a bug) if we simply set value of a PathSettings object (like settings.classpath), the isDefault is not set to true (this is a flag showing if the variable is modified), so it makes the PathResolver loads the default CLASSPATH environment variable value to calculated the path (see https://github.com/scala/scala/blob/2.10.x/src/compiler/scala/tools/util/PathResolver.scala#L215) what we have to do is to manually make this flag set, (https://github.com/CodingCat/incubator-spark/blob/e3991d97ddc33e77645e4559b13bf78b9e68239a/repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala#L884) Author: CodingCat Closes #13 from CodingCat/SPARK-1089 and squashes the following commits: 8af81e7 [CodingCat] impose non-null settings 9aa2125 [CodingCat] code cleaning ce36676 [CodingCat] code cleaning e045582 [CodingCat] fix the regression problem on ADD_JARS in 0.9 (cherry picked from commit 345df5f4a9c16a6a87440afa2b09082fc3d224bd) Signed-off-by: Patrick Wendell --- .../main/scala/org/apache/spark/repl/SparkILoop.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala b/repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala index 87d94d51be199..f262faa597b8f 100644 --- a/repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala +++ b/repl/src/main/scala/org/apache/spark/repl/SparkILoop.scala @@ -180,8 +180,13 @@ class SparkILoop(in0: Option[BufferedReader], protected val out: JPrintWriter, /** Create a new interpreter. */ def createInterpreter() { - if (addedClasspath != "") - settings.classpath append addedClasspath + require(settings != null) + + if (addedClasspath != "") settings.classpath.append(addedClasspath) + // work around for Scala bug + val totalClassPath = SparkILoop.getAddedJars.foldLeft( + settings.classpath.value)((l, r) => ClassPath.join(l, r)) + this.settings.classpath.value = totalClassPath intp = new SparkILoopInterpreter } From f2bf44adc8374c9cf683675db8067743bb48cfa2 Mon Sep 17 00:00:00 2001 From: Reynold Xin Date: Thu, 27 Feb 2014 21:13:22 -0800 Subject: [PATCH 121/133] Removed reference to incubation in Spark user docs. Author: Reynold Xin Closes #2 from rxin/docs and squashes the following commits: 08bbd5f [Reynold Xin] Removed reference to incubation in Spark user docs. (cherry picked from commit 40e080a68a8fd025435e9ff84fa9280b4aba4dcf) Conflicts: docs/_config.yml --- docs/README.md | 2 +- docs/_config.yml | 2 +- docs/_layouts/global.html | 10 ---------- docs/bagel-programming-guide.md | 2 +- docs/index.md | 12 ++++++------ docs/java-programming-guide.md | 2 +- docs/scala-programming-guide.md | 2 +- docs/spark-debugger.md | 4 ++-- 8 files changed, 13 insertions(+), 23 deletions(-) diff --git a/docs/README.md b/docs/README.md index dfcf7535538f0..0b7c32409a7a0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ Welcome to the Spark documentation! -This readme will walk you through navigating and building the Spark documentation, which is included here with the Spark source code. You can also find documentation specific to release versions of Spark at http://spark.incubator.apache.org/documentation.html. +This readme will walk you through navigating and building the Spark documentation, which is included here with the Spark source code. You can also find documentation specific to release versions of Spark at http://spark.apache.org/documentation.html. Read on to learn more about viewing documentation in plain text (i.e., markdown) or building the documentation yourself. Why build it yourself? So that you have the docs that corresponds to whichever version of Spark you currently have checked out of revision control. diff --git a/docs/_config.yml b/docs/_config.yml index 868fa2410fde2..a7f46ffa7b810 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -9,4 +9,4 @@ SCALA_BINARY_VERSION: "2.10" SCALA_VERSION: "2.10.3" MESOS_VERSION: 0.13.0 SPARK_ISSUE_TRACKER_URL: https://spark-project.atlassian.net -SPARK_GITHUB_URL: https://github.com/apache/incubator-spark +SPARK_GITHUB_URL: https://github.com/apache/spark diff --git a/docs/_layouts/global.html b/docs/_layouts/global.html index 33525953ac4f6..f2c101fd409cb 100755 --- a/docs/_layouts/global.html +++ b/docs/_layouts/global.html @@ -159,16 +159,6 @@

    Heading


    --> -
    -
    -

    - Apache Spark is an effort undergoing incubation at the Apache Software Foundation. - - - -

    -
    -
    diff --git a/docs/bagel-programming-guide.md b/docs/bagel-programming-guide.md index b070d8e73a38b..da6d0c9dcd97b 100644 --- a/docs/bagel-programming-guide.md +++ b/docs/bagel-programming-guide.md @@ -108,7 +108,7 @@ _Example_ ## Operations -Here are the actions and types in the Bagel API. See [Bagel.scala](https://github.com/apache/incubator-spark/blob/master/bagel/src/main/scala/org/apache/spark/bagel/Bagel.scala) for details. +Here are the actions and types in the Bagel API. See [Bagel.scala](https://github.com/apache/spark/blob/master/bagel/src/main/scala/org/apache/spark/bagel/Bagel.scala) for details. ### Actions diff --git a/docs/index.md b/docs/index.md index aa9c8666e7d75..4eb297df39144 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,7 @@ It also supports a rich set of higher-level tools including [Shark](http://shark # Downloading -Get Spark by visiting the [downloads page](http://spark.incubator.apache.org/downloads.html) of the Apache Spark site. This documentation is for Spark version {{site.SPARK_VERSION}}. +Get Spark by visiting the [downloads page](http://spark.apache.org/downloads.html) of the Apache Spark site. This documentation is for Spark version {{site.SPARK_VERSION}}. Spark runs on both Windows and UNIX-like systems (e.g. Linux, Mac OS). All you need to run it is to have `java` to installed on your system `PATH`, or the `JAVA_HOME` environment variable pointing to a Java installation. @@ -96,7 +96,7 @@ For this version of Spark (0.8.1) Hadoop 2.2.x (or newer) users will have to bui * [Amazon EC2](ec2-scripts.html): scripts that let you launch a cluster on EC2 in about 5 minutes * [Standalone Deploy Mode](spark-standalone.html): launch a standalone cluster quickly without a third-party cluster manager * [Mesos](running-on-mesos.html): deploy a private cluster using - [Apache Mesos](http://incubator.apache.org/mesos) + [Apache Mesos](http://mesos.apache.org) * [YARN](running-on-yarn.html): deploy Spark on top of Hadoop NextGen (YARN) **Other documents:** @@ -110,20 +110,20 @@ For this version of Spark (0.8.1) Hadoop 2.2.x (or newer) users will have to bui **External resources:** -* [Spark Homepage](http://spark.incubator.apache.org) +* [Spark Homepage](http://spark.apache.org) * [Shark](http://shark.cs.berkeley.edu): Apache Hive over Spark -* [Mailing Lists](http://spark.incubator.apache.org/mailing-lists.html): ask questions about Spark here +* [Mailing Lists](http://spark.apache.org/mailing-lists.html): ask questions about Spark here * [AMP Camps](http://ampcamp.berkeley.edu/): a series of training camps at UC Berkeley that featured talks and exercises about Spark, Shark, Mesos, and more. [Videos](http://ampcamp.berkeley.edu/agenda-2012), [slides](http://ampcamp.berkeley.edu/agenda-2012) and [exercises](http://ampcamp.berkeley.edu/exercises-2012) are available online for free. -* [Code Examples](http://spark.incubator.apache.org/examples.html): more are also available in the [examples subfolder](https://github.com/apache/incubator-spark/tree/master/examples/src/main/scala/) of Spark +* [Code Examples](http://spark.apache.org/examples.html): more are also available in the [examples subfolder](https://github.com/apache/spark/tree/master/examples/src/main/scala/) of Spark * [Paper Describing Spark](http://www.cs.berkeley.edu/~matei/papers/2012/nsdi_spark.pdf) * [Paper Describing Spark Streaming](http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-259.pdf) # Community -To get help using Spark or keep up with Spark development, sign up for the [user mailing list](http://spark.incubator.apache.org/mailing-lists.html). +To get help using Spark or keep up with Spark development, sign up for the [user mailing list](http://spark.apache.org/mailing-lists.html). If you're in the San Francisco Bay Area, there's a regular [Spark meetup](http://www.meetup.com/spark-users/) every few weeks. Come by to meet the developers and other users. diff --git a/docs/java-programming-guide.md b/docs/java-programming-guide.md index 07732fa1229f3..5c73dbb25ede8 100644 --- a/docs/java-programming-guide.md +++ b/docs/java-programming-guide.md @@ -189,7 +189,7 @@ We hope to generate documentation with Java-style syntax in the future. # Where to Go from Here Spark includes several sample programs using the Java API in -[`examples/src/main/java`](https://github.com/apache/incubator-spark/tree/master/examples/src/main/java/org/apache/spark/examples). You can run them by passing the class name to the +[`examples/src/main/java`](https://github.com/apache/spark/tree/master/examples/src/main/java/org/apache/spark/examples). You can run them by passing the class name to the `bin/run-example` script included in Spark; for example: ./bin/run-example org.apache.spark.examples.JavaWordCount diff --git a/docs/scala-programming-guide.md b/docs/scala-programming-guide.md index 506d3faa767f3..99412733d4268 100644 --- a/docs/scala-programming-guide.md +++ b/docs/scala-programming-guide.md @@ -365,7 +365,7 @@ res2: Int = 10 # Where to Go from Here -You can see some [example Spark programs](http://spark.incubator.apache.org/examples.html) on the Spark website. +You can see some [example Spark programs](http://spark.apache.org/examples.html) on the Spark website. In addition, Spark includes several samples in `examples/src/main/scala`. Some of them have both Spark versions and local (non-parallel) versions, allowing you to see what had to be changed to make the program run on a cluster. You can run them using by passing the class name to the `bin/run-example` script included in Spark; for example: ./bin/run-example org.apache.spark.examples.SparkPi diff --git a/docs/spark-debugger.md b/docs/spark-debugger.md index 11c51d5cde7c9..891c2bfa8943d 100644 --- a/docs/spark-debugger.md +++ b/docs/spark-debugger.md @@ -2,7 +2,7 @@ layout: global title: The Spark Debugger --- -**Summary:** The Spark debugger provides replay debugging for deterministic (logic) errors in Spark programs. It's currently in development, but you can try it out in the [arthur branch](https://github.com/apache/incubator-spark/tree/arthur). +**Summary:** The Spark debugger provides replay debugging for deterministic (logic) errors in Spark programs. It's currently in development, but you can try it out in the [arthur branch](https://github.com/apache/spark/tree/arthur). ## Introduction @@ -19,7 +19,7 @@ For deterministic errors, debugging a Spark program is now as easy as debugging ## Approach -As your Spark program runs, the slaves report key events back to the master -- for example, RDD creations, RDD contents, and uncaught exceptions. (A full list of event types is in [EventLogging.scala](https://github.com/apache/incubator-spark/blob/arthur/core/src/main/scala/spark/EventLogging.scala).) The master logs those events, and you can load the event log into the debugger after your program is done running. +As your Spark program runs, the slaves report key events back to the master -- for example, RDD creations, RDD contents, and uncaught exceptions. (A full list of event types is in [EventLogging.scala](https://github.com/apache/spark/blob/arthur/core/src/main/scala/spark/EventLogging.scala).) The master logs those events, and you can load the event log into the debugger after your program is done running. _A note on nondeterminism:_ For fault recovery, Spark requires RDD transformations (for example, the function passed to `RDD.map`) to be deterministic. The Spark debugger also relies on this property, and it can also warn you if your transformation is nondeterministic. This works by checksumming the contents of each RDD and comparing the checksums from the original execution to the checksums after recomputing the RDD in the debugger. From 267d96c3db0f4918b15c0c0264a1c846016fefcb Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sun, 2 Mar 2014 18:18:44 -0800 Subject: [PATCH 122/133] Add Jekyll tag to isolate "production-only" doc components. (0.9 version) Author: Patrick Wendell Closes #57 from pwendell/jekyll-prod-0.9 and squashes the following commits: 69a7614 [Patrick Wendell] Add Jekyll tag to isolate "production-only" doc components. --- docs/README.md | 18 +++++++++++++++--- docs/_layouts/global.html | 4 ++-- docs/_plugins/production_tag.rb | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 docs/_plugins/production_tag.rb diff --git a/docs/README.md b/docs/README.md index 0b7c32409a7a0..d35990c03ef15 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,9 +10,21 @@ We include the Spark documentation as part of the source (as opposed to using a In this directory you will find textfiles formatted using Markdown, with an ".md" suffix. You can read those text files directly if you want. Start with index.md. -To make things quite a bit prettier and make the links easier to follow, generate the html version of the documentation based on the src directory by running `jekyll` in the docs directory. Use the command `SKIP_SCALADOC=1 jekyll` to skip building and copying over the scaladoc which can be timely. To use the `jekyll` command, you will need to have Jekyll installed, the easiest way to do this is via a Ruby Gem, see the [jekyll installation instructions](https://github.com/mojombo/jekyll/wiki/install). This will create a directory called _site containing index.html as well as the rest of the compiled files. Read more about Jekyll at https://github.com/mojombo/jekyll/wiki. - -In addition to generating the site as html from the markdown files, jekyll can serve up the site via a webserver. To build and run a webserver use the command `jekyll --server` which (currently) runs the webserver on port 4000, then visit the site at http://localhost:4000. +The markdown code can be compiled to HTML using the +[Jekyll tool](http://jekyllrb.com). To use the `jekyll` command, you will +need to have Jekyll installed. The easiest way to do this is via a Ruby Gem, see the +[jekyll installation instructions](http://jekyllrb.com/docs/installation). +Compiling the site with Jekyll will create a directory called +_site containing index.html as well as the rest of the compiled files. + +You can modify the default Jekyll build as follows: + + # Skip generating API docs (which takes a while) + $ SKIP_SCALADOC=1 jekyll build + # Serve content locally on port 4000 + $ jekyll serve --watch + # Build the site with extra features used on the live page + $ PRODUCTION=1 jekyll build ## Pygments diff --git a/docs/_layouts/global.html b/docs/_layouts/global.html index f2c101fd409cb..c487dd9cdee3c 100755 --- a/docs/_layouts/global.html +++ b/docs/_layouts/global.html @@ -24,9 +24,9 @@ + {% production %} + {% endproduction %} diff --git a/docs/_plugins/production_tag.rb b/docs/_plugins/production_tag.rb new file mode 100644 index 0000000000000..9f870cf2137af --- /dev/null +++ b/docs/_plugins/production_tag.rb @@ -0,0 +1,14 @@ +module Jekyll + class ProductionTag < Liquid::Block + + def initialize(tag_name, markup, tokens) + super + end + + def render(context) + if ENV['PRODUCTION'] then super else "" end + end + end +end + +Liquid::Template.register_tag('production', Jekyll::ProductionTag) From 7ea89ec4596f06fccd13973e049ac3f847c5c474 Mon Sep 17 00:00:00 2001 From: Prashant Sharma Date: Tue, 4 Mar 2014 15:32:43 -0800 Subject: [PATCH 123/133] SPARK-1109 wrong API docs for pyspark map function Author: Prashant Sharma Closes #73 from ScrapCodes/SPARK-1109/wrong-API-docs and squashes the following commits: 1a55b58 [Prashant Sharma] SPARK-1109 wrong API docs for pyspark map function (cherry picked from commit 02836657cfec50bc6cc357541e40f8d36c90b352) Signed-off-by: Matei Zaharia --- python/pyspark/rdd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pyspark/rdd.py b/python/pyspark/rdd.py index 1ad4b5298758b..60d4cb28ef009 100644 --- a/python/pyspark/rdd.py +++ b/python/pyspark/rdd.py @@ -163,7 +163,7 @@ def getCheckpointFile(self): def map(self, f, preservesPartitioning=False): """ - Return a new RDD containing the distinct elements in this RDD. + Return a new RDD by applying a function to each element of this RDD. """ def func(split, iterator): return imap(f, iterator) return PipelinedRDD(self, func, preservesPartitioning) From 0fc0fdb127f244edd75e5200a6905fb3185e3b2e Mon Sep 17 00:00:00 2001 From: Mark Grover Date: Wed, 5 Mar 2014 16:52:58 -0800 Subject: [PATCH 124/133] SPARK-1184: Update the distribution tar.gz to include spark-assembly jar See JIRA for details. Author: Mark Grover Closes #78 from markgrover/SPARK-1184 and squashes the following commits: 12b78e6 [Mark Grover] SPARK-1184: Update the distribution tar.gz to include spark-assembly jar (cherry picked from commit cda381f88cc03340fdf7b2d681699babbae2a56e) Conflicts: assembly/pom.xml --- assembly/pom.xml | 7 +++++-- assembly/src/main/assembly/assembly.xml | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/assembly/pom.xml b/assembly/pom.xml index 3303d326449a1..52733092343a2 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -28,10 +28,13 @@ org.apache.spark spark-assembly_2.10 Spark Project Assembly - http://spark.incubator.apache.org/ + http://spark.apache.org/ + pom - ${project.build.directory}/scala-${scala.binary.version}/${project.artifactId}-${project.version}-hadoop${hadoop.version}.jar + scala-${scala.binary.version} + ${project.artifactId}-${project.version}-hadoop${hadoop.version}.jar + ${project.build.directory}/${spark.jar.dir}/${spark.jar.basename} spark /usr/share/spark root diff --git a/assembly/src/main/assembly/assembly.xml b/assembly/src/main/assembly/assembly.xml index 6af383db65d47..711156337b7c3 100644 --- a/assembly/src/main/assembly/assembly.xml +++ b/assembly/src/main/assembly/assembly.xml @@ -55,6 +55,15 @@ **/* + + + ${project.parent.basedir}/assembly/target/${spark.jar.dir} + + / + + ${spark.jar.basename} + + @@ -75,6 +84,8 @@ org.apache.hadoop:*:jar org.apache.spark:*:jar + org.apache.zookeeper:*:jar + org.apache.avro:*:jar From 0f0d044c3a8211f0fe7099da555f59d4a2c1b494 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Sat, 8 Mar 2014 16:02:42 -0800 Subject: [PATCH 125/133] SPARK-1190: Do not initialize log4j if slf4j log4j backend is not being used Author: Patrick Wendell Closes #107 from pwendell/logging and squashes the following commits: be21c11 [Patrick Wendell] Logging fix (cherry picked from commit e59a3b6c415b95e8137f5a154716b12653a8aed0) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/Logging.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/org/apache/spark/Logging.scala b/core/src/main/scala/org/apache/spark/Logging.scala index b749e5414dab6..7423082e34f47 100644 --- a/core/src/main/scala/org/apache/spark/Logging.scala +++ b/core/src/main/scala/org/apache/spark/Logging.scala @@ -19,6 +19,7 @@ package org.apache.spark import org.apache.log4j.{LogManager, PropertyConfigurator} import org.slf4j.{Logger, LoggerFactory} +import org.slf4j.impl.StaticLoggerBinder /** * Utility trait for classes that want to log data. Creates a SLF4J logger for the class and allows @@ -101,9 +102,11 @@ trait Logging { } private def initializeLogging() { - // If Log4j doesn't seem initialized, load a default properties file + // If Log4j is being used, but is not initialized, load a default properties file + val binder = StaticLoggerBinder.getSingleton + val usingLog4j = binder.getLoggerFactoryClassStr.endsWith("Log4jLoggerFactory") val log4jInitialized = LogManager.getRootLogger.getAllAppenders.hasMoreElements - if (!log4jInitialized) { + if (!log4jInitialized && usingLog4j) { val defaultLogProps = "org/apache/spark/log4j-defaults.properties" val classLoader = this.getClass.getClassLoader Option(classLoader.getResource(defaultLogProps)) match { From 6f0db0ada859e9f5493acc087061f7c529b706a0 Mon Sep 17 00:00:00 2001 From: Bryn Keller Date: Mon, 24 Feb 2014 17:35:22 -0800 Subject: [PATCH 126/133] For outputformats that are Configurable, call setConf before sending data to them. [SPARK-1108] This allows us to use, e.g. HBase's TableOutputFormat with PairRDDFunctions.saveAsNewAPIHadoopFile, which otherwise would throw NullPointerException because the output table name hasn't been configured. Note this bug also affects branch-0.9 Author: Bryn Keller Closes #638 from xoltar/SPARK-1108 and squashes the following commits: 7e94e7d [Bryn Keller] Import, comment, and format cleanup per code review 7cbcaa1 [Bryn Keller] For outputformats that are Configurable, call setConf before sending data to them. This allows us to use, e.g. HBase TableOutputFormat, which otherwise would throw NullPointerException because the output table name hasn't been configured (cherry picked from commit 4d880304867b55a4f2138617b30600b7fa013b14) Conflicts: core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala core/src/test/scala/org/apache/spark/rdd/PairRDDFunctionsSuite.scala --- .../apache/spark/rdd/PairRDDFunctions.scala | 6 +- .../spark/rdd/PairRDDFunctionsSuite.scala | 76 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala b/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala index 9bafe41f0da58..0b2917b80ab00 100644 --- a/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala +++ b/core/src/main/scala/org/apache/spark/rdd/PairRDDFunctions.scala @@ -28,7 +28,7 @@ import scala.collection.mutable.ArrayBuffer import scala.collection.JavaConversions._ import scala.reflect.{ClassTag, classTag} -import org.apache.hadoop.conf.Configuration +import org.apache.hadoop.conf.{Configurable, Configuration} import org.apache.hadoop.fs.Path import org.apache.hadoop.io.SequenceFile.CompressionType import org.apache.hadoop.io.compress.CompressionCodec @@ -620,6 +620,10 @@ class PairRDDFunctions[K: ClassTag, V: ClassTag](self: RDD[(K, V)]) attemptNumber) val hadoopContext = newTaskAttemptContext(wrappedConf.value, attemptId) val format = outputFormatClass.newInstance + format match { + case c: Configurable => c.setConf(wrappedConf.value) + case _ => () + } val committer = format.getOutputCommitter(hadoopContext) committer.setupTask(hadoopContext) val writer = format.getRecordWriter(hadoopContext).asInstanceOf[NewRecordWriter[K,V]] diff --git a/core/src/test/scala/org/apache/spark/rdd/PairRDDFunctionsSuite.scala b/core/src/test/scala/org/apache/spark/rdd/PairRDDFunctionsSuite.scala index 5da538a1ddfd5..9c78630944277 100644 --- a/core/src/test/scala/org/apache/spark/rdd/PairRDDFunctionsSuite.scala +++ b/core/src/test/scala/org/apache/spark/rdd/PairRDDFunctionsSuite.scala @@ -24,6 +24,9 @@ import scala.util.Random import org.scalatest.FunSuite import com.google.common.io.Files +import org.apache.hadoop.mapreduce._ +import org.apache.hadoop.conf.{Configuration, Configurable} + import org.apache.spark.SparkContext._ import org.apache.spark.{Partitioner, SharedSparkContext} @@ -331,4 +334,77 @@ class PairRDDFunctionsSuite extends FunSuite with SharedSparkContext { (1, ArrayBuffer(1)), (2, ArrayBuffer(1)))) } + + test("saveNewAPIHadoopFile should call setConf if format is configurable") { + val pairs = sc.parallelize(Array((new Integer(1), new Integer(1)))) + + // No error, non-configurable formats still work + pairs.saveAsNewAPIHadoopFile[FakeFormat]("ignored") + + /* + Check that configurable formats get configured: + ConfigTestFormat throws an exception if we try to write + to it when setConf hasn't been called first. + Assertion is in ConfigTestFormat.getRecordWriter. + */ + pairs.saveAsNewAPIHadoopFile[ConfigTestFormat]("ignored") + } +} + +/* + These classes are fakes for testing + "saveNewAPIHadoopFile should call setConf if format is configurable". + Unfortunately, they have to be top level classes, and not defined in + the test method, because otherwise Scala won't generate no-args constructors + and the test will therefore throw InstantiationException when saveAsNewAPIHadoopFile + tries to instantiate them with Class.newInstance. + */ +class FakeWriter extends RecordWriter[Integer, Integer] { + + def close(p1: TaskAttemptContext) = () + + def write(p1: Integer, p2: Integer) = () + +} + +class FakeCommitter extends OutputCommitter { + def setupJob(p1: JobContext) = () + + def needsTaskCommit(p1: TaskAttemptContext): Boolean = false + + def setupTask(p1: TaskAttemptContext) = () + + def commitTask(p1: TaskAttemptContext) = () + + def abortTask(p1: TaskAttemptContext) = () +} + +class FakeFormat() extends OutputFormat[Integer, Integer]() { + + def checkOutputSpecs(p1: JobContext) = () + + def getRecordWriter(p1: TaskAttemptContext): RecordWriter[Integer, Integer] = { + new FakeWriter() + } + + def getOutputCommitter(p1: TaskAttemptContext): OutputCommitter = { + new FakeCommitter() + } } + +class ConfigTestFormat() extends FakeFormat() with Configurable { + + var setConfCalled = false + def setConf(p1: Configuration) = { + setConfCalled = true + () + } + + def getConf: Configuration = null + + override def getRecordWriter(p1: TaskAttemptContext): RecordWriter[Integer, Integer] = { + assert(setConfCalled, "setConf was never called") + super.getRecordWriter(p1) + } +} + From 0c919271ff77e36a83ad25245acab5d73255eff3 Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 11 Mar 2014 11:16:59 -0700 Subject: [PATCH 127/133] SPARK-1167: Remove metrics-ganglia from default build due to LGPL issues... This patch removes Ganglia integration from the default build. It allows users willing to link against LGPL code to use Ganglia by adding build flags or linking against a new Spark artifact called spark-ganglia-lgpl. This brings Spark in line with the Apache policy on LGPL code enumerated here: https://www.apache.org/legal/3party.html#options-optional Author: Patrick Wendell Closes #108 from pwendell/ganglia and squashes the following commits: 326712a [Patrick Wendell] Responding to review feedback 5f28ee4 [Patrick Wendell] SPARK-1167: Remove metrics-ganglia from default build due to LGPL issues. (cherry picked from commit 16788a654246067fd966033b5dc9bc0d4c759b70) Conflicts: core/pom.xml dev/audit-release/sbt_app_core/src/main/scala/SparkApp.scala dev/create-release/create-release.sh pom.xml project/SparkBuild.scala --- assembly/pom.xml | 10 +++++ core/pom.xml | 4 -- docs/monitoring.md | 13 +++++- extras/spark-ganglia-lgpl/pom.xml | 45 +++++++++++++++++++ .../spark/metrics/sink/GangliaSink.scala | 0 pom.xml | 12 +++-- project/SparkBuild.scala | 27 +++++++---- 7 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 extras/spark-ganglia-lgpl/pom.xml rename {core => extras/spark-ganglia-lgpl}/src/main/scala/org/apache/spark/metrics/sink/GangliaSink.scala (100%) diff --git a/assembly/pom.xml b/assembly/pom.xml index 52733092343a2..cdae0f9f5e820 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -158,6 +158,16 @@
    + + spark-ganglia-lgpl + + + org.apache.spark + spark-ganglia-lgpl_${scala.binary.version} + ${project.version} + + + bigtop-dist + + 4.0.0 + + org.apache.spark + spark-parent + 1.0.0-SNAPSHOT + ../../pom.xml + + + + org.apache.spark + spark-ganglia-lgpl_2.10 + jar + Spark Ganglia Integration + + + + org.apache.spark + spark-core_${scala.binary.version} + ${project.version} + + + + com.codahale.metrics + metrics-ganglia + + + diff --git a/core/src/main/scala/org/apache/spark/metrics/sink/GangliaSink.scala b/extras/spark-ganglia-lgpl/src/main/scala/org/apache/spark/metrics/sink/GangliaSink.scala similarity index 100% rename from core/src/main/scala/org/apache/spark/metrics/sink/GangliaSink.scala rename to extras/spark-ganglia-lgpl/src/main/scala/org/apache/spark/metrics/sink/GangliaSink.scala diff --git a/pom.xml b/pom.xml index 2a3f8fcc30b98..e53c930ad0aa4 100644 --- a/pom.xml +++ b/pom.xml @@ -743,11 +743,9 @@ 0.23.7 - yarn - @@ -760,7 +758,15 @@ yarn - + + + + spark-ganglia-lgpl + + extras/spark-ganglia-lgpl + + + diff --git a/project/SparkBuild.scala b/project/SparkBuild.scala index b8f901d71a56a..f9eeeb0e2821d 100644 --- a/project/SparkBuild.scala +++ b/project/SparkBuild.scala @@ -61,7 +61,7 @@ object SparkBuild extends Build { lazy val mllib = Project("mllib", file("mllib"), settings = mllibSettings) dependsOn(core) lazy val assemblyProj = Project("assembly", file("assembly"), settings = assemblyProjSettings) - .dependsOn(core, graphx, bagel, mllib, repl, streaming) dependsOn(maybeYarn: _*) + .dependsOn(core, graphx, bagel, mllib, repl, streaming) dependsOn(maybeYarn: _*) dependsOn(maybeGanglia: _*) lazy val assembleDeps = TaskKey[Unit]("assemble-deps", "Build assembly of dependencies and packages Spark projects") @@ -90,14 +90,21 @@ object SparkBuild extends Build { case None => DEFAULT_YARN case Some(v) => v.toBoolean } - lazy val hadoopClient = if (hadoopVersion.startsWith("0.20.") || hadoopVersion == "1.0.0") "hadoop-core" else "hadoop-client" - - // Conditionally include the yarn sub-project + lazy val hadoopClient = if (hadoopVersion.startsWith("0.20.") || hadoopVersion == "1.0.0") "hadoop-core" else "hadoop-client" + + // Include Ganglia integration if the user has enabled Ganglia + // This is isolated from the normal build due to LGPL-licensed code in the library + lazy val isGangliaEnabled = Properties.envOrNone("SPARK_GANGLIA_LGPL").isDefined + lazy val gangliaProj = Project("spark-ganglia-lgpl", file("extras/spark-ganglia-lgpl"), settings = gangliaSettings).dependsOn(core) + val maybeGanglia: Seq[ClasspathDependency] = if (isGangliaEnabled) Seq(gangliaProj) else Seq() + val maybeGangliaRef: Seq[ProjectReference] = if (isGangliaEnabled) Seq(gangliaProj) else Seq() + + // Include the YARN project if the user has enabled YARN lazy val yarnAlpha = Project("yarn-alpha", file("yarn/alpha"), settings = yarnAlphaSettings) dependsOn(core) lazy val yarn = Project("yarn", file("yarn/stable"), settings = yarnSettings) dependsOn(core) - lazy val maybeYarn = if (isYarnEnabled) Seq[ClasspathDependency](if (isNewHadoop) yarn else yarnAlpha) else Seq[ClasspathDependency]() - lazy val maybeYarnRef = if (isYarnEnabled) Seq[ProjectReference](if (isNewHadoop) yarn else yarnAlpha) else Seq[ProjectReference]() + lazy val maybeYarn: Seq[ClasspathDependency] = if (isYarnEnabled) Seq(if (isNewHadoop) yarn else yarnAlpha) else Seq() + lazy val maybeYarnRef: Seq[ProjectReference] = if (isYarnEnabled) Seq(if (isNewHadoop) yarn else yarnAlpha) else Seq() lazy val externalTwitter = Project("external-twitter", file("external/twitter"), settings = twitterSettings) .dependsOn(streaming % "compile->compile;test->test") @@ -121,7 +128,7 @@ object SparkBuild extends Build { .dependsOn(core, mllib, graphx, bagel, streaming, externalTwitter) dependsOn(allExternal: _*) // Everything except assembly, tools and examples belong to packageProjects - lazy val packageProjects = Seq[ProjectReference](core, repl, bagel, streaming, mllib, graphx) ++ maybeYarnRef + lazy val packageProjects = Seq[ProjectReference](core, repl, bagel, streaming, mllib, graphx) ++ maybeYarnRef ++ maybeGangliaRef lazy val allProjects = packageProjects ++ allExternalRefs ++ Seq[ProjectReference](examples, tools, assemblyProj) @@ -281,7 +288,6 @@ object SparkBuild extends Build { "com.codahale.metrics" % "metrics-core" % "3.0.0", "com.codahale.metrics" % "metrics-jvm" % "3.0.0", "com.codahale.metrics" % "metrics-json" % "3.0.0", - "com.codahale.metrics" % "metrics-ganglia" % "3.0.0", "com.codahale.metrics" % "metrics-graphite" % "3.0.0", "com.twitter" %% "chill" % "0.3.1", "com.twitter" % "chill-java" % "0.3.1", @@ -371,6 +377,11 @@ object SparkBuild extends Build { name := "spark-yarn" ) + def gangliaSettings = sharedSettings ++ Seq( + name := "spark-ganglia-lgpl", + libraryDependencies += "com.codahale.metrics" % "metrics-ganglia" % "3.0.0" + ) + // Conditionally include the YARN dependencies because some tools look at all sub-projects and will complain // if we refer to nonexistent dependencies (e.g. hadoop-yarn-api from a Hadoop version without YARN). def extraYarnSettings = if(isYarnEnabled) yarnEnabledSettings else Seq() From 6cbd5800c71d961228382be57c2688af4e41b3ea Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 11 Mar 2014 11:53:29 -0700 Subject: [PATCH 128/133] Log4j build fix on 0.9 branch Spark should include log4j by default. Downstream packagers can exclude log4j if they want to use another logging backend. --- core/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 4901bb00efc73..6b6167c34822f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -189,7 +189,6 @@ org.slf4j slf4j-log4j12 - test From 70491642f9b2fc3d990438c2a36ab29654bff0dc Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Tue, 11 Mar 2014 14:48:01 -0700 Subject: [PATCH 129/133] Version fix in pom file --- extras/spark-ganglia-lgpl/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/spark-ganglia-lgpl/pom.xml b/extras/spark-ganglia-lgpl/pom.xml index 11ac827ed54a0..e39b07dd2f15d 100644 --- a/extras/spark-ganglia-lgpl/pom.xml +++ b/extras/spark-ganglia-lgpl/pom.xml @@ -20,7 +20,7 @@ org.apache.spark spark-parent - 1.0.0-SNAPSHOT + 0.9.1-incubating-SNAPSHOT ../../pom.xml From 51a77e9779b64e464d07580de12ac3e1fe77e41a Mon Sep 17 00:00:00 2001 From: Prashant Sharma Date: Wed, 12 Mar 2014 15:57:44 -0700 Subject: [PATCH 130/133] SPARK-1162 Added top in python. Author: Prashant Sharma Closes #93 from ScrapCodes/SPARK-1162/pyspark-top-takeOrdered and squashes the following commits: ece1fa4 [Prashant Sharma] Added top in python. (cherry picked from commit b8afe3052086547879ebf28d6e36207e0d370710) Signed-off-by: Matei Zaharia --- python/pyspark/rdd.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/python/pyspark/rdd.py b/python/pyspark/rdd.py index 60d4cb28ef009..678b005414c0d 100644 --- a/python/pyspark/rdd.py +++ b/python/pyspark/rdd.py @@ -28,6 +28,7 @@ from tempfile import NamedTemporaryFile from threading import Thread import warnings +from heapq import heappush, heappop, heappushpop from pyspark.serializers import NoOpSerializer, CartesianDeserializer, \ BatchedSerializer, CloudPickleSerializer, pack_long @@ -616,6 +617,30 @@ def mergeMaps(m1, m2): m1[k] += v return m1 return self.mapPartitions(countPartition).reduce(mergeMaps) + + def top(self, num): + """ + Get the top N elements from a RDD. + + Note: It returns the list sorted in ascending order. + >>> sc.parallelize([10, 4, 2, 12, 3]).top(1) + [12] + >>> sc.parallelize([2, 3, 4, 5, 6]).cache().top(2) + [5, 6] + """ + def topIterator(iterator): + q = [] + for k in iterator: + if len(q) < num: + heappush(q, k) + else: + heappushpop(q, k) + yield q + + def merge(a, b): + return next(topIterator(a + b)) + + return sorted(self.mapPartitions(topIterator).reduce(merge)) def take(self, num): """ From 87e4dd58ce75fcabf9582528f65510bc24ebc85e Mon Sep 17 00:00:00 2001 From: jianghan Date: Wed, 12 Mar 2014 19:46:12 -0700 Subject: [PATCH 131/133] Fix example bug: compile error Author: jianghan Closes #132 from pooorman/master and squashes the following commits: 54afbe0 [jianghan] Fix example bug: compile error (cherry picked from commit 31a704004f9b4ad34f92ae5c95ae6e90d0ab62c7) Signed-off-by: Patrick Wendell --- .../main/java/org/apache/spark/examples/JavaLogQuery.java | 2 +- .../main/java/org/apache/spark/examples/JavaPageRank.java | 6 +++--- .../main/java/org/apache/spark/examples/JavaWordCount.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src/main/java/org/apache/spark/examples/JavaLogQuery.java b/examples/src/main/java/org/apache/spark/examples/JavaLogQuery.java index 9eb1cadd71d22..a933f483c710f 100644 --- a/examples/src/main/java/org/apache/spark/examples/JavaLogQuery.java +++ b/examples/src/main/java/org/apache/spark/examples/JavaLogQuery.java @@ -124,7 +124,7 @@ public Stats call(Stats stats, Stats stats2) { List, Stats>> output = counts.collect(); for (Tuple2 t : output) { - System.out.println(t._1 + "\t" + t._2); + System.out.println(t._1() + "\t" + t._2()); } System.exit(0); } diff --git a/examples/src/main/java/org/apache/spark/examples/JavaPageRank.java b/examples/src/main/java/org/apache/spark/examples/JavaPageRank.java index a84245b0c7449..cdcc2c9e67cf9 100644 --- a/examples/src/main/java/org/apache/spark/examples/JavaPageRank.java +++ b/examples/src/main/java/org/apache/spark/examples/JavaPageRank.java @@ -90,8 +90,8 @@ public Double call(List rs) { @Override public Iterable> call(Tuple2, Double> s) { List> results = new ArrayList>(); - for (String n : s._1) { - results.add(new Tuple2(n, s._2 / s._1.size())); + for (String n : s._1()) { + results.add(new Tuple2(n, s._2() / s._1().size())); } return results; } @@ -109,7 +109,7 @@ public Double call(Double sum) { // Collects all URL ranks and dump them to console. List> output = ranks.collect(); for (Tuple2 tuple : output) { - System.out.println(tuple._1 + " has rank: " + tuple._2 + "."); + System.out.println(tuple._1() + " has rank: " + tuple._2() + "."); } System.exit(0); diff --git a/examples/src/main/java/org/apache/spark/examples/JavaWordCount.java b/examples/src/main/java/org/apache/spark/examples/JavaWordCount.java index 6651f98d56711..95a2f3ab5290d 100644 --- a/examples/src/main/java/org/apache/spark/examples/JavaWordCount.java +++ b/examples/src/main/java/org/apache/spark/examples/JavaWordCount.java @@ -65,7 +65,7 @@ public Integer call(Integer i1, Integer i2) { List> output = counts.collect(); for (Tuple2 tuple : output) { - System.out.println(tuple._1 + ": " + tuple._2); + System.out.println(tuple._1() + ": " + tuple._2()); } System.exit(0); } From ef74e44e04517abd4c7058c87abd1f4e8fbaa09d Mon Sep 17 00:00:00 2001 From: Patrick Wendell Date: Wed, 12 Mar 2014 23:16:59 -0700 Subject: [PATCH 132/133] SPARK-1019: pyspark RDD take() throws an NPE Author: Patrick Wendell Closes #112 from pwendell/pyspark-take and squashes the following commits: daae80e [Patrick Wendell] SPARK-1019: pyspark RDD take() throws an NPE (cherry picked from commit 4ea23db0efff2f39ac5b8f0bd1d9a6ffa3eceb0d) Signed-off-by: Patrick Wendell --- core/src/main/scala/org/apache/spark/TaskContext.scala | 3 ++- .../scala/org/apache/spark/api/python/PythonRDD.scala | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/org/apache/spark/TaskContext.scala b/core/src/main/scala/org/apache/spark/TaskContext.scala index cae983ed4c652..be53ca2968cfb 100644 --- a/core/src/main/scala/org/apache/spark/TaskContext.scala +++ b/core/src/main/scala/org/apache/spark/TaskContext.scala @@ -46,6 +46,7 @@ class TaskContext( } def executeOnCompleteCallbacks() { - onCompleteCallbacks.foreach{_()} + // Process complete callbacks in the reverse order of registration + onCompleteCallbacks.reverse.foreach{_()} } } diff --git a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala index 9cbd26b607b24..e03c6f9c184c9 100644 --- a/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala +++ b/core/src/main/scala/org/apache/spark/api/python/PythonRDD.scala @@ -99,6 +99,14 @@ private[spark] class PythonRDD[T: ClassTag]( } }.start() + /* + * Partial fix for SPARK-1019: Attempts to stop reading the input stream since + * other completion callbacks might invalidate the input. Because interruption + * is not synchronous this still leaves a potential race where the interruption is + * processed only after the stream becomes invalid. + */ + context.addOnCompleteCallback(() => context.interrupted = true) + // Return an iterator that read lines from the process's stdout val stream = new DataInputStream(new BufferedInputStream(worker.getInputStream, bufferSize)) val stdoutIterator = new Iterator[Array[Byte]] { From a7c3da8d7dba299e4edb13a37a81766b9a2200df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?baishuo=28=E7=99=BD=E7=A1=95=29?= Date: Fri, 21 Mar 2014 23:28:19 +0800 Subject: [PATCH 133/133] Update spark-daemon.sh Since the previous command is : cd "$SPARK_PREFIX" , so we can call spark-class by "./bin/spark-class" instead of "$SPARK_PREFIX"/bin/spark-class --- sbin/spark-daemon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/spark-daemon.sh b/sbin/spark-daemon.sh index 2be2b3d7c0933..5a21ebe8a4ce9 100755 --- a/sbin/spark-daemon.sh +++ b/sbin/spark-daemon.sh @@ -147,7 +147,7 @@ case $startStop in spark_rotate_log "$log" echo starting $command, logging to $log cd "$SPARK_PREFIX" - nohup nice -n $SPARK_NICENESS "$SPARK_PREFIX"/bin/spark-class $command "$@" >> "$log" 2>&1 < /dev/null & + nohup nice -n $SPARK_NICENESS ./bin/spark-class $command "$@" >> "$log" 2>&1 < /dev/null & newpid=$! echo $newpid > $pid sleep 2
  • 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/img/streaming-dstream-window.png b/docs/img/streaming-dstream-window.png new file mode 100644 index 0000000000000000000000000000000000000000..276d2fee5e30e49dd0465e41baa483e5f8ee7ceb GIT binary patch literal 40938 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 TSpW7GU^$+3wXHex%dh_ecwyEY literal 0 HcmV?d00001 diff --git a/docs/img/streaming-dstream.png b/docs/img/streaming-dstream.png new file mode 100644 index 0000000000000000000000000000000000000000..90f43b8c7138c8ae2e93cd02d7006ffa9254252d GIT binary patch literal 26823 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 W&lP?v1paB{fR3iY&C(l>p8gkS9uJBD literal 0 HcmV?d00001 diff --git a/docs/img/streaming-figures.pptx b/docs/img/streaming-figures.pptx new file mode 100644 index 0000000000000000000000000000000000000000..1b18c2ee0ea3e6c07bdb24c0a5d5784c972631f7 GIT binary patch literal 887545 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