From a9371c229b977370cbbe84ff0b01d5ddfcb944e6 Mon Sep 17 00:00:00 2001 From: debasishg Date: Mon, 11 Jan 2010 15:30:38 +0530 Subject: [PATCH] Implemented persistent transactional queue with Redis backend --- .../src/main/scala/Storage.scala | 129 +++++++++++++++++ .../src/main/scala/StorageBackend.scala | 35 +++++ .../src/main/scala/RedisStorage.scala | 18 ++- .../src/main/scala/RedisStorageBackend.scala | 87 ++++++++++++ .../src/test/scala/RedisPersistentQSpec.scala | 133 ++++++++++++++++++ .../test/scala/RedisStorageBackendSpec.scala | 53 +++++++ .../redisclient/1.0.1/redisclient-1.0.1.jar | Bin 42194 -> 50730 bytes 7 files changed, 453 insertions(+), 2 deletions(-) create mode 100644 akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentQSpec.scala diff --git a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala index cac0004879..78cdd5c207 100644 --- a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala +++ b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala @@ -40,6 +40,7 @@ class NoTransactionInScopeException extends RuntimeException * * * @author Jonas Bonér + * @author Debasish Ghosh */ trait Storage { type ElementType @@ -47,14 +48,17 @@ trait Storage { def newMap: PersistentMap[ElementType, ElementType] def newVector: PersistentVector[ElementType] def newRef: PersistentRef[ElementType] + def newQueue: PersistentQueue[ElementType] def getMap(id: String): PersistentMap[ElementType, ElementType] def getVector(id: String): PersistentVector[ElementType] def getRef(id: String): PersistentRef[ElementType] + def getQueue(id: String): PersistentQueue[ElementType] def newMap(id: String): PersistentMap[ElementType, ElementType] def newVector(id: String): PersistentVector[ElementType] def newRef(id: String): PersistentRef[ElementType] + def newQueue(id: String): PersistentQueue[ElementType] } @@ -269,3 +273,128 @@ trait PersistentRef[T] extends Transactional with Committable { currentTransaction.get.get.register(uuid, this) } } + +/** + * Implementation of PersistentQueue for every concrete + * storage will have the same workflow. This abstracts the workflow. + *

+ * Enqueue is simpler, we just have to record the operation in a local + * transactional store for playback during commit. This store + * enqueueNDequeuedEntries stores the entire history of enqueue + * and dequeue that will be played at commit on the underlying store. + *

+ * The main challenge with dequeue is that we need to return the element + * that has been dequeued. Hence in addition to the above store, we need to + * have another local queue that actually does the enqueue dequeue operations + * that take place only during this transaction. This gives us the + * element that will be dequeued next from the set of elements enqueued + * during this transaction. + *

+ * The third item that we need is an index to the underlying storage element + * that may also have to be dequeued as part of the current transaction. This + * is modeled using a ref to an Int that points to elements in the underlyinng store. + *

+ * Subclasses just need to provide the actual concrete instance for the + * abstract val storage. + * + * @author Debasish Ghosh + */ +trait PersistentQueue[A] extends scala.collection.mutable.Queue[A] + with Transactional with Committable with Logging { + + abstract case class QueueOp + case object ENQ extends QueueOp + case object DEQ extends QueueOp + + import scala.collection.immutable.Queue + + // current trail that will be played on commit to the underlying store + protected val enqueuedNDequeuedEntries = TransactionalState.newVector[(Option[A], QueueOp)] + protected val shouldClearOnCommit = TransactionalRef[Boolean]() + + // local queue that will record all enqueues and dequeues in the current txn + protected val localQ = TransactionalRef[Queue[A]]() + + // keeps a pointer to the underlying storage for the enxt candidate to be dequeued + protected val pickMeForDQ = TransactionalRef[Int]() + + localQ.swap(Queue.Empty) + pickMeForDQ.swap(0) + + // to be concretized in subclasses + val storage: QueueStorageBackend[A] + + def commit = { + enqueuedNDequeuedEntries.toList.foreach { e => + e._2 match { + case ENQ => storage.enqueue(uuid, e._1.get) + case DEQ => storage.dequeue(uuid) + } + } + if (shouldClearOnCommit.isDefined && shouldClearOnCommit.get.get) { + storage.remove(uuid) + } + enqueuedNDequeuedEntries.clear + localQ.swap(Queue.Empty) + pickMeForDQ.swap(0) + } + + override def enqueue(elems: A*) { + register + elems.foreach(e => { + enqueuedNDequeuedEntries.add((Some(e), ENQ)) + localQ.get.get.enqueue(e) + }) + } + + override def dequeue: A = { + register + // record for later playback + enqueuedNDequeuedEntries.add((None, DEQ)) + + val i = pickMeForDQ.get.get + if (i < storage.size(uuid)) { + // still we can DQ from storage + pickMeForDQ.swap(i + 1) + storage.peek(uuid, i, 1)(0) + } else { + // check we have transient candidates in localQ for DQ + if (localQ.get.get.isEmpty == false) { + val (a, q) = localQ.get.get.dequeue + localQ.swap(q) + a + } + else + throw new NoSuchElementException("trying to dequeue from empty queue") + } + } + + override def clear = { + register + shouldClearOnCommit.swap(true) + localQ.swap(Queue.Empty) + pickMeForDQ.swap(0) + } + + override def size: Int = try { + storage.size(uuid) + localQ.get.get.length + } catch { case e: Exception => 0 } + + override def isEmpty: Boolean = + size == 0 + + override def +=(elem: A): Unit = enqueue(elem) + override def ++=(elems: Iterator[A]): Unit = enqueue(elems.toList: _*) + override def ++=(elems: Iterable[A]): Unit = this ++= elems.elements + + override def dequeueFirst(p: A => Boolean): Option[A] = + throw new UnsupportedOperationException("dequeueFirst not supported") + + override def dequeueAll(p: A => Boolean): Seq[A] = + throw new UnsupportedOperationException("dequeueAll not supported") + + private def register = { + if (currentTransaction.get.isEmpty) throw new NoTransactionInScopeException + currentTransaction.get.get.register(uuid, this) + } +} diff --git a/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala b/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala index e616b0599a..94233acd0a 100644 --- a/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala +++ b/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala @@ -34,3 +34,38 @@ trait RefStorageBackend[T] extends StorageBackend { def insertRefStorageFor(name: String, element: T) def getRefStorageFor(name: String): Option[T] } + +// for Queue +trait QueueStorageBackend[T] extends StorageBackend { + // add to the end of the queue + def enqueue(name: String, item: T): Boolean + + // pop from the front of the queue + def dequeue(name: String): Option[T] + + // get the size of the queue + def size(name: String): Int + + // return an array of items currently stored in the queue + // start is the item to begin, count is how many items to return + def peek(name: String, start: Int, count: Int): List[T] + + // completely delete the queue + def remove(name: String): Boolean +} + +trait SortedSetStorageBackend[T] extends StorageBackend { + // add item to sorted set identified by name + def zadd(name: String, zscore: String, item: T): Boolean + + // remove item from sorted set identified by name + def zrem(name: String, item: T): Boolean + + // cardinality of the set idnetified by name + def zcard(name: String): Int + + def zscore(name: String, item: T): String + + def zrange(name: String, start: Int, end: Int): List[T] +} + diff --git a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala index 0eba6dbb62..886245d147 100644 --- a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala +++ b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala @@ -12,18 +12,21 @@ object RedisStorage extends Storage { 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 newQueue: PersistentQueue[ElementType] = newQueue(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 getQueue(id: String): PersistentQueue[ElementType] = newQueue(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) + def newQueue(id: String): PersistentQueue[ElementType] = new RedisPersistentQueue(id) } /** - * Implements a persistent transactional map based on the MongoDB document storage. + * Implements a persistent transactional map based on the Redis storage. * * @author Debasish Ghosh */ @@ -34,7 +37,7 @@ class RedisPersistentMap(id: String) extends PersistentMap[Array[Byte], Array[By /** * Implements a persistent transactional vector based on the Redis - * document storage. + * storage. * * @author Debasish Ghosh */ @@ -47,3 +50,14 @@ class RedisPersistentRef(id: String) extends PersistentRef[Array[Byte]] { val uuid = id val storage = RedisStorageBackend } + +/** + * Implements a persistent transactional queue based on the Redis + * storage. + * + * @author Debasish Ghosh + */ +class RedisPersistentQueue(id: String) extends PersistentQueue[Array[Byte]] { + val uuid = id + val storage = RedisStorageBackend +} diff --git a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala index 802319cfad..00a44d0513 100644 --- a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala +++ b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala @@ -38,6 +38,8 @@ private [akka] object RedisStorageBackend extends MapStorageBackend[Array[Byte], Array[Byte]] with VectorStorageBackend[Array[Byte]] with RefStorageBackend[Array[Byte]] with + QueueStorageBackend[Array[Byte]] with + SortedSetStorageBackend[Array[Byte]] with Logging { val REDIS_SERVER_HOSTNAME = config.getString("akka.storage.redis.hostname", "127.0.0.1") @@ -246,6 +248,91 @@ private [akka] object RedisStorageBackend extends case Some(s) => Some(s.getBytes) } } + + // add to the end of the queue + def enqueue(name: String, item: Array[Byte]): Boolean = { + db.pushTail(new String(encode(name.getBytes)), new String(item)) + } + + // pop from the front of the queue + def dequeue(name: String): Option[Array[Byte]] = { + db.popHead(new String(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(s) => + Some(s.getBytes) + } + } + + // get the size of the queue + def size(name: String): Int = { + db.listLength(new String(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(l) => l + } + } + + // return an array of items currently stored in the queue + // start is the item to begin, count is how many items to return + def peek(name: String, start: Int, count: Int): List[Array[Byte]] = count match { + case 1 => + db.listIndex(new String(encode(name.getBytes)), start) match { + case None => + throw new Predef.NoSuchElementException("No element at " + start) + case Some(s) => + List(s.getBytes) + } + case n => + db.listRange(new String(encode(name.getBytes)), start, start + count - 1) match { + case None => + throw new Predef.NoSuchElementException( + "No element found between " + start + " and " + (start + count - 1)) + case Some(es) => + es.map(_.getBytes) + } + } + + // completely delete the queue + def remove(name: String): Boolean = { + db.delete(new String(encode(name.getBytes))) + } + + // add item to sorted set identified by name + def zadd(name: String, zscore: String, item: Array[Byte]): Boolean = { + db.zAdd(new String(encode(name.getBytes)), zscore, new String(item)) + } + + // remove item from sorted set identified by name + def zrem(name: String, item: Array[Byte]): Boolean = { + db.zRem(new String(encode(name.getBytes)), new String(item)) + } + + // cardinality of the set identified by name + def zcard(name: String): Int = { + db.zCard(new String(encode(name.getBytes))) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(l) => l + } + } + + def zscore(name: String, item: Array[Byte]): String = { + db.zScore(new String(encode(name.getBytes)), new String(item)) match { + case None => + throw new Predef.NoSuchElementException(new String(item) + " not present") + case Some(s) => s + } + } + + def zrange(name: String, start: Int, end: Int): List[Array[Byte]] = { + db.zRange(new String(encode(name.getBytes)), start.toString, end.toString, SocketOperations.ASC, false) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(s) => + s.map(_.getBytes) + } + } def flushDB = db.flushDb } diff --git a/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentQSpec.scala b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentQSpec.scala new file mode 100644 index 0000000000..2adc980aad --- /dev/null +++ b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentQSpec.scala @@ -0,0 +1,133 @@ +package se.scalablesolutions.akka.state + +import junit.framework.TestCase + +import org.junit.{Test, Before} +import org.junit.Assert._ + +import se.scalablesolutions.akka.actor.{Actor, Transactor} + +/** + * A persistent actor based on Redis queue storage. + *

+ * Needs a running Redis server. + * @author Debasish Ghosh + */ + +case class NQ(accountNo: String) +case class DQ +case class MNDQ(accountNos: List[String], noOfDQs: Int, failer: Actor) +case class SZ + +class QueueActor extends Transactor { + private val accounts = RedisStorage.newQueue + + def receive = { + // enqueue + case NQ(accountNo) => + accounts.enqueue(accountNo.getBytes) + reply(true) + + // dequeue + case DQ => + val d = new String(accounts.dequeue) + reply(d) + + // multiple NQ and DQ + case MNDQ(enqs, no, failer) => + accounts.enqueue(enqs.map(_.getBytes): _*) + try { + (1 to no).foreach(e => accounts.dequeue) + } catch { + case e: Exception => + failer !! "Failure" + } + reply(true) + + // size + case SZ => + reply(accounts.size) + } +} + +class RedisPersistentQSpec extends TestCase { + @Test + def testSuccessfulNQ = { + val qa = new QueueActor + qa.start + qa !! NQ("a-123") + qa !! NQ("a-124") + qa !! NQ("a-125") + assertEquals(3, (qa !! SZ).get) + } + + @Test + def testSuccessfulDQ = { + val qa = new QueueActor + qa.start + qa !! NQ("a-123") + qa !! NQ("a-124") + qa !! NQ("a-125") + assertEquals(3, (qa !! SZ).get) + assertEquals("a-123", (qa !! DQ).get) + assertEquals("a-124", (qa !! DQ).get) + assertEquals("a-125", (qa !! DQ).get) + assertEquals(0, (qa !! SZ).get) + } + + @Test + def testSuccessfulMNDQ = { + val qa = new QueueActor + qa.start + val failer = new PersistentFailerActor + failer.start + + qa !! NQ("a-123") + qa !! NQ("a-124") + qa !! NQ("a-125") + assertEquals(3, (qa !! SZ).get) + assertEquals("a-123", (qa !! DQ).get) + assertEquals(2, (qa !! SZ).get) + qa !! MNDQ(List("a-126", "a-127"), 2, failer) + assertEquals(2, (qa !! SZ).get) + } + + @Test + def testMixedMNDQ = { + val qa = new QueueActor + qa.start + val failer = new PersistentFailerActor + failer.start + + // 3 enqueues + qa !! NQ("a-123") + qa !! NQ("a-124") + qa !! NQ("a-125") + + assertEquals(3, (qa !! SZ).get) + + // dequeue 1 + assertEquals("a-123", (qa !! DQ).get) + + // size == 2 + assertEquals(2, (qa !! SZ).get) + + // enqueue 2, dequeue 2 => size == 2 + qa !! MNDQ(List("a-126", "a-127"), 2, failer) + assertEquals(2, (qa !! SZ).get) + + // enqueue 2 => size == 4 + qa !! NQ("a-128") + qa !! NQ("a-129") + assertEquals(4, (qa !! SZ).get) + + // enqueue 1 => size 5 + // dequeue 6 => fail transaction + // size should remain 4 + try { + qa !! MNDQ(List("a-130"), 6, failer) + } catch { case e: Exception => {} } + + assertEquals(4, (qa !! SZ).get) + } +} diff --git a/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala b/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala index cd91d4a591..504a0e114d 100644 --- a/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala +++ b/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala @@ -113,6 +113,59 @@ class RedisStorageBackendSpec extends n.fromBytes(getRefStorageFor("T-4").get) should equal(n) } } + + describe("store and query in queue") { + it("should give proper queue semantics") { + enqueue("T-5", "alan kay".getBytes) + enqueue("T-5", "alan turing".getBytes) + enqueue("T-5", "richard stallman".getBytes) + enqueue("T-5", "yukihiro matsumoto".getBytes) + enqueue("T-5", "claude shannon".getBytes) + enqueue("T-5", "linus torvalds".getBytes) + + RedisStorageBackend.size("T-5") should equal(6) + + new String(dequeue("T-5").get) should equal("alan kay") + new String(dequeue("T-5").get) should equal("alan turing") + + RedisStorageBackend.size("T-5") should equal(4) + + val l = peek("T-5", 0, 3) + l.size should equal(3) + new String(l(0)) should equal("richard stallman") + new String(l(1)) should equal("yukihiro matsumoto") + new String(l(2)) should equal("claude shannon") + } + } + + describe("store and query in sorted set") { + it("should give proper sorted set semantics") { + zadd("hackers", "1965", "yukihiro matsumoto".getBytes) + zadd("hackers", "1953", "richard stallman".getBytes) + zadd("hackers", "1916", "claude shannon".getBytes) + zadd("hackers", "1969", "linus torvalds".getBytes) + zadd("hackers", "1940", "alan kay".getBytes) + zadd("hackers", "1912", "alan turing".getBytes) + + zcard("hackers") should equal(6) + + zscore("hackers", "alan turing".getBytes) should equal("1912") + zscore("hackers", "richard stallman".getBytes) should equal("1953") + zscore("hackers", "claude shannon".getBytes) should equal("1916") + zscore("hackers", "linus torvalds".getBytes) should equal("1969") + + val s: List[Array[Byte]] = zrange("hackers", 0, 2) + s.size should equal(3) + s.map(new String(_)) should equal(List("alan turing", "claude shannon", "alan kay")) + + var sorted: List[String] = + List("alan turing", "claude shannon", "alan kay", "richard stallman", "yukihiro matsumoto", "linus torvalds") + + val t: List[Array[Byte]] = zrange("hackers", 0, -1) + t.size should equal(6) + t.map(new String(_)) should equal(sorted) + } + } } case class Name(id: Int, name: String, address: String) 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 index d4a293effa9c046fd41993742f5b23d8e5fc9c97..ec9c6c8ab44d2552946c18f1ae0daee03f2570c4 100644 GIT binary patch delta 21078 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