
com.signalcollect.messaging.AbstractMessageBus.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of signal-collect_2.11 Show documentation
Show all versions of signal-collect_2.11 Show documentation
A framework for parallel and distributed graph processing.
The newest version!
/*
* @author Philip Stutz
* @author Mihaela Verman
*
* Copyright 2010 University of Zurich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.signalcollect.messaging
import java.util.Random
import java.util.concurrent.atomic.AtomicInteger
import scala.Array.canBuildFrom
import com.signalcollect.Edge
import com.signalcollect.GraphEditor
import com.signalcollect.Vertex
import com.signalcollect.interfaces.Coordinator
import com.signalcollect.interfaces.EdgeId
import com.signalcollect.interfaces.MessageBus
import com.signalcollect.interfaces.Request
import com.signalcollect.interfaces.VertexToWorkerMapper
import com.signalcollect.interfaces.WorkerApi
import akka.actor.ActorRef
import akka.actor.actorRef2Scala
import com.signalcollect.interfaces.AddVertex
import com.signalcollect.interfaces.AddEdge
import akka.event.Logging
import akka.actor.ActorSystem
import com.signalcollect.interfaces.SignalMessageWithSourceId
import com.signalcollect.interfaces.SignalMessageWithoutSourceId
abstract class AbstractMessageBus[Id, Signal]
extends MessageBus[Id, Signal] with GraphEditor[Id, Signal] {
protected def system: ActorSystem
val log = Logging.getLogger(system, this)
def reset(): Unit = {}
protected val registrations = new AtomicInteger()
def flush(): Unit = {}
def isInitialized = registrations.get == numberOfWorkers + numberOfNodes + 1
// Results of requests are received using temporary actors, but for termination detection to work,
// the send count should be still credited to the actual recipient of the reply.
protected def sendCountIncrementorForRequests: MessageBus[_, _] => Unit
protected val mapper: VertexToWorkerMapper[Id]
protected val workers = new Array[ActorRef](numberOfWorkers)
protected val nodes = new Array[ActorRef](numberOfNodes)
protected val workerIds = (0 until numberOfWorkers).toList
protected var coordinator: ActorRef = _
def incrementMessagesSentToWorker(workerId: Int): Unit = sentWorkerMessageCounters(workerId).incrementAndGet
def incrementMessagesSentToNode(nodeId: Int): Unit = sentNodeMessageCounters(nodeId).incrementAndGet
def incrementMessagesSentToCoordinator(): Unit = sentCoordinatorMessageCounter.incrementAndGet
def incrementMessagesSentToOthers(): Unit = sentOtherMessageCounter.incrementAndGet()
protected val sentWorkerMessageCounters: Array[AtomicInteger] = getInitializedAtomicArray(numberOfWorkers)
protected val sentNodeMessageCounters: Array[AtomicInteger] = getInitializedAtomicArray(numberOfNodes)
protected val sentCoordinatorMessageCounter = new AtomicInteger(0)
protected val sentOtherMessageCounter = new AtomicInteger(0)
def messagesSentToWorkers(): Array[Int] = sentWorkerMessageCounters.map((c: AtomicInteger) => c.get)
def messagesSentToNodes(): Array[Int] = sentNodeMessageCounters.map((c: AtomicInteger) => c.get)
def messagesSentToCoordinator(): Int = sentCoordinatorMessageCounter.get
def messagesSentToOthers(): Int = sentOtherMessageCounter.get
protected def getInitializedAtomicArray(numberOfEntries: Int): Array[AtomicInteger] = {
val atomicInts = new Array[AtomicInteger](numberOfEntries)
for (i <- 0 until numberOfEntries) {
atomicInts(i) = new AtomicInteger(0)
}
atomicInts
}
protected val receivedMessagesCounter = new AtomicInteger(0)
def getReceivedMessagesCounter: AtomicInteger = receivedMessagesCounter
lazy val workerProxies: Array[WorkerApi[Id, Signal]] = {
val result = new Array[WorkerApi[Id, Signal]](numberOfWorkers)
for (workerId <- workerIds) {
result(workerId) = AkkaProxy.newInstanceWithIncrementor[WorkerApi[Id, Signal]](
workers(workerId),
sendCountIncrementorForRequests,
sentWorkerMessageCounters(workerId),
receivedMessagesCounter)
}
result
}
def workerApi: WorkerApi[Id, Signal]
def messagesReceived = receivedMessagesCounter.get
//--------------------MessageRecipientRegistry--------------------
override def registerWorker(workerId: Int, worker: ActorRef): Unit = {
workers(workerId) = worker
registrations.incrementAndGet
}
override def registerNode(nodeId: Int, node: ActorRef): Unit = {
nodes(nodeId) = node
registrations.incrementAndGet
}
override def registerCoordinator(c: ActorRef): Unit = {
coordinator = c
registrations.incrementAndGet
}
//--------------------MessageBus--------------------
override def sendToActor(actor: ActorRef, message: Any): Unit = {
actor.tell(message, ActorRef.noSender)
}
override def sendToWorkerForVertexId(message: Any, recipientId: Id): Unit = {
val workerId = mapper.getWorkerIdForVertexId(recipientId)
sendToWorker(workerId, message)
}
override def sendToWorkerForVertexIdHash(message: Any, recipientIdHash: Int): Unit = {
val workerId = mapper.getWorkerIdForVertexIdHash(recipientIdHash)
sendToWorker(workerId, message)
}
override def sendToWorker(workerId: Int, message: Any): Unit = {
incrementMessagesSentToWorker(workerId)
workers(workerId).tell(message, ActorRef.noSender)
}
override def sendToWorkerUncounted(workerId: Int, message: Any): Unit = {
workers(workerId).tell(message, ActorRef.noSender)
}
override def sendToWorkers(message: Any, messageCounting: Boolean): Unit = {
for (workerId <- 0 until numberOfWorkers) {
if (messageCounting) {
incrementMessagesSentToWorker(workerId)
}
workers(workerId).tell(message, ActorRef.noSender)
}
}
override def sendToNode(nodeId: Int, message: Any): Unit = {
incrementMessagesSentToNode(nodeId)
nodes(nodeId).tell(message, ActorRef.noSender)
}
override def sendToNodeUncounted(nodeId: Int, message: Any): Unit = {
nodes(nodeId).tell(message, ActorRef.noSender)
}
override def sendToNodes(message: Any, messageCounting: Boolean): Unit = {
for (nodeId <- 0 until numberOfNodes) {
if (messageCounting) {
incrementMessagesSentToNode(nodeId)
}
nodes(nodeId).tell(message, ActorRef.noSender)
}
}
override def sendToCoordinator(message: Any): Unit = {
incrementMessagesSentToCoordinator
coordinator.tell(message, ActorRef.noSender)
}
override def sendToCoordinatorUncounted(message: Any): Unit = {
coordinator.tell(message, ActorRef.noSender)
}
override def getWorkerIdForVertexId(vertexId: Id): Int = mapper.getWorkerIdForVertexId(vertexId)
override def getWorkerIdForVertexIdHash(vertexIdHash: Int): Int = mapper.getWorkerIdForVertexIdHash(vertexIdHash)
//--------------------GraphEditor--------------------
/**
* Sends a signal to the vertex with vertex.id=edgeId.targetId
*/
override def sendSignal(signal: Signal, targetId: Id, sourceId: Option[Id], blocking: Boolean = false) {
if (blocking) {
// Use proxy.
if (sourceId.isDefined) {
workerApi.processSignalWithSourceId(signal, targetId, sourceId.get)
} else {
workerApi.processSignalWithoutSourceId(signal, targetId)
}
} else {
// Manually send a fire & forget request.
if (sourceId.isDefined) {
sendToWorkerForVertexId(SignalMessageWithSourceId(targetId, sourceId.get, signal), targetId)
} else {
sendToWorkerForVertexId(SignalMessageWithoutSourceId(targetId, signal), targetId)
}
}
}
override def addVertex(vertex: Vertex[Id, _, Id, Signal], blocking: Boolean = false) {
if (blocking) {
// Use proxy.
workerApi.addVertex(vertex)
} else {
// Manually send a fire & forget request.
sendToWorkerForVertexId(AddVertex(vertex), vertex.id)
}
}
override def addEdge(sourceId: Id, edge: Edge[Id], blocking: Boolean = false) {
// thread that uses an object should instantiate it (performance)
if (blocking) {
// use proxy
workerApi.addEdge(sourceId, edge)
} else {
// Manually send a fire & forget request.
sendToWorkerForVertexId(AddEdge(sourceId, edge), sourceId)
}
}
override def removeVertex(vertexId: Id, blocking: Boolean = false) {
if (blocking) {
// use proxy
workerApi.removeVertex(vertexId)
} else {
// manually send a fire & forget request
val request = Request[WorkerApi[Id, Signal]](
(_.removeVertex(vertexId)),
returnResult = false,
sendCountIncrementorForRequests)
sendToWorkerForVertexId(request, vertexId)
}
}
override def removeEdge(edgeId: EdgeId[Id], blocking: Boolean = false) {
if (blocking) {
// use proxy
workerApi.removeEdge(edgeId)
} else {
// manually send a fire & forget request
val request = Request[WorkerApi[Id, Signal]](
(_.removeEdge(edgeId)),
returnResult = false,
sendCountIncrementorForRequests)
sendToWorkerForVertexId(request, edgeId.sourceId)
}
}
override def modifyGraph(graphModification: GraphEditor[Id, Signal] => Unit, vertexIdHint: Option[Id] = None, blocking: Boolean = false) {
if (blocking) {
workerApi.modifyGraph(graphModification, vertexIdHint)
} else {
val request = Request[WorkerApi[Id, Signal]](
(_.modifyGraph(graphModification)),
returnResult = false,
sendCountIncrementorForRequests)
if (vertexIdHint.isDefined) {
val workerId = mapper.getWorkerIdForVertexId(vertexIdHint.get)
sendToWorker(workerId, request)
} else {
val rand = new Random
sendToWorker(rand.nextInt(numberOfWorkers), request)
}
}
}
override def loadGraph(graphModifications: Iterator[GraphEditor[Id, Signal] => Unit], vertexIdHint: Option[Id]) {
val request = Request[WorkerApi[Id, Signal]](
(_.loadGraph(graphModifications)),
false,
sendCountIncrementorForRequests)
if (vertexIdHint.isDefined) {
val workerId = mapper.getWorkerIdForVertexId(vertexIdHint.get)
sendToWorker(workerId, request)
} else {
val rand = new Random
sendToWorker(rand.nextInt(numberOfWorkers), request)
}
}
/**
* Recalculates the signal/collect scores of the vertex with the id @vertexId.
*
* @param vertexId The vertex id of the vertex which should have its scores recalculated.
*
* @note If the scores are above the respective thresholds, the signal/collect operations
* will be executed when the computation is executed again.
*
* @note This operation is meant to be used after the forVertexWithId operation in case
* the vertex signal/collect scores have changed.
*
* @see `forVertexWithId`
*/
def recalculateScoresForVertexWithId(vertexId: Id) {
val request = Request[WorkerApi[Id, Signal]](
(_.recalculateScoresForVertexWithId(vertexId)),
returnResult = false,
sendCountIncrementorForRequests)
val workerId = mapper.getWorkerIdForVertexId(vertexId)
sendToWorker(workerId, request)
}
//--------------------Access to high-level messaging constructs--------------------
def getGraphEditor: GraphEditor[Id, Signal] = this
def getWorkerApi: WorkerApi[Id, Signal] = workerApi
def getWorkerProxies: Array[WorkerApi[Id, Signal]] = workerProxies
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy