Quantcast
Channel: c0nnexx10n : C0nnect1ng L1fe w1th Techn010gy » Architecture
Viewing all articles
Browse latest Browse all 10

Creating Object Pool(s) in Scala

$
0
0

We are currently working on a very exciting web scale project. The framework is built using Scala and Akka actors and till date we are quite pleased with the performance. The architecture is plugin based where we can dynamically add plugins to our framework for processing incoming messages. Now, this is where it gets interesting and is the reason for this post.

Some of the plugins are expensive to create. They would rather be created when the framework is started and pooled in memory. That brings us to the way we created our object pool(s). For our scenario, the we could actually end up having multiple object pools because each plugin would have a different # of pooled plugins. So we end up with something like this in our configuration file

…
…
  <pluginpool>
     <plugin>
         <name>foo</name>
         <size>10</size>
     </plugin>
  <pluginpool>
  <pluginpool>
     <plugin>
         <name>bar</name>
         <size>5</size>
     </plugin>
  <pluginpool>
…
…

As you would notice, we have a pool of 10 for foo and 5 for bar. Now, when our Akka actors need to pick up a plugin, they go to the PoolManager and ask for the plugin.

The PoolManager (is a Scala object) keeps track of the PluginPool(s) which are populated when the framework is initialized. It maintains a map of all the PluginPool(s) available. Hence, at the time of framework initialization the following function of PoolManager is called,

def createPluginPool(pluginName: String, pluginClassName: String, size: Int) {
    val pluginPool = new PluginPool(pluginClassName, size)
    for (i  pluginPool)
  }

The PluginPool class looks like this

import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.TimeUnit

class PluginPool(pluginClassName: String, number: Int) extends Pool {

  private val size = new AtomicInteger(0)
  private val pool = new ArrayBlockingQueue[DPMPlugin](number)

  def fetchPlugin(): DPMPlugin = {
    pool.poll() match {
      case plugin: DPMPlugin => return plugin
      case null => createOrBlock
    }
  }

  def releasePlugin(plugin: DPMPlugin): Unit = {
    pool.offer(plugin)
  }

  def addPlugin(plugin: DPMPlugin):Unit ={
    pool.add(plugin)
  }

  private def createOrBlock: DPMPlugin = {
    size.get match {
      case e: Int if e == number => block
      case _ => create
    }
  }

  private def create: DPMPlugin = {
    size.incrementAndGet match {
      case e: Int if e > number => size.decrementAndGet; fetchPlugin()
      case e: Int => Class.forName(pluginClassName).newInstance().asInstanceOf[DPMPlugin]
    }
  }

  private def block: DPMPlugin = {
    val timeout = 5000
    pool.poll(timeout, TimeUnit.MILLISECONDS) match {
      case plugin: DPMPlugin => plugin
      case _ => throw new Exception("Couldn't acquire a connection in %d milliseconds.".format(timeout))
    }
  }
}

This has been inspired by the connection pool written for scala.

And now, let us look at how the Akka actor gets the plugin. It makes a call to getPlugin() with the name of the plugin

 def getPlugin(name: String): Option[DPMPlugin] = {
    val pluginPool = fetchPluginPool(name)
    pluginPool match {
      case null => None
      case _ => {
        logger.debug("Got the plugin_ _ _")
        Some(pluginPool.fetchPlugin())
      }
    }
  }

private def fetchPluginPool(name: String): PluginPool = {
    val pluginPool = pluginsPoolMap.get(name)
    pluginPool match {
      case Some(pool) => {
        logger.debug("Fetching plugin from persistent pool.")
        pool.asInstanceOf[PluginPool]
      }
      case None => {
        null
      }
    }
  }

The PoolManager picks up the right pool and calls fetchPlugin on the pool.

Once the actor is done with its processing, it releases the plugin back to the pool so that it is available for a different actor.

 def releasePlugin(name: String, plugin: DPMPlugin) {
    val pluginPool = fetchPluginPool(name)
    if (pluginPool != null) pluginPool.releasePlugin(plugin)

  }

Filed under: Architecture, Scala Tagged: Object Pool, scala

Viewing all articles
Browse latest Browse all 10

Trending Articles