#22035 Make it possible to use anything as the key in a map
- All Map types are now generic in their key: ORMap, ORMultiMap, LWWMap, PNCounterMap - test for binary compatibility with previous version for serialization - entries are sorted for deterministic SHA-1 on same value
This commit is contained in:
parent
5c79b81e92
commit
8499ff6faf
28 changed files with 2231 additions and 584 deletions
|
|
@ -3,10 +3,11 @@
|
|||
*/
|
||||
package akka.cluster.ddata.protobuf
|
||||
|
||||
import java.{ lang ⇒ jl }
|
||||
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._
|
||||
import scala.collection.breakOut
|
||||
|
|
@ -17,11 +18,137 @@ 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
|
||||
import akka.protobuf.{ ByteString, GeneratedMessage }
|
||||
import akka.util.ByteString.UTF_8
|
||||
|
||||
import scala.collection.immutable.TreeMap
|
||||
import akka.cluster.UniqueAddress
|
||||
import java.io.NotSerializableException
|
||||
import akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage
|
||||
|
||||
private object ReplicatedDataSerializer {
|
||||
/*
|
||||
* Generic superclass to allow to compare Entry types used in protobuf.
|
||||
*/
|
||||
abstract class KeyComparator[A <: GeneratedMessage] extends Comparator[A] {
|
||||
/**
|
||||
* Get the key from the entry. The key may be a String, Integer, Long, or Any
|
||||
* @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)
|
||||
}
|
||||
}
|
||||
|
||||
implicit object ORMapEntryComparator extends KeyComparator[rd.ORMap.Entry] {
|
||||
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] {
|
||||
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] {
|
||||
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] {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
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
|
||||
}
|
||||
|
||||
implicit object PNCounterMapEntry extends ProtoMapEntryWriter[rd.PNCounterMap.Entry, rd.PNCounterMap.Entry.Builder, rd.PNCounter] with ProtoMapEntryReader[rd.PNCounterMap.Entry, rd.PNCounter] {
|
||||
override def setStringKey(builder: rd.PNCounterMap.Entry.Builder, key: String, value: rd.PNCounter): rd.PNCounterMap.Entry = builder.setStringKey(key).setValue(value).build()
|
||||
override def setLongKey(builder: rd.PNCounterMap.Entry.Builder, key: Long, value: rd.PNCounter): rd.PNCounterMap.Entry = builder.setLongKey(key).setValue(value).build()
|
||||
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 = 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
|
||||
}
|
||||
|
||||
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()
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Protobuf serializer of ReplicatedData.
|
||||
|
|
@ -29,6 +156,8 @@ import java.io.NotSerializableException
|
|||
class ReplicatedDataSerializer(val system: ExtendedActorSystem)
|
||||
extends SerializerWithStringManifest with SerializationSupport with BaseSerializer {
|
||||
|
||||
import ReplicatedDataSerializer._
|
||||
|
||||
private val DeletedDataManifest = "A"
|
||||
private val GSetManifest = "B"
|
||||
private val GSetKeyManifest = "b"
|
||||
|
|
@ -78,48 +207,48 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem)
|
|||
ORMultiMapKeyManifest → (bytes ⇒ ORMultiMapKey(keyIdFromBinary(bytes))))
|
||||
|
||||
override def manifest(obj: AnyRef): String = obj match {
|
||||
case _: ORSet[_] ⇒ ORSetManifest
|
||||
case _: GSet[_] ⇒ GSetManifest
|
||||
case _: GCounter ⇒ GCounterManifest
|
||||
case _: PNCounter ⇒ PNCounterManifest
|
||||
case _: Flag ⇒ FlagManifest
|
||||
case _: LWWRegister[_] ⇒ LWWRegisterManifest
|
||||
case _: ORMap[_] ⇒ ORMapManifest
|
||||
case _: LWWMap[_] ⇒ LWWMapManifest
|
||||
case _: PNCounterMap ⇒ PNCounterMapManifest
|
||||
case _: ORMultiMap[_] ⇒ ORMultiMapManifest
|
||||
case DeletedData ⇒ DeletedDataManifest
|
||||
case _: VersionVector ⇒ VersionVectorManifest
|
||||
case _: ORSet[_] ⇒ ORSetManifest
|
||||
case _: GSet[_] ⇒ GSetManifest
|
||||
case _: GCounter ⇒ GCounterManifest
|
||||
case _: PNCounter ⇒ PNCounterManifest
|
||||
case _: Flag ⇒ FlagManifest
|
||||
case _: LWWRegister[_] ⇒ LWWRegisterManifest
|
||||
case _: ORMap[_, _] ⇒ ORMapManifest
|
||||
case _: LWWMap[_, _] ⇒ LWWMapManifest
|
||||
case _: PNCounterMap[_] ⇒ PNCounterMapManifest
|
||||
case _: ORMultiMap[_, _] ⇒ ORMultiMapManifest
|
||||
case DeletedData ⇒ DeletedDataManifest
|
||||
case _: VersionVector ⇒ VersionVectorManifest
|
||||
|
||||
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 _: 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 _ ⇒
|
||||
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: 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: 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[_] ⇒ compress(orsetToProto(m))
|
||||
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: 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 _ ⇒
|
||||
throw new IllegalArgumentException(s"Can't serialize object of type ${obj.getClass} in [${getClass.getName}]")
|
||||
}
|
||||
|
|
@ -328,83 +457,88 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem)
|
|||
}
|
||||
}
|
||||
|
||||
def ormapToProto(ormap: ORMap[_]): rd.ORMap = {
|
||||
val b = rd.ORMap.newBuilder().setKeys(orsetToProto(ormap.keys))
|
||||
ormap.entries.toVector.sortBy { case (key, _) ⇒ key }.foreach {
|
||||
case (key, value) ⇒ b.addEntries(rd.ORMap.Entry.newBuilder().
|
||||
setKey(key).setValue(otherMessageToProto(value)))
|
||||
/*
|
||||
* Convert a Map[A, B] to an Iterable[Entry] where Entry is the protobuf map entry.
|
||||
*/
|
||||
private def getEntries[IKey, IValue, EntryBuilder <: GeneratedMessage.Builder[EntryBuilder], PEntry <: GeneratedMessage, PValue <: GeneratedMessage](input: Map[IKey, IValue], createBuilder: () ⇒ EntryBuilder, valueConverter: IValue ⇒ PValue)(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)))
|
||||
case (key, value) ⇒ protoEntries.add(eh.setOtherKey(createBuilder(), otherMessageToProto(key), valueConverter(value)))
|
||||
}
|
||||
b.build()
|
||||
protoEntries
|
||||
}
|
||||
|
||||
def ormapFromBinary(bytes: Array[Byte]): ORMap[ReplicatedData] =
|
||||
def ormapToProto(ormap: ORMap[_, _]): rd.ORMap = {
|
||||
val entries: jl.Iterable[rd.ORMap.Entry] = getEntries(ormap.values, rd.ORMap.Entry.newBuilder, otherMessageToProto)
|
||||
rd.ORMap.newBuilder().setKeys(orsetToProto(ormap.keys)).addAllEntries(entries).build()
|
||||
}
|
||||
|
||||
def ormapFromBinary(bytes: Array[Byte]): ORMap[Any, ReplicatedData] =
|
||||
ormapFromProto(rd.ORMap.parseFrom(decompress(bytes)))
|
||||
|
||||
def ormapFromProto(ormap: rd.ORMap): ORMap[ReplicatedData] = {
|
||||
val entries = ormap.getEntriesList.asScala.map(entry ⇒
|
||||
entry.getKey → otherMessageFromProto(entry.getValue).asInstanceOf[ReplicatedData]).toMap
|
||||
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))
|
||||
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] = {
|
||||
val entries = mapTypeFromProto(ormap.getEntriesList, (v: dm.OtherMessage) ⇒ otherMessageFromProto(v).asInstanceOf[ReplicatedData])
|
||||
new ORMap(
|
||||
keys = orsetFromProto(ormap.getKeys).asInstanceOf[ORSet[String]],
|
||||
keys = orsetFromProto(ormap.getKeys),
|
||||
entries)
|
||||
}
|
||||
|
||||
def lwwmapToProto(lwwmap: LWWMap[_]): rd.LWWMap = {
|
||||
val b = rd.LWWMap.newBuilder().setKeys(orsetToProto(lwwmap.underlying.keys))
|
||||
lwwmap.underlying.entries.toVector.sortBy { case (key, _) ⇒ key }.foreach {
|
||||
case (key, value) ⇒ b.addEntries(rd.LWWMap.Entry.newBuilder().
|
||||
setKey(key).setValue(lwwRegisterToProto(value)))
|
||||
}
|
||||
b.build()
|
||||
def lwwmapToProto(lwwmap: LWWMap[_, _]): rd.LWWMap = {
|
||||
val entries: jl.Iterable[rd.LWWMap.Entry] = getEntries(lwwmap.underlying.entries, rd.LWWMap.Entry.newBuilder, lwwRegisterToProto)
|
||||
rd.LWWMap.newBuilder().setKeys(orsetToProto(lwwmap.underlying.keys)).addAllEntries(entries).build()
|
||||
}
|
||||
|
||||
def lwwmapFromBinary(bytes: Array[Byte]): LWWMap[Any] =
|
||||
def lwwmapFromBinary(bytes: Array[Byte]): LWWMap[Any, Any] =
|
||||
lwwmapFromProto(rd.LWWMap.parseFrom(decompress(bytes)))
|
||||
|
||||
def lwwmapFromProto(lwwmap: rd.LWWMap): LWWMap[Any] = {
|
||||
val entries = lwwmap.getEntriesList.asScala.map(entry ⇒
|
||||
entry.getKey → lwwRegisterFromProto(entry.getValue)).toMap
|
||||
def lwwmapFromProto(lwwmap: rd.LWWMap): LWWMap[Any, Any] = {
|
||||
val entries = mapTypeFromProto(lwwmap.getEntriesList, lwwRegisterFromProto)
|
||||
new LWWMap(new ORMap(
|
||||
keys = orsetFromProto(lwwmap.getKeys).asInstanceOf[ORSet[String]],
|
||||
keys = orsetFromProto(lwwmap.getKeys),
|
||||
entries))
|
||||
}
|
||||
|
||||
def pncountermapToProto(pncountermap: PNCounterMap): rd.PNCounterMap = {
|
||||
val b = rd.PNCounterMap.newBuilder().setKeys(orsetToProto(pncountermap.underlying.keys))
|
||||
pncountermap.underlying.entries.toVector.sortBy { case (key, _) ⇒ key }.foreach {
|
||||
case (key, value: PNCounter) ⇒ b.addEntries(rd.PNCounterMap.Entry.newBuilder().
|
||||
setKey(key).setValue(pncounterToProto(value)))
|
||||
}
|
||||
b.build()
|
||||
def pncountermapToProto(pncountermap: PNCounterMap[_]): rd.PNCounterMap = {
|
||||
val entries: jl.Iterable[rd.PNCounterMap.Entry] = getEntries(pncountermap.underlying.entries, rd.PNCounterMap.Entry.newBuilder, pncounterToProto)
|
||||
rd.PNCounterMap.newBuilder().setKeys(orsetToProto(pncountermap.underlying.keys)).addAllEntries(entries).build()
|
||||
}
|
||||
|
||||
def pncountermapFromBinary(bytes: Array[Byte]): PNCounterMap =
|
||||
def pncountermapFromBinary(bytes: Array[Byte]): PNCounterMap[_] =
|
||||
pncountermapFromProto(rd.PNCounterMap.parseFrom(decompress(bytes)))
|
||||
|
||||
def pncountermapFromProto(pncountermap: rd.PNCounterMap): PNCounterMap = {
|
||||
val entries = pncountermap.getEntriesList.asScala.map(entry ⇒
|
||||
entry.getKey → pncounterFromProto(entry.getValue)).toMap
|
||||
def pncountermapFromProto(pncountermap: rd.PNCounterMap): PNCounterMap[_] = {
|
||||
val entries = mapTypeFromProto(pncountermap.getEntriesList, pncounterFromProto)
|
||||
new PNCounterMap(new ORMap(
|
||||
keys = orsetFromProto(pncountermap.getKeys).asInstanceOf[ORSet[String]],
|
||||
keys = orsetFromProto(pncountermap.getKeys),
|
||||
entries))
|
||||
}
|
||||
|
||||
def multimapToProto(multimap: ORMultiMap[_]): rd.ORMultiMap = {
|
||||
val b = rd.ORMultiMap.newBuilder().setKeys(orsetToProto(multimap.underlying.keys))
|
||||
multimap.underlying.entries.toVector.sortBy { case (key, _) ⇒ key }.foreach {
|
||||
case (key, value) ⇒ b.addEntries(rd.ORMultiMap.Entry.newBuilder().
|
||||
setKey(key).setValue(orsetToProto(value)))
|
||||
}
|
||||
b.build()
|
||||
def multimapToProto(multimap: ORMultiMap[_, _]): rd.ORMultiMap = {
|
||||
val entries: jl.Iterable[rd.ORMultiMap.Entry] = getEntries(multimap.underlying.entries, rd.ORMultiMap.Entry.newBuilder, orsetToProto)
|
||||
rd.ORMultiMap.newBuilder().setKeys(orsetToProto(multimap.underlying.keys)).addAllEntries(entries).build()
|
||||
}
|
||||
|
||||
def multimapFromBinary(bytes: Array[Byte]): ORMultiMap[Any] =
|
||||
def multimapFromBinary(bytes: Array[Byte]): ORMultiMap[Any, Any] =
|
||||
multimapFromProto(rd.ORMultiMap.parseFrom(decompress(bytes)))
|
||||
|
||||
def multimapFromProto(multimap: rd.ORMultiMap): ORMultiMap[Any] = {
|
||||
val entries = multimap.getEntriesList.asScala.map(entry ⇒
|
||||
entry.getKey → orsetFromProto(entry.getValue)).toMap
|
||||
def multimapFromProto(multimap: rd.ORMultiMap): ORMultiMap[Any, Any] = {
|
||||
val entries = mapTypeFromProto(multimap.getEntriesList, orsetFromProto)
|
||||
new ORMultiMap(new ORMap(
|
||||
keys = orsetFromProto(multimap.getKeys).asInstanceOf[ORSet[String]],
|
||||
keys = orsetFromProto(multimap.getKeys),
|
||||
entries))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue