[PIO-115] Implement Storage app & channel name-to-ID cache Closes #424
Project: http://git-wip-us.apache.org/repos/asf/incubator-predictionio/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-predictionio/commit/eb613580 Tree: http://git-wip-us.apache.org/repos/asf/incubator-predictionio/tree/eb613580 Diff: http://git-wip-us.apache.org/repos/asf/incubator-predictionio/diff/eb613580 Branch: refs/heads/livedoc Commit: eb6135809f66ccd2db71a3f78404a4aa0ccb16cd Parents: bcc0afe Author: Mars Hall <[email protected]> Authored: Tue Aug 29 11:28:19 2017 -0700 Committer: Mars Hall <[email protected]> Committed: Tue Aug 29 11:28:19 2017 -0700 ---------------------------------------------------------------------- .../apache/predictionio/data/store/Common.scala | 43 ++++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-predictionio/blob/eb613580/data/src/main/scala/org/apache/predictionio/data/store/Common.scala ---------------------------------------------------------------------- diff --git a/data/src/main/scala/org/apache/predictionio/data/store/Common.scala b/data/src/main/scala/org/apache/predictionio/data/store/Common.scala index 552064f..7daf19c 100644 --- a/data/src/main/scala/org/apache/predictionio/data/store/Common.scala +++ b/data/src/main/scala/org/apache/predictionio/data/store/Common.scala @@ -19,6 +19,7 @@ package org.apache.predictionio.data.store import org.apache.predictionio.data.storage.Storage +import scala.collection.mutable import grizzled.slf4j.Logger private[predictionio] object Common { @@ -26,28 +27,34 @@ private[predictionio] object Common { @transient lazy val logger = Logger[this.type] @transient lazy private val appsDb = Storage.getMetaDataApps() @transient lazy private val channelsDb = Storage.getMetaDataChannels() + // Memoize app & channel name-to-ID resolution to avoid excessive storage IO + @transient lazy val appNameToIdCache = + mutable.Map[(String, Option[String]), (Int, Option[Int])]() /* throw exception if invalid app name or channel name */ def appNameToId(appName: String, channelName: Option[String]): (Int, Option[Int]) = { - val appOpt = appsDb.getByName(appName) - - appOpt.map { app => - val channelMap: Map[String, Int] = channelsDb.getByAppid(app.id) - .map(c => (c.name, c.id)).toMap - - val channelId: Option[Int] = channelName.map { ch => - if (channelMap.contains(ch)) { - channelMap(ch) - } else { - logger.error(s"Invalid channel name ${ch}.") - throw new IllegalArgumentException(s"Invalid channel name ${ch}.") + appNameToIdCache.getOrElseUpdate((appName, channelName), { + val appOpt = appsDb.getByName(appName) + + appOpt.map { app => + val channelMap: Map[String, Int] = channelsDb.getByAppid(app.id) + .map(c => (c.name, c.id)).toMap + + val channelId: Option[Int] = channelName.map { ch => + if (channelMap.contains(ch)) { + channelMap(ch) + } else { + logger.error(s"Invalid channel name ${ch}.") + throw new IllegalArgumentException(s"Invalid channel name ${ch}.") + } } - } - (app.id, channelId) - }.getOrElse { - logger.error(s"Invalid app name ${appName}") - throw new IllegalArgumentException(s"Invalid app name ${appName}") - } + appNameToIdCache((appName, channelName)) = (app.id, channelId) + (app.id, channelId) + }.getOrElse { + logger.error(s"Invalid app name ${appName}") + throw new IllegalArgumentException(s"Invalid app name ${appName}") + } + }) } }
