From b8080f3895903eb1d7a40da466c9044ea870aeba Mon Sep 17 00:00:00 2001 From: debasishg Date: Thu, 24 Dec 2009 12:20:39 +0530 Subject: [PATCH] added redis backend storage for akka transactors --- akka-persistence-redis/pom.xml | 46 ++++ .../src/main/scala/RedisStorage.scala | 49 ++++ .../src/main/scala/RedisStorageBackend.scala | 251 ++++++++++++++++++ .../test/scala/RedisPersistentActorTest.scala | 157 +++++++++++ .../test/scala/RedisStorageBackendTest.scala | 139 ++++++++++ config/akka-reference.conf | 5 + .../redisclient/1.0.1/redisclient-1.0.1.jar | Bin 0 -> 42194 bytes 7 files changed, 647 insertions(+) create mode 100644 akka-persistence-redis/pom.xml create mode 100644 akka-persistence-redis/src/main/scala/RedisStorage.scala create mode 100644 akka-persistence-redis/src/main/scala/RedisStorageBackend.scala create mode 100644 akka-persistence-redis/src/test/scala/RedisPersistentActorTest.scala create mode 100644 akka-persistence-redis/src/test/scala/RedisStorageBackendTest.scala create mode 100644 embedded-repo/com/redis/redisclient/1.0.1/redisclient-1.0.1.jar diff --git a/akka-persistence-redis/pom.xml b/akka-persistence-redis/pom.xml new file mode 100644 index 0000000000..ba2f295aaf --- /dev/null +++ b/akka-persistence-redis/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + akka-persistence-redis + Akka Persistence Redis Module + + jar + + + akka + se.scalablesolutions.akka + 0.6 + ../pom.xml + + + + + akka-persistence-common + ${project.groupId} + ${project.version} + + + + + com.redis + redisclient + 1.0.1 + + + + + org.scalatest + scalatest + 1.0 + test + + + junit + junit + 4.5 + test + + + + diff --git a/akka-persistence-redis/src/main/scala/RedisStorage.scala b/akka-persistence-redis/src/main/scala/RedisStorage.scala new file mode 100644 index 0000000000..f836cfa293 --- /dev/null +++ b/akka-persistence-redis/src/main/scala/RedisStorage.scala @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2009 Scalable Solutions. + */ + +package se.scalablesolutions.akka.state + +import org.codehaus.aspectwerkz.proxy.Uuid + +object RedisStorage extends Storage { + type ElementType = Array[Byte] + + def newMap: PersistentMap[ElementType, ElementType] = newMap(Uuid.newUuid.toString) + def newVector: PersistentVector[ElementType] = newVector(Uuid.newUuid.toString) + def newRef: PersistentRef[ElementType] = newRef(Uuid.newUuid.toString) + + def getMap(id: String): PersistentMap[ElementType, ElementType] = newMap(id) + def getVector(id: String): PersistentVector[ElementType] = newVector(id) + def getRef(id: String): PersistentRef[ElementType] = newRef(id) + + def newMap(id: String): PersistentMap[ElementType, ElementType] = new RedisPersistentMap(id) + def newVector(id: String): PersistentVector[ElementType] = new RedisPersistentVector(id) + def newRef(id: String): PersistentRef[ElementType] = new RedisPersistentRef(id) +} + +/** + * Implements a persistent transactional map based on the MongoDB document storage. + * + * @author Debasish Ghosh + */ +class RedisPersistentMap(id: String) extends PersistentMap[Array[Byte], Array[Byte]] { + val uuid = id + val storage = RedisStorageBackend +} + +/** + * Implements a persistent transactional vector based on the Redis + * document storage. + * + * @author Debasish Ghosh + */ +class RedisPersistentVector(id: String) extends PersistentVector[Array[Byte]] { + val uuid = id + val storage = RedisStorageBackend +} + +class RedisPersistentRef(id: String) extends PersistentRef[Array[Byte]] { + val uuid = id + val storage = RedisStorageBackend +} diff --git a/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala b/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala new file mode 100644 index 0000000000..2a9f5f1c61 --- /dev/null +++ b/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala @@ -0,0 +1,251 @@ +/** + * Copyright (C) 2009 Scalable Solutions. + */ + +package se.scalablesolutions.akka.state + +import se.scalablesolutions.akka.util.Logging +import se.scalablesolutions.akka.Config.config + +import com.redis._ + +trait Encoder { + def encode(bytes: Array[Byte]): Array[Byte] + def decode(bytes: Array[Byte]): Array[Byte] +} + +trait CommonsCodecBase64 { + val base64 = new org.apache.commons.codec.binary.Base64 + + def encode(bytes: Array[Byte]): Array[Byte] = base64.encode(bytes) + def decode(bytes: Array[Byte]): Array[Byte] = base64.decode(bytes) +} + +object Base64Encoder extends Encoder with CommonsCodecBase64 +import Base64Encoder._ + +/** + * A module for supporting Redis based persistence. + *

+ * The module offers functionality for: + *

  • Persistent Maps
  • + *
  • Persistent Vectors
  • + *
  • Persistent Refs
  • + *

    + * @author Debasish Ghosh + */ +private [akka] object RedisStorageBackend extends + MapStorageBackend[Array[Byte], Array[Byte]] with + VectorStorageBackend[Array[Byte]] with + RefStorageBackend[Array[Byte]] with + Logging { + + val REDIS_SERVER_HOSTNAME = config.getString("akka.storage.redis.hostname", "127.0.0.1") + val REDIS_SERVER_PORT = config.getInt("akka.storage.redis.port", 6379) + + val db = new Redis(REDIS_SERVER_HOSTNAME, REDIS_SERVER_PORT) + + /** + * Map storage in Redis. + *

    + * Maps are stored as key/value pairs in redis. Redis keys cannot contain spaces. But with + * our use case, the keys will be specified by the user. Hence we need to encode the key + * ourselves before sending to Redis. We use base64 encoding. + *

    + * Also since we are storing the key/value in the global namespace, we need to construct the + * key suitably so as to avoid namespace clash. The following strategy is used: + * + * Unique identifier for the map = T1 (say) + *

    +   * Map(
    +   *   "debasish.address" -> "kolkata, India",
    +   *   "debasish.company" -> "anshinsoft",
    +   *   "debasish.programming_language" -> "scala",
    +   * )
    + * will be stored as the following key-value pair in Redis: + * + * + * base64(T1):base64("debasish.address") -> "kolkata, India" + * base64(T1):base64("debasish.company") -> "anshinsoft" + * base64(T1):base64("debasish.programming_language") -> "scala" + * + */ + def insertMapStorageEntryFor(name: String, key: Array[Byte], value: Array[Byte]) { + insertMapStorageEntriesFor(name, List((key, value))) + } + + def insertMapStorageEntriesFor(name: String, entries: List[Tuple2[Array[Byte], Array[Byte]]]) { + mset(entries.map(e => + (makeRedisKey(name, e._1), new String(e._2)))) + } + + /** + * Make a redis key from an Akka Map key. + *

    + * The key is made as follows: + *

  • redis key is composed of 2 parts: the transaction id and the map key separated by :
  • + *
  • : is chosen since it cannot appear in base64 encoding charset
  • + *
  • both parts of the key need to be based64 encoded since there can be spaces within each of them
  • + */ + private [this] def makeRedisKey(name: String, key: Array[Byte]): String = { + "%s:%s".format(new String(encode(name.getBytes)), new String(encode(key))) + } + + private [this] def makeKeyFromRedisKey(redisKey: String) = { + val nk = redisKey.split(':').map{e: String => decode(e.getBytes)} + (nk(0), nk(1)) + } + + private [this] def mset(entries: List[(String, String)]) { + entries.foreach {e: (String, String) => + db.set(e._1, e._2) + } + } + + def removeMapStorageFor(name: String): Unit = { + db.keys("%s:*".format(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(keys) => + keys.foreach(db.delete(_)) + } + } + + def removeMapStorageFor(name: String, key: Array[Byte]): Unit = { + db.delete(makeRedisKey(name, key)) + } + + def getMapStorageEntryFor(name: String, key: Array[Byte]): Option[Array[Byte]] = + db.get(makeRedisKey(name, key)) match { + case None => + throw new Predef.NoSuchElementException(new String(key) + " not present") + case Some(s) => Some(s.getBytes) + } + + def getMapStorageSizeFor(name: String): Int = { + db.keys("%s:*".format(new String(encode(name.getBytes)))) match { + case None => 0 + case Some(keys) => + keys.length + } + } + + def getMapStorageFor(name: String): List[(Array[Byte], Array[Byte])] = { + db.keys("%s:*".format(new String(encode(name.getBytes)))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(keys) => + keys.map(key => (makeKeyFromRedisKey(key)._2, db.get(key).get.getBytes)).toList + } + } + + def getMapStorageRangeFor(name: String, start: Option[Array[Byte]], + finish: Option[Array[Byte]], + count: Int): List[(Array[Byte], Array[Byte])] = { + + import scala.collection.immutable.TreeMap + val wholeSorted = + TreeMap(getMapStorageFor(name).map(e => (new String(e._1), e._2)): _*) + + if (wholeSorted isEmpty) List() + + val startKey = + start match { + case Some(bytes) => Some(new String(bytes)) + case None => None + } + + val endKey = + finish match { + case Some(bytes) => Some(new String(bytes)) + case None => None + } + + ((startKey, endKey, count): @unchecked) match { + case ((Some(s), Some(e), _)) => + wholeSorted.range(s, e) + .toList + .map(e => (e._1.getBytes, e._2)) + .toList + case ((Some(s), None, c)) if c > 0 => + wholeSorted.from(s) + .elements + .take(count) + .map(e => (e._1.getBytes, e._2)) + .toList + case ((Some(s), None, _)) => + wholeSorted.from(s) + .toList + .map(e => (e._1.getBytes, e._2)) + .toList + case ((None, Some(e), _)) => + wholeSorted.until(e) + .toList + .map(e => (e._1.getBytes, e._2)) + .toList + } + } + + def insertVectorStorageEntryFor(name: String, element: Array[Byte]) { + db.pushHead(new String(encode(name.getBytes)), new String(element)) + } + + def insertVectorStorageEntriesFor(name: String, elements: List[Array[Byte]]) { + elements.foreach(insertVectorStorageEntryFor(name, _)) + } + + def updateVectorStorageEntryFor(name: String, index: Int, elem: Array[Byte]) { + db.listSet(new String(encode(name.getBytes)), index, new String(elem)) + } + + def getVectorStorageEntryFor(name: String, index: Int): Array[Byte] = { + db.listIndex(new String(encode(name.getBytes)), index) match { + case None => + throw new Predef.NoSuchElementException(name + " does not have element at " + index) + case Some(e) => e.getBytes + } + } + + def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): List[Array[Byte]] = { + /** + * count is the max number of results to return. Start with + * start or 0 (if start is not defined) and go until + * you hit finish or count. + */ + val s = if (start.isDefined) start.get else 0 + val cnt = + if (finish.isDefined) { + val f = finish.get + if (f >= s) Math.min(count, (f - s)) else count + } + else count + db.listRange(new String(encode(name.getBytes)), s, s + cnt - 1) match { + case None => + throw new Predef.NoSuchElementException(name + " does not have elements in the range specified") + case Some(l) => + l map (_.getBytes) + } + } + + def getVectorStorageSizeFor(name: String): Int = { + db.listLength(new String(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(l) => l + } + } + + def insertRefStorageFor(name: String, element: Array[Byte]) { + db.set(new String(encode(name.getBytes)), new String(element)) + } + + def getRefStorageFor(name: String): Option[Array[Byte]] = { + db.get(new String(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(s) => Some(s.getBytes) + } + } + + def flushDB = db.flushDb +} diff --git a/akka-persistence-redis/src/test/scala/RedisPersistentActorTest.scala b/akka-persistence-redis/src/test/scala/RedisPersistentActorTest.scala new file mode 100644 index 0000000000..e4b8bfd22b --- /dev/null +++ b/akka-persistence-redis/src/test/scala/RedisPersistentActorTest.scala @@ -0,0 +1,157 @@ +package se.scalablesolutions.akka.state + +import junit.framework.TestCase + +import org.junit.{Test, Before} +import org.junit.Assert._ + +import se.scalablesolutions.akka.actor.Actor + +/** + * A persistent actor based on Redis storage. + *

    + * Demonstrates a bank account operation consisting of messages that: + *

  • checks balance Balance
  • + *
  • debits amountDebit
  • + *
  • debits multiple amountsMultiDebit
  • + *
  • credits amountCredit
  • + *

    + * Needs a running Redis server. + * @author Debasish Ghosh + */ + +case class Balance(accountNo: String) +case class Debit(accountNo: String, amount: BigInt, failer: Actor) +case class MultiDebit(accountNo: String, amounts: List[BigInt], failer: Actor) +case class Credit(accountNo: String, amount: BigInt) +case object LogSize + +class AccountActor extends Actor { + makeTransactionRequired + private val accountState = RedisStorage.newMap + private val txnLog = RedisStorage.newVector + + def receive: PartialFunction[Any, Unit] = { + // check balance + case Balance(accountNo) => + txnLog.add("Balance:%s".format(accountNo).getBytes) + reply(BigInt(new String(accountState.get(accountNo.getBytes).get))) + + // debit amount: can fail + case Debit(accountNo, amount, failer) => + txnLog.add("Debit:%s %s".format(accountNo, amount.toString).getBytes) + + val m: BigInt = + accountState.get(accountNo.getBytes) match { + case Some(bytes) => BigInt(new String(bytes)) + case None => 0 + } + accountState.put(accountNo.getBytes, (m - amount).toString.getBytes) + if (amount > m) + failer !! "Failure" + reply(m - amount) + + // many debits: can fail + // demonstrates true rollback even if multiple puts have been done + case MultiDebit(accountNo, amounts, failer) => + txnLog.add("MultiDebit:%s %s".format(accountNo, amounts.map(_.intValue).foldLeft(0)(_ + _).toString).getBytes) + + val m: BigInt = + accountState.get(accountNo.getBytes) match { + case Some(bytes) => BigInt(new String(bytes)) + case None => 0 + } + var bal: BigInt = 0 + amounts.foreach {amount => + bal = bal + amount + accountState.put(accountNo.getBytes, (m - bal).toString.getBytes) + } + if (bal > m) failer !! "Failure" + reply(m - bal) + + // credit amount + case Credit(accountNo, amount) => + txnLog.add("Credit:%s %s".format(accountNo, amount.toString).getBytes) + + val m: BigInt = + accountState.get(accountNo.getBytes) match { + case Some(bytes) => BigInt(new String(bytes)) + case None => 0 + } + accountState.put(accountNo.getBytes, (m + amount).toString.getBytes) + reply(m + amount) + + case LogSize => + reply(txnLog.length.asInstanceOf[AnyRef]) + } +} + +@serializable class PersistentFailerActor extends Actor { + makeTransactionRequired + def receive = { + case "Failure" => + throw new RuntimeException("expected") + } +} + +class RedisPersistentActorTest extends TestCase { + @Test + def testSuccessfulDebit = { + val bactor = new AccountActor + bactor.start + val failer = new PersistentFailerActor + failer.start + bactor !! Credit("a-123", 5000) + bactor !! Debit("a-123", 3000, failer) + assertEquals(BigInt(2000), (bactor !! Balance("a-123")).get) + + bactor !! Credit("a-123", 7000) + assertEquals(BigInt(9000), (bactor !! Balance("a-123")).get) + + bactor !! Debit("a-123", 8000, failer) + assertEquals(BigInt(1000), (bactor !! Balance("a-123")).get) + + assertEquals(7, (bactor !! LogSize).get) + } + + @Test + def testUnsuccessfulDebit = { + val bactor = new AccountActor + bactor.start + bactor !! Credit("a-123", 5000) + assertEquals(BigInt(5000), (bactor !! Balance("a-123")).get) + + val failer = new PersistentFailerActor + failer.start + try { + bactor !! Debit("a-123", 7000, failer) + fail("should throw exception") + } catch { case e: RuntimeException => {}} + + assertEquals(BigInt(5000), (bactor !! Balance("a-123")).get) + + // should not count the failed one + assertEquals(3, (bactor !! LogSize).get) + } + + @Test + def testUnsuccessfulMultiDebit = { + val bactor = new AccountActor + bactor.start + bactor !! Credit("a-123", 5000) + + assertEquals(BigInt(5000), (bactor !! Balance("a-123")).get) + + val failer = new PersistentFailerActor + failer.start + try { + bactor !! MultiDebit("a-123", List(500, 2000, 1000, 3000), failer) + fail("should throw exception") + } catch { case e: RuntimeException => {}} + + assertEquals(BigInt(5000), (bactor !! Balance("a-123")).get) + + // should not count the failed one + assertEquals(3, (bactor !! LogSize).get) + } +} diff --git a/akka-persistence-redis/src/test/scala/RedisStorageBackendTest.scala b/akka-persistence-redis/src/test/scala/RedisStorageBackendTest.scala new file mode 100644 index 0000000000..262bda47eb --- /dev/null +++ b/akka-persistence-redis/src/test/scala/RedisStorageBackendTest.scala @@ -0,0 +1,139 @@ +package se.scalablesolutions.akka.state + +import org.scalatest.Spec +import org.scalatest.matchers.ShouldMatchers +import org.scalatest.BeforeAndAfterAll +import org.scalatest.junit.JUnitRunner +import org.junit.runner.RunWith + +import se.scalablesolutions.akka.serialization.Serializable + +import RedisStorageBackend._ + +@RunWith(classOf[JUnitRunner]) +class RedisStorageBackendTest extends + Spec with + ShouldMatchers with + BeforeAndAfterAll { + + override def beforeAll { + flushDB + println("** destroyed database") + } + + override def afterAll { + flushDB + println("** destroyed database") + } + + describe("Store and query in maps") { + it("should enter 4 entries in redis for transaction T-1") { + insertMapStorageEntryFor("T-1", "debasish.company".getBytes, "anshinsoft".getBytes) + insertMapStorageEntryFor("T-1", "debasish.language".getBytes, "java".getBytes) + insertMapStorageEntryFor("T-1", "debasish.age".getBytes, "44".getBytes) + insertMapStorageEntryFor("T-1", "debasish.spouse".getBytes, "paramita".getBytes) + + getMapStorageSizeFor("T-1") should equal(4) + new String(getMapStorageEntryFor( + "T-1", "debasish.language".getBytes).get) should equal("java") + } + + it("should enter a custom object for transaction T-1") { + val n = Name(100, "debasish", "kolkata") + insertMapStorageEntryFor("T-1", "debasish.identity".getBytes, n.toBytes) + getMapStorageSizeFor("T-1") should equal(5) + } + + it("should enter key/values for another transaction T-2") { + insertMapStorageEntryFor("T-2", "debasish.age".getBytes, "49".getBytes) + insertMapStorageEntryFor("T-2", "debasish.spouse".getBytes, "paramita".getBytes) + getMapStorageSizeFor("T-1") should equal(5) + getMapStorageSizeFor("T-2") should equal(2) + } + + it("should remove map storage for T-1 and T2") { + removeMapStorageFor("T-1") + removeMapStorageFor("T-2") + } + } + + describe("Range query in maps") { + it("should enter 7 entries in redis for transaction T-5") { + insertMapStorageEntryFor("T-5", "trade.refno".getBytes, "R-123".getBytes) + insertMapStorageEntryFor("T-5", "trade.instrument".getBytes, "IBM".getBytes) + insertMapStorageEntryFor("T-5", "trade.type".getBytes, "BUY".getBytes) + insertMapStorageEntryFor("T-5", "trade.account".getBytes, "A-123".getBytes) + insertMapStorageEntryFor("T-5", "trade.amount".getBytes, "1000000".getBytes) + insertMapStorageEntryFor("T-5", "trade.quantity".getBytes, "1000".getBytes) + insertMapStorageEntryFor("T-5", "trade.broker".getBytes, "Nomura".getBytes) + getMapStorageSizeFor("T-5") should equal(7) + + getMapStorageRangeFor("T-5", + Some("trade.account".getBytes), + None, 3).map(e => (new String(e._1), new String(e._2))).size should equal(3) + + getMapStorageRangeFor("T-5", + Some("trade.account".getBytes), + Some("trade.type".getBytes), 3).map(e => (new String(e._1), new String(e._2))).size should equal(6) + + getMapStorageRangeFor("T-5", + Some("trade.account".getBytes), + Some("trade.type".getBytes), 0).map(e => (new String(e._1), new String(e._2))).size should equal(6) + + getMapStorageRangeFor("T-5", + Some("trade.account".getBytes), + None, 0).map(e => (new String(e._1), new String(e._2))).size should equal(7) + } + it("should remove map storage for T5") { + removeMapStorageFor("T-5") + } + } + + describe("Store and query in vectors") { + it("should write 4 entries in a vector for transaction T-3") { + insertVectorStorageEntryFor("T-3", "debasish".getBytes) + insertVectorStorageEntryFor("T-3", "maulindu".getBytes) + val n = Name(100, "debasish", "kolkata") + insertVectorStorageEntryFor("T-3", n.toBytes) + insertVectorStorageEntryFor("T-3", "1200".getBytes) + getVectorStorageSizeFor("T-3") should equal(4) + } + } + + describe("Store and query in ref") { + it("should write 4 entries in 4 refs for transaction T-4") { + insertRefStorageFor("T-4", "debasish".getBytes) + insertRefStorageFor("T-4", "maulindu".getBytes) + + insertRefStorageFor("T-4", "1200".getBytes) + new String(getRefStorageFor("T-4").get) should equal("1200") + + val n = Name(100, "debasish", "kolkata") + insertRefStorageFor("T-4", n.toBytes) + n.fromBytes(getRefStorageFor("T-4").get) should equal(n) + } + } +} + +case class Name(id: Int, name: String, address: String) + extends Serializable.SBinary[Name] { + import sbinary.DefaultProtocol._ + + def this() = this(0, null, null) + + implicit object NameFormat extends Format[Name] { + def reads(in : Input) = Name( + read[Int](in), + read[String](in), + read[String](in)) + def writes(out: Output, value: Name) = { + write[Int](out, value.id) + write[String](out, value.name) + write[String](out, value.address) + } + } + + def fromBytes(bytes: Array[Byte]) = fromByteArray[Name](bytes) + + def toBytes: Array[Byte] = toByteArray(this) +} diff --git a/config/akka-reference.conf b/config/akka-reference.conf index 7bdfa6b4f1..799d18f61d 100644 --- a/config/akka-reference.conf +++ b/config/akka-reference.conf @@ -77,5 +77,10 @@ port = 27017 dbname = "mydb" + + + hostname = "127.0.0.1" # IP address or hostname of the Redis instance + port = 27017 + diff --git a/embedded-repo/com/redis/redisclient/1.0.1/redisclient-1.0.1.jar b/embedded-repo/com/redis/redisclient/1.0.1/redisclient-1.0.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..d4a293effa9c046fd41993742f5b23d8e5fc9c97 GIT binary patch literal 42194 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 literal 0 HcmV?d00001