pekko/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala

1002 lines
45 KiB
Scala
Raw Normal View History

/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.cluster.ddata.protobuf
import java.{ util, lang => jl }
import java.util.ArrayList
import java.util.Collections
import java.util.Comparator
import java.util.TreeSet
import scala.annotation.tailrec
import scala.collection.JavaConverters._
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
import scala.collection.immutable
import akka.actor.ExtendedActorSystem
import akka.cluster.ddata._
import akka.cluster.ddata.Replicator.Internal._
import akka.cluster.ddata.protobuf.msg.{ ReplicatedDataMessages => rd }
import akka.cluster.ddata.protobuf.msg.{ ReplicatorMessages => dm }
import akka.serialization.SerializerWithStringManifest
import akka.serialization.BaseSerializer
import akka.protobuf.{ ByteString, GeneratedMessage }
import akka.util.ByteString.UTF_8
import java.io.NotSerializableException
import akka.actor.ActorRef
import akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage
import akka.serialization.Serialization
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
import akka.util.ccompat._
private object ReplicatedDataSerializer {
/*
* Generic superclass to allow to compare Entry types used in protobuf.
*/
abstract class KeyComparator[A <: GeneratedMessage] extends Comparator[A] {
2019-03-11 10:38:24 +01:00
/**
* Get the key from the entry. The key may be a String, Int, Long, or OtherMessage
* @param entry The protobuf entry used with Map types
* @return The Key
*/
def getKey(entry: A): Any
final def compare(x: A, y: A): Int = compareKeys(getKey(x), getKey(y))
private final def compareKeys(t1: Any, t2: Any): Int = (t1, t2) match {
case (k1: String, k2: String) => k1.compareTo(k2)
case (k1: String, k2) => -1
case (k1, k2: String) => 1
case (k1: Int, k2: Int) => k1.compareTo(k2)
case (k1: Int, k2) => -1
case (k1, k2: Int) => 1
case (k1: Long, k2: Long) => k1.compareTo(k2)
case (k1: Long, k2) => -1
case (k1, k2: Long) => 1
case (k1: OtherMessage, k2: OtherMessage) => OtherMessageComparator.compare(k1, k2)
case (k1, k2) =>
throw new IllegalStateException(
s"Invalid keys (${k1.getClass}, ${k2.getClass}): must be of type String, Int, Long or OtherMessage")
}
}
implicit object ORMapEntryComparator extends KeyComparator[rd.ORMap.Entry] {
2019-03-11 10:38:24 +01:00
override def getKey(e: rd.ORMap.Entry): Any =
if (e.hasStringKey) e.getStringKey
else if (e.hasIntKey) e.getIntKey
else if (e.hasLongKey) e.getLongKey
else e.getOtherKey
}
implicit object LWWMapEntryComparator extends KeyComparator[rd.LWWMap.Entry] {
2019-03-11 10:38:24 +01:00
override def getKey(e: rd.LWWMap.Entry): Any =
if (e.hasStringKey) e.getStringKey
else if (e.hasIntKey) e.getIntKey
else if (e.hasLongKey) e.getLongKey
else e.getOtherKey
}
implicit object PNCounterMapEntryComparator extends KeyComparator[rd.PNCounterMap.Entry] {
2019-03-11 10:38:24 +01:00
override def getKey(e: rd.PNCounterMap.Entry): Any =
if (e.hasStringKey) e.getStringKey
else if (e.hasIntKey) e.getIntKey
else if (e.hasLongKey) e.getLongKey
else e.getOtherKey
}
implicit object ORMultiMapEntryComparator extends KeyComparator[rd.ORMultiMap.Entry] {
2019-03-11 10:38:24 +01:00
override def getKey(e: rd.ORMultiMap.Entry): Any =
if (e.hasStringKey) e.getStringKey
else if (e.hasIntKey) e.getIntKey
else if (e.hasLongKey) e.getLongKey
else e.getOtherKey
}
2019-03-11 10:38:24 +01:00
sealed trait ProtoMapEntryWriter[
Entry <: GeneratedMessage, EntryBuilder <: GeneratedMessage.Builder[EntryBuilder], Value <: GeneratedMessage] {
def setStringKey(builder: EntryBuilder, key: String, value: Value): Entry
def setLongKey(builder: EntryBuilder, key: Long, value: Value): Entry
def setIntKey(builder: EntryBuilder, key: Int, value: Value): Entry
def setOtherKey(builder: EntryBuilder, key: dm.OtherMessage, value: Value): Entry
}
sealed trait ProtoMapEntryReader[Entry <: GeneratedMessage, A <: GeneratedMessage] {
def hasStringKey(entry: Entry): Boolean
def getStringKey(entry: Entry): String
def hasIntKey(entry: Entry): Boolean
def getIntKey(entry: Entry): Int
def hasLongKey(entry: Entry): Boolean
def getLongKey(entry: Entry): Long
def hasOtherKey(entry: Entry): Boolean
def getOtherKey(entry: Entry): dm.OtherMessage
def getValue(entry: Entry): A
}
2019-03-11 10:38:24 +01:00
implicit object ORMapEntry
extends ProtoMapEntryWriter[rd.ORMap.Entry, rd.ORMap.Entry.Builder, dm.OtherMessage]
with ProtoMapEntryReader[rd.ORMap.Entry, dm.OtherMessage] {
override def setStringKey(builder: rd.ORMap.Entry.Builder, key: String, value: dm.OtherMessage): rd.ORMap.Entry =
builder.setStringKey(key).setValue(value).build()
override def setLongKey(builder: rd.ORMap.Entry.Builder, key: Long, value: dm.OtherMessage): rd.ORMap.Entry =
builder.setLongKey(key).setValue(value).build()
override def setIntKey(builder: rd.ORMap.Entry.Builder, key: Int, value: dm.OtherMessage): rd.ORMap.Entry =
builder.setIntKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setOtherKey(
builder: rd.ORMap.Entry.Builder,
key: dm.OtherMessage,
value: dm.OtherMessage): rd.ORMap.Entry = builder.setOtherKey(key).setValue(value).build()
override def hasStringKey(entry: rd.ORMap.Entry): Boolean = entry.hasStringKey
override def getStringKey(entry: rd.ORMap.Entry): String = entry.getStringKey
override def hasIntKey(entry: rd.ORMap.Entry): Boolean = entry.hasIntKey
override def getIntKey(entry: rd.ORMap.Entry): Int = entry.getIntKey
override def hasLongKey(entry: rd.ORMap.Entry): Boolean = entry.hasLongKey
override def getLongKey(entry: rd.ORMap.Entry): Long = entry.getLongKey
override def hasOtherKey(entry: rd.ORMap.Entry): Boolean = entry.hasOtherKey
override def getOtherKey(entry: rd.ORMap.Entry): OtherMessage = entry.getOtherKey
override def getValue(entry: rd.ORMap.Entry): dm.OtherMessage = entry.getValue
}
2019-03-11 10:38:24 +01:00
implicit object LWWMapEntry
extends ProtoMapEntryWriter[rd.LWWMap.Entry, rd.LWWMap.Entry.Builder, rd.LWWRegister]
with ProtoMapEntryReader[rd.LWWMap.Entry, rd.LWWRegister] {
override def setStringKey(builder: rd.LWWMap.Entry.Builder, key: String, value: rd.LWWRegister): rd.LWWMap.Entry =
builder.setStringKey(key).setValue(value).build()
override def setLongKey(builder: rd.LWWMap.Entry.Builder, key: Long, value: rd.LWWRegister): rd.LWWMap.Entry =
builder.setLongKey(key).setValue(value).build()
override def setIntKey(builder: rd.LWWMap.Entry.Builder, key: Int, value: rd.LWWRegister): rd.LWWMap.Entry =
builder.setIntKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setOtherKey(
builder: rd.LWWMap.Entry.Builder,
key: OtherMessage,
value: rd.LWWRegister): rd.LWWMap.Entry = builder.setOtherKey(key).setValue(value).build()
override def hasStringKey(entry: rd.LWWMap.Entry): Boolean = entry.hasStringKey
override def getStringKey(entry: rd.LWWMap.Entry): String = entry.getStringKey
override def hasIntKey(entry: rd.LWWMap.Entry): Boolean = entry.hasIntKey
override def getIntKey(entry: rd.LWWMap.Entry): Int = entry.getIntKey
override def hasLongKey(entry: rd.LWWMap.Entry): Boolean = entry.hasLongKey
override def getLongKey(entry: rd.LWWMap.Entry): Long = entry.getLongKey
override def hasOtherKey(entry: rd.LWWMap.Entry): Boolean = entry.hasOtherKey
override def getOtherKey(entry: rd.LWWMap.Entry): OtherMessage = entry.getOtherKey
override def getValue(entry: rd.LWWMap.Entry): rd.LWWRegister = entry.getValue
}
2019-03-11 10:38:24 +01:00
implicit object PNCounterMapEntry
extends ProtoMapEntryWriter[rd.PNCounterMap.Entry, rd.PNCounterMap.Entry.Builder, rd.PNCounter]
with ProtoMapEntryReader[rd.PNCounterMap.Entry, rd.PNCounter] {
2019-03-13 10:56:20 +01:00
override def setStringKey(
builder: rd.PNCounterMap.Entry.Builder,
key: String,
value: rd.PNCounter): rd.PNCounterMap.Entry =
2019-03-11 10:38:24 +01:00
builder.setStringKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setLongKey(
builder: rd.PNCounterMap.Entry.Builder,
key: Long,
value: rd.PNCounter): rd.PNCounterMap.Entry =
2019-03-11 10:38:24 +01:00
builder.setLongKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setIntKey(
builder: rd.PNCounterMap.Entry.Builder,
key: Int,
value: rd.PNCounter): rd.PNCounterMap.Entry = builder.setIntKey(key).setValue(value).build()
override def setOtherKey(
builder: rd.PNCounterMap.Entry.Builder,
key: OtherMessage,
value: rd.PNCounter): rd.PNCounterMap.Entry =
2019-03-11 10:38:24 +01:00
builder.setOtherKey(key).setValue(value).build()
override def hasStringKey(entry: rd.PNCounterMap.Entry): Boolean = entry.hasStringKey
override def getStringKey(entry: rd.PNCounterMap.Entry): String = entry.getStringKey
override def hasIntKey(entry: rd.PNCounterMap.Entry): Boolean = entry.hasIntKey
override def getIntKey(entry: rd.PNCounterMap.Entry): Int = entry.getIntKey
override def hasLongKey(entry: rd.PNCounterMap.Entry): Boolean = entry.hasLongKey
override def getLongKey(entry: rd.PNCounterMap.Entry): Long = entry.getLongKey
override def hasOtherKey(entry: rd.PNCounterMap.Entry): Boolean = entry.hasOtherKey
override def getOtherKey(entry: rd.PNCounterMap.Entry): OtherMessage = entry.getOtherKey
override def getValue(entry: rd.PNCounterMap.Entry): rd.PNCounter = entry.getValue
}
2019-03-11 10:38:24 +01:00
implicit object ORMultiMapEntry
extends ProtoMapEntryWriter[rd.ORMultiMap.Entry, rd.ORMultiMap.Entry.Builder, rd.ORSet]
with ProtoMapEntryReader[rd.ORMultiMap.Entry, rd.ORSet] {
override def setStringKey(builder: rd.ORMultiMap.Entry.Builder, key: String, value: rd.ORSet): rd.ORMultiMap.Entry =
builder.setStringKey(key).setValue(value).build()
override def setLongKey(builder: rd.ORMultiMap.Entry.Builder, key: Long, value: rd.ORSet): rd.ORMultiMap.Entry =
builder.setLongKey(key).setValue(value).build()
override def setIntKey(builder: rd.ORMultiMap.Entry.Builder, key: Int, value: rd.ORSet): rd.ORMultiMap.Entry =
builder.setIntKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setOtherKey(
builder: rd.ORMultiMap.Entry.Builder,
key: dm.OtherMessage,
value: rd.ORSet): rd.ORMultiMap.Entry = builder.setOtherKey(key).setValue(value).build()
override def hasStringKey(entry: rd.ORMultiMap.Entry): Boolean = entry.hasStringKey
override def getStringKey(entry: rd.ORMultiMap.Entry): String = entry.getStringKey
override def hasIntKey(entry: rd.ORMultiMap.Entry): Boolean = entry.hasIntKey
override def getIntKey(entry: rd.ORMultiMap.Entry): Int = entry.getIntKey
override def hasLongKey(entry: rd.ORMultiMap.Entry): Boolean = entry.hasLongKey
override def getLongKey(entry: rd.ORMultiMap.Entry): Long = entry.getLongKey
override def hasOtherKey(entry: rd.ORMultiMap.Entry): Boolean = entry.hasOtherKey
override def getOtherKey(entry: rd.ORMultiMap.Entry): OtherMessage = entry.getOtherKey
override def getValue(entry: rd.ORMultiMap.Entry): rd.ORSet = entry.getValue
}
2019-03-11 10:38:24 +01:00
implicit object ORMapDeltaGroupEntry
extends ProtoMapEntryWriter[rd.ORMapDeltaGroup.MapEntry, rd.ORMapDeltaGroup.MapEntry.Builder, dm.OtherMessage]
with ProtoMapEntryReader[rd.ORMapDeltaGroup.MapEntry, dm.OtherMessage] {
2019-03-13 10:56:20 +01:00
override def setStringKey(
builder: rd.ORMapDeltaGroup.MapEntry.Builder,
key: String,
value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry =
2019-03-11 10:38:24 +01:00
builder.setStringKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setLongKey(
builder: rd.ORMapDeltaGroup.MapEntry.Builder,
key: Long,
value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry =
2019-03-11 10:38:24 +01:00
builder.setLongKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setIntKey(
builder: rd.ORMapDeltaGroup.MapEntry.Builder,
key: Int,
value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry =
2019-03-11 10:38:24 +01:00
builder.setIntKey(key).setValue(value).build()
2019-03-13 10:56:20 +01:00
override def setOtherKey(
builder: rd.ORMapDeltaGroup.MapEntry.Builder,
key: dm.OtherMessage,
value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry =
2019-03-11 10:38:24 +01:00
builder.setOtherKey(key).setValue(value).build()
2017-02-23 01:20:33 +01:00
override def hasStringKey(entry: rd.ORMapDeltaGroup.MapEntry): Boolean = entry.hasStringKey
override def getStringKey(entry: rd.ORMapDeltaGroup.MapEntry): String = entry.getStringKey
override def hasIntKey(entry: rd.ORMapDeltaGroup.MapEntry): Boolean = entry.hasIntKey
override def getIntKey(entry: rd.ORMapDeltaGroup.MapEntry): Int = entry.getIntKey
override def hasLongKey(entry: rd.ORMapDeltaGroup.MapEntry): Boolean = entry.hasLongKey
override def getLongKey(entry: rd.ORMapDeltaGroup.MapEntry): Long = entry.getLongKey
override def hasOtherKey(entry: rd.ORMapDeltaGroup.MapEntry): Boolean = entry.hasOtherKey
override def getOtherKey(entry: rd.ORMapDeltaGroup.MapEntry): OtherMessage = entry.getOtherKey
override def getValue(entry: rd.ORMapDeltaGroup.MapEntry): dm.OtherMessage = entry.getValue
}
}
/**
* Protobuf serializer of ReplicatedData.
*/
class ReplicatedDataSerializer(val system: ExtendedActorSystem)
2019-03-11 10:38:24 +01:00
extends SerializerWithStringManifest
with SerializationSupport
with BaseSerializer {
import ReplicatedDataSerializer._
private val DeletedDataManifest = "A"
private val GSetManifest = "B"
private val GSetKeyManifest = "b"
private val ORSetManifest = "C"
private val ORSetKeyManifest = "c"
private val ORSetAddManifest = "Ca"
private val ORSetRemoveManifest = "Cr"
private val ORSetFullManifest = "Cf"
private val ORSetDeltaGroupManifest = "Cg"
private val FlagManifest = "D"
private val FlagKeyManifest = "d"
private val LWWRegisterManifest = "E"
private val LWWRegisterKeyManifest = "e"
private val GCounterManifest = "F"
private val GCounterKeyManifest = "f"
private val PNCounterManifest = "G"
private val PNCounterKeyManifest = "g"
private val ORMapManifest = "H"
private val ORMapKeyManifest = "h"
2017-02-23 01:20:33 +01:00
private val ORMapPutManifest = "Ha"
private val ORMapRemoveManifest = "Hr"
private val ORMapRemoveKeyManifest = "Hk"
private val ORMapUpdateManifest = "Hu"
private val ORMapDeltaGroupManifest = "Hg"
private val LWWMapManifest = "I"
private val LWWMapKeyManifest = "i"
private val PNCounterMapManifest = "J"
private val PNCounterMapKeyManifest = "j"
2015-06-18 16:17:53 +02:00
private val ORMultiMapManifest = "K"
private val ORMultiMapKeyManifest = "k"
private val VersionVectorManifest = "L"
private val fromBinaryMap = collection.immutable.HashMap[String, Array[Byte] => AnyRef](
GSetManifest -> gsetFromBinary,
ORSetManifest -> orsetFromBinary,
ORSetAddManifest -> orsetAddFromBinary,
ORSetRemoveManifest -> orsetRemoveFromBinary,
ORSetFullManifest -> orsetFullFromBinary,
ORSetDeltaGroupManifest -> orsetDeltaGroupFromBinary,
FlagManifest -> flagFromBinary,
LWWRegisterManifest -> lwwRegisterFromBinary,
GCounterManifest -> gcounterFromBinary,
PNCounterManifest -> pncounterFromBinary,
ORMapManifest -> ormapFromBinary,
ORMapPutManifest -> ormapPutFromBinary,
ORMapRemoveManifest -> ormapRemoveFromBinary,
ORMapRemoveKeyManifest -> ormapRemoveKeyFromBinary,
ORMapUpdateManifest -> ormapUpdateFromBinary,
ORMapDeltaGroupManifest -> ormapDeltaGroupFromBinary,
LWWMapManifest -> lwwmapFromBinary,
PNCounterMapManifest -> pncountermapFromBinary,
ORMultiMapManifest -> multimapFromBinary,
DeletedDataManifest -> (_ => DeletedData),
VersionVectorManifest -> versionVectorFromBinary,
GSetKeyManifest -> (bytes => GSetKey(keyIdFromBinary(bytes))),
ORSetKeyManifest -> (bytes => ORSetKey(keyIdFromBinary(bytes))),
FlagKeyManifest -> (bytes => FlagKey(keyIdFromBinary(bytes))),
LWWRegisterKeyManifest -> (bytes => LWWRegisterKey(keyIdFromBinary(bytes))),
GCounterKeyManifest -> (bytes => GCounterKey(keyIdFromBinary(bytes))),
PNCounterKeyManifest -> (bytes => PNCounterKey(keyIdFromBinary(bytes))),
ORMapKeyManifest -> (bytes => ORMapKey(keyIdFromBinary(bytes))),
LWWMapKeyManifest -> (bytes => LWWMapKey(keyIdFromBinary(bytes))),
PNCounterMapKeyManifest -> (bytes => PNCounterMapKey(keyIdFromBinary(bytes))),
ORMultiMapKeyManifest -> (bytes => ORMultiMapKey(keyIdFromBinary(bytes))))
override def manifest(obj: AnyRef): String = obj match {
case _: ORSet[_] => ORSetManifest
case _: ORSet.AddDeltaOp[_] => ORSetAddManifest
case _: ORSet.RemoveDeltaOp[_] => ORSetRemoveManifest
case _: GSet[_] => GSetManifest
case _: GCounter => GCounterManifest
case _: PNCounter => PNCounterManifest
case _: Flag => FlagManifest
case _: LWWRegister[_] => LWWRegisterManifest
case _: ORMap[_, _] => ORMapManifest
case _: ORMap.PutDeltaOp[_, _] => ORMapPutManifest
case _: ORMap.RemoveDeltaOp[_, _] => ORMapRemoveManifest
case _: ORMap.RemoveKeyDeltaOp[_, _] => ORMapRemoveKeyManifest
case _: ORMap.UpdateDeltaOp[_, _] => ORMapUpdateManifest
case _: LWWMap[_, _] => LWWMapManifest
case _: PNCounterMap[_] => PNCounterMapManifest
case _: ORMultiMap[_, _] => ORMultiMapManifest
case DeletedData => DeletedDataManifest
case _: VersionVector => VersionVectorManifest
2019-03-11 10:38:24 +01:00
case _: ORSetKey[_] => ORSetKeyManifest
case _: GSetKey[_] => GSetKeyManifest
case _: GCounterKey => GCounterKeyManifest
case _: PNCounterKey => PNCounterKeyManifest
case _: FlagKey => FlagKeyManifest
case _: LWWRegisterKey[_] => LWWRegisterKeyManifest
case _: ORMapKey[_, _] => ORMapKeyManifest
case _: LWWMapKey[_, _] => LWWMapKeyManifest
case _: PNCounterMapKey[_] => PNCounterMapKeyManifest
case _: ORMultiMapKey[_, _] => ORMultiMapKeyManifest
case _: ORSet.DeltaGroup[_] => ORSetDeltaGroupManifest
case _: ORMap.DeltaGroup[_, _] => ORMapDeltaGroupManifest
case _: ORSet.FullStateDeltaOp[_] => ORSetFullManifest
case _ =>
throw new IllegalArgumentException(s"Can't serialize object of type ${obj.getClass} in [${getClass.getName}]")
}
def toBinary(obj: AnyRef): Array[Byte] = obj match {
case m: ORSet[_] => compress(orsetToProto(m))
case m: ORSet.AddDeltaOp[_] => orsetToProto(m.underlying).toByteArray
case m: ORSet.RemoveDeltaOp[_] => orsetToProto(m.underlying).toByteArray
case m: GSet[_] => gsetToProto(m).toByteArray
case m: GCounter => gcounterToProto(m).toByteArray
case m: PNCounter => pncounterToProto(m).toByteArray
case m: Flag => flagToProto(m).toByteArray
case m: LWWRegister[_] => lwwRegisterToProto(m).toByteArray
case m: ORMap[_, _] => compress(ormapToProto(m))
case m: ORMap.PutDeltaOp[_, _] => ormapPutToProto(m).toByteArray
case m: ORMap.RemoveDeltaOp[_, _] => ormapRemoveToProto(m).toByteArray
case m: ORMap.RemoveKeyDeltaOp[_, _] => ormapRemoveKeyToProto(m).toByteArray
case m: ORMap.UpdateDeltaOp[_, _] => ormapUpdateToProto(m).toByteArray
case m: LWWMap[_, _] => compress(lwwmapToProto(m))
case m: PNCounterMap[_] => compress(pncountermapToProto(m))
case m: ORMultiMap[_, _] => compress(multimapToProto(m))
case DeletedData => dm.Empty.getDefaultInstance.toByteArray
case m: VersionVector => versionVectorToProto(m).toByteArray
case Key(id) => keyIdToBinary(id)
case m: ORSet.DeltaGroup[_] => orsetDeltaGroupToProto(m).toByteArray
case m: ORMap.DeltaGroup[_, _] => ormapDeltaGroupToProto(m).toByteArray
case m: ORSet.FullStateDeltaOp[_] => orsetToProto(m.underlying).toByteArray
case _ =>
throw new IllegalArgumentException(s"Can't serialize object of type ${obj.getClass} in [${getClass.getName}]")
}
override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
fromBinaryMap.get(manifest) match {
case Some(f) => f(bytes)
2019-03-11 10:38:24 +01:00
case None =>
throw new NotSerializableException(
s"Unimplemented deserialization of message with manifest [$manifest] in [${getClass.getName}]")
}
def gsetToProto(gset: GSet[_]): rd.GSet = {
val b = rd.GSet.newBuilder()
// using java collections and sorting for performance (avoid conversions)
val stringElements = new ArrayList[String]
val intElements = new ArrayList[Integer]
val longElements = new ArrayList[jl.Long]
val otherElements = new ArrayList[dm.OtherMessage]
val actorRefElements = new ArrayList[String]
gset.elements.foreach {
case s: String => stringElements.add(s)
case i: Int => intElements.add(i)
case l: Long => longElements.add(l)
case ref: ActorRef => actorRefElements.add(Serialization.serializedActorPath(ref))
case other => otherElements.add(otherMessageToProto(other))
}
if (!stringElements.isEmpty) {
Collections.sort(stringElements)
b.addAllStringElements(stringElements)
}
if (!intElements.isEmpty) {
Collections.sort(intElements)
b.addAllIntElements(intElements)
}
if (!longElements.isEmpty) {
Collections.sort(longElements)
b.addAllLongElements(longElements)
}
if (!otherElements.isEmpty) {
Collections.sort(otherElements, OtherMessageComparator)
b.addAllOtherElements(otherElements)
}
if (!actorRefElements.isEmpty) {
Collections.sort(actorRefElements)
b.addAllActorRefElements(actorRefElements)
}
b.build()
}
def gsetFromBinary(bytes: Array[Byte]): GSet[_] =
gsetFromProto(rd.GSet.parseFrom(bytes))
def gsetFromProto(gset: rd.GSet): GSet[Any] = {
val elements: Iterator[Any] = {
gset.getStringElementsList.iterator.asScala ++
2019-03-11 10:38:24 +01:00
gset.getIntElementsList.iterator.asScala ++
gset.getLongElementsList.iterator.asScala ++
gset.getOtherElementsList.iterator.asScala.map(otherMessageFromProto) ++
gset.getActorRefElementsList.iterator.asScala.map(resolveActorRef)
}
GSet(elements.toSet)
}
def orsetToProto(orset: ORSet[_]): rd.ORSet =
orsetToProtoImpl(orset.asInstanceOf[ORSet[Any]])
private def orsetToProtoImpl(orset: ORSet[Any]): rd.ORSet = {
val b = rd.ORSet.newBuilder().setVvector(versionVectorToProto(orset.vvector))
// using java collections and sorting for performance (avoid conversions)
val stringElements = new ArrayList[String]
val intElements = new ArrayList[Integer]
val longElements = new ArrayList[jl.Long]
val otherElements = new ArrayList[dm.OtherMessage]
var otherElementsMap = Map.empty[dm.OtherMessage, Any]
val actorRefElements = new ArrayList[ActorRef]
orset.elementsMap.keysIterator.foreach {
case s: String => stringElements.add(s)
case i: Int => intElements.add(i)
case l: Long => longElements.add(l)
case ref: ActorRef => actorRefElements.add(ref)
case other =>
val enclosedMsg = otherMessageToProto(other)
otherElements.add(enclosedMsg)
// need the mapping back to the `other` when adding dots
otherElementsMap = otherElementsMap.updated(enclosedMsg, other)
}
def addDots(elements: ArrayList[_]): Unit = {
// add corresponding dots in same order
val iter = elements.iterator
while (iter.hasNext) {
val element = iter.next() match {
case enclosedMsg: dm.OtherMessage => otherElementsMap(enclosedMsg)
case e => e
}
b.addDots(versionVectorToProto(orset.elementsMap(element)))
}
}
if (!stringElements.isEmpty) {
Collections.sort(stringElements)
b.addAllStringElements(stringElements)
addDots(stringElements)
}
if (!intElements.isEmpty) {
Collections.sort(intElements)
b.addAllIntElements(intElements)
addDots(intElements)
}
if (!longElements.isEmpty) {
Collections.sort(longElements)
b.addAllLongElements(longElements)
addDots(longElements)
}
if (!otherElements.isEmpty) {
Collections.sort(otherElements, OtherMessageComparator)
b.addAllOtherElements(otherElements)
addDots(otherElements)
}
if (!actorRefElements.isEmpty) {
Collections.sort(actorRefElements)
val iter = actorRefElements.iterator
while (iter.hasNext) {
b.addActorRefElements(Serialization.serializedActorPath(iter.next()))
}
addDots(actorRefElements)
}
b.build()
}
def orsetFromBinary(bytes: Array[Byte]): ORSet[Any] =
orsetFromProto(rd.ORSet.parseFrom(decompress(bytes)))
private def orsetAddFromBinary(bytes: Array[Byte]): ORSet.AddDeltaOp[Any] =
new ORSet.AddDeltaOp(orsetFromProto(rd.ORSet.parseFrom(bytes)))
private def orsetRemoveFromBinary(bytes: Array[Byte]): ORSet.RemoveDeltaOp[Any] =
new ORSet.RemoveDeltaOp(orsetFromProto(rd.ORSet.parseFrom(bytes)))
private def orsetFullFromBinary(bytes: Array[Byte]): ORSet.FullStateDeltaOp[Any] =
new ORSet.FullStateDeltaOp(orsetFromProto(rd.ORSet.parseFrom(bytes)))
private def orsetDeltaGroupToProto(deltaGroup: ORSet.DeltaGroup[_]): rd.ORSetDeltaGroup = {
def createEntry(opType: rd.ORSetDeltaOp, u: ORSet[_]) = {
2019-03-11 10:38:24 +01:00
rd.ORSetDeltaGroup.Entry.newBuilder().setOperation(opType).setUnderlying(orsetToProto(u))
}
val b = rd.ORSetDeltaGroup.newBuilder()
deltaGroup.ops.foreach {
case ORSet.AddDeltaOp(u) =>
b.addEntries(createEntry(rd.ORSetDeltaOp.Add, u))
case ORSet.RemoveDeltaOp(u) =>
b.addEntries(createEntry(rd.ORSetDeltaOp.Remove, u))
case ORSet.FullStateDeltaOp(u) =>
b.addEntries(createEntry(rd.ORSetDeltaOp.Full, u))
case ORSet.DeltaGroup(_) =>
throw new IllegalArgumentException("ORSet.DeltaGroup should not be nested")
}
b.build()
}
private def orsetDeltaGroupFromBinary(bytes: Array[Byte]): ORSet.DeltaGroup[Any] = {
val deltaGroup = rd.ORSetDeltaGroup.parseFrom(bytes)
val ops: Vector[ORSet.DeltaOp] =
2019-03-11 10:38:24 +01:00
deltaGroup.getEntriesList.asScala.iterator
.map { entry =>
if (entry.getOperation == rd.ORSetDeltaOp.Add)
ORSet.AddDeltaOp(orsetFromProto(entry.getUnderlying))
else if (entry.getOperation == rd.ORSetDeltaOp.Remove)
ORSet.RemoveDeltaOp(orsetFromProto(entry.getUnderlying))
else if (entry.getOperation == rd.ORSetDeltaOp.Full)
ORSet.FullStateDeltaOp(orsetFromProto(entry.getUnderlying))
else
throw new NotSerializableException(s"Unknow ORSet delta operation ${entry.getOperation}")
}
.to(immutable.Vector)
ORSet.DeltaGroup(ops)
}
def orsetFromProto(orset: rd.ORSet): ORSet[Any] = {
val elements: Iterator[Any] = {
orset.getStringElementsList.iterator.asScala ++
2019-03-11 10:38:24 +01:00
orset.getIntElementsList.iterator.asScala ++
orset.getLongElementsList.iterator.asScala ++
orset.getOtherElementsList.iterator.asScala.map(otherMessageFromProto) ++
orset.getActorRefElementsList.iterator.asScala.map(resolveActorRef)
}
val dots = orset.getDotsList.asScala.map(versionVectorFromProto).iterator
val elementsMap = elements.zip(dots).toMap
new ORSet(elementsMap, vvector = versionVectorFromProto(orset.getVvector))
}
def flagToProto(flag: Flag): rd.Flag =
rd.Flag.newBuilder().setEnabled(flag.enabled).build()
def flagFromBinary(bytes: Array[Byte]): Flag =
flagFromProto(rd.Flag.parseFrom(bytes))
def flagFromProto(flag: rd.Flag): Flag =
if (flag.getEnabled) Flag.Enabled else Flag.Disabled
def lwwRegisterToProto(lwwRegister: LWWRegister[_]): rd.LWWRegister =
2019-03-11 10:38:24 +01:00
rd.LWWRegister
.newBuilder()
.setTimestamp(lwwRegister.timestamp)
.setNode(uniqueAddressToProto(lwwRegister.node))
.setState(otherMessageToProto(lwwRegister.value))
.build()
def lwwRegisterFromBinary(bytes: Array[Byte]): LWWRegister[Any] =
lwwRegisterFromProto(rd.LWWRegister.parseFrom(bytes))
def lwwRegisterFromProto(lwwRegister: rd.LWWRegister): LWWRegister[Any] =
2019-03-13 10:56:20 +01:00
new LWWRegister(
uniqueAddressFromProto(lwwRegister.getNode),
otherMessageFromProto(lwwRegister.getState),
lwwRegister.getTimestamp)
def gcounterToProto(gcounter: GCounter): rd.GCounter = {
val b = rd.GCounter.newBuilder()
gcounter.state.toVector.sortBy { case (address, _) => address }.foreach {
2019-03-11 10:38:24 +01:00
case (address, value) =>
b.addEntries(
rd.GCounter.Entry
.newBuilder()
.setNode(uniqueAddressToProto(address))
.setValue(ByteString.copyFrom(value.toByteArray)))
}
b.build()
}
def gcounterFromBinary(bytes: Array[Byte]): GCounter =
gcounterFromProto(rd.GCounter.parseFrom(bytes))
def gcounterFromProto(gcounter: rd.GCounter): GCounter = {
2019-03-11 10:38:24 +01:00
new GCounter(
state = gcounter.getEntriesList.asScala.iterator
.map(entry => uniqueAddressFromProto(entry.getNode) -> BigInt(entry.getValue.toByteArray))
.toMap)
}
def pncounterToProto(pncounter: PNCounter): rd.PNCounter =
2019-03-11 10:38:24 +01:00
rd.PNCounter
.newBuilder()
.setIncrements(gcounterToProto(pncounter.increments))
.setDecrements(gcounterToProto(pncounter.decrements))
.build()
def pncounterFromBinary(bytes: Array[Byte]): PNCounter =
pncounterFromProto(rd.PNCounter.parseFrom(bytes))
def pncounterFromProto(pncounter: rd.PNCounter): PNCounter = {
2019-03-13 10:56:20 +01:00
new PNCounter(
increments = gcounterFromProto(pncounter.getIncrements),
decrements = gcounterFromProto(pncounter.getDecrements))
}
/*
* Convert a Map[A, B] to an Iterable[Entry] where Entry is the protobuf map entry.
*/
2019-03-13 10:56:20 +01:00
private def getEntries[
IKey,
IValue,
EntryBuilder <: GeneratedMessage.Builder[EntryBuilder],
PEntry <: GeneratedMessage,
PValue <: GeneratedMessage](
input: Map[IKey, IValue],
createBuilder: () => EntryBuilder,
valueConverter: IValue => PValue)(
2019-03-11 10:38:24 +01:00
implicit comparator: Comparator[PEntry],
eh: ProtoMapEntryWriter[PEntry, EntryBuilder, PValue]): java.lang.Iterable[PEntry] = {
// The resulting Iterable needs to be ordered deterministically in order to create same signature upon serializing same data
val protoEntries = new TreeSet[PEntry](comparator)
input.foreach {
case (key: String, value) => protoEntries.add(eh.setStringKey(createBuilder(), key, valueConverter(value)))
case (key: Int, value) => protoEntries.add(eh.setIntKey(createBuilder(), key, valueConverter(value)))
case (key: Long, value) => protoEntries.add(eh.setLongKey(createBuilder(), key, valueConverter(value)))
2019-03-11 10:38:24 +01:00
case (key, value) =>
protoEntries.add(eh.setOtherKey(createBuilder(), otherMessageToProto(key), valueConverter(value)))
}
protoEntries
}
def ormapToProto(ormap: ORMap[_, _]): rd.ORMap = {
2017-02-23 01:20:33 +01:00
val ormapBuilder = rd.ORMap.newBuilder()
2019-03-11 10:38:24 +01:00
val entries: jl.Iterable[rd.ORMap.Entry] =
getEntries(ormap.values, rd.ORMap.Entry.newBuilder _, otherMessageToProto)
2017-02-23 01:20:33 +01:00
ormapBuilder.setKeys(orsetToProto(ormap.keys)).addAllEntries(entries).build()
}
def ormapFromBinary(bytes: Array[Byte]): ORMap[Any, ReplicatedData] =
ormapFromProto(rd.ORMap.parseFrom(decompress(bytes)))
2019-03-11 10:38:24 +01:00
def mapTypeFromProto[PEntry <: GeneratedMessage, A <: GeneratedMessage, B <: ReplicatedData](
input: util.List[PEntry],
valueCreator: A => B)(implicit eh: ProtoMapEntryReader[PEntry, A]): Map[Any, B] = {
input.asScala.map { entry =>
if (eh.hasStringKey(entry)) eh.getStringKey(entry) -> valueCreator(eh.getValue(entry))
else if (eh.hasIntKey(entry)) eh.getIntKey(entry) -> valueCreator(eh.getValue(entry))
else if (eh.hasLongKey(entry)) eh.getLongKey(entry) -> valueCreator(eh.getValue(entry))
else if (eh.hasOtherKey(entry)) otherMessageFromProto(eh.getOtherKey(entry)) -> valueCreator(eh.getValue(entry))
2019-03-11 10:38:24 +01:00
else
throw new IllegalArgumentException(
s"Can't deserialize ${entry.getClass} because it does not have any key in the serialized message.")
}.toMap
}
def ormapFromProto(ormap: rd.ORMap): ORMap[Any, ReplicatedData] = {
2019-03-13 10:56:20 +01:00
val entries = mapTypeFromProto(
ormap.getEntriesList,
(v: dm.OtherMessage) => otherMessageFromProto(v).asInstanceOf[ReplicatedData])
2019-03-11 10:38:24 +01:00
new ORMap(keys = orsetFromProto(ormap.getKeys), entries, ORMap.VanillaORMapTag)
2017-02-23 01:20:33 +01:00
}
2019-03-11 10:38:24 +01:00
def singleMapEntryFromProto[PEntry <: GeneratedMessage, A <: GeneratedMessage, B <: ReplicatedData](
input: util.List[PEntry],
valueCreator: A => B)(implicit eh: ProtoMapEntryReader[PEntry, A]): Map[Any, B] = {
val map = mapTypeFromProto(input, valueCreator)
if (map.size > 1)
2019-03-11 10:38:24 +01:00
throw new IllegalArgumentException(
s"Can't deserialize the key/value pair in the ORMap delta - too many pairs on the wire")
else
map
}
2019-03-11 10:38:24 +01:00
def singleKeyEntryFromProto[PEntry <: GeneratedMessage, A <: GeneratedMessage](entryOption: Option[PEntry])(
implicit eh: ProtoMapEntryReader[PEntry, A]): Any =
entryOption match {
2019-03-11 10:38:24 +01:00
case Some(entry) =>
if (eh.hasStringKey(entry)) eh.getStringKey(entry)
else if (eh.hasIntKey(entry)) eh.getIntKey(entry)
else if (eh.hasLongKey(entry)) eh.getLongKey(entry)
else if (eh.hasOtherKey(entry)) otherMessageFromProto(eh.getOtherKey(entry))
else throw new IllegalArgumentException(s"Can't deserialize the key in the ORMap delta")
case _ => throw new IllegalArgumentException(s"Can't deserialize the key in the ORMap delta")
}
2017-03-20 12:22:49 +01:00
2017-02-23 01:20:33 +01:00
// wire protocol is always DeltaGroup
private def ormapPutFromBinary(bytes: Array[Byte]): ORMap.PutDeltaOp[Any, ReplicatedData] = {
val ops = ormapDeltaGroupOpsFromBinary(bytes)
if (ops.size == 1 && ops.head.isInstanceOf[ORMap.PutDeltaOp[_, _]])
ops.head.asInstanceOf[ORMap.PutDeltaOp[Any, ReplicatedData]]
2017-02-23 01:20:33 +01:00
else
throw new NotSerializableException("Improper ORMap delta put operation size or kind")
}
// wire protocol is always delta group
private def ormapRemoveFromBinary(bytes: Array[Byte]): ORMap.RemoveDeltaOp[Any, ReplicatedData] = {
val ops = ormapDeltaGroupOpsFromBinary(bytes)
if (ops.size == 1 && ops.head.isInstanceOf[ORMap.RemoveDeltaOp[_, _]])
ops.head.asInstanceOf[ORMap.RemoveDeltaOp[Any, ReplicatedData]]
2017-02-23 01:20:33 +01:00
else
throw new NotSerializableException("Improper ORMap delta remove operation size or kind")
}
// wire protocol is always delta group
private def ormapRemoveKeyFromBinary(bytes: Array[Byte]): ORMap.RemoveKeyDeltaOp[Any, ReplicatedData] = {
val ops = ormapDeltaGroupOpsFromBinary(bytes)
if (ops.size == 1 && ops.head.isInstanceOf[ORMap.RemoveKeyDeltaOp[_, _]])
ops.head.asInstanceOf[ORMap.RemoveKeyDeltaOp[Any, ReplicatedData]]
2017-02-23 01:20:33 +01:00
else
throw new NotSerializableException("Improper ORMap delta remove key operation size or kind")
}
// wire protocol is always delta group
private def ormapUpdateFromBinary(bytes: Array[Byte]): ORMap.UpdateDeltaOp[Any, ReplicatedDelta] = {
val ops = ormapDeltaGroupOpsFromBinary(bytes)
if (ops.size == 1 && ops.head.isInstanceOf[ORMap.UpdateDeltaOp[_, _]])
ops.head.asInstanceOf[ORMap.UpdateDeltaOp[Any, ReplicatedDelta]]
2017-02-23 01:20:33 +01:00
else
throw new NotSerializableException("Improper ORMap delta update operation size or kind")
}
// this can be made client-extendable in the same way as Http codes in Spray are
private def zeroTagFromCode(code: Int) = code match {
2019-03-11 10:38:24 +01:00
case ORMap.VanillaORMapTag.value => ORMap.VanillaORMapTag
case PNCounterMap.PNCounterMapTag.value => PNCounterMap.PNCounterMapTag
case ORMultiMap.ORMultiMapTag.value => ORMultiMap.ORMultiMapTag
case ORMultiMap.ORMultiMapWithValueDeltasTag.value => ORMultiMap.ORMultiMapWithValueDeltasTag
2019-03-11 10:38:24 +01:00
case LWWMap.LWWMapTag.value => LWWMap.LWWMapTag
case _ => throw new IllegalArgumentException("Invalid ZeroTag code")
2017-02-23 01:20:33 +01:00
}
private def ormapDeltaGroupFromBinary(bytes: Array[Byte]): ORMap.DeltaGroup[Any, ReplicatedData] = {
ORMap.DeltaGroup(ormapDeltaGroupOpsFromBinary(bytes))
}
private def ormapDeltaGroupOpsFromBinary(bytes: Array[Byte]): scala.collection.immutable.IndexedSeq[ORMap.DeltaOp] = {
2017-02-23 01:20:33 +01:00
val deltaGroup = rd.ORMapDeltaGroup.parseFrom(bytes)
val ops: Vector[ORMap.DeltaOp] =
2019-03-11 10:38:24 +01:00
deltaGroup.getEntriesList.asScala.iterator
.map { entry =>
if (entry.getOperation == rd.ORMapDeltaOp.ORMapPut) {
val map =
2019-03-13 10:56:20 +01:00
singleMapEntryFromProto(
entry.getEntryDataList,
(v: dm.OtherMessage) => otherMessageFromProto(v).asInstanceOf[ReplicatedData])
ORMap.PutDeltaOp(
ORSet.AddDeltaOp(orsetFromProto(entry.getUnderlying)),
map.head,
zeroTagFromCode(entry.getZeroTag))
2019-03-11 10:38:24 +01:00
} else if (entry.getOperation == rd.ORMapDeltaOp.ORMapRemove) {
2019-03-13 10:56:20 +01:00
ORMap.RemoveDeltaOp(
ORSet.RemoveDeltaOp(orsetFromProto(entry.getUnderlying)),
zeroTagFromCode(entry.getZeroTag))
2019-03-11 10:38:24 +01:00
} else if (entry.getOperation == rd.ORMapDeltaOp.ORMapRemoveKey) {
val elem = singleKeyEntryFromProto(entry.getEntryDataList.asScala.headOption)
2019-03-13 10:56:20 +01:00
ORMap.RemoveKeyDeltaOp(
ORSet.RemoveDeltaOp(orsetFromProto(entry.getUnderlying)),
elem,
zeroTagFromCode(entry.getZeroTag))
2019-03-11 10:38:24 +01:00
} else if (entry.getOperation == rd.ORMapDeltaOp.ORMapUpdate) {
2019-03-13 10:56:20 +01:00
val map = mapTypeFromProto(
entry.getEntryDataList,
(v: dm.OtherMessage) => otherMessageFromProto(v).asInstanceOf[ReplicatedDelta])
ORMap.UpdateDeltaOp(
ORSet.AddDeltaOp(orsetFromProto(entry.getUnderlying)),
map,
zeroTagFromCode(entry.getZeroTag))
2019-03-11 10:38:24 +01:00
} else
throw new NotSerializableException(s"Unknown ORMap delta operation ${entry.getOperation}")
}
.to(immutable.Vector)
ops
2017-02-23 01:20:33 +01:00
}
2017-03-20 10:42:38 +01:00
private def ormapPutToProto(deltaOp: ORMap.PutDeltaOp[_, _]): rd.ORMapDeltaGroup = {
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
ormapDeltaGroupOpsToProto(immutable.IndexedSeq(deltaOp.asInstanceOf[ORMap.DeltaOp]))
2017-02-23 01:20:33 +01:00
}
2017-03-20 10:42:38 +01:00
private def ormapRemoveToProto(deltaOp: ORMap.RemoveDeltaOp[_, _]): rd.ORMapDeltaGroup = {
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
ormapDeltaGroupOpsToProto(immutable.IndexedSeq(deltaOp.asInstanceOf[ORMap.DeltaOp]))
2017-02-23 01:20:33 +01:00
}
2017-03-20 10:42:38 +01:00
private def ormapRemoveKeyToProto(deltaOp: ORMap.RemoveKeyDeltaOp[_, _]): rd.ORMapDeltaGroup = {
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
ormapDeltaGroupOpsToProto(immutable.IndexedSeq(deltaOp.asInstanceOf[ORMap.DeltaOp]))
2017-02-23 01:20:33 +01:00
}
2017-03-20 10:42:38 +01:00
private def ormapUpdateToProto(deltaOp: ORMap.UpdateDeltaOp[_, _]): rd.ORMapDeltaGroup = {
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
ormapDeltaGroupOpsToProto(immutable.IndexedSeq(deltaOp.asInstanceOf[ORMap.DeltaOp]))
2017-02-23 01:20:33 +01:00
}
private def ormapDeltaGroupToProto(deltaGroup: ORMap.DeltaGroup[_, _]): rd.ORMapDeltaGroup = {
ormapDeltaGroupOpsToProto(deltaGroup.ops)
}
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
private def ormapDeltaGroupOpsToProto(deltaGroupOps: immutable.IndexedSeq[ORMap.DeltaOp]): rd.ORMapDeltaGroup = {
2017-02-23 01:20:33 +01:00
def createEntry(opType: rd.ORMapDeltaOp, u: ORSet[_], m: Map[_, _], zt: Int) = {
if (m.size > 1 && opType != rd.ORMapDeltaOp.ORMapUpdate)
2017-02-23 01:20:33 +01:00
throw new IllegalArgumentException("Invalid size of ORMap delta map")
else {
2019-03-11 10:38:24 +01:00
val builder =
rd.ORMapDeltaGroup.Entry.newBuilder().setOperation(opType).setUnderlying(orsetToProto(u)).setZeroTag(zt)
m.foreach {
2019-03-11 10:38:24 +01:00
case (key: String, value) =>
builder.addEntryData(
rd.ORMapDeltaGroup.MapEntry.newBuilder().setStringKey(key).setValue(otherMessageToProto(value)).build())
case (key: Int, value) =>
builder.addEntryData(
rd.ORMapDeltaGroup.MapEntry.newBuilder().setIntKey(key).setValue(otherMessageToProto(value)).build())
case (key: Long, value) =>
builder.addEntryData(
rd.ORMapDeltaGroup.MapEntry.newBuilder().setLongKey(key).setValue(otherMessageToProto(value)).build())
case (key, value) =>
builder.addEntryData(
rd.ORMapDeltaGroup.MapEntry
.newBuilder()
.setOtherKey(otherMessageToProto(key))
.setValue(otherMessageToProto(value))
.build())
}
2017-02-23 01:20:33 +01:00
builder
}
}
2017-03-20 12:22:49 +01:00
def createEntryWithKey(opType: rd.ORMapDeltaOp, u: ORSet[_], k: Any, zt: Int) = {
val entryDataBuilder = rd.ORMapDeltaGroup.MapEntry.newBuilder()
k match {
case key: String => entryDataBuilder.setStringKey(key)
case key: Int => entryDataBuilder.setIntKey(key)
case key: Long => entryDataBuilder.setLongKey(key)
case key => entryDataBuilder.setOtherKey(otherMessageToProto(key))
2017-03-20 12:22:49 +01:00
}
2019-03-11 10:38:24 +01:00
val builder =
rd.ORMapDeltaGroup.Entry.newBuilder().setOperation(opType).setUnderlying(orsetToProto(u)).setZeroTag(zt)
builder.addEntryData(entryDataBuilder.build())
2017-03-20 12:22:49 +01:00
builder
}
2017-02-23 01:20:33 +01:00
val b = rd.ORMapDeltaGroup.newBuilder()
deltaGroupOps.foreach {
case ORMap.PutDeltaOp(op, pair, zt) =>
2019-03-11 10:38:24 +01:00
b.addEntries(
createEntry(rd.ORMapDeltaOp.ORMapPut, op.asInstanceOf[ORSet.AddDeltaOp[_]].underlying, Map(pair), zt.value))
case ORMap.RemoveDeltaOp(op, zt) =>
2019-03-11 10:38:24 +01:00
b.addEntries(
2019-03-13 10:56:20 +01:00
createEntry(
rd.ORMapDeltaOp.ORMapRemove,
op.asInstanceOf[ORSet.RemoveDeltaOp[_]].underlying,
Map.empty,
zt.value))
case ORMap.RemoveKeyDeltaOp(op, k, zt) =>
2019-03-11 10:38:24 +01:00
b.addEntries(
2019-03-13 10:56:20 +01:00
createEntryWithKey(
rd.ORMapDeltaOp.ORMapRemoveKey,
op.asInstanceOf[ORSet.RemoveDeltaOp[_]].underlying,
k,
zt.value))
case ORMap.UpdateDeltaOp(op, m, zt) =>
2019-03-11 10:38:24 +01:00
b.addEntries(
createEntry(rd.ORMapDeltaOp.ORMapUpdate, op.asInstanceOf[ORSet.AddDeltaOp[_]].underlying, m, zt.value))
case ORMap.DeltaGroup(_) =>
2017-02-23 01:20:33 +01:00
throw new IllegalArgumentException("ORMap.DeltaGroup should not be nested")
}
b.build()
}
def lwwmapToProto(lwwmap: LWWMap[_, _]): rd.LWWMap = {
2017-02-23 01:20:33 +01:00
val lwwmapBuilder = rd.LWWMap.newBuilder()
2019-03-11 10:38:24 +01:00
val entries: jl.Iterable[rd.LWWMap.Entry] =
getEntries(lwwmap.underlying.entries, rd.LWWMap.Entry.newBuilder _, lwwRegisterToProto)
2017-02-23 01:20:33 +01:00
lwwmapBuilder.setKeys(orsetToProto(lwwmap.underlying.keys)).addAllEntries(entries).build()
}
def lwwmapFromBinary(bytes: Array[Byte]): LWWMap[Any, Any] =
lwwmapFromProto(rd.LWWMap.parseFrom(decompress(bytes)))
def lwwmapFromProto(lwwmap: rd.LWWMap): LWWMap[Any, Any] = {
val entries = mapTypeFromProto(lwwmap.getEntriesList, lwwRegisterFromProto)
2019-03-11 10:38:24 +01:00
new LWWMap(new ORMap(keys = orsetFromProto(lwwmap.getKeys), entries, LWWMap.LWWMapTag))
}
def pncountermapToProto(pncountermap: PNCounterMap[_]): rd.PNCounterMap = {
2017-02-23 01:20:33 +01:00
val pncountermapBuilder = rd.PNCounterMap.newBuilder()
2019-03-11 10:38:24 +01:00
val entries: jl.Iterable[rd.PNCounterMap.Entry] =
getEntries(pncountermap.underlying.entries, rd.PNCounterMap.Entry.newBuilder _, pncounterToProto)
2017-02-23 01:20:33 +01:00
pncountermapBuilder.setKeys(orsetToProto(pncountermap.underlying.keys)).addAllEntries(entries).build()
}
def pncountermapFromBinary(bytes: Array[Byte]): PNCounterMap[_] =
pncountermapFromProto(rd.PNCounterMap.parseFrom(decompress(bytes)))
def pncountermapFromProto(pncountermap: rd.PNCounterMap): PNCounterMap[_] = {
val entries = mapTypeFromProto(pncountermap.getEntriesList, pncounterFromProto)
2019-03-11 10:38:24 +01:00
new PNCounterMap(new ORMap(keys = orsetFromProto(pncountermap.getKeys), entries, PNCounterMap.PNCounterMapTag))
}
def multimapToProto(multimap: ORMultiMap[_, _]): rd.ORMultiMap = {
2017-02-23 01:20:33 +01:00
val ormultimapBuilder = rd.ORMultiMap.newBuilder()
2019-03-11 10:38:24 +01:00
val entries: jl.Iterable[rd.ORMultiMap.Entry] =
getEntries(multimap.underlying.entries, rd.ORMultiMap.Entry.newBuilder _, orsetToProto)
2017-02-23 01:20:33 +01:00
ormultimapBuilder.setKeys(orsetToProto(multimap.underlying.keys)).addAllEntries(entries)
if (multimap.withValueDeltas)
ormultimapBuilder.setWithValueDeltas(true)
ormultimapBuilder.build()
2015-06-18 16:17:53 +02:00
}
def multimapFromBinary(bytes: Array[Byte]): ORMultiMap[Any, Any] =
2015-06-18 16:17:53 +02:00
multimapFromProto(rd.ORMultiMap.parseFrom(decompress(bytes)))
def multimapFromProto(multimap: rd.ORMultiMap): ORMultiMap[Any, Any] = {
val entries = mapTypeFromProto(multimap.getEntriesList, orsetFromProto)
2019-03-11 10:38:24 +01:00
val withValueDeltas =
if (multimap.hasWithValueDeltas)
multimap.getWithValueDeltas
else false
2019-03-13 10:56:20 +01:00
new ORMultiMap(
new ORMap(
keys = orsetFromProto(multimap.getKeys),
entries,
if (withValueDeltas)
ORMultiMap.ORMultiMapWithValueDeltasTag
else
ORMultiMap.ORMultiMapTag),
withValueDeltas)
2015-06-18 16:17:53 +02:00
}
def keyIdToBinary(id: String): Array[Byte] =
id.getBytes(UTF_8)
def keyIdFromBinary(bytes: Array[Byte]): String =
new String(bytes, UTF_8)
}
object OtherMessageComparator extends Comparator[dm.OtherMessage] {
override def compare(a: dm.OtherMessage, b: dm.OtherMessage): Int = {
val aByteString = a.getEnclosedMessage
val bByteString = b.getEnclosedMessage
val aSize = aByteString.size
val bSize = bByteString.size
if (aSize == bSize) {
val aIter = aByteString.iterator
val bIter = bByteString.iterator
@tailrec def findDiff(): Int = {
if (aIter.hasNext) {
val aByte = aIter.nextByte()
val bByte = bIter.nextByte()
if (aByte < bByte) -1
else if (aByte > bByte) 1
else findDiff()
} else 0
}
findDiff()
} else if (aSize < bSize) -1
else 1
}
}