+cdd #16799 Add Distributed Data module

Previously know as [patriknw/akka-data-replication](https://github.com/patriknw/akka-data-replication),
which was originally inspired by [jboner/akka-crdt](https://github.com/jboner/akka-crdt).

The functionality is very similar to akka-data-replication 0.11.

Here is a list of the most important changes:

* The package name changed to `akka.cluster.ddata`
* The extension was renamed to `DistributedData`
* The keys changed from strings to classes with unique identifiers and type information of the data values,
  e.g. `ORSetKey[Int]("set2")`
* The optional read consistency parameter was removed from the `Update` message. If you need to read from
  other replicas before performing the update you have to first send a `Get` message and then continue with
  the ``Update`` when the ``GetSuccess`` is received.
* `BigInt` is used in `GCounter` and `PNCounter` instead of `Long`
* Improvements of java api
* Better documentation
This commit is contained in:
Patrik Nordwall 2015-05-17 12:28:47 +02:00
parent bf28260cd0
commit cbe5dd2cf5
69 changed files with 40036 additions and 3 deletions

View file

@ -0,0 +1,173 @@
/**
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.cluster.ddata.protobuf
import scala.concurrent.duration._
import org.scalatest.BeforeAndAfterAll
import org.scalatest.Matchers
import org.scalatest.WordSpecLike
import akka.actor.ActorSystem
import akka.actor.Address
import akka.actor.ExtendedActorSystem
import akka.cluster.ddata.Flag
import akka.cluster.ddata.GCounter
import akka.cluster.ddata.GSet
import akka.cluster.ddata.LWWMap
import akka.cluster.ddata.LWWRegister
import akka.cluster.ddata.ORMap
import akka.cluster.ddata.ORSet
import akka.cluster.ddata.PNCounter
import akka.cluster.ddata.PNCounterMap
import akka.cluster.ddata.Replicator._
import akka.cluster.ddata.Replicator.Internal._
import akka.cluster.ddata.VersionVector
import akka.testkit.TestKit
import akka.cluster.UniqueAddress
import com.typesafe.config.ConfigFactory
class ReplicatedDataSerializerSpec extends TestKit(ActorSystem("ReplicatedDataSerializerSpec",
ConfigFactory.parseString("""
akka.actor.provider=akka.cluster.ClusterActorRefProvider
akka.remote.netty.tcp.port=0
"""))) with WordSpecLike with Matchers with BeforeAndAfterAll {
val serializer = new ReplicatedDataSerializer(system.asInstanceOf[ExtendedActorSystem])
val address1 = UniqueAddress(Address("akka.tcp", system.name, "some.host.org", 4711), 1)
val address2 = UniqueAddress(Address("akka.tcp", system.name, "other.host.org", 4711), 2)
val address3 = UniqueAddress(Address("akka.tcp", system.name, "some.host.org", 4712), 3)
override def afterAll {
shutdown()
}
def checkSerialization(obj: AnyRef): Unit = {
val blob = serializer.toBinary(obj)
val ref = serializer.fromBinary(blob, serializer.manifest(obj))
ref should be(obj)
}
def checkSameContent(a: AnyRef, b: AnyRef): Unit = {
a should be(b)
val blobA = serializer.toBinary(a)
val blobB = serializer.toBinary(b)
blobA.toSeq should be(blobB.toSeq)
}
"ReplicatedDataSerializer" must {
"serialize GSet" in {
checkSerialization(GSet())
checkSerialization(GSet() + "a")
checkSerialization(GSet() + "a" + "b")
checkSerialization(GSet() + 1 + 2 + 3)
checkSerialization(GSet() + address1 + address2)
checkSerialization(GSet() + 1L + "2" + 3 + address1)
checkSameContent(GSet() + "a" + "b", GSet() + "a" + "b")
checkSameContent(GSet() + "a" + "b", GSet() + "b" + "a")
checkSameContent(GSet() + address1 + address2 + address3, GSet() + address2 + address1 + address3)
checkSameContent(GSet() + address1 + address2 + address3, GSet() + address3 + address2 + address1)
}
"serialize ORSet" in {
checkSerialization(ORSet())
checkSerialization(ORSet().add(address1, "a"))
checkSerialization(ORSet().add(address1, "a").add(address2, "a"))
checkSerialization(ORSet().add(address1, "a").remove(address2, "a"))
checkSerialization(ORSet().add(address1, "a").add(address2, "b").remove(address1, "a"))
checkSerialization(ORSet().add(address1, 1).add(address2, 2))
checkSerialization(ORSet().add(address1, 1L).add(address2, 2L))
checkSerialization(ORSet().add(address1, "a").add(address2, 2).add(address3, 3L).add(address3, address3))
val s1 = ORSet().add(address1, "a").add(address2, "b")
val s2 = ORSet().add(address2, "b").add(address1, "a")
checkSameContent(s1.merge(s2), s2.merge(s1))
val s3 = ORSet().add(address1, "a").add(address2, 17).remove(address3, 17)
val s4 = ORSet().add(address2, 17).remove(address3, 17).add(address1, "a")
checkSameContent(s3.merge(s4), s4.merge(s3))
}
"serialize Flag" in {
checkSerialization(Flag())
checkSerialization(Flag().switchOn)
}
"serialize LWWRegister" in {
checkSerialization(LWWRegister(address1, "value1", LWWRegister.defaultClock))
checkSerialization(LWWRegister(address1, "value2", LWWRegister.defaultClock[String])
.withValue(address2, "value3", LWWRegister.defaultClock[String]))
}
"serialize GCounter" in {
checkSerialization(GCounter())
checkSerialization(GCounter().increment(address1, 3))
checkSerialization(GCounter().increment(address1, 2).increment(address2, 5))
checkSameContent(
GCounter().increment(address1, 2).increment(address2, 5),
GCounter().increment(address2, 5).increment(address1, 1).increment(address1, 1))
checkSameContent(
GCounter().increment(address1, 2).increment(address3, 5),
GCounter().increment(address3, 5).increment(address1, 2))
}
"serialize PNCounter" in {
checkSerialization(PNCounter())
checkSerialization(PNCounter().increment(address1, 3))
checkSerialization(PNCounter().increment(address1, 3).decrement(address1, 1))
checkSerialization(PNCounter().increment(address1, 2).increment(address2, 5))
checkSerialization(PNCounter().increment(address1, 2).increment(address2, 5).decrement(address1, 1))
checkSameContent(
PNCounter().increment(address1, 2).increment(address2, 5),
PNCounter().increment(address2, 5).increment(address1, 1).increment(address1, 1))
checkSameContent(
PNCounter().increment(address1, 2).increment(address3, 5),
PNCounter().increment(address3, 5).increment(address1, 2))
checkSameContent(
PNCounter().increment(address1, 2).decrement(address1, 1).increment(address3, 5),
PNCounter().increment(address3, 5).increment(address1, 2).decrement(address1, 1))
}
"serialize ORMap" in {
checkSerialization(ORMap())
checkSerialization(ORMap().put(address1, "a", GSet() + "A"))
checkSerialization(ORMap().put(address1, "a", GSet() + "A").put(address2, "b", GSet() + "B"))
}
"serialize LWWMap" in {
checkSerialization(LWWMap())
checkSerialization(LWWMap().put(address1, "a", "value1", LWWRegister.defaultClock[Any]))
checkSerialization(LWWMap().put(address1, "a", "value1", LWWRegister.defaultClock[Any])
.put(address2, "b", 17, LWWRegister.defaultClock[Any]))
}
"serialize PNCounterMap" in {
checkSerialization(PNCounterMap())
checkSerialization(PNCounterMap().increment(address1, "a", 3))
checkSerialization(PNCounterMap().increment(address1, "a", 3).decrement(address2, "a", 2).
increment(address2, "b", 5))
}
"serialize DeletedData" in {
checkSerialization(DeletedData)
}
"serialize VersionVector" in {
checkSerialization(VersionVector())
checkSerialization(VersionVector().increment(address1))
checkSerialization(VersionVector().increment(address1).increment(address2))
val v1 = VersionVector().increment(address1).increment(address1)
val v2 = VersionVector().increment(address2)
checkSameContent(v1.merge(v2), v2.merge(v1))
}
}
}