Akka version conflict when running test command in sbt shell - akka

i'm trying to run a test command in sbt-shell of intellij ide for this -> [https://github.com/theiterators/akka-http-microservice#akka-http-microservice-example] project then it shows Akka version conflict. how to resolve it?
this is build.sbt
enablePlugins(JavaAppPackaging , GatlingPlugin)
name := "akka-http-microservice"
organization := "com.theiterators"
version := "1.0"
scalaVersion := "2.13.5"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8",
"-target:jvm-1.8",
"-feature",
"-language:implicitConversions",
"-language:postfixOps")
libraryDependencies ++= {
val akkaHttpV = "10.2.4"
val akkaV = "2.6.14"
val scalaTestV = "3.2.8"
val circeV = "0.13.0"
val akkaHttpCirceV = "1.36.0"
val gatlingVersion = "3.5.1"
Seq(
"com.typesafe.akka" %% "akka-actor" % akkaV,
"com.typesafe.akka" %% "akka-stream" % akkaV,
"com.typesafe.akka" %% "akka-http" % akkaHttpV,
"io.circe" %% "circe-core" % circeV,
"io.circe" %% "circe-generic" % circeV,
"de.heikoseeberger" %% "akka-http-circe" % akkaHttpCirceV,
"com.typesafe.akka" %% "akka-testkit" % akkaV,
"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV % "test",
"org.scalatest" %% "scalatest" % scalaTestV % "test",
"io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion % "test,it",
"io.gatling" % "gatling-test-framework" % gatlingVersion % "test,it"
)
}
Revolver.settings
this is plugin.sbt
addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.8.1")
addSbtPlugin("io.gatling" % "gatling-sbt" % "3.2.2")
addSbtPlugin("io.gatling" % "gatling-sbt" % "MANUALLY_REPLACE_WITH_LATEST_VERSION")
this is service specification
import akka.event.NoLogging
import akka.http.scaladsl.model.ContentTypes._
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.testkit.ScalatestRouteTest
import akka.stream.scaladsl.Flow
import org.scalatest.flatspec.AsyncFlatSpec
import org.scalatest.matchers.should.Matchers
class ServiceSpec extends AsyncFlatSpec with Matchers with ScalatestRouteTest with Service with Protocols {
override def testConfigSource = "akka.loglevel = WARNING"
override def config = testConfig
override val logger = NoLogging
val ip1Info = IpInfo("8.8.8.8", Option("United States"), Option("Mountain View"), Option(37.386), Option(-122.0838))
val ip2Info = IpInfo("8.8.4.4", Option("United States"), None, Option(38.0), Option(-97.0))
val ipPairSummary = IpPairSummary(ip1Info, ip2Info)
override lazy val ipApiConnectionFlow = Flow[HttpRequest].map { request =>
if (request.uri.toString().endsWith(ip1Info.query))
HttpResponse(status = OK, entity = marshal(ip1Info))
else if(request.uri.toString().endsWith(ip2Info.query))
HttpResponse(status = OK, entity = marshal(ip2Info))
else
HttpResponse(status = BadRequest, entity = marshal("Bad ip format"))
}
"Service" should "respond to single IP query" in {
Get(s"/ip/${ip1Info.query}") ~> routes ~> check {
status shouldBe OK
contentType shouldBe `application/json`
responseAs[IpInfo] shouldBe ip1Info
}
Get(s"/ip/${ip2Info.query}") ~> routes ~> check {
status shouldBe OK
contentType shouldBe `application/json`
responseAs[IpInfo] shouldBe ip2Info
}
}
it should "respond to IP pair query" in {
Post(s"/ip", IpPairSummaryRequest(ip1Info.query, ip2Info.query)) ~> routes ~> check {
status shouldBe OK
contentType shouldBe `application/json`
responseAs[IpPairSummary] shouldBe ipPairSummary
}
}
it should "respond with bad request on incorrect IP format" in {
Get("/ip/asdfg") ~> routes ~> check {
status shouldBe BadRequest
responseAs[String].length should be > 0
}
Post(s"/ip", IpPairSummaryRequest(ip1Info.query, "asdfg")) ~> routes ~> check {
status shouldBe BadRequest
responseAs[String].length should be > 0
}
Post(s"/ip", IpPairSummaryRequest("asdfg", ip1Info.query)) ~> routes ~> check {
status shouldBe BadRequest
responseAs[String].length should be > 0
}
}
}
Error given below--
[info] ServiceSpec *** ABORTED ***
[info] java.lang.IllegalStateException: You are using version 2.6.14 of Akka, but it appears you (perhaps indirectly) also depend on older versions of related artifacts. You can solve this by adding an explicit dependency on version 2.6.14 of the [akka-slf4j] artifacts to your project. Here's a complete collection of detected artifacts: (2.6.11, [akka-slf4j]), (2.6.14, [akka-actor, akka-protobuf-v3, akka-stream, akka-testkit]). See also: https://doc.akka.io/docs/akka/current/common/binary-compatibility-rules.html#mixed-versioning-is-not-allowed
[info] at akka.util.ManifestInfo.checkSameVersion(ManifestInfo.scala:184)
[info] at akka.util.ManifestInfo.checkSameVersion(ManifestInfo.scala:162)
[info] at akka.actor.ActorSystemImpl.liftedTree2$1(ActorSystem.scala:1033)
[info] at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:1022)
[info] at akka.actor.ActorSystemImpl._start(ActorSystem.scala:1022)
[info] at akka.actor.ActorSystemImpl.start(ActorSystem.scala:1045)
[info] at akka.actor.ActorSystem$.apply(ActorSystem.scala:272)
[info] at akka.actor.ActorSystem$.apply(ActorSystem.scala:316)
[info] at akka.actor.ActorSystem$.apply(ActorSystem.scala:290)
[info] at akka.http.scaladsl.testkit.RouteTest.createActorSystem(RouteTest.scala:36)
[info] ...
[info] Run completed in 1 second, 568 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 1
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] *** 1 SUITE ABORTED ***
[error] Error during tests:
[error] ServiceSpec
[error] (Test / test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 8 s, completed 22 Apr. 2021, 3:14:59 pm

Adding
"com.typesafe.akka" %% "akka-slf4j" % akkaV
to the Seq in your libraryDependencies block should resolve this. In general in Akka it's best to not rely on transitive dependencies.

Related

Akka Remote Performance issue

I am facing a performance issue in Akka remoting. I have 2 actors Actor1 and Actor2. The message sending between the actor is synchronous ask request from Actor1 to Actor2 and the response back from Actor2 to Actor1. Below is the sample code snippets and config of my Actor:
Actor1.java:
object Actor1 extends App {
val conf = ConfigFactory.load()
val system = ActorSystem("testSystem1", conf.getConfig("remote1"))
val actor = system.actorOf(Props[Actor1].withDispatcher("my-dispatcher"), "actor1")
implicit val timeOut: Timeout = Timeout(10 seconds)
class Actor1 extends Actor {
var value = 0
var actorRef: ActorRef = null
override def preStart(): Unit = {
println(self.path)
}
override def receive: Receive = {
case "register" =>
actorRef = sender()
println("Registering the actor")
val time = System.currentTimeMillis()
(1 to 300000).foreach(value => {
if (value % 10000 == 0) {
println("message count -- " + value + " --- time taken - " + (System.currentTimeMillis() - time))
}
Await.result(actorRef ? value, 10 seconds)
})
val totalTime = System.currentTimeMillis() - time
println("Total Time - " + totalTime)
}
}
}
Actor2.java:
object Actor2 extends App {
val conf = ConfigFactory.load()
val system = ActorSystem("testSystem1", conf.getConfig("remote2"))
val actor = system.actorOf(Props[Actor2].withDispatcher("my-dispatcher"), "actor2")
implicit val timeOut: Timeout = Timeout(10 seconds)
actor ! "send"
class Actor2 extends Actor {
var value = 0
var actorSelection: ActorSelection = context.actorSelection("akka://testSystem1#127.0.0.1:6061/user/actor1")
override def receive: Receive = {
case "send" =>
actorSelection ! "register"
case int: Int => {
sender() ! 1
}
}
}
}
application.conf:
remote1 {
my-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
akka {
actor {
provider = remote
}
remote {
artery {
transport = tcp # See Selecting a transport below
canonical.hostname = "127.0.0.1"
canonical.port = 6061
}
}
}
}
remote2 {
my-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
akka {
actor {
provider = remote
}
remote {
artery {
transport = tcp # See Selecting a transport below
canonical.hostname = "127.0.0.1"
canonical.port = 6062
}
}
}
}
Output:
message count -- 10000 --- time taken - 5871
message count -- 20000 --- time taken - 9043
message count -- 30000 --- time taken - 12198
message count -- 40000 --- time taken - 15363
message count -- 50000 --- time taken - 18649
message count -- 60000 --- time taken - 22074
message count -- 70000 --- time taken - 25487
message count -- 80000 --- time taken - 28820
message count -- 90000 --- time taken - 32118
message count -- 100000 --- time taken - 35634
message count -- 110000 --- time taken - 39146
message count -- 120000 --- time taken - 42539
message count -- 130000 --- time taken - 45997
message count -- 140000 --- time taken - 50013
message count -- 150000 --- time taken - 53466
message count -- 160000 --- time taken - 57117
message count -- 170000 --- time taken - 61246
message count -- 180000 --- time taken - 65051
message count -- 190000 --- time taken - 68809
message count -- 200000 --- time taken - 72908
message count -- 210000 --- time taken - 77091
message count -- 220000 --- time taken - 80855
message count -- 230000 --- time taken - 84679
message count -- 240000 --- time taken - 89089
message count -- 250000 --- time taken - 93132
message count -- 260000 --- time taken - 97360
message count -- 270000 --- time taken - 101442
message count -- 280000 --- time taken - 105656
message count -- 290000 --- time taken - 109665
message count -- 300000 --- time taken - 113706
Total Time - 113707
Is there any wrong I am doing here?. Any observation or suggestion to improve the performance?
The main issue I see with the code is Await.result(). That is a blocking operation, and will most likely affect performance.
I suggest collecting the results in a fixed array / list, use an integer as an array, and consider it complete when the expected number of responses have been received.

Exit Value Undef Erlang Spawn

I am getting an error running the following Erlang code on an Ubuntu Server machine, it runs properly on my machine running Solus. I am new to Erlang and am not sure how to read the error, as all other examples only have one function and module in the error code.
I have two files
Sensor:
-module(sensor).
-export([start/2, senseAndReport/3]).
start(WatcherPid, SensorId) ->
Ref = make_ref(),
senseAndReport(WatcherPid, SensorId, Ref).
senseAndReport(WatcherPid, SensorId, Ref) ->
Measurement = rand:uniform(11),
if
Measurement == 11 ->
WatcherPid ! {kill, {self(), SensorId}, error},
exit(error);
true ->
WatcherPid ! {Measurement, {self(), SensorId}, Ref}
end,
receive
{ok, Ref} ->
Sleep_time = rand:uniform(10000),
timer:sleep(Sleep_time),
senseAndReport(WatcherPid, SensorId, Ref)
end.
And Watcher:
-module(watcher).
-export([start/1, createSensor/3, restartASensor/2, watch/1]).
start(NumOfSensor) ->
if
NumOfSensor == 0 ->
io:format("Please enter a number greater than 0.~n");
true ->
createSensor(NumOfSensor, [], 0)
end.
createSensor(NumOfSensor, SensorList, SensorId) ->
if
length(SensorList) == 10 ->
io:format("Start watching:~n"),
[io:format(" Id: ~p, Pid: ~p~n", [Id, Pid]) || {Id, Pid} <- SensorList],
if NumOfSensor /= 0 ->
spawn(watcher, createSensor, [NumOfSensor, [], SensorId]),
watch(SensorList);
true ->
watch(SensorList)
end;
NumOfSensor == 0 ->
io:format("Start watching~n"),
[io:format(" Id: ~p, Pid: ~p~n", [Id, Pid]) || {Id, Pid} <- SensorList],
watch(SensorList);
true ->
SensorPid = spawn_monitor(sensor, start, [self(), SensorId]),
createSensor(NumOfSensor - 1, lists:merge(SensorList, [{SensorId, SensorPid}]), SensorId + 1)
end.
restartASensor(SensorList, SensorId) ->
{SensorPid, _} = spawn_monitor(sensor, start, [self(), SensorId]),
io:format(" Restarted sensor: ~p, new Pid: ~p~n", [SensorId, SensorPid]),
NewList = lists:merge(SensorList, [{SensorId, SensorPid}]),
watch(NewList).
watch(SensorList) ->
receive
{kill, {From, FromId}, error} ->
io:format(" Sensor ~p died~n", [FromId]),
restartASensor(lists:delete({FromId, From}, SensorList), FromId);
{Measurement, {From, FromId}, Ref} ->
io:format("MSG: ~2p, From sensor ~4p~n", [Measurement, FromId]),
From ! {ok, Ref},
watch(SensorList)
end.
This give me the following output:
Eshell V5.8.5 (abort with ^G)
1> c(watcher).
{ok,watcher}
2> watcher:start(1).
Start watching
Id: 0, Pid: <0.39.0>
=ERROR REPORT==== 18-Nov-2016::19:32:35 ===
Error in process <0.39.0> with exit value: {undef,[{rand,uniform,[11]},{sensor,senseAndReport,3}]}
Dogbert's comment is the correct answer. The version of Erlang I was using was older on the Ubuntu machine, needed to replace the rand module with the random module.

fseek, ftell resulting in segmentation fault

I am trying to seek till the end of a file using fseek, seeking in steps of 2560 * 5 bytes at a time. No idea why I am getting a segmentation fault
I am running this code on TDA2x board. Is here a problem in the particular environment which I am unaware of?
Starting value of uNumFrames is 1000
This code is basically trying to read the data from an externally connected SSD drive, and is reading the file byte by byte, skipping certain containers in the file using fseek. The problem I am facing is that while trying to read the files like this, the code is crashing with the following details
while(uNumFrames > 500)
{
logger::addLog(logger::LOGGER_INFO,"Inside while loop, uNumFrames = %d", uNumFrames);
/*Skip packet Header*/
ui_skip_count = fseek(fp, HeaderSize * 5, SEEK_CUR);
fsize = ftell(fp);
logger::addLog(logger::LOGGER_INFO,"fsize = %ld\n", fsize);
if (ferror(fp))
{
logger::addLog(logger::LOGGER_INFO,"fseek Error");
fclose (fp);
break;
}
if(0 != ui_skip_count)
{
logger::addLog(logger::LOGGER_INFO,"fseek for fp failed");
}
else
{
logger::addLog(logger::LOGGER_INFO,"Inside else for read and scale");
}
uNumFrames--;
}
Sample output looks something like this:
[HOST ] [INFO] 86.234680 s: Inside while loop, uNumFrames = 978
[HOST ] [INFO] 86.234680 s: fsize = 3368961
[HOST ] [INFO] 86.234710 s: Inside else for read and scale
[HOST ] [INFO] 86.234710 s: Inside while loop, uNumFrames = 977
[HOST ] [INFO] 86.234710 s: fsize = 3381761
[HOST ] [INFO] 86.234710 s: Inside else for read and scale
[HOST ] [INFO] 86.234710 s: Inside while loop, uNumFrames = 976
[HOST ] [INFO] 86.234741 s: fsize = 3394561
[HOST ] [INFO] 86.234741 s: Inside else for read and scale
[HOST ] [INFO] 86.234741 s: Inside while loop, uNumFrames = 975
[HOST ] [INFO] 86.234741 s: fsize = 3407361
[HOST ] [INFO] 86.234741 s: Inside else for read and scale
[HOST ] [INFO] 86.234741 s: Inside while loop, uNumFrames = 974
[HOST ] [INFO] 86.234771 s: fsize = 3420161
[HOST ] [INFO] 86.234771 s: Inside else for read and scale
[HOST ] [INFO] 86.234771 s: Inside while loop, uNumFrames = 973
[HOST ] [INFO] 86.234771 s: fsize = 3432961
[HOST ] [INFO] 86.234771 s: Inside else for read and scale
[HOST ] [INFO] 86.234771 s: Inside while loop, uNumFrames = 972
[HOST ] [INFO] 86.234802 s: fsize = 3445761
[HOST ] [INFO] 86.234802 s: Inside else for read and scale
[HOST ] [INFO] 86.234802 s: Inside while loop, uNumFrames = 971
[HOST ] [INFO] 86.234802 s: fsize = 3458561
[HOST ] [INFO] 86.234802 s: Inside else for read and scale
****** Segmentation fault caught ....
Faulty address is 0xa6499020, called from 0x77ddb
Totally Obtained 0 stack frames. signal number =11
Signal number = 11, Signal errno = 0
SI code = 1 (Address not mapped to object)
Fault addr = 0xa6499020
[bt] Execution path:

Scala Regex example not working

I'm pretty new to scala, and I'm trying to use regex to solve a problem, but I'm getting an error.
I copied an example directly from the docs (2.10.4), and I'm getting the same error.
What am I missing here:
println(scala.tools.nsc.Properties.versionString)
val p1 = "ab*c".r
val p2 = "a(b*)c".r
val p1Matches = "abbbc" match {
case p1() => true
case _ => false
}
produces:
version 2.10.4
Exception in thread "main" java.lang.NoSuchMethodError: scala.util.matching.Regex.unapplySeq(Ljava/lang/CharSequence;)Lscala/Option;
at SparkGrep$.argsParser(SparkGrep.scala:67)
at SparkGrep$.main(SparkGrep.scala:23)
at SparkGrep.main(SparkGrep.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
...
line 67 is the line that says:
case p1() => true
for reference this example is copied directly from the unappplyseq example at http://www.scala-lang.org/api/2.10.4/index.html#scala.util.matching.Regex
Update, I have created an example project where this does, in fact work. I've figured out that it has something to do withmy build process, but I have no idea why.
Here's the build.sbt for the broken project
name := "logdata-demo-07-22-2015"
version := "1.0"
scalaVersion := "2.10.4"
resolvers ++= Seq(
"Typesafe Releases" at "http://repo.typesafe.com/ typesafe/releases",
"spray repo" at "http://repo.spray.io"
)
resolvers += "spray" at "http://repo.spray.io/"
val sparkVersion = "1.3.0"
libraryDependencies ++= Seq(
"org.apache.spark" %% "spark-mllib" % sparkVersion,
"org.apache.spark" %% "spark-sql" % sparkVersion,
"com.databricks" %% "spark-csv" % "1.1.0",
"com.github.scopt" %% "scopt" % "3.3.0"
)
assemblyMergeStrategy in assembly := {
case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
case m if m.toLowerCase.matches("meta-inf.*\\.sf$") => MergeStrategy.discard
case "log4j.properties" => MergeStrategy.discard
case m if m.toLowerCase.startsWith("meta-inf/services/") => MergeStrategy.filterDistinctLines
case "reference.conf" => MergeStrategy.concat
case _ => MergeStrategy.first
}
assemblyOutputPath in assembly := new File("output/logdata-demo.jar")
I tried it on Scala 2.11.6 everything works fine.
Could be connected to the Scala version.
Best action would be to update to 2.11.x. If you are stuck with 2.10 you could try 2.10.5.
scala> :paste
// Entering paste mode (ctrl-D to finish)
println(scala.tools.nsc.Properties.versionString)
val p1 = "ab*c".r
val p2 = "a(b*)c".r
val p1Matches = "abbbc" match {
case p1() => true
case _ => false
}
// Exiting paste mode, now interpreting.
version 2.11.6
p1: scala.util.matching.Regex = ab*c
p2: scala.util.matching.Regex = a(b*)c
p1Matches: Boolean = true
I tried this code in Scala 2.10.4 and it worked fine.
You should try getting the Scala version in the following way to make sure you're using 2.10.4:
scala.util.Properties.scalaPropOrElse("version.number", "unknown")
val p1 = "ab*c".r
val p2 = "a(b*)c".r
val p1Matches = "abbbc" match {
case p1() => true
case _ => false
}
This was caused by inappropriate placement of the class files. They were in a scala 2.11 folder at build time. moving them to a scala-2.10 folder fixed the issue.
SBT is weird

Trouble getting scala actors to work over a range in parallel

A homework assignment for a computer networking software dev class, the prof has us building a port scanner for ports 1-1024 to be run against the local host. The point of the exercise is to demonstrate task level parallelism using actors. The prof provided code that scans each port in sequence. We are to create a version that does this in parallel, with an actor for each processor or hyper thread available to the system. The goal is to get the time to complete a full scan of all ports 1-1024 and compare the results of a parallel scan against the results of a serial scan. Here's my code for the parallel scan:
import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer
object LowPortScanner {
var lastPort = 0
var openPorts = ArrayBuffer[Int]()
var longestRunTime = 00.00
var results = List[Tuple3[Int, Range, Double]]()
val host = "localhost"
val numProcs = 1 to Runtime.getRuntime().availableProcessors()
val portsPerProc = 1024 / numProcs.size
val caller = self
def main(args: Array[String]): Unit = {
//spawn an actor for each processor that scans a given port range
numProcs.foreach { proc =>
actor {
val portRange: Range = (lastPort + 1) to (lastPort + portsPerProc)
lastPort = lastPort + portsPerProc
caller ! scan(proc, portRange)
}
}
//catch results from the processor actors above
def act {
loop {
reactWithin(100) {
//update the list of results returned from scan
case scanResult: Tuple3[Int, Range, Double] =>
results = results ::: List(scanResult)
//check if all results have been returned for each actor
case TIMEOUT =>
if (results.size == numProcs.size) wrapUp
case _ =>
println("got back something weird from one of the port scan actors!")
wrapUp
}
}
}
//Attempt to open a socket on each port in the given range
//returns a Tuple3[procID: Int, ports: Range, time: Double
def scan(proc: Int, ports: Range) {
val startTime = System.nanoTime()
ports.foreach { n =>
try {
println("Processor " + proc + "is checking port " + n)
val socket = new Socket(host, n)
//println("Found open port: " + n)
openPorts += n
socket.close
} catch {
case e: Exception =>
//println("While scanning port " + n + " caught Exception: " + e)
}
}
(proc, ports, startTime - System.nanoTime())
}
//output results and kill the main actor
def wrapUp {
println("These are the open ports in the range 1-1024:")
openPorts.foreach { port => println(port) }
results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3} }
println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
caller ! exit
}
}
}
I have a quad core i7, so my numProcs = 8. On this hardware platform, each proc actor should scan 128 ports (1024/8 = 128). My intention is for the proc1 actor scan 0 - 128, proc2 should scan 129-256, etc... However, this isn't what's happening. Some of the actors end up working on the same range as other actors. The output sample below illustrates the issue:
Processor 2 is checking port 1
Processor 7 is checking port 385
Processor 1 is checking port 1
Processor 5 is checking port 1
Processor 4 is checking port 1
Processor 8 is checking port 129
Processor 3 is checking port 1
Processor 6 is checking port 257
Processor 1 is checking port 2
Processor 5 is checking port 2
Processor 1 is checking port 3
Processor 3 is checking port 2
Processor 5 is checking port 3
Processor 1 is checking port 4
EDIT
Final "working" code:
import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer
object LowPortScanner {
var lastPort = 0
var openPorts = ArrayBuffer[Int]()
var longestRunTime = 00.00
var results = List[Tuple3[Int, Range, Double]]()
val host = "localhost"
val numProcs = 1 to Runtime.getRuntime().availableProcessors()
val portsPerProc = 1024 / numProcs.size
val caller = self
val procPortRanges = numProcs.foldLeft(List[Tuple2[Int, Range]]()) { (portRanges, proc) =>
val tuple2 = (proc.toInt, (lastPort + 1) to (lastPort + portsPerProc))
lastPort += portsPerProc
tuple2 :: portRanges
}
def main(args: Array[String]): Unit = {
//spawn an actor for each processor that scans a given port range
procPortRanges.foreach { proc =>
actor {
caller ! scan(proc._1, proc._2)
}
}
//catch results from the processor actors above
def act {
loop {
reactWithin(100) {
//update the list of results returned from scan
case scanResult: Tuple3[Int, Range, Double] =>
results = results ::: List(scanResult)
//check if results have been returned for each actor
case TIMEOUT =>
if (results.size == numProcs.size) wrapUp
case _ =>
println("got back something weird from one of the port scan actors!")
wrapUp
}
}
}
//Attempt to open a socket on each port in the given range
//returns a Tuple3[procID: Int, ports: Range, time: Double
def scan(proc: Int, ports: Range) {
val startTime = System.nanoTime()
ports.foreach { n =>
try {
println("Processor " + proc + "is checking port " + n)
val socket = new Socket(host, n)
//println("Found open port: " + n)
openPorts += n
socket.close
} catch {
case e: Exception =>
//println("While scanning port " + n + " caught Exception: " + e)
}
}
(proc, ports, startTime - System.nanoTime())
}
//output results and kill the main actor
def wrapUp {
println("These are the open ports in the range 1-1024:")
openPorts.foreach { port => println(port) }
results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3} }
println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
caller ! exit
}
}
}
On this hardware platform, each proc actor should scan 128 ports (1024/8 = 128).
Except you have
val portsPerProc = numProcs.size / 1024
and 8/1024 is 0. Note that you also have an off-by-one error which causes every actor to scan 1 more port than portsPerProc, it should scan either lastPort to (lastPort + portsPerProc) - 1 or (lastPort + 1) to (lastPort + portsPerProc).
For the future, if you have a different question, you should ask it separately :) But here you have a very obvious race condition: all actors are trying to execute
val portRange: Range = (lastPort + 1) to (lastPort + portsPerProc)
lastPort = lastPort + portsPerProc
concurrently. Think what happens when (for example) actors 1 and 2 execute first line before any actor gets to the second one.