This is an automated email from the ASF dual-hosted git repository.

chl501 pushed a commit to branch componentization
in repository https://gitbox.apache.org/repos/asf/hama.git


The following commit(s) were added to refs/heads/componentization by this push:
     new aa8e9fc  Add Subscription, Publication operations, and a test case.
aa8e9fc is described below

commit aa8e9fc504b1fbd11125da2e3e7aceab3812907b
Author: Chiahung Lin <[email protected]>
AuthorDate: Sun Apr 28 17:28:42 2019 +0200

    Add Subscription, Publication operations, and a test case.
---
 .../org/apache/hama/membership/Communicator.scala  | 115 +++++++++++++++++++--
 .../scala/org/apache/hama/membership/package.scala |   2 -
 .../apache/hama/membership/CommunicatorSpec.scala  |  59 +++++++++++
 3 files changed, 164 insertions(+), 12 deletions(-)

diff --git 
a/membership/src/main/scala/org/apache/hama/membership/Communicator.scala 
b/membership/src/main/scala/org/apache/hama/membership/Communicator.scala
index 26f0117..5705baa 100644
--- a/membership/src/main/scala/org/apache/hama/membership/Communicator.scala
+++ b/membership/src/main/scala/org/apache/hama/membership/Communicator.scala
@@ -31,6 +31,7 @@ import org.agrona.BufferUtil
 import org.agrona.DirectBuffer
 import org.agrona.concurrent.BusySpinIdleStrategy
 import org.agrona.concurrent.SigInt
+import org.agrona.concurrent.ShutdownSignalBarrier
 import org.agrona.concurrent.UnsafeBuffer
 import org.apache.hama.logging.Logging
 import org.apache.hama.util.Utils._
@@ -44,13 +45,115 @@ import scalaz.zio._
 trait Communicator
 object Communicator {
 
-  def driver: Task[MediaDriver] = ZIO.effect {
+  val localhost = "localhost"
+
+  final case object BackPressured extends RuntimeException (
+    "Failure due to back pressure!"
+  )
+
+  final case object NotConnected extends RuntimeException (
+    "Failure because publisher is not connected to subscriber!"
+  )
+
+  final case object AdminAction extends RuntimeException (
+    "Failure because of administration action!"
+  )
+   
+  final case object Closed extends RuntimeException (
+    "Failure because publication is closed!"
+  )
+
+  final case object MaxPositionExceeded extends RuntimeException (
+    "Failure due to publication reaching max position!"
+  )
+
+  final case object UnknownReason extends RuntimeException (
+    "Failure due to unknown reason!"
+  )
+
+  case class Channel(host: String = localhost, port: Int = 12345) {
+    override def toString(): String = s"aeron:udp?endpoint=$host:$port"
+  }
+
+  implicit class SubscriberOps(aeron: Task[Aeron]) {
+    def subscriber(channel: Channel = Channel(), streamId: Int = 10): 
+      Task[Subscription] = aeron.flatMap { a => 
+        Task.effect(a.addSubscription(channel.toString, streamId))
+      }
+  }
+
+  implicit class ReceiveOps(subscriber: Task[Subscription]) {
+    def receive(f: (DirectBuffer, Int, Int, Header) => Boolean) = ZIO.effect {
+      var continuous = true 
+      val handler = new FragmentAssembler({ 
+        (buffer: DirectBuffer, offset: Int, length: Int, header: Header) => 
+          val shouldContinuous = f(buffer, offset, length, header)
+          continuous = shouldContinuous
+      })
+      val idleStrategy = new BusySpinIdleStrategy()
+      while(continuous) subscriber.flatMap { s =>
+        val read = s.poll(handler, 10)
+        idleStrategy.idle(read)
+        ZIO.unit
+      }
+      this
+    }
+
+    def close() = subscriber.flatMap { sub => sub.close; ZIO.unit }
+    
+  }
+
+  implicit class PublisherOps(aeron: Task[Aeron]) {
+    def publisher(channel: Channel = Channel(), streamId: Int = 10): 
+      Task[Publication] = aeron.flatMap { a => 
+        Task.effect(a.addPublication(channel.toString, streamId)) 
+      }
+  }
+
+  implicit class PublishOps(publisher: Task[Publication]) {
+    def publish (
+      messageBytes: Array[Byte],
+      bufferCapacity: Int = 512,
+      boundaryAlighment: Int = CACHE_LINE_LENGTH,
+      deadline: Long = (System.nanoTime + 3.seconds.toNanos),
+      sleep: () => Unit = { () => Thread.sleep(1) }
+    ): ZIO[Any, Throwable, PublishOps] = publisher.flatMap { pub => 
+      while(!pub.isConnected) {
+        if(System.nanoTime >= deadline) return ZIO.fail(new RuntimeException (
+          s"Publication can't connect: ${pub.toString}"
+        ))
+        sleep()
+      }
+      val buffer = new UnsafeBuffer(BufferUtil.allocateDirectAligned (
+        bufferCapacity, boundaryAlighment
+      ))
+      buffer.putBytes(0, messageBytes)
+      val result = pub.offer(buffer, 0, messageBytes.length)
+      result match {
+        case res if res < 0L && BACK_PRESSURED == res => 
ZIO.fail(BackPressured)
+        case res if res < 0L && NOT_CONNECTED == res => ZIO.fail(NotConnected)
+        case res if res < 0L && ADMIN_ACTION == res => ZIO.fail(AdminAction)
+        case res if res < 0L && CLOSED == res => ZIO.fail(Closed)
+        case res if res < 0L && MAX_POSITION_EXCEEDED == res => ZIO.fail(
+          MaxPositionExceeded
+        )
+        case res if res < 0L => ZIO.fail(UnknownReason)
+        case _ => ZIO.succeed(this)
+      }
+    }
+
+    def close() = publisher.flatMap { pub => pub.close; ZIO.unit }
+  }
+
+  def driver(barrier: ShutdownSignalBarrier): Task[MediaDriver] = ZIO.effect {
     val context = new MediaDriver.Context().
       threadingMode(DEDICATED).
       conductorIdleStrategy(new BusySpinIdleStrategy).
       receiverIdleStrategy(new BusySpinIdleStrategy).
       senderIdleStrategy(new BusySpinIdleStrategy)
-    MediaDriver.launch(context)
+    val driver = MediaDriver.launch(context)
+    barrier.await
+    driver
   }
 
   def aeron: Task[Aeron] = ZIO.effect {
@@ -58,12 +161,4 @@ object Communicator {
     Aeron.connect(context) 
   }
 
-  def subscriber(aeron: Task[Aeron]): Task[Subscription] = aeron.flatMap { a =>
-    Task.effect(a.addSubscription("aeron:udp?endpoint=localhost:12345", 10))
-  }
-
-  def publisher(aeron: Task[Aeron]): Task[Publication] = aeron.flatMap { a => 
-    Task.effect(a.addPublication("aeron:udp?endpoint=localhost:12344", 10))
-  }
-
 }
diff --git a/membership/src/main/scala/org/apache/hama/membership/package.scala 
b/membership/src/main/scala/org/apache/hama/membership/package.scala
index 2c7c29f..e01e7a3 100644
--- a/membership/src/main/scala/org/apache/hama/membership/package.scala
+++ b/membership/src/main/scala/org/apache/hama/membership/package.scala
@@ -23,6 +23,4 @@ package object membership {
 
   type ValidatedResult[A] = ValidatedNel[Throwable, A]
 
-  val localhost = "localhost"
-
 }
diff --git 
a/membership/src/test/scala/org/apache/hama/membership/CommunicatorSpec.scala 
b/membership/src/test/scala/org/apache/hama/membership/CommunicatorSpec.scala
new file mode 100644
index 0000000..49740b8
--- /dev/null
+++ 
b/membership/src/test/scala/org/apache/hama/membership/CommunicatorSpec.scala
@@ -0,0 +1,59 @@
+/**
+ * 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.hama.membership
+
+import io.aeron.logbuffer.Header
+import org.scalatest._
+import org.agrona.DirectBuffer
+import org.agrona.concurrent.ShutdownSignalBarrier
+import scalaz.zio._
+
+class CommunicatorSpec extends FlatSpec with Matchers {
+
+  import Communicator._
+
+  "Communicator" should "" in {
+
+
+    val barrier = new ShutdownSignalBarrier
+    val dio = driver(barrier)
+    val a = aeron
+    val subio = a.subscriber().receive { 
+      (buffer: DirectBuffer, offset: Int, length: Int, header: Header) =>
+        val data = new Array[Byte](length)
+        buffer.getBytes(offset, data)
+        val hello = new String(data)
+        false
+    }.flatMap(_.close)
+    val pubio = a.publisher().publish(messageBytes = 
"hello".getBytes).flatMap(_.close)
+
+    val handler = for {
+      forked_d <- dio.fork
+      forked_sub <- subio.fork
+      forked_pub <- pubio.fork
+      forked_b <- ZIO.effect { barrier.signal; ZIO.unit }.fork
+      _ <- forked_b.join
+      p <- forked_pub.join
+      s <- forked_sub.join
+      d <- forked_d.join
+    } yield (p, s, d)
+
+    val runtime = new DefaultRuntime {}
+    runtime.unsafeRun { handler.run }
+  }
+}

Reply via email to