Created
February 20, 2011 17:58
-
-
Save KirinDave/836153 to your computer and use it in GitHub Desktop.
An actor to address a tight-timeline horde problem, where many request for identical (and potentially non-trivial) pieces of data enter the system at once.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.swipr.lib | |
import akka.actor._ | |
import akka.dispatch._ | |
import scala.collection.immutable._ | |
package HordeProtocol { | |
case class GetOrCreate(key: Any, valueGenerator: () => Any) | |
case class ClearJob(keyToClear: Any, value: Any) | |
} | |
class HordeMaster extends Actor { | |
import HordeProtocol._ | |
type Generator = () => Any | |
private var currentJobs = Map[Any,List[CompletableFuture[Any]]]() | |
override def receive = { | |
case GetOrCreate(key,vg) => getOrGenerateJob(self.senderFuture.get, | |
key, | |
vg.asInstanceOf[Generator]) | |
case ClearJob(key,vg) => clearJob(key, vg) | |
} | |
private def getOrGenerateJob(sender: CompletableFuture[Any], | |
key: Any, | |
g: Generator) = { | |
if(currentJobs.contains(key)) { | |
val pendingActors = sender +: currentJobs(key) | |
currentJobs = currentJobs + (key -> pendingActors) | |
} else { | |
val endpoint = self | |
currentJobs += (key -> List(sender)) | |
Actor.spawn { endpoint ! ClearJob(key,g()) } | |
} | |
} | |
private def clearJob(key: Any, result: Any) = { | |
currentJobs.getOrElse(key,List()) foreach { (a) => | |
a.completeWithResult(result) | |
} | |
currentJobs = currentJobs - key | |
} | |
} | |
object HordeMaster { | |
import HordeProtocol._ | |
def computeWithKey[R](key: String)(thunk: => R)(implicit i: ActorRef): Option[R] = { | |
val generator: () => R = () => thunk | |
val m = GetOrCreate(key,generator) | |
(i !! m).asInstanceOf[Option[R]] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If anyone who happens to peek at this code has advice for how to restructure computeWithKey and where I should put an implicit (and how I should keep other ActorRefs from falling in there), I'm very open to ideas.