rewrote the persistent storage with support for unit-of-work and new multiverse stm

This commit is contained in:
jboner 2009-09-10 01:33:01 +02:00
parent e4a4451533
commit dfc08f559d
21 changed files with 1275 additions and 3835 deletions

View file

@ -1,15 +1,20 @@
This software is licensed under the Apache 2 license, quoted below.
Copyright 2009 Scalable Solutions AB <http://scalablesolutions.se>
Copyright 2009 Scalable Solutions AB [http://scalablesolutions.se]
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
[http://www.apache.org/licenses/LICENSE-2.0]
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
---------------
Licenses for dependency projects can be found here:
[http://wiki.github.com/jboner/akka/licenses]

View file

@ -62,6 +62,11 @@
<artifactId>javautils</artifactId>
<version>2.7.4-0.1</version>
</dependency>
<dependency>
<groupId>org.multiverse</groupId>
<artifactId>multiverse</artifactId>
<version>0.3</version>
</dependency>
<!-- For Protocol/Serialization -->
<dependency>

View file

@ -1,29 +0,0 @@
/**
* Copyright (C) 2009 Scalable Solutions.
*/
package se.scalablesolutions.akka.stm
import state.{Transactional, TransactionalMap}
import util.Helpers.ReadWriteLock
import scala.collection.immutable.HashSet
@serializable
class ChangeSet {
private val lock = new ReadWriteLock
private var transactionalItems: Set[Transactional] = new HashSet
private[akka] def +(item: Transactional) = lock.withWriteLock {
transactionalItems += item
}
private[akka] def items: List[Transactional] = lock.withReadLock {
transactionalItems.toList.asInstanceOf[List[Transactional]]
}
private[akka] def clear = lock.withWriteLock {
transactionalItems = new HashSet
}
// FIXME: add hashCode and equals - VERY IMPORTANT
}

View file

@ -34,6 +34,8 @@
package se.scalablesolutions.akka.collection
trait PersistentDataStructure
/**
* A clean-room port of Rich Hickey's persistent hash trie implementation from
* Clojure (http://clojure.org). Originally presented as a mutable structure in
@ -43,7 +45,7 @@ package se.scalablesolutions.akka.collection
* @author Rich Hickey
*/
@serializable
final class HashTrie[K, +V] private (root: Node[K, V]) extends Map[K, V] {
final class HashTrie[K, +V] private (root: Node[K, V]) extends Map[K, V] with PersistentDataStructure {
lazy val size = root.size
def this() = this(new EmptyNode[K])

View file

@ -12,6 +12,7 @@ import org.multiverse.api.{Transaction => MultiverseTransaction}
import org.multiverse.stms.alpha.AlphaStm
import org.multiverse.utils.GlobalStmInstance
import org.multiverse.utils.TransactionThreadLocal._
import org.multiverse.templates.{OrElseTemplate, AtomicTemplate}
import java.util.concurrent.atomic.AtomicInteger
@ -24,6 +25,33 @@ object Multiverse {
setThreadLocalTransaction(null)
}
/**
* Example of Or-Else transaction management.
* <pre>
* import se.scalablesolutions.akka.stm.{Transaction => Tx}
* Tx.Or {
* .. // try to do something
* } Tx.Else {
* .. // if transaction clashes try do do something else to minimize contention
* }
* </pre>
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
object Transaction {
// -- Monad --------------------------
// -- OrElse --------------------------
def Or[A](orBody: => A) = elseBody(orBody)
def elseBody[A](orBody: => A) = new {
def Else(elseBody: => A) = new OrElseTemplate[A] {
def run(t: MultiverseTransaction) = orBody
def orelserun(t: MultiverseTransaction) = elseBody
}.execute
}
}
/**
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
@ -31,9 +59,7 @@ object Multiverse {
private[this] var _id = 0L
def id = _id
@volatile private[this] var status: TransactionStatus = TransactionStatus.New
private[kernel] var transaction: MultiverseTransaction = _
private[this] val transactionalItems = new ChangeSet
private[akka] var transaction: MultiverseTransaction = _
private[this] var participants: List[String] = Nil
private[this] var precommitted: List[String] = Nil
@ -46,12 +72,11 @@ object Multiverse {
def register(transactional: Transactional) = synchronized {
ensureIsActiveOrNew
transactionalItems + transactional
}
def begin(participant: String) = synchronized {
ensureIsActiveOrNew
transaction = Multiverse.STM.startUpdateTransaction
transaction = Multiverse.STM.startUpdateTransaction("akka")
_id = transaction.getReadVersion
log.debug("Creating a new transaction with id [%s]", _id)
@ -80,7 +105,6 @@ object Multiverse {
} else false
if (haveAllPreCommitted && transaction != null) {
transaction.commit
transactionalItems.items.foreach(_.commit)
status = TransactionStatus.Completed
reset
true
@ -118,7 +142,6 @@ object Multiverse {
def isAborted = status == TransactionStatus.Aborted
private def reset = {
transactionalItems.clear
participants = Nil
precommitted = Nil
}
@ -133,7 +156,7 @@ object Multiverse {
throw new IllegalStateException("Expected ACTIVE or NEW transaction - current status [" + status + "]: " + toString)
// For reinitialize transaction after sending it over the wire
private[kernel] def reinit = synchronized {
private[akka] def reinit = synchronized {
import net.lag.logging.{Logger, Level}
if (log == null) {
log = Logger.get(this.getClass.getName)
@ -155,31 +178,6 @@ object Multiverse {
}
@serializable sealed abstract class TransactionStatus
object TransactionStatus {
case object New extends TransactionStatus

View file

@ -50,7 +50,6 @@ trait TransactionManagement extends Logging {
activeTx = tx
threadBoundTx.set(tx)
setThreadLocalTransaction(tx.get.transaction)
println("------ Start: " + tx.get.transaction)
tx
}

View file

@ -4,6 +4,7 @@
package se.scalablesolutions.akka.state
import org.multiverse.datastructures.refs.manual.Ref
import stm.TransactionManagement
import akka.collection._
@ -17,6 +18,14 @@ import scala.collection.mutable.{ArrayBuffer, HashMap}
* Example Scala usage:
* <pre>
* val myMap = TransactionalState.newMap
* val myVector = TransactionalState.newVector
* val myRef = TransactionalState.newRef
* </pre>
* Or:
* <pre>
* val myMap = TransactionalMap()
* val myVector = TransactionalVector()
* val myRef = TransactionalRef()
* </pre>
*/
object TransactionalState extends TransactionalState
@ -31,9 +40,9 @@ object TransactionalState extends TransactionalState
* </pre>
*/
class TransactionalState {
def newMap[K, V]: TransactionalMap[K, V] = new InMemoryTransactionalMap[K, V]
def newVector[T]: TransactionalVector[T] = new InMemoryTransactionalVector[T]
def newRef[T]: TransactionalRef[T] = new TransactionalRef[T]
def newMap[K, V] = new TransactionalMap[K, V]
def newVector[T] = new TransactionalVector[T]
def newRef[T] = new TransactionalRef[T]
}
/**
@ -43,203 +52,175 @@ class TransactionalState {
trait Transactional {
// FIXME: won't work across the cluster
val uuid = Uuid.newUuid.toString
private[akka] def begin
private[akka] def commit
private[akka] def rollback
protected def verifyTransaction = {
val cflowTx = TransactionManagement.threadBoundTx.get
if (!cflowTx.isDefined) {
throw new IllegalStateException("Can't access transactional reference outside the scope of a transaction [" + this + "]")
} else {
cflowTx.get.register(this)
}
}
}
/**
* Base trait for all state implementations (persistent or in-memory).
*
* FIXME: Create Java versions using pcollections
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
trait TransactionalMap[K, V] extends Transactional with scala.collection.mutable.Map[K, V] {
override def hashCode: Int = System.identityHashCode(this);
override def equals(other: Any): Boolean = false
def remove(key: K)
}
/**
* Not thread-safe, but should only be using from within an Actor, e.g. one single thread at a time.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class InMemoryTransactionalMap[K, V] extends TransactionalMap[K, V] {
protected[akka] var state = new HashTrie[K, V]
protected[akka] var snapshot = state
// ---- For Transactional ----
override def begin = snapshot = state
override def commit = snapshot = state
override def rollback = state = snapshot
// ---- Overriding scala.collection.mutable.Map behavior ----
override def contains(key: K): Boolean = {
verifyTransaction
state.contains(key)
}
override def clear = {
verifyTransaction
state = new HashTrie[K, V]
}
override def size: Int = {
verifyTransaction
state.size
}
// ---- For scala.collection.mutable.Map ----
override def remove(key: K) = {
verifyTransaction
state = state - key
}
override def elements: Iterator[(K, V)] = {
// verifyTransaction
state.elements
}
override def get(key: K): Option[V] = {
verifyTransaction
state.get(key)
}
override def put(key: K, value: V): Option[V] = {
verifyTransaction
val oldValue = state.get(key)
state = state.update(key, value)
oldValue
}
override def -=(key: K) = {
verifyTransaction
remove(key)
}
override def update(key: K, value: V) = {
verifyTransaction
put(key, value)
}
}
/**
* Base for all transactional vector implementations.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
abstract class TransactionalVector[T] extends Transactional with RandomAccessSeq[T] {
override def hashCode: Int = System.identityHashCode(this);
override def equals(other: Any): Boolean = false
def add(elem: T)
def get(index: Int): T
def getRange(start: Int, count: Int): List[T]
}
/**
* Implements an in-memory transactional vector.
*
* Not thread-safe, but should only be using from within an Actor, e.g. one single thread at a time.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class InMemoryTransactionalVector[T] extends TransactionalVector[T] {
private[akka] var state: Vector[T] = EmptyVector
private[akka] var snapshot = state
def add(elem: T) = {
verifyTransaction
state = state + elem
}
def get(index: Int): T = {
verifyTransaction
state(index)
}
def getRange(start: Int, count: Int): List[T] = {
verifyTransaction
state.slice(start, count).toList.asInstanceOf[List[T]]
}
// ---- For Transactional ----
override def begin = snapshot = state
override def commit = snapshot = state
override def rollback = state = snapshot
// ---- For Seq ----
def length: Int = {
verifyTransaction
state.length
}
def apply(index: Int): T = {
verifyTransaction
state(index)
}
override def elements: Iterator[T] = {
//verifyTransaction
state.elements
}
override def toList: List[T] = {
verifyTransaction
state.toList
}
}
/**
* Implements a transactional reference.
*
* Not thread-safe, but should only be using from within an Actor, e.g. one single thread at a time.
* Implements a transactional managed reference.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class TransactionalRef[T] extends Transactional {
private[akka] var ref: Option[T] = None
private[akka] var snapshot: Option[T] = None
protected[this] var ref: Option[Ref[T]] = None
override def begin = if (ref.isDefined) snapshot = Some(ref.get)
override def commit = if (ref.isDefined) snapshot = Some(ref.get)
override def rollback = if (snapshot.isDefined) ref = Some(snapshot.get)
def set(elem: T) = swap(elem)
def swap(elem: T) = {
verifyTransaction
ref = Some(elem)
synchronized { if (ref.isEmpty) ref = Some(new Ref[T]) }
ref.get.set(elem)
}
def get: Option[T] =
if (isEmpty) None
else Some(ref.get.get)
def getOrWait: T = {
synchronized { if (ref.isEmpty) ref = Some(new Ref[T]) }
ref.get.getOrAwait
}
def getOrElse(default: => T): T =
if (isEmpty) default
else ref.get.get
def isDefined: Boolean = ref.isDefined && !ref.get.isNull
def isEmpty: Boolean = !isDefined
}
object TransactionalRef {
def apply[T](elem: T) = {
if (elem == null) throw new IllegalArgumentException("Can't define TransactionalRef with a null initial value, needs to be a PersistentDataStructure")
val ref = new TransactionalRef[T]
ref.swap(elem)
ref
}
}
/**
* Implements an in-memory transactional Map based on Clojure's PersistentMap.
*
* Not thread-safe, but should only be using from within an Actor, e.g. one single thread at a time.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class TransactionalMap[K, V] extends Transactional with scala.collection.mutable.Map[K, V] {
protected[this] val ref = TransactionalRef[HashTrie[K, V]](new HashTrie[K, V])
def -=(key: K) = remove(key)
def +=(key: K, value: V) = put(key, value)
def remove(key: K) = ref.swap(ref.get.get - key)
def apply(key: K): Option[V] = get(key)
def get(key: K): Option[V] = ref.get.get.get(key)
override def put(key: K, value: V): Option[V] = {
val map = ref.get.get
val oldValue = map.get(key)
ref.swap(map.update(key, value))
oldValue
}
def update(key: K, value: V) = {
val map = ref.get.get
val oldValue = map.get(key)
ref.swap(map.update(key, value))
}
def elements: Iterator[(K, V)] = ref.get.get.elements
override def contains(key: K): Boolean = ref.get.get.contains(key)
override def clear = ref.swap(new HashTrie[K, V])
def size: Int = ref.get.get.size
override def hashCode: Int = System.identityHashCode(this);
override def equals(other: Any): Boolean =
other.isInstanceOf[TransactionalMap[_, _]] &&
other.hashCode == hashCode
}
object TransactionalMap {
def apply[T]() = new TransactionalMap
}
/**
* Implements an in-memory transactional Vector based on Clojure's PersistentVector.
*
* Not thread-safe, but should only be using from within an Actor, e.g. one single thread at a time.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class TransactionalVector[T] extends Transactional with RandomAccessSeq[T] {
private[this] val ref = TransactionalRef[Vector[T]](EmptyVector)
def clear = ref.swap(EmptyVector)
def +(elem: T) = add(elem)
def add(elem: T) = ref.swap(ref.get.get + elem)
def get(index: Int): T = ref.get.get.apply(index)
/**
* Removes the <i>tail</i> element of this vector.
*/
def pop = ref.swap(ref.get.get.pop)
def update(index: Int, elem: T) = ref.swap(ref.get.get.update(index, elem))
def length: Int = ref.get.get.length
def apply(index: Int): T = ref.get.get.apply(index)
override def hashCode: Int = System.identityHashCode(this);
override def equals(other: Any): Boolean =
other.isInstanceOf[TransactionalVector[_]] &&
other.hashCode == hashCode
}
object TransactionalVector {
def apply[T]() = new TransactionalVector
}
/*
class TransactionalRef[T] private(elem: T) extends Transactional {
private[this] val ref = new Ref[T](elem)
def swap(elem: T) = {
println("----- setting ref: " + ref)
println("----- setting in thread: " + Thread.currentThread)
ref.set(elem)
}
def get: Option[T] = {
verifyTransaction
ref
if (ref.isNull) None
else Some(ref.get)
}
def getOrWait: T = ref.getOrAwait
def getOrElse(default: => T): T = {
verifyTransaction
ref.getOrElse(default)
if (ref.isNull) default
else ref.get
}
def isDefined: Boolean = {
verifyTransaction
ref.isDefined
def isDefined: Boolean = !ref.isNull
def isEmpty: Boolean = ref.isNull
}
object TransactionalRef {
def apply[T](elem: T) = {
if (elem == null) throw new IllegalArgumentException("Can't define TransactionalRef with a null initial value")
new TransactionalRef[T](elem)
}
}
*/

View file

@ -43,7 +43,8 @@ import Vector._
* @author Rich Hickey
*/
@serializable
class Vector[+T] private (val length: Int, shift: Int, root: Array[AnyRef], tail: Array[AnyRef]) extends RandomAccessSeq[T] { outer =>
class Vector[+T] private (val length: Int, shift: Int, root: Array[AnyRef], tail: Array[AnyRef])
extends RandomAccessSeq[T] with PersistentDataStructure { outer =>
private val tailOff = length - tail.length
/*

View file

@ -26,6 +26,7 @@ case class FailureOneWay(key: String, value: String, failer: Actor)
class InMemStatefulActor extends Actor {
timeout = 100000
makeTransactionRequired
//dispatcher = se.scalablesolutions.akka.reactor.Dispatchers.newThreadBasedDispatcher(this)
private val mapState = TransactionalState.newMap[String, String]
private val vectorState = TransactionalState.newVector[String]
private val refState = TransactionalState.newRef[String]
@ -86,7 +87,7 @@ class InMemFailerActor extends Actor {
}
class InMemoryActorSpec extends TestCase {
/*
@Test
def testOneWayMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
val stateful = new InMemStatefulActor
@ -213,7 +214,7 @@ class InMemoryActorSpec extends TestCase {
Thread.sleep(100)
assertEquals("init", (stateful !! GetRefState).get) // check that state is == init state
}
*/
@Test
def testRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
val stateful = new InMemStatefulActor

View file

@ -95,15 +95,14 @@
<version>2.7.4-0.1</version>
</dependency>
<dependency>
<<<<<<< HEAD:kernel/pom.xml
<groupId>org.multiverse</groupId>
<artifactId>multiverse</artifactId>
<version>0.3</version>
=======
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>rabbitmq-client</artifactId>
<version>0.9.1</version>
>>>>>>> master:akka-kernel/pom.xml
</dependency>
<!-- For Protocol/Serialization -->

View file

@ -9,11 +9,14 @@ import java.io.{Flushable, Closeable}
import util.Logging
import util.Helpers._
import serialization.Serializer
import akka.Config.config
import Config.config
import org.apache.cassandra.db.ColumnFamily
import org.apache.cassandra.service._
import org.apache.commons.pool._
import org.apache.commons.pool.impl._
import org.apache.thrift.transport._
import org.apache.thrift.protocol._
@ -238,3 +241,89 @@ object Protocol {
object SimpleJSON extends Protocol(new TSimpleJSONProtocol.Factory)
object JSON extends Protocol(new TJSONProtocol.Factory)
}
trait Pool[T] extends java.io.Closeable {
def borrowObject: T
def returnObject(t: T): Unit
def invalidateObject(t: T): Unit
def addObject: Unit
def getNumIdle: Int
def getNumActive: Int
def clear: Unit
def setFactory(factory: PoolItemFactory[T]): Unit
}
trait PoolFactory[T] {
def createPool: Pool[T]
}
trait PoolItemFactory[T] {
def makeObject: T
def destroyObject(t: T): Unit
def validateObject(t: T): Boolean
def activateObject(t: T): Unit
def passivateObject(t: T): Unit
}
trait PoolBridge[T, OP <: ObjectPool] extends Pool[T] {
val impl: OP
override def borrowObject: T = impl.borrowObject.asInstanceOf[T]
override def returnObject(t: T) = impl.returnObject(t)
override def invalidateObject(t: T) = impl.invalidateObject(t)
override def addObject = impl.addObject
override def getNumIdle: Int = impl.getNumIdle
override def getNumActive: Int = impl.getNumActive
override def clear: Unit = impl.clear
override def close: Unit = impl.close
override def setFactory(factory: PoolItemFactory[T]) = impl.setFactory(toPoolableObjectFactory(factory))
def toPoolableObjectFactory[T](pif: PoolItemFactory[T]) = new PoolableObjectFactory {
def makeObject: Object = pif.makeObject.asInstanceOf[Object]
def destroyObject(o: Object): Unit = pif.destroyObject(o.asInstanceOf[T])
def validateObject(o: Object): Boolean = pif.validateObject(o.asInstanceOf[T])
def activateObject(o: Object): Unit = pif.activateObject(o.asInstanceOf[T])
def passivateObject(o: Object): Unit = pif.passivateObject(o.asInstanceOf[T])
}
}
object StackPool {
def apply[T](factory: PoolItemFactory[T]) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory))
}
def apply[T](factory: PoolItemFactory[T], maxIdle: Int) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory),maxIdle)
}
def apply[T](factory: PoolItemFactory[T], maxIdle: Int, initIdleCapacity: Int) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory),maxIdle,initIdleCapacity)
}
}
object SoftRefPool {
def apply[T](factory: PoolItemFactory[T]) = new PoolBridge[T,SoftReferenceObjectPool] {
val impl = new SoftReferenceObjectPool(toPoolableObjectFactory(factory))
}
def apply[T](factory: PoolItemFactory[T], initSize: Int) = new PoolBridge[T,SoftReferenceObjectPool] {
val impl = new SoftReferenceObjectPool(toPoolableObjectFactory(factory),initSize)
}
}
trait TransportFactory[T <: TTransport] extends PoolItemFactory[T] {
def createTransport: T
def makeObject: T = createTransport
def destroyObject(transport: T): Unit = transport.close
def validateObject(transport: T) = transport.isOpen
def activateObject(transport: T): Unit = if( !transport.isOpen ) transport.open else ()
def passivateObject(transport: T): Unit = transport.flush
}
case class SocketProvider(val host: String, val port: Int) extends TransportFactory[TSocket] {
def createTransport = {
val t = new TSocket(host, port)
t.open
t
}
}

View file

@ -17,6 +17,8 @@ import org.apache.cassandra.service._
import org.apache.thrift.transport._
import org.apache.thrift.protocol._
import scala.collection.mutable.ArrayBuffer
/**
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
@ -62,11 +64,12 @@ object CassandraStorage extends MapStorage
StackPool(SocketProvider(CASSANDRA_SERVER_HOSTNAME, CASSANDRA_SERVER_PORT)),
protocol,
CONSISTENCY_LEVEL)
// ===============================================================
// For Ref
// ===============================================================
override def insertRefStorageFor(name: String, element: AnyRef) = {
def insertRefStorageFor(name: String, element: AnyRef) = {
sessions.withSession {
_ ++| (name,
new ColumnPath(REF_COLUMN_PARENT.getColumn_family, null, REF_KEY),
@ -76,7 +79,7 @@ object CassandraStorage extends MapStorage
}
}
override def getRefStorageFor(name: String): Option[AnyRef] = {
def getRefStorageFor(name: String): Option[AnyRef] = {
try {
val column: Option[Column] = sessions.withSession {
_ | (name, new ColumnPath(REF_COLUMN_PARENT.getColumn_family, null, REF_KEY))
@ -94,7 +97,7 @@ object CassandraStorage extends MapStorage
// For Vector
// ===============================================================
override def insertVectorStorageEntryFor(name: String, element: AnyRef) = {
def insertVectorStorageEntryFor(name: String, element: AnyRef) = {
sessions.withSession {
_ ++| (name,
new ColumnPath(VECTOR_COLUMN_PARENT.getColumn_family, null, intToBytes(getVectorStorageSizeFor(name))),
@ -104,10 +107,20 @@ object CassandraStorage extends MapStorage
}
}
override def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef]) = {
def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef]) = {
}
override def getVectorStorageEntryFor(name: String, index: Int): AnyRef = {
def updateVectorStorageEntryFor(name: String, index: Int, elem: AnyRef) = {
sessions.withSession {
_ ++| (name,
new ColumnPath(VECTOR_COLUMN_PARENT.getColumn_family, null, intToBytes(index)),
serializer.out(elem),
System.currentTimeMillis,
CONSISTENCY_LEVEL)
}
}
def getVectorStorageEntryFor(name: String, index: Int): AnyRef = {
val column: Option[Column] = sessions.withSession {
_ | (name, new ColumnPath(VECTOR_COLUMN_PARENT.getColumn_family, null, intToBytes(index)))
}
@ -115,7 +128,7 @@ object CassandraStorage extends MapStorage
else throw new NoSuchElementException("No element for vector [" + name + "] and index [" + index + "]")
}
override def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): List[AnyRef] = {
def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): RandomAccessSeq[AnyRef] = {
val startBytes = if (start.isDefined) intToBytes(start.get) else null
val finishBytes = if (finish.isDefined) intToBytes(finish.get) else null
val columns: List[Column] = sessions.withSession {
@ -126,10 +139,12 @@ object CassandraStorage extends MapStorage
count,
CONSISTENCY_LEVEL)
}
columns.map(column => serializer.in(column.value, None))
val buffer = new ArrayBuffer[AnyRef]
for (elem <- columns.map(column => serializer.in(column.value, None))) buffer.append(elem)
buffer
}
override def getVectorStorageSizeFor(name: String): Int = {
def getVectorStorageSizeFor(name: String): Int = {
sessions.withSession {
_ |# (name, VECTOR_COLUMN_PARENT)
}
@ -139,7 +154,7 @@ object CassandraStorage extends MapStorage
// For Map
// ===============================================================
override def insertMapStorageEntryFor(name: String, key: AnyRef, element: AnyRef) = {
def insertMapStorageEntryFor(name: String, key: AnyRef, element: AnyRef) = {
sessions.withSession {
_ ++| (name,
new ColumnPath(MAP_COLUMN_PARENT.getColumn_family, null, serializer.out(key)),
@ -149,7 +164,7 @@ object CassandraStorage extends MapStorage
}
}
override def insertMapStorageEntriesFor(name: String, entries: List[Tuple2[AnyRef, AnyRef]]) = {
def insertMapStorageEntriesFor(name: String, entries: List[Tuple2[AnyRef, AnyRef]]) = {
val cf2columns: java.util.Map[String, java.util.List[Column]] = new java.util.HashMap
for (entry <- entries) {
val columns: java.util.List[Column] = new java.util.ArrayList
@ -161,7 +176,7 @@ object CassandraStorage extends MapStorage
}
}
override def getMapStorageEntryFor(name: String, key: AnyRef): Option[AnyRef] = {
def getMapStorageEntryFor(name: String, key: AnyRef): Option[AnyRef] = {
try {
val column: Option[Column] = sessions.withSession {
_ | (name, new ColumnPath(MAP_COLUMN_PARENT.getColumn_family, null, serializer.out(key)))
@ -175,7 +190,7 @@ object CassandraStorage extends MapStorage
}
}
override def getMapStorageFor(name: String): List[Tuple2[AnyRef, AnyRef]] = {
def getMapStorageFor(name: String): List[Tuple2[AnyRef, AnyRef]] = {
throw new UnsupportedOperationException
/*
val columns = server.get_columns_since(name, MAP_COLUMN_FAMILY, -1)
@ -187,15 +202,15 @@ object CassandraStorage extends MapStorage
*/
}
override def getMapStorageSizeFor(name: String): Int = {
def getMapStorageSizeFor(name: String): Int = {
sessions.withSession {
_ |# (name, MAP_COLUMN_PARENT)
}
}
override def removeMapStorageFor(name: String): Unit = removeMapStorageFor(name, null)
def removeMapStorageFor(name: String): Unit = removeMapStorageFor(name, null)
override def removeMapStorageFor(name: String, key: AnyRef): Unit = {
def removeMapStorageFor(name: String, key: AnyRef): Unit = {
val keyBytes = if (key == null) null else serializer.out(key)
sessions.withSession {
_ -- (name,
@ -205,7 +220,7 @@ object CassandraStorage extends MapStorage
}
}
override def getMapStorageRangeFor(name: String, start: Option[AnyRef], finish: Option[AnyRef], count: Int):
def getMapStorageRangeFor(name: String, start: Option[AnyRef], finish: Option[AnyRef], count: Int):
List[Tuple2[AnyRef, AnyRef]] = {
val startBytes = if (start.isDefined) serializer.out(start.get) else null
val finishBytes = if (finish.isDefined) serializer.out(finish.get) else null

View file

@ -1,12 +1,18 @@
/**
* Copyright (C) 2009 Scalable Solutions.
*/
package se.scalablesolutions.akka.state
import akka.util.Logging
import serialization.{Serializer}
import akka.Config.config
import Config.config
import sjson.json.Serializer._
import com.mongodb._
import scala.collection.mutable.ArrayBuffer
import java.util.{Map=>JMap, List=>JList, ArrayList=>JArrayList}
/**
@ -47,19 +53,17 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
// FIXME: make this pluggable
private[this] val serializer = SJSON
override def insertMapStorageEntryFor(name: String,
def insertMapStorageEntryFor(name: String,
key: AnyRef, value: AnyRef) {
insertMapStorageEntriesFor(name, List((key, value)))
}
override def insertMapStorageEntriesFor(name: String,
def insertMapStorageEntriesFor(name: String,
entries: List[Tuple2[AnyRef, AnyRef]]) {
import java.util.{Map, HashMap}
val m: Map[AnyRef, AnyRef] = new HashMap
for ((k, v) <- entries) {
m.put(k, serializer.out(v))
}
for ((k, v) <- entries) m.put(k, serializer.out(v))
nullSafeFindOne(name) match {
case None =>
@ -77,13 +81,13 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
}
}
override def removeMapStorageFor(name: String) = {
def removeMapStorageFor(name: String) = {
val q = new BasicDBObject
q.put(KEY, name)
coll.remove(q)
}
override def removeMapStorageFor(name: String, key: AnyRef) = {
def removeMapStorageFor(name: String, key: AnyRef) = {
nullSafeFindOne(name) match {
case None =>
case Some(dbo) => {
@ -98,12 +102,11 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
}
}
override def getMapStorageEntryFor(name: String,
key: AnyRef): Option[AnyRef] = {
def getMapStorageEntryFor(name: String, key: AnyRef): Option[AnyRef] = {
getValueForKey(name, key.asInstanceOf[String])
}
override def getMapStorageSizeFor(name: String): Int = {
def getMapStorageSizeFor(name: String): Int = {
nullSafeFindOne(name) match {
case None => 0
case Some(dbo) =>
@ -111,27 +114,22 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
}
}
override def getMapStorageFor(name: String): List[Tuple2[AnyRef, AnyRef]] = {
val m =
nullSafeFindOne(name) match {
def getMapStorageFor(name: String): List[Tuple2[AnyRef, AnyRef]] = {
val m = nullSafeFindOne(name) match {
case None =>
throw new Predef.NoSuchElementException(name + " not present")
case Some(dbo) =>
dbo.get(VALUE).asInstanceOf[JMap[String, AnyRef]]
}
val n =
List(m.keySet.toArray: _*).asInstanceOf[List[String]]
val vals =
for(s <- n)
yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
val n = List(m.keySet.toArray: _*).asInstanceOf[List[String]]
val vals = for(s <- n) yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
vals.asInstanceOf[List[Tuple2[String, AnyRef]]]
}
override def getMapStorageRangeFor(name: String, start: Option[AnyRef],
def getMapStorageRangeFor(name: String, start: Option[AnyRef],
finish: Option[AnyRef],
count: Int): List[Tuple2[AnyRef, AnyRef]] = {
val m =
nullSafeFindOne(name) match {
val m = nullSafeFindOne(name) match {
case None =>
throw new Predef.NoSuchElementException(name + " not present")
case Some(dbo) =>
@ -151,11 +149,8 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
}
else count
val n =
List(m.keySet.toArray: _*).asInstanceOf[List[String]].sort((e1, e2) => (e1 compareTo e2) < 0).slice(s, s + cnt)
val vals =
for(s <- n)
yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
val n = List(m.keySet.toArray: _*).asInstanceOf[List[String]].sort((e1, e2) => (e1 compareTo e2) < 0).slice(s, s + cnt)
val vals = for(s <- n) yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
vals.asInstanceOf[List[Tuple2[String, AnyRef]]]
}
@ -164,18 +159,16 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
nullSafeFindOne(name) match {
case None => None
case Some(dbo) =>
Some(serializer.in[AnyRef](
dbo.get(VALUE)
.asInstanceOf[JMap[String, AnyRef]]
.get(key).asInstanceOf[Array[Byte]]))
Some(serializer.in[AnyRef](dbo.get(VALUE).asInstanceOf[JMap[String, AnyRef]].get(key).asInstanceOf[Array[Byte]]))
}
} catch {
case e =>
throw new Predef.NoSuchElementException(e.getMessage)
case e => throw new Predef.NoSuchElementException(e.getMessage)
}
}
override def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef]) = {
def updateVectorStorageEntryFor(name: String, index: Int, elem: AnyRef) = throw new UnsupportedOperationException("The updateVectorStorageEntryFor method is not yet implemented for MongoDB")
def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef]) = {
val q = new BasicDBObject
q.put(KEY, name)
@ -194,61 +187,45 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
// add to the current list
elements.map(serializer.out(_)).foreach(currentList.add(_))
coll.insert(
new BasicDBObject()
.append(KEY, name)
.append(VALUE, currentList)
)
coll.insert(new BasicDBObject().append(KEY, name).append(VALUE, currentList))
}
override def insertVectorStorageEntryFor(name: String, element: AnyRef) = {
insertVectorStorageEntriesFor(name, List(element))
}
def insertVectorStorageEntryFor(name: String, element: AnyRef) = insertVectorStorageEntriesFor(name, List(element))
override def getVectorStorageEntryFor(name: String, index: Int): AnyRef = {
def getVectorStorageEntryFor(name: String, index: Int): AnyRef = {
try {
val o =
nullSafeFindOne(name) match {
val o = nullSafeFindOne(name) match {
case None =>
throw new Predef.NoSuchElementException(name + " not present")
case Some(dbo) =>
dbo.get(VALUE).asInstanceOf[JList[AnyRef]]
}
serializer.in[AnyRef](
o.get(index).asInstanceOf[Array[Byte]])
serializer.in[AnyRef](o.get(index).asInstanceOf[Array[Byte]])
} catch {
case e =>
throw new Predef.NoSuchElementException(e.getMessage)
case e => throw new Predef.NoSuchElementException(e.getMessage)
}
}
override def getVectorStorageRangeFor(name: String,
start: Option[Int], finish: Option[Int], count: Int): List[AnyRef] = {
def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): RandomAccessSeq[AnyRef] = {
try {
val o =
nullSafeFindOne(name) match {
val o = nullSafeFindOne(name) match {
case None =>
throw new Predef.NoSuchElementException(name + " not present")
case Some(dbo) =>
dbo.get(VALUE).asInstanceOf[JList[AnyRef]]
}
// pick the subrange and make a Scala list
val l =
List(o.subList(start.get, start.get + count).toArray: _*)
for(e <- l)
yield serializer.in[AnyRef](e.asInstanceOf[Array[Byte]])
val l = List(o.subList(start.get, start.get + count).toArray: _*)
val buffer = new ArrayBuffer[AnyRef]
for (elem <- l.map(e => serializer.in[AnyRef](e.asInstanceOf[Array[Byte]]))) buffer.append(elem)
buffer
} catch {
case e =>
throw new Predef.NoSuchElementException(e.getMessage)
case e => throw new Predef.NoSuchElementException(e.getMessage)
}
}
override def getVectorStorageSizeFor(name: String): Int = {
def getVectorStorageSizeFor(name: String): Int = {
nullSafeFindOne(name) match {
case None => 0
case Some(dbo) =>
@ -262,7 +239,7 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
coll.findOneNS(o)
}
override def insertRefStorageFor(name: String, element: AnyRef) = {
def insertRefStorageFor(name: String, element: AnyRef) = {
nullSafeFindOne(name) match {
case None =>
case Some(dbo) => {
@ -271,13 +248,10 @@ object MongoStorage extends MapStorage with VectorStorage with RefStorage with L
coll.remove(q)
}
}
coll.insert(
new BasicDBObject()
.append(KEY, name)
.append(VALUE, serializer.out(element)))
coll.insert(new BasicDBObject().append(KEY, name).append(VALUE, serializer.out(element)))
}
override def getRefStorageFor(name: String): Option[AnyRef] = {
def getRefStorageFor(name: String): Option[AnyRef] = {
nullSafeFindOne(name) match {
case None => None
case Some(dbo) =>

View file

@ -38,23 +38,23 @@ object PersistentState extends PersistentState
* </pre>
*/
class PersistentState {
def newMap(config: PersistentStorageConfig): TransactionalMap[AnyRef, AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentTransactionalMap
case MongoStorageConfig() => new MongoPersistentTransactionalMap
def newMap(config: PersistentStorageConfig): PersistentMap[AnyRef, AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentMap
case MongoStorageConfig() => new MongoPersistentMap
case TerracottaStorageConfig() => throw new UnsupportedOperationException
case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException
}
def newVector(config: PersistentStorageConfig): TransactionalVector[AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentTransactionalVector
case MongoStorageConfig() => new MongoPersistentTransactionalVector
def newVector(config: PersistentStorageConfig): PersistentVector[AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentVector
case MongoStorageConfig() => new MongoPersistentVector
case TerracottaStorageConfig() => throw new UnsupportedOperationException
case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException
}
def newRef(config: PersistentStorageConfig): TransactionalRef[AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentTransactionalRef
case MongoStorageConfig() => new MongoPersistentTransactionalRef
def newRef(config: PersistentStorageConfig): PersistentRef[AnyRef] = config match {
case CassandraStorageConfig() => new CassandraPersistentRef
case MongoStorageConfig() => new MongoPersistentRef
case TerracottaStorageConfig() => throw new UnsupportedOperationException
case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException
}
@ -68,32 +68,10 @@ class PersistentState {
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] {
// FIXME: need to handle remove in another changeSet
protected[akka] val changeSet = new HashMap[K, V]
def getRange(start: Option[AnyRef], count: Int)
// ---- For Transactional ----
override def begin = {}
override def rollback = changeSet.clear
// ---- For scala.collection.mutable.Map ----
override def put(key: K, value: V): Option[V] = {
verifyTransaction
changeSet += key -> value
None // always return None to speed up writes (else need to go to DB to get
}
override def -=(key: K) = remove(key)
override def update(key: K, value: V) = put(key, value)
}
trait PersistentMap[K, V] extends Transactional with scala.collection.mutable.Map[K, V]
/**
* Implementation of <tt>PersistentTransactionalMap</tt> for every concrete
* Implementation of <tt>PersistentMap</tt> for every concrete
* storage will have the same workflow. This abstracts the workflow.
*
* Subclasses just need to provide the actual concrete instance for the
@ -101,86 +79,65 @@ abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] {
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
abstract class TemplatePersistentTransactionalMap extends PersistentTransactionalMap[AnyRef, AnyRef] {
trait TemplatePersistentMap extends PersistentMap[AnyRef, AnyRef] {
protected val newAndUpdatedEntries = TransactionalState.newMap[AnyRef, AnyRef]
protected val removedEntries = TransactionalState.newMap[AnyRef, AnyRef]
protected val shouldClearOnCommit = TransactionalRef[Boolean](false)
// to be concretized in subclasses
val storage: MapStorage
override def remove(key: AnyRef) = {
verifyTransaction
if (changeSet.contains(key)) changeSet -= key
else storage.removeMapStorageFor(uuid, key)
def commit = {
storage.removeMapStorageFor(uuid, removedEntries.toList)
storage.insertMapStorageEntriesFor(uuid, newAndUpdatedEntries.toList)
if (shouldClearOnCommit.isDefined & shouldClearOnCommit.get.get) storage.removeMapStorageFor(uuid)
newAndUpdatedEntries.clear
removedEntries.clear
}
override def getRange(start: Option[AnyRef], count: Int) =
getRange(start, None, count)
def -=(key: AnyRef) = remove(key)
def getRange(start: Option[AnyRef], finish: Option[AnyRef], count: Int) = {
verifyTransaction
try {
def +=(key: AnyRef, value: AnyRef) = put(key, value)
override def put(key: AnyRef, value: AnyRef): Option[AnyRef] = newAndUpdatedEntries.put(key, value)
override def update(key: AnyRef, value: AnyRef) = newAndUpdatedEntries.update(key, value)
def remove(key: AnyRef) = removedEntries.remove(key)
def slice(start: Option[AnyRef], count: Int): List[Tuple2[AnyRef, AnyRef]] = slice(start, None, count)
def slice(start: Option[AnyRef], finish: Option[AnyRef], count: Int): List[Tuple2[AnyRef, AnyRef]] = try {
storage.getMapStorageRangeFor(uuid, start, finish, count)
} catch {
case e: Exception => Nil
}
}
} catch { case e: Exception => Nil }
// ---- For Transactional ----
override def commit = {
storage.insertMapStorageEntriesFor(uuid, changeSet.toList)
changeSet.clear
}
override def clear = shouldClearOnCommit.swap(true)
// ---- Overriding scala.collection.mutable.Map behavior ----
override def clear = {
verifyTransaction
try {
storage.removeMapStorageFor(uuid)
} catch {
case e: Exception => {}
}
}
override def contains(key: AnyRef): Boolean = {
try {
verifyTransaction
override def contains(key: AnyRef): Boolean = try {
newAndUpdatedEntries.contains(key) ||
storage.getMapStorageEntryFor(uuid, key).isDefined
} catch {
case e: Exception => false
}
}
} catch { case e: Exception => false }
override def size: Int = {
verifyTransaction
try {
storage.getMapStorageSizeFor(uuid)
} catch {
case e: Exception => 0
}
}
override def size: Int = try {
storage.getMapStorageSizeFor(uuid) + newAndUpdatedEntries.size
} catch { case e: Exception => 0 }
// ---- For scala.collection.mutable.Map ----
override def get(key: AnyRef): Option[AnyRef] = {
verifyTransaction
// if (changeSet.contains(key)) changeSet.get(key)
// else {
val result = try {
if (newAndUpdatedEntries.contains(key)) newAndUpdatedEntries.get(key)
else try {
storage.getMapStorageEntryFor(uuid, key)
} catch {
case e: Exception => None
}
result
//}
} catch { case e: Exception => None }
}
override def elements: Iterator[Tuple2[AnyRef, AnyRef]] = {
//verifyTransaction
new Iterator[Tuple2[AnyRef, AnyRef]] {
private val originalList: List[Tuple2[AnyRef, AnyRef]] = try {
storage.getMapStorageFor(uuid)
} catch {
case e: Throwable => Nil
}
private var elements = originalList.reverse
// FIXME how to deal with updated entries, these should be replaced in the originalList not just added
private var elements = newAndUpdatedEntries.toList ::: originalList.reverse
override def next: Tuple2[AnyRef, AnyRef]= synchronized {
val element = elements.head
elements = elements.tail
@ -197,7 +154,7 @@ abstract class TemplatePersistentTransactionalMap extends PersistentTransactiona
*
* @author <a href="http://debasishg.blogspot.com">Debasish Ghosh</a>
*/
class CassandraPersistentTransactionalMap extends TemplatePersistentTransactionalMap {
class CassandraPersistentMap extends TemplatePersistentMap {
val storage = CassandraStorage
}
@ -206,7 +163,7 @@ class CassandraPersistentTransactionalMap extends TemplatePersistentTransactiona
*
* @author <a href="http://debasishg.blogspot.com">Debasish Ghosh</a>
*/
class MongoPersistentTransactionalMap extends TemplatePersistentTransactionalMap {
class MongoPersistentMap extends TemplatePersistentMap {
val storage = MongoStorage
}
@ -218,69 +175,62 @@ class MongoPersistentTransactionalMap extends TemplatePersistentTransactionalMap
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
abstract class PersistentTransactionalVector[T] extends TransactionalVector[T] {
// FIXME: need to handle remove in another changeSet
protected[akka] val changeSet = new ArrayBuffer[T]
// ---- For Transactional ----
override def begin = {}
override def rollback = changeSet.clear
// ---- For TransactionalVector ----
override def add(value: T) = {
verifyTransaction
changeSet += value
}
}
trait PersistentVector[T] extends Transactional with RandomAccessSeq[T]
/**
* Implements a template for a concrete persistent transactional vector based storage.
*
* @author <a href="http://debasishg.blogspot.com">Debasish Ghosh</a>
*/
abstract class TemplatePersistentTransactionalVector extends PersistentTransactionalVector[AnyRef] {
trait TemplatePersistentVector extends PersistentVector[AnyRef] {
protected val newElems = TransactionalState.newVector[AnyRef]
protected val updatedElems = TransactionalState.newMap[Int, AnyRef]
protected val removedElems = TransactionalState.newVector[AnyRef]
protected val shouldClearOnCommit = TransactionalRef[Boolean](false)
val storage: VectorStorage
// ---- For TransactionalVector ----
override def get(index: Int): AnyRef = {
verifyTransaction
if (changeSet.size > index) changeSet(index)
def commit = {
// FIXME: should use batch function once the bug is resolved
for (element <- newElems) storage.insertVectorStorageEntryFor(uuid, element)
for (entry <- updatedElems) storage.updateVectorStorageEntryFor(uuid, entry._1, entry._2)
newElems.clear
updatedElems.clear
}
def apply(index: Int): AnyRef = get(index)
def get(index: Int): AnyRef = {
if (newElems.size > index) newElems(index)
else storage.getVectorStorageEntryFor(uuid, index)
}
override def getRange(start: Int, count: Int): List[AnyRef] =
getRange(Some(start), None, count)
override def slice(start: Int, count: Int): RandomAccessSeq[AnyRef] = slice(Some(start), None, count)
def getRange(start: Option[Int], finish: Option[Int], count: Int): List[AnyRef] = {
verifyTransaction
def slice(start: Option[Int], finish: Option[Int], count: Int): RandomAccessSeq[AnyRef] =
storage.getVectorStorageRangeFor(uuid, start, finish, count)
}
override def length: Int = {
verifyTransaction
storage.getVectorStorageSizeFor(uuid)
}
/**
* Removes the <i>tail</i> element of this vector.
*/
// FIXME
def pop: AnyRef = throw new UnsupportedOperationException("need to implement persistent vector pop")
override def apply(index: Int): AnyRef = get(index)
// FIXME
def update(index: Int, newElem: AnyRef) = storage.updateVectorStorageEntryFor(uuid, index, newElem)
override def first: AnyRef = get(0)
override def last: AnyRef = {
verifyTransaction
val l = length
if (l == 0) throw new NoSuchElementException("Vector is empty")
get(length - 1)
if (newElems.length != 0) newElems.last
else {
val len = length
if (len == 0) throw new NoSuchElementException("Vector is empty")
get(len - 1)
}
}
// ---- For Transactional ----
override def commit = {
// FIXME: should use batch function once the bug is resolved
for (element <- changeSet) storage.insertVectorStorageEntryFor(uuid, element)
changeSet.clear
}
def length: Int = storage.getVectorStorageSizeFor(uuid) + newElems.length
}
/**
@ -288,7 +238,7 @@ abstract class TemplatePersistentTransactionalVector extends PersistentTransacti
*
* @author <a href="http://debasishg.blogspot.com">Debaissh Ghosh</a>
*/
class CassandraPersistentTransactionalVector extends TemplatePersistentTransactionalVector {
class CassandraPersistentVector extends TemplatePersistentVector {
val storage = CassandraStorage
}
@ -297,38 +247,37 @@ class CassandraPersistentTransactionalVector extends TemplatePersistentTransacti
*
* @author <a href="http://debasishg.blogspot.com">Debaissh Ghosh</a>
*/
class MongoPersistentTransactionalVector extends TemplatePersistentTransactionalVector {
class MongoPersistentVector extends TemplatePersistentVector {
val storage = MongoStorage
}
abstract class TemplatePersistentTransactionalRef extends TransactionalRef[AnyRef] {
trait PersistentRef[T] extends Transactional
trait TemplatePersistentRef extends PersistentRef[AnyRef] {
protected val ref = new TransactionalRef[AnyRef]
val storage: RefStorage
override def commit = if (ref.isDefined) {
def commit = if (ref.isDefined) {
storage.insertRefStorageFor(uuid, ref.get)
ref = None
ref.swap(null)
}
override def rollback = ref = None
def get: Option[AnyRef] = if (ref.isDefined) ref.get else storage.getRefStorageFor(uuid)
override def get: Option[AnyRef] = {
verifyTransaction
storage.getRefStorageFor(uuid)
}
def isDefined: Boolean = ref.isDefined || storage.getRefStorageFor(uuid).isDefined
override def isDefined: Boolean = get.isDefined
override def getOrElse(default: => AnyRef): AnyRef = {
val ref = get
if (ref.isDefined) ref
def getOrElse(default: => AnyRef): AnyRef = {
val current = get
if (current.isDefined) current
else default
}
}
class CassandraPersistentTransactionalRef extends TemplatePersistentTransactionalRef {
class CassandraPersistentRef extends TemplatePersistentRef {
val storage = CassandraStorage
}
class MongoPersistentTransactionalRef extends TemplatePersistentTransactionalRef {
class MongoPersistentRef extends TemplatePersistentRef {
val storage = MongoStorage
}

View file

@ -1,96 +0,0 @@
/**
* Copyright (C) 2009 Scalable Solutions.
*/
package se.scalablesolutions.akka.state
import org.apache.commons.pool._
import org.apache.commons.pool.impl._
import org.apache.thrift.transport._
trait Pool[T] extends java.io.Closeable {
def borrowObject: T
def returnObject(t: T): Unit
def invalidateObject(t: T): Unit
def addObject: Unit
def getNumIdle: Int
def getNumActive: Int
def clear: Unit
def setFactory(factory: PoolItemFactory[T]): Unit
}
trait PoolFactory[T] {
def createPool: Pool[T]
}
trait PoolItemFactory[T] {
def makeObject: T
def destroyObject(t: T): Unit
def validateObject(t: T): Boolean
def activateObject(t: T): Unit
def passivateObject(t: T): Unit
}
trait PoolBridge[T, OP <: ObjectPool] extends Pool[T] {
val impl: OP
override def borrowObject: T = impl.borrowObject.asInstanceOf[T]
override def returnObject(t: T) = impl.returnObject(t)
override def invalidateObject(t: T) = impl.invalidateObject(t)
override def addObject = impl.addObject
override def getNumIdle: Int = impl.getNumIdle
override def getNumActive: Int = impl.getNumActive
override def clear: Unit = impl.clear
override def close: Unit = impl.close
override def setFactory(factory: PoolItemFactory[T]) = impl.setFactory(toPoolableObjectFactory(factory))
def toPoolableObjectFactory[T](pif: PoolItemFactory[T]) = new PoolableObjectFactory {
def makeObject: Object = pif.makeObject.asInstanceOf[Object]
def destroyObject(o: Object): Unit = pif.destroyObject(o.asInstanceOf[T])
def validateObject(o: Object): Boolean = pif.validateObject(o.asInstanceOf[T])
def activateObject(o: Object): Unit = pif.activateObject(o.asInstanceOf[T])
def passivateObject(o: Object): Unit = pif.passivateObject(o.asInstanceOf[T])
}
}
object StackPool {
def apply[T](factory: PoolItemFactory[T]) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory))
}
def apply[T](factory: PoolItemFactory[T], maxIdle: Int) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory),maxIdle)
}
def apply[T](factory: PoolItemFactory[T], maxIdle: Int, initIdleCapacity: Int) = new PoolBridge[T,StackObjectPool] {
val impl = new StackObjectPool(toPoolableObjectFactory(factory),maxIdle,initIdleCapacity)
}
}
object SoftRefPool {
def apply[T](factory: PoolItemFactory[T]) = new PoolBridge[T,SoftReferenceObjectPool] {
val impl = new SoftReferenceObjectPool(toPoolableObjectFactory(factory))
}
def apply[T](factory: PoolItemFactory[T], initSize: Int) = new PoolBridge[T,SoftReferenceObjectPool] {
val impl = new SoftReferenceObjectPool(toPoolableObjectFactory(factory),initSize)
}
}
trait TransportFactory[T <: TTransport] extends PoolItemFactory[T] {
def createTransport: T
def makeObject: T = createTransport
def destroyObject(transport: T): Unit = transport.close
def validateObject(transport: T) = transport.isOpen
def activateObject(transport: T): Unit = if( !transport.isOpen ) transport.open else ()
def passivateObject(transport: T): Unit = transport.flush
}
case class SocketProvider(val host: String, val port: Int) extends TransportFactory[TSocket] {
def createTransport = {
val t = new TSocket(host, port)
t.open
t
}
}

View file

@ -1,3 +1,7 @@
/**
* Copyright (C) 2009 Scalable Solutions.
*/
package se.scalablesolutions.akka.state
// abstracts persistence storage
@ -15,12 +19,13 @@ trait MapStorage extends Storage {
def getMapStorageRangeFor(name: String, start: Option[AnyRef], finish: Option[AnyRef], count: Int): List[Tuple2[AnyRef, AnyRef]]
}
// for vectors
// for Vectors
trait VectorStorage extends Storage {
def insertVectorStorageEntryFor(name: String, element: AnyRef)
def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef])
def updateVectorStorageEntryFor(name: String, index: Int, elem: AnyRef)
def getVectorStorageEntryFor(name: String, index: Int): AnyRef
def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): List[AnyRef]
def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): RandomAccessSeq[AnyRef]
def getVectorStorageSizeFor(name: String): Int
}

6
akka.iml Executable file → Normal file
View file

@ -1,14 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Scala" name="Scala">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>

1486
akka.ipr Executable file → Normal file

File diff suppressed because it is too large Load diff

2098
akka.iws Executable file → Normal file

File diff suppressed because it is too large Load diff