diff --git a/akka-distributed-data/src/main/java/akka/cluster/ddata/protobuf/msg/ReplicatedDataMessages.java b/akka-distributed-data/src/main/java/akka/cluster/ddata/protobuf/msg/ReplicatedDataMessages.java index 306256493a..1f25776e93 100644 --- a/akka-distributed-data/src/main/java/akka/cluster/ddata/protobuf/msg/ReplicatedDataMessages.java +++ b/akka-distributed-data/src/main/java/akka/cluster/ddata/protobuf/msg/ReplicatedDataMessages.java @@ -99,6 +99,106 @@ public final class ReplicatedDataMessages { // @@protoc_insertion_point(enum_scope:akka.cluster.ddata.ORSetDeltaOp) } + /** + * Protobuf enum {@code akka.cluster.ddata.ORMapDeltaOp} + */ + public enum ORMapDeltaOp + implements akka.protobuf.ProtocolMessageEnum { + /** + * ORMapPut = 0; + */ + ORMapPut(0, 0), + /** + * ORMapRemove = 1; + */ + ORMapRemove(1, 1), + /** + * ORMapRemoveKey = 2; + */ + ORMapRemoveKey(2, 2), + /** + * ORMapUpdate = 3; + */ + ORMapUpdate(3, 3), + ; + + /** + * ORMapPut = 0; + */ + public static final int ORMapPut_VALUE = 0; + /** + * ORMapRemove = 1; + */ + public static final int ORMapRemove_VALUE = 1; + /** + * ORMapRemoveKey = 2; + */ + public static final int ORMapRemoveKey_VALUE = 2; + /** + * ORMapUpdate = 3; + */ + public static final int ORMapUpdate_VALUE = 3; + + + public final int getNumber() { return value; } + + public static ORMapDeltaOp valueOf(int value) { + switch (value) { + case 0: return ORMapPut; + case 1: return ORMapRemove; + case 2: return ORMapRemoveKey; + case 3: return ORMapUpdate; + default: return null; + } + } + + public static akka.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static akka.protobuf.Internal.EnumLiteMap + internalValueMap = + new akka.protobuf.Internal.EnumLiteMap() { + public ORMapDeltaOp findValueByNumber(int number) { + return ORMapDeltaOp.valueOf(number); + } + }; + + public final akka.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final akka.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final akka.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.getDescriptor().getEnumTypes().get(1); + } + + private static final ORMapDeltaOp[] VALUES = values(); + + public static ORMapDeltaOp valueOf( + akka.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private ORMapDeltaOp(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:akka.cluster.ddata.ORMapDeltaOp) + } + public interface GSetOrBuilder extends akka.protobuf.MessageOrBuilder { @@ -9599,6 +9699,2651 @@ public final class ReplicatedDataMessages { // @@protoc_insertion_point(class_scope:akka.cluster.ddata.ORMap) } + public interface ORMapDeltaGroupOrBuilder + extends akka.protobuf.MessageOrBuilder { + + // repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + java.util.List + getEntriesList(); + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry getEntries(int index); + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + int getEntriesCount(); + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + java.util.List + getEntriesOrBuilderList(); + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder getEntriesOrBuilder( + int index); + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup} + */ + public static final class ORMapDeltaGroup extends + akka.protobuf.GeneratedMessage + implements ORMapDeltaGroupOrBuilder { + // Use ORMapDeltaGroup.newBuilder() to construct. + private ORMapDeltaGroup(akka.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private ORMapDeltaGroup(boolean noInit) { this.unknownFields = akka.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final ORMapDeltaGroup defaultInstance; + public static ORMapDeltaGroup getDefaultInstance() { + return defaultInstance; + } + + public ORMapDeltaGroup getDefaultInstanceForType() { + return defaultInstance; + } + + private final akka.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final akka.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private ORMapDeltaGroup( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + akka.protobuf.UnknownFieldSet.Builder unknownFields = + akka.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + entries_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + entries_.add(input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.PARSER, extensionRegistry)); + break; + } + } + } + } catch (akka.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new akka.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + entries_ = java.util.Collections.unmodifiableList(entries_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Builder.class); + } + + public static akka.protobuf.Parser PARSER = + new akka.protobuf.AbstractParser() { + public ORMapDeltaGroup parsePartialFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return new ORMapDeltaGroup(input, extensionRegistry); + } + }; + + @java.lang.Override + public akka.protobuf.Parser getParserForType() { + return PARSER; + } + + public interface MapEntryOrBuilder + extends akka.protobuf.MessageOrBuilder { + + // optional string stringKey = 1; + /** + * optional string stringKey = 1; + */ + boolean hasStringKey(); + /** + * optional string stringKey = 1; + */ + java.lang.String getStringKey(); + /** + * optional string stringKey = 1; + */ + akka.protobuf.ByteString + getStringKeyBytes(); + + // required .akka.cluster.ddata.OtherMessage value = 2; + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + boolean hasValue(); + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getValue(); + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getValueOrBuilder(); + + // optional sint32 intKey = 3; + /** + * optional sint32 intKey = 3; + */ + boolean hasIntKey(); + /** + * optional sint32 intKey = 3; + */ + int getIntKey(); + + // optional sint64 longKey = 4; + /** + * optional sint64 longKey = 4; + */ + boolean hasLongKey(); + /** + * optional sint64 longKey = 4; + */ + long getLongKey(); + + // optional .akka.cluster.ddata.OtherMessage otherKey = 5; + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + boolean hasOtherKey(); + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getOtherKey(); + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getOtherKeyOrBuilder(); + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup.MapEntry} + */ + public static final class MapEntry extends + akka.protobuf.GeneratedMessage + implements MapEntryOrBuilder { + // Use MapEntry.newBuilder() to construct. + private MapEntry(akka.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private MapEntry(boolean noInit) { this.unknownFields = akka.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final MapEntry defaultInstance; + public static MapEntry getDefaultInstance() { + return defaultInstance; + } + + public MapEntry getDefaultInstanceForType() { + return defaultInstance; + } + + private final akka.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final akka.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private MapEntry( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + akka.protobuf.UnknownFieldSet.Builder unknownFields = + akka.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + stringKey_ = input.readBytes(); + break; + } + case 18: { + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder subBuilder = null; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + subBuilder = value_.toBuilder(); + } + value_ = input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(value_); + value_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000002; + break; + } + case 24: { + bitField0_ |= 0x00000004; + intKey_ = input.readSInt32(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + longKey_ = input.readSInt64(); + break; + } + case 42: { + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder subBuilder = null; + if (((bitField0_ & 0x00000010) == 0x00000010)) { + subBuilder = otherKey_.toBuilder(); + } + otherKey_ = input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(otherKey_); + otherKey_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000010; + break; + } + } + } + } catch (akka.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new akka.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder.class); + } + + public static akka.protobuf.Parser PARSER = + new akka.protobuf.AbstractParser() { + public MapEntry parsePartialFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return new MapEntry(input, extensionRegistry); + } + }; + + @java.lang.Override + public akka.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional string stringKey = 1; + public static final int STRINGKEY_FIELD_NUMBER = 1; + private java.lang.Object stringKey_; + /** + * optional string stringKey = 1; + */ + public boolean hasStringKey() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional string stringKey = 1; + */ + public java.lang.String getStringKey() { + java.lang.Object ref = stringKey_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + akka.protobuf.ByteString bs = + (akka.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + stringKey_ = s; + } + return s; + } + } + /** + * optional string stringKey = 1; + */ + public akka.protobuf.ByteString + getStringKeyBytes() { + java.lang.Object ref = stringKey_; + if (ref instanceof java.lang.String) { + akka.protobuf.ByteString b = + akka.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + stringKey_ = b; + return b; + } else { + return (akka.protobuf.ByteString) ref; + } + } + + // required .akka.cluster.ddata.OtherMessage value = 2; + public static final int VALUE_FIELD_NUMBER = 2; + private akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value_; + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public boolean hasValue() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getValue() { + return value_; + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getValueOrBuilder() { + return value_; + } + + // optional sint32 intKey = 3; + public static final int INTKEY_FIELD_NUMBER = 3; + private int intKey_; + /** + * optional sint32 intKey = 3; + */ + public boolean hasIntKey() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional sint32 intKey = 3; + */ + public int getIntKey() { + return intKey_; + } + + // optional sint64 longKey = 4; + public static final int LONGKEY_FIELD_NUMBER = 4; + private long longKey_; + /** + * optional sint64 longKey = 4; + */ + public boolean hasLongKey() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional sint64 longKey = 4; + */ + public long getLongKey() { + return longKey_; + } + + // optional .akka.cluster.ddata.OtherMessage otherKey = 5; + public static final int OTHERKEY_FIELD_NUMBER = 5; + private akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage otherKey_; + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public boolean hasOtherKey() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getOtherKey() { + return otherKey_; + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getOtherKeyOrBuilder() { + return otherKey_; + } + + private void initFields() { + stringKey_ = ""; + value_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + intKey_ = 0; + longKey_ = 0L; + otherKey_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasValue()) { + memoizedIsInitialized = 0; + return false; + } + if (!getValue().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + if (hasOtherKey()) { + if (!getOtherKey().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(akka.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getStringKeyBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, value_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeSInt32(3, intKey_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeSInt64(4, longKey_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeMessage(5, otherKey_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += akka.protobuf.CodedOutputStream + .computeBytesSize(1, getStringKeyBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += akka.protobuf.CodedOutputStream + .computeMessageSize(2, value_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += akka.protobuf.CodedOutputStream + .computeSInt32Size(3, intKey_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += akka.protobuf.CodedOutputStream + .computeSInt64Size(4, longKey_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += akka.protobuf.CodedOutputStream + .computeMessageSize(5, otherKey_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + akka.protobuf.ByteString data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + akka.protobuf.ByteString data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom(byte[] data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + byte[] data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseDelimitedFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + akka.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parseFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup.MapEntry} + */ + public static final class Builder extends + akka.protobuf.GeneratedMessage.Builder + implements akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder { + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder.class); + } + + // Construct using akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (akka.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getValueFieldBuilder(); + getOtherKeyFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + stringKey_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + if (valueBuilder_ == null) { + value_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + } else { + valueBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + intKey_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + longKey_ = 0L; + bitField0_ = (bitField0_ & ~0x00000008); + if (otherKeyBuilder_ == null) { + otherKey_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + } else { + otherKeyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public akka.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry getDefaultInstanceForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance(); + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry build() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry buildPartial() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry result = new akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.stringKey_ = stringKey_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (valueBuilder_ == null) { + result.value_ = value_; + } else { + result.value_ = valueBuilder_.build(); + } + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.intKey_ = intKey_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.longKey_ = longKey_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + if (otherKeyBuilder_ == null) { + result.otherKey_ = otherKey_; + } else { + result.otherKey_ = otherKeyBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(akka.protobuf.Message other) { + if (other instanceof akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry) { + return mergeFrom((akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry other) { + if (other == akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance()) return this; + if (other.hasStringKey()) { + bitField0_ |= 0x00000001; + stringKey_ = other.stringKey_; + onChanged(); + } + if (other.hasValue()) { + mergeValue(other.getValue()); + } + if (other.hasIntKey()) { + setIntKey(other.getIntKey()); + } + if (other.hasLongKey()) { + setLongKey(other.getLongKey()); + } + if (other.hasOtherKey()) { + mergeOtherKey(other.getOtherKey()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasValue()) { + + return false; + } + if (!getValue().isInitialized()) { + + return false; + } + if (hasOtherKey()) { + if (!getOtherKey().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (akka.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional string stringKey = 1; + private java.lang.Object stringKey_ = ""; + /** + * optional string stringKey = 1; + */ + public boolean hasStringKey() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional string stringKey = 1; + */ + public java.lang.String getStringKey() { + java.lang.Object ref = stringKey_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((akka.protobuf.ByteString) ref) + .toStringUtf8(); + stringKey_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string stringKey = 1; + */ + public akka.protobuf.ByteString + getStringKeyBytes() { + java.lang.Object ref = stringKey_; + if (ref instanceof String) { + akka.protobuf.ByteString b = + akka.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + stringKey_ = b; + return b; + } else { + return (akka.protobuf.ByteString) ref; + } + } + /** + * optional string stringKey = 1; + */ + public Builder setStringKey( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + stringKey_ = value; + onChanged(); + return this; + } + /** + * optional string stringKey = 1; + */ + public Builder clearStringKey() { + bitField0_ = (bitField0_ & ~0x00000001); + stringKey_ = getDefaultInstance().getStringKey(); + onChanged(); + return this; + } + /** + * optional string stringKey = 1; + */ + public Builder setStringKeyBytes( + akka.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + stringKey_ = value; + onChanged(); + return this; + } + + // required .akka.cluster.ddata.OtherMessage value = 2; + private akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder> valueBuilder_; + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public boolean hasValue() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getValue() { + if (valueBuilder_ == null) { + return value_; + } else { + return valueBuilder_.getMessage(); + } + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public Builder setValue(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value) { + if (valueBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + value_ = value; + onChanged(); + } else { + valueBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public Builder setValue( + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder builderForValue) { + if (valueBuilder_ == null) { + value_ = builderForValue.build(); + onChanged(); + } else { + valueBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public Builder mergeValue(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value) { + if (valueBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + value_ != akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance()) { + value_ = + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.newBuilder(value_).mergeFrom(value).buildPartial(); + } else { + value_ = value; + } + onChanged(); + } else { + valueBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public Builder clearValue() { + if (valueBuilder_ == null) { + value_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + onChanged(); + } else { + valueBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder getValueBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getValueFieldBuilder().getBuilder(); + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getValueOrBuilder() { + if (valueBuilder_ != null) { + return valueBuilder_.getMessageOrBuilder(); + } else { + return value_; + } + } + /** + * required .akka.cluster.ddata.OtherMessage value = 2; + */ + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder> + getValueFieldBuilder() { + if (valueBuilder_ == null) { + valueBuilder_ = new akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder>( + value_, + getParentForChildren(), + isClean()); + value_ = null; + } + return valueBuilder_; + } + + // optional sint32 intKey = 3; + private int intKey_ ; + /** + * optional sint32 intKey = 3; + */ + public boolean hasIntKey() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional sint32 intKey = 3; + */ + public int getIntKey() { + return intKey_; + } + /** + * optional sint32 intKey = 3; + */ + public Builder setIntKey(int value) { + bitField0_ |= 0x00000004; + intKey_ = value; + onChanged(); + return this; + } + /** + * optional sint32 intKey = 3; + */ + public Builder clearIntKey() { + bitField0_ = (bitField0_ & ~0x00000004); + intKey_ = 0; + onChanged(); + return this; + } + + // optional sint64 longKey = 4; + private long longKey_ ; + /** + * optional sint64 longKey = 4; + */ + public boolean hasLongKey() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional sint64 longKey = 4; + */ + public long getLongKey() { + return longKey_; + } + /** + * optional sint64 longKey = 4; + */ + public Builder setLongKey(long value) { + bitField0_ |= 0x00000008; + longKey_ = value; + onChanged(); + return this; + } + /** + * optional sint64 longKey = 4; + */ + public Builder clearLongKey() { + bitField0_ = (bitField0_ & ~0x00000008); + longKey_ = 0L; + onChanged(); + return this; + } + + // optional .akka.cluster.ddata.OtherMessage otherKey = 5; + private akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage otherKey_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder> otherKeyBuilder_; + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public boolean hasOtherKey() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage getOtherKey() { + if (otherKeyBuilder_ == null) { + return otherKey_; + } else { + return otherKeyBuilder_.getMessage(); + } + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public Builder setOtherKey(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value) { + if (otherKeyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + otherKey_ = value; + onChanged(); + } else { + otherKeyBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public Builder setOtherKey( + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder builderForValue) { + if (otherKeyBuilder_ == null) { + otherKey_ = builderForValue.build(); + onChanged(); + } else { + otherKeyBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public Builder mergeOtherKey(akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage value) { + if (otherKeyBuilder_ == null) { + if (((bitField0_ & 0x00000010) == 0x00000010) && + otherKey_ != akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance()) { + otherKey_ = + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.newBuilder(otherKey_).mergeFrom(value).buildPartial(); + } else { + otherKey_ = value; + } + onChanged(); + } else { + otherKeyBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000010; + return this; + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public Builder clearOtherKey() { + if (otherKeyBuilder_ == null) { + otherKey_ = akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.getDefaultInstance(); + onChanged(); + } else { + otherKeyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder getOtherKeyBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return getOtherKeyFieldBuilder().getBuilder(); + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder getOtherKeyOrBuilder() { + if (otherKeyBuilder_ != null) { + return otherKeyBuilder_.getMessageOrBuilder(); + } else { + return otherKey_; + } + } + /** + * optional .akka.cluster.ddata.OtherMessage otherKey = 5; + */ + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder> + getOtherKeyFieldBuilder() { + if (otherKeyBuilder_ == null) { + otherKeyBuilder_ = new akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage.Builder, akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessageOrBuilder>( + otherKey_, + getParentForChildren(), + isClean()); + otherKey_ = null; + } + return otherKeyBuilder_; + } + + // @@protoc_insertion_point(builder_scope:akka.cluster.ddata.ORMapDeltaGroup.MapEntry) + } + + static { + defaultInstance = new MapEntry(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:akka.cluster.ddata.ORMapDeltaGroup.MapEntry) + } + + public interface EntryOrBuilder + extends akka.protobuf.MessageOrBuilder { + + // required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + boolean hasOperation(); + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp getOperation(); + + // required .akka.cluster.ddata.ORSet underlying = 2; + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + boolean hasUnderlying(); + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet getUnderlying(); + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder getUnderlyingOrBuilder(); + + // required sint32 zeroTag = 3; + /** + * required sint32 zeroTag = 3; + */ + boolean hasZeroTag(); + /** + * required sint32 zeroTag = 3; + */ + int getZeroTag(); + + // optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + boolean hasEntryData(); + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry getEntryData(); + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder getEntryDataOrBuilder(); + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup.Entry} + */ + public static final class Entry extends + akka.protobuf.GeneratedMessage + implements EntryOrBuilder { + // Use Entry.newBuilder() to construct. + private Entry(akka.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Entry(boolean noInit) { this.unknownFields = akka.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Entry defaultInstance; + public static Entry getDefaultInstance() { + return defaultInstance; + } + + public Entry getDefaultInstanceForType() { + return defaultInstance; + } + + private final akka.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final akka.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Entry( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + akka.protobuf.UnknownFieldSet.Builder unknownFields = + akka.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + int rawValue = input.readEnum(); + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp value = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(1, rawValue); + } else { + bitField0_ |= 0x00000001; + operation_ = value; + } + break; + } + case 18: { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder subBuilder = null; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + subBuilder = underlying_.toBuilder(); + } + underlying_ = input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(underlying_); + underlying_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000002; + break; + } + case 24: { + bitField0_ |= 0x00000004; + zeroTag_ = input.readSInt32(); + break; + } + case 34: { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder subBuilder = null; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + subBuilder = entryData_.toBuilder(); + } + entryData_ = input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(entryData_); + entryData_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000008; + break; + } + } + } + } catch (akka.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new akka.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder.class); + } + + public static akka.protobuf.Parser PARSER = + new akka.protobuf.AbstractParser() { + public Entry parsePartialFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return new Entry(input, extensionRegistry); + } + }; + + @java.lang.Override + public akka.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + public static final int OPERATION_FIELD_NUMBER = 1; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp operation_; + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public boolean hasOperation() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp getOperation() { + return operation_; + } + + // required .akka.cluster.ddata.ORSet underlying = 2; + public static final int UNDERLYING_FIELD_NUMBER = 2; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet underlying_; + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public boolean hasUnderlying() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet getUnderlying() { + return underlying_; + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder getUnderlyingOrBuilder() { + return underlying_; + } + + // required sint32 zeroTag = 3; + public static final int ZEROTAG_FIELD_NUMBER = 3; + private int zeroTag_; + /** + * required sint32 zeroTag = 3; + */ + public boolean hasZeroTag() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required sint32 zeroTag = 3; + */ + public int getZeroTag() { + return zeroTag_; + } + + // optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + public static final int ENTRYDATA_FIELD_NUMBER = 4; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry entryData_; + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public boolean hasEntryData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry getEntryData() { + return entryData_; + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder getEntryDataOrBuilder() { + return entryData_; + } + + private void initFields() { + operation_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp.ORMapPut; + underlying_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance(); + zeroTag_ = 0; + entryData_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasOperation()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasUnderlying()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasZeroTag()) { + memoizedIsInitialized = 0; + return false; + } + if (!getUnderlying().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + if (hasEntryData()) { + if (!getEntryData().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(akka.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeEnum(1, operation_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, underlying_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeSInt32(3, zeroTag_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeMessage(4, entryData_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += akka.protobuf.CodedOutputStream + .computeEnumSize(1, operation_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += akka.protobuf.CodedOutputStream + .computeMessageSize(2, underlying_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += akka.protobuf.CodedOutputStream + .computeSInt32Size(3, zeroTag_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += akka.protobuf.CodedOutputStream + .computeMessageSize(4, entryData_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + akka.protobuf.ByteString data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + akka.protobuf.ByteString data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom(byte[] data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + byte[] data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseDelimitedFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + akka.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parseFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup.Entry} + */ + public static final class Builder extends + akka.protobuf.GeneratedMessage.Builder + implements akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder { + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder.class); + } + + // Construct using akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (akka.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getUnderlyingFieldBuilder(); + getEntryDataFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + operation_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp.ORMapPut; + bitField0_ = (bitField0_ & ~0x00000001); + if (underlyingBuilder_ == null) { + underlying_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance(); + } else { + underlyingBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + zeroTag_ = 0; + bitField0_ = (bitField0_ & ~0x00000004); + if (entryDataBuilder_ == null) { + entryData_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance(); + } else { + entryDataBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public akka.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry getDefaultInstanceForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.getDefaultInstance(); + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry build() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry buildPartial() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry result = new akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.operation_ = operation_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (underlyingBuilder_ == null) { + result.underlying_ = underlying_; + } else { + result.underlying_ = underlyingBuilder_.build(); + } + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.zeroTag_ = zeroTag_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + if (entryDataBuilder_ == null) { + result.entryData_ = entryData_; + } else { + result.entryData_ = entryDataBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(akka.protobuf.Message other) { + if (other instanceof akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry) { + return mergeFrom((akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry other) { + if (other == akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.getDefaultInstance()) return this; + if (other.hasOperation()) { + setOperation(other.getOperation()); + } + if (other.hasUnderlying()) { + mergeUnderlying(other.getUnderlying()); + } + if (other.hasZeroTag()) { + setZeroTag(other.getZeroTag()); + } + if (other.hasEntryData()) { + mergeEntryData(other.getEntryData()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasOperation()) { + + return false; + } + if (!hasUnderlying()) { + + return false; + } + if (!hasZeroTag()) { + + return false; + } + if (!getUnderlying().isInitialized()) { + + return false; + } + if (hasEntryData()) { + if (!getEntryData().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (akka.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp operation_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp.ORMapPut; + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public boolean hasOperation() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp getOperation() { + return operation_; + } + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public Builder setOperation(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + operation_ = value; + onChanged(); + return this; + } + /** + * required .akka.cluster.ddata.ORMapDeltaOp operation = 1; + */ + public Builder clearOperation() { + bitField0_ = (bitField0_ & ~0x00000001); + operation_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaOp.ORMapPut; + onChanged(); + return this; + } + + // required .akka.cluster.ddata.ORSet underlying = 2; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet underlying_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance(); + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder> underlyingBuilder_; + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public boolean hasUnderlying() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet getUnderlying() { + if (underlyingBuilder_ == null) { + return underlying_; + } else { + return underlyingBuilder_.getMessage(); + } + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public Builder setUnderlying(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet value) { + if (underlyingBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + underlying_ = value; + onChanged(); + } else { + underlyingBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public Builder setUnderlying( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder builderForValue) { + if (underlyingBuilder_ == null) { + underlying_ = builderForValue.build(); + onChanged(); + } else { + underlyingBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public Builder mergeUnderlying(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet value) { + if (underlyingBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + underlying_ != akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance()) { + underlying_ = + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.newBuilder(underlying_).mergeFrom(value).buildPartial(); + } else { + underlying_ = value; + } + onChanged(); + } else { + underlyingBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public Builder clearUnderlying() { + if (underlyingBuilder_ == null) { + underlying_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance(); + onChanged(); + } else { + underlyingBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder getUnderlyingBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getUnderlyingFieldBuilder().getBuilder(); + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder getUnderlyingOrBuilder() { + if (underlyingBuilder_ != null) { + return underlyingBuilder_.getMessageOrBuilder(); + } else { + return underlying_; + } + } + /** + * required .akka.cluster.ddata.ORSet underlying = 2; + */ + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder> + getUnderlyingFieldBuilder() { + if (underlyingBuilder_ == null) { + underlyingBuilder_ = new akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSetOrBuilder>( + underlying_, + getParentForChildren(), + isClean()); + underlying_ = null; + } + return underlyingBuilder_; + } + + // required sint32 zeroTag = 3; + private int zeroTag_ ; + /** + * required sint32 zeroTag = 3; + */ + public boolean hasZeroTag() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required sint32 zeroTag = 3; + */ + public int getZeroTag() { + return zeroTag_; + } + /** + * required sint32 zeroTag = 3; + */ + public Builder setZeroTag(int value) { + bitField0_ |= 0x00000004; + zeroTag_ = value; + onChanged(); + return this; + } + /** + * required sint32 zeroTag = 3; + */ + public Builder clearZeroTag() { + bitField0_ = (bitField0_ & ~0x00000004); + zeroTag_ = 0; + onChanged(); + return this; + } + + // optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + private akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry entryData_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance(); + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder> entryDataBuilder_; + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public boolean hasEntryData() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry getEntryData() { + if (entryDataBuilder_ == null) { + return entryData_; + } else { + return entryDataBuilder_.getMessage(); + } + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public Builder setEntryData(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry value) { + if (entryDataBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + entryData_ = value; + onChanged(); + } else { + entryDataBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public Builder setEntryData( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder builderForValue) { + if (entryDataBuilder_ == null) { + entryData_ = builderForValue.build(); + onChanged(); + } else { + entryDataBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public Builder mergeEntryData(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry value) { + if (entryDataBuilder_ == null) { + if (((bitField0_ & 0x00000008) == 0x00000008) && + entryData_ != akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance()) { + entryData_ = + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.newBuilder(entryData_).mergeFrom(value).buildPartial(); + } else { + entryData_ = value; + } + onChanged(); + } else { + entryDataBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public Builder clearEntryData() { + if (entryDataBuilder_ == null) { + entryData_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.getDefaultInstance(); + onChanged(); + } else { + entryDataBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder getEntryDataBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return getEntryDataFieldBuilder().getBuilder(); + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder getEntryDataOrBuilder() { + if (entryDataBuilder_ != null) { + return entryDataBuilder_.getMessageOrBuilder(); + } else { + return entryData_; + } + } + /** + * optional .akka.cluster.ddata.ORMapDeltaGroup.MapEntry entryData = 4; + */ + private akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder> + getEntryDataFieldBuilder() { + if (entryDataBuilder_ == null) { + entryDataBuilder_ = new akka.protobuf.SingleFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.MapEntryOrBuilder>( + entryData_, + getParentForChildren(), + isClean()); + entryData_ = null; + } + return entryDataBuilder_; + } + + // @@protoc_insertion_point(builder_scope:akka.cluster.ddata.ORMapDeltaGroup.Entry) + } + + static { + defaultInstance = new Entry(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:akka.cluster.ddata.ORMapDeltaGroup.Entry) + } + + // repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + public static final int ENTRIES_FIELD_NUMBER = 1; + private java.util.List entries_; + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public java.util.List getEntriesList() { + return entries_; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public java.util.List + getEntriesOrBuilderList() { + return entries_; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public int getEntriesCount() { + return entries_.size(); + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry getEntries(int index) { + return entries_.get(index); + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder getEntriesOrBuilder( + int index) { + return entries_.get(index); + } + + private void initFields() { + entries_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + for (int i = 0; i < getEntriesCount(); i++) { + if (!getEntries(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(akka.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + for (int i = 0; i < entries_.size(); i++) { + output.writeMessage(1, entries_.get(i)); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < entries_.size(); i++) { + size += akka.protobuf.CodedOutputStream + .computeMessageSize(1, entries_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + akka.protobuf.ByteString data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + akka.protobuf.ByteString data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom(byte[] data) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + byte[] data, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws akka.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseDelimitedFrom( + java.io.InputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + akka.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parseFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code akka.cluster.ddata.ORMapDeltaGroup} + */ + public static final class Builder extends + akka.protobuf.GeneratedMessage.Builder + implements akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroupOrBuilder { + public static final akka.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor; + } + + protected akka.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.class, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Builder.class); + } + + // Construct using akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + akka.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (akka.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getEntriesFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + if (entriesBuilder_ == null) { + entries_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + entriesBuilder_.clear(); + } + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public akka.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup getDefaultInstanceForType() { + return akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.getDefaultInstance(); + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup build() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup buildPartial() { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup result = new akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup(this); + int from_bitField0_ = bitField0_; + if (entriesBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + entries_ = java.util.Collections.unmodifiableList(entries_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.entries_ = entries_; + } else { + result.entries_ = entriesBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder mergeFrom(akka.protobuf.Message other) { + if (other instanceof akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup) { + return mergeFrom((akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup other) { + if (other == akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.getDefaultInstance()) return this; + if (entriesBuilder_ == null) { + if (!other.entries_.isEmpty()) { + if (entries_.isEmpty()) { + entries_ = other.entries_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureEntriesIsMutable(); + entries_.addAll(other.entries_); + } + onChanged(); + } + } else { + if (!other.entries_.isEmpty()) { + if (entriesBuilder_.isEmpty()) { + entriesBuilder_.dispose(); + entriesBuilder_ = null; + entries_ = other.entries_; + bitField0_ = (bitField0_ & ~0x00000001); + entriesBuilder_ = + akka.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getEntriesFieldBuilder() : null; + } else { + entriesBuilder_.addAllMessages(other.entries_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + for (int i = 0; i < getEntriesCount(); i++) { + if (!getEntries(i).isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + akka.protobuf.CodedInputStream input, + akka.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (akka.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + private java.util.List entries_ = + java.util.Collections.emptyList(); + private void ensureEntriesIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + entries_ = new java.util.ArrayList(entries_); + bitField0_ |= 0x00000001; + } + } + + private akka.protobuf.RepeatedFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder> entriesBuilder_; + + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public java.util.List getEntriesList() { + if (entriesBuilder_ == null) { + return java.util.Collections.unmodifiableList(entries_); + } else { + return entriesBuilder_.getMessageList(); + } + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public int getEntriesCount() { + if (entriesBuilder_ == null) { + return entries_.size(); + } else { + return entriesBuilder_.getCount(); + } + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry getEntries(int index) { + if (entriesBuilder_ == null) { + return entries_.get(index); + } else { + return entriesBuilder_.getMessage(index); + } + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder setEntries( + int index, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry value) { + if (entriesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEntriesIsMutable(); + entries_.set(index, value); + onChanged(); + } else { + entriesBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder setEntries( + int index, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder builderForValue) { + if (entriesBuilder_ == null) { + ensureEntriesIsMutable(); + entries_.set(index, builderForValue.build()); + onChanged(); + } else { + entriesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder addEntries(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry value) { + if (entriesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEntriesIsMutable(); + entries_.add(value); + onChanged(); + } else { + entriesBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder addEntries( + int index, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry value) { + if (entriesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureEntriesIsMutable(); + entries_.add(index, value); + onChanged(); + } else { + entriesBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder addEntries( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder builderForValue) { + if (entriesBuilder_ == null) { + ensureEntriesIsMutable(); + entries_.add(builderForValue.build()); + onChanged(); + } else { + entriesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder addEntries( + int index, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder builderForValue) { + if (entriesBuilder_ == null) { + ensureEntriesIsMutable(); + entries_.add(index, builderForValue.build()); + onChanged(); + } else { + entriesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder addAllEntries( + java.lang.Iterable values) { + if (entriesBuilder_ == null) { + ensureEntriesIsMutable(); + super.addAll(values, entries_); + onChanged(); + } else { + entriesBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder clearEntries() { + if (entriesBuilder_ == null) { + entries_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + entriesBuilder_.clear(); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public Builder removeEntries(int index) { + if (entriesBuilder_ == null) { + ensureEntriesIsMutable(); + entries_.remove(index); + onChanged(); + } else { + entriesBuilder_.remove(index); + } + return this; + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder getEntriesBuilder( + int index) { + return getEntriesFieldBuilder().getBuilder(index); + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder getEntriesOrBuilder( + int index) { + if (entriesBuilder_ == null) { + return entries_.get(index); } else { + return entriesBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public java.util.List + getEntriesOrBuilderList() { + if (entriesBuilder_ != null) { + return entriesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(entries_); + } + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder addEntriesBuilder() { + return getEntriesFieldBuilder().addBuilder( + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.getDefaultInstance()); + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder addEntriesBuilder( + int index) { + return getEntriesFieldBuilder().addBuilder( + index, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.getDefaultInstance()); + } + /** + * repeated .akka.cluster.ddata.ORMapDeltaGroup.Entry entries = 1; + */ + public java.util.List + getEntriesBuilderList() { + return getEntriesFieldBuilder().getBuilderList(); + } + private akka.protobuf.RepeatedFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder> + getEntriesFieldBuilder() { + if (entriesBuilder_ == null) { + entriesBuilder_ = new akka.protobuf.RepeatedFieldBuilder< + akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.Entry.Builder, akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMapDeltaGroup.EntryOrBuilder>( + entries_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + entries_ = null; + } + return entriesBuilder_; + } + + // @@protoc_insertion_point(builder_scope:akka.cluster.ddata.ORMapDeltaGroup) + } + + static { + defaultInstance = new ORMapDeltaGroup(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:akka.cluster.ddata.ORMapDeltaGroup) + } + public interface LWWMapOrBuilder extends akka.protobuf.MessageOrBuilder { @@ -13524,6 +16269,16 @@ public final class ReplicatedDataMessages { */ akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMultiMap.EntryOrBuilder getEntriesOrBuilder( int index); + + // optional bool withValueDeltas = 3; + /** + * optional bool withValueDeltas = 3; + */ + boolean hasWithValueDeltas(); + /** + * optional bool withValueDeltas = 3; + */ + boolean getWithValueDeltas(); } /** * Protobuf type {@code akka.cluster.ddata.ORMultiMap} @@ -13597,6 +16352,11 @@ public final class ReplicatedDataMessages { entries_.add(input.readMessage(akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORMultiMap.Entry.PARSER, extensionRegistry)); break; } + case 24: { + bitField0_ |= 0x00000002; + withValueDeltas_ = input.readBool(); + break; + } } } } catch (akka.protobuf.InvalidProtocolBufferException e) { @@ -14743,9 +17503,26 @@ public final class ReplicatedDataMessages { return entries_.get(index); } + // optional bool withValueDeltas = 3; + public static final int WITHVALUEDELTAS_FIELD_NUMBER = 3; + private boolean withValueDeltas_; + /** + * optional bool withValueDeltas = 3; + */ + public boolean hasWithValueDeltas() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bool withValueDeltas = 3; + */ + public boolean getWithValueDeltas() { + return withValueDeltas_; + } + private void initFields() { keys_ = akka.cluster.ddata.protobuf.msg.ReplicatedDataMessages.ORSet.getDefaultInstance(); entries_ = java.util.Collections.emptyList(); + withValueDeltas_ = false; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -14779,6 +17556,9 @@ public final class ReplicatedDataMessages { for (int i = 0; i < entries_.size(); i++) { output.writeMessage(2, entries_.get(i)); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBool(3, withValueDeltas_); + } getUnknownFields().writeTo(output); } @@ -14796,6 +17576,10 @@ public final class ReplicatedDataMessages { size += akka.protobuf.CodedOutputStream .computeMessageSize(2, entries_.get(i)); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += akka.protobuf.CodedOutputStream + .computeBoolSize(3, withValueDeltas_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -14926,6 +17710,8 @@ public final class ReplicatedDataMessages { } else { entriesBuilder_.clear(); } + withValueDeltas_ = false; + bitField0_ = (bitField0_ & ~0x00000004); return this; } @@ -14971,6 +17757,10 @@ public final class ReplicatedDataMessages { } else { result.entries_ = entriesBuilder_.build(); } + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.withValueDeltas_ = withValueDeltas_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -15016,6 +17806,9 @@ public final class ReplicatedDataMessages { } } } + if (other.hasWithValueDeltas()) { + setWithValueDeltas(other.getWithValueDeltas()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -15414,6 +18207,39 @@ public final class ReplicatedDataMessages { return entriesBuilder_; } + // optional bool withValueDeltas = 3; + private boolean withValueDeltas_ ; + /** + * optional bool withValueDeltas = 3; + */ + public boolean hasWithValueDeltas() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional bool withValueDeltas = 3; + */ + public boolean getWithValueDeltas() { + return withValueDeltas_; + } + /** + * optional bool withValueDeltas = 3; + */ + public Builder setWithValueDeltas(boolean value) { + bitField0_ |= 0x00000004; + withValueDeltas_ = value; + onChanged(); + return this; + } + /** + * optional bool withValueDeltas = 3; + */ + public Builder clearWithValueDeltas() { + bitField0_ = (bitField0_ & ~0x00000004); + withValueDeltas_ = false; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:akka.cluster.ddata.ORMultiMap) } @@ -15480,6 +18306,21 @@ public final class ReplicatedDataMessages { private static akka.protobuf.GeneratedMessage.FieldAccessorTable internal_static_akka_cluster_ddata_ORMap_Entry_fieldAccessorTable; + private static akka.protobuf.Descriptors.Descriptor + internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor; + private static + akka.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_akka_cluster_ddata_ORMapDeltaGroup_fieldAccessorTable; + private static akka.protobuf.Descriptors.Descriptor + internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor; + private static + akka.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_fieldAccessorTable; + private static akka.protobuf.Descriptors.Descriptor + internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor; + private static + akka.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_fieldAccessorTable; private static akka.protobuf.Descriptors.Descriptor internal_static_akka_cluster_ddata_LWWMap_descriptor; private static @@ -15552,29 +18393,43 @@ public final class ReplicatedDataMessages { " \002(\0132 .akka.cluster.ddata.OtherMessage\022\016" + "\n\006intKey\030\003 \001(\021\022\017\n\007longKey\030\004 \001(\022\0222\n\010other" + "Key\030\005 \001(\0132 .akka.cluster.ddata.OtherMess" + - "age\"\206\002\n\006LWWMap\022\'\n\004keys\030\001 \002(\0132\031.akka.clus" + - "ter.ddata.ORSet\0221\n\007entries\030\002 \003(\0132 .akka." + - "cluster.ddata.LWWMap.Entry\032\237\001\n\005Entry\022\021\n\t" + - "stringKey\030\001 \001(\t\022.\n\005value\030\002 \002(\0132\037.akka.cl" + - "uster.ddata.LWWRegister\022\016\n\006intKey\030\003 \001(\021\022" + - "\017\n\007longKey\030\004 \001(\022\0222\n\010otherKey\030\005 \001(\0132 .akk" + - "a.cluster.ddata.OtherMessage\"\220\002\n\014PNCount", - "erMap\022\'\n\004keys\030\001 \002(\0132\031.akka.cluster.ddata" + - ".ORSet\0227\n\007entries\030\002 \003(\0132&.akka.cluster.d" + - "data.PNCounterMap.Entry\032\235\001\n\005Entry\022\021\n\tstr" + - "ingKey\030\001 \001(\t\022,\n\005value\030\002 \002(\0132\035.akka.clust" + - "er.ddata.PNCounter\022\016\n\006intKey\030\003 \001(\021\022\017\n\007lo" + - "ngKey\030\004 \001(\022\0222\n\010otherKey\030\005 \001(\0132 .akka.clu" + - "ster.ddata.OtherMessage\"\210\002\n\nORMultiMap\022\'" + - "\n\004keys\030\001 \002(\0132\031.akka.cluster.ddata.ORSet\022" + - "5\n\007entries\030\002 \003(\0132$.akka.cluster.ddata.OR" + - "MultiMap.Entry\032\231\001\n\005Entry\022\021\n\tstringKey\030\001 ", - "\001(\t\022(\n\005value\030\002 \002(\0132\031.akka.cluster.ddata." + - "ORSet\022\016\n\006intKey\030\003 \001(\021\022\017\n\007longKey\030\004 \001(\022\0222" + - "\n\010otherKey\030\005 \001(\0132 .akka.cluster.ddata.Ot" + - "herMessage*-\n\014ORSetDeltaOp\022\007\n\003Add\020\000\022\n\n\006R" + - "emove\020\001\022\010\n\004Full\020\002B#\n\037akka.cluster.ddata." + - "protobuf.msgH\001" + "age\"\263\003\n\017ORMapDeltaGroup\022:\n\007entries\030\001 \003(\013" + + "2).akka.cluster.ddata.ORMapDeltaGroup.En" + + "try\032\243\001\n\010MapEntry\022\021\n\tstringKey\030\001 \001(\t\022/\n\005v" + + "alue\030\002 \002(\0132 .akka.cluster.ddata.OtherMes" + + "sage\022\016\n\006intKey\030\003 \001(\021\022\017\n\007longKey\030\004 \001(\022\0222\n" + + "\010otherKey\030\005 \001(\0132 .akka.cluster.ddata.Oth" + + "erMessage\032\275\001\n\005Entry\0223\n\toperation\030\001 \002(\0162 ", + ".akka.cluster.ddata.ORMapDeltaOp\022-\n\nunde" + + "rlying\030\002 \002(\0132\031.akka.cluster.ddata.ORSet\022" + + "\017\n\007zeroTag\030\003 \002(\021\022?\n\tentryData\030\004 \001(\0132,.ak" + + "ka.cluster.ddata.ORMapDeltaGroup.MapEntr" + + "y\"\206\002\n\006LWWMap\022\'\n\004keys\030\001 \002(\0132\031.akka.cluste" + + "r.ddata.ORSet\0221\n\007entries\030\002 \003(\0132 .akka.cl" + + "uster.ddata.LWWMap.Entry\032\237\001\n\005Entry\022\021\n\tst" + + "ringKey\030\001 \001(\t\022.\n\005value\030\002 \002(\0132\037.akka.clus" + + "ter.ddata.LWWRegister\022\016\n\006intKey\030\003 \001(\021\022\017\n" + + "\007longKey\030\004 \001(\022\0222\n\010otherKey\030\005 \001(\0132 .akka.", + "cluster.ddata.OtherMessage\"\220\002\n\014PNCounter" + + "Map\022\'\n\004keys\030\001 \002(\0132\031.akka.cluster.ddata.O" + + "RSet\0227\n\007entries\030\002 \003(\0132&.akka.cluster.dda" + + "ta.PNCounterMap.Entry\032\235\001\n\005Entry\022\021\n\tstrin" + + "gKey\030\001 \001(\t\022,\n\005value\030\002 \002(\0132\035.akka.cluster" + + ".ddata.PNCounter\022\016\n\006intKey\030\003 \001(\021\022\017\n\007long" + + "Key\030\004 \001(\022\0222\n\010otherKey\030\005 \001(\0132 .akka.clust" + + "er.ddata.OtherMessage\"\241\002\n\nORMultiMap\022\'\n\004" + + "keys\030\001 \002(\0132\031.akka.cluster.ddata.ORSet\0225\n" + + "\007entries\030\002 \003(\0132$.akka.cluster.ddata.ORMu", + "ltiMap.Entry\022\027\n\017withValueDeltas\030\003 \001(\010\032\231\001" + + "\n\005Entry\022\021\n\tstringKey\030\001 \001(\t\022(\n\005value\030\002 \002(" + + "\0132\031.akka.cluster.ddata.ORSet\022\016\n\006intKey\030\003" + + " \001(\021\022\017\n\007longKey\030\004 \001(\022\0222\n\010otherKey\030\005 \001(\0132" + + " .akka.cluster.ddata.OtherMessage*-\n\014ORS" + + "etDeltaOp\022\007\n\003Add\020\000\022\n\n\006Remove\020\001\022\010\n\004Full\020\002" + + "*R\n\014ORMapDeltaOp\022\014\n\010ORMapPut\020\000\022\017\n\013ORMapR" + + "emove\020\001\022\022\n\016ORMapRemoveKey\020\002\022\017\n\013ORMapUpda" + + "te\020\003B#\n\037akka.cluster.ddata.protobuf.msgH" + + "\001" }; akka.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new akka.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -15647,8 +18502,26 @@ public final class ReplicatedDataMessages { akka.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_akka_cluster_ddata_ORMap_Entry_descriptor, new java.lang.String[] { "StringKey", "Value", "IntKey", "LongKey", "OtherKey", }); - internal_static_akka_cluster_ddata_LWWMap_descriptor = + internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor = getDescriptor().getMessageTypes().get(8); + internal_static_akka_cluster_ddata_ORMapDeltaGroup_fieldAccessorTable = new + akka.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor, + new java.lang.String[] { "Entries", }); + internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor = + internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor.getNestedTypes().get(0); + internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_fieldAccessorTable = new + akka.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_akka_cluster_ddata_ORMapDeltaGroup_MapEntry_descriptor, + new java.lang.String[] { "StringKey", "Value", "IntKey", "LongKey", "OtherKey", }); + internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor = + internal_static_akka_cluster_ddata_ORMapDeltaGroup_descriptor.getNestedTypes().get(1); + internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_fieldAccessorTable = new + akka.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_akka_cluster_ddata_ORMapDeltaGroup_Entry_descriptor, + new java.lang.String[] { "Operation", "Underlying", "ZeroTag", "EntryData", }); + internal_static_akka_cluster_ddata_LWWMap_descriptor = + getDescriptor().getMessageTypes().get(9); internal_static_akka_cluster_ddata_LWWMap_fieldAccessorTable = new akka.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_akka_cluster_ddata_LWWMap_descriptor, @@ -15660,7 +18533,7 @@ public final class ReplicatedDataMessages { internal_static_akka_cluster_ddata_LWWMap_Entry_descriptor, new java.lang.String[] { "StringKey", "Value", "IntKey", "LongKey", "OtherKey", }); internal_static_akka_cluster_ddata_PNCounterMap_descriptor = - getDescriptor().getMessageTypes().get(9); + getDescriptor().getMessageTypes().get(10); internal_static_akka_cluster_ddata_PNCounterMap_fieldAccessorTable = new akka.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_akka_cluster_ddata_PNCounterMap_descriptor, @@ -15672,11 +18545,11 @@ public final class ReplicatedDataMessages { internal_static_akka_cluster_ddata_PNCounterMap_Entry_descriptor, new java.lang.String[] { "StringKey", "Value", "IntKey", "LongKey", "OtherKey", }); internal_static_akka_cluster_ddata_ORMultiMap_descriptor = - getDescriptor().getMessageTypes().get(10); + getDescriptor().getMessageTypes().get(11); internal_static_akka_cluster_ddata_ORMultiMap_fieldAccessorTable = new akka.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_akka_cluster_ddata_ORMultiMap_descriptor, - new java.lang.String[] { "Keys", "Entries", }); + new java.lang.String[] { "Keys", "Entries", "WithValueDeltas", }); internal_static_akka_cluster_ddata_ORMultiMap_Entry_descriptor = internal_static_akka_cluster_ddata_ORMultiMap_descriptor.getNestedTypes().get(0); internal_static_akka_cluster_ddata_ORMultiMap_Entry_fieldAccessorTable = new diff --git a/akka-distributed-data/src/main/protobuf/ReplicatedDataMessages.proto b/akka-distributed-data/src/main/protobuf/ReplicatedDataMessages.proto index 6a5020923c..33efe55f5a 100644 --- a/akka-distributed-data/src/main/protobuf/ReplicatedDataMessages.proto +++ b/akka-distributed-data/src/main/protobuf/ReplicatedDataMessages.proto @@ -72,7 +72,32 @@ message ORMap { } required ORSet keys = 1; - repeated Entry entries = 2; + repeated Entry entries = 2; +} + +message ORMapDeltaGroup { + message MapEntry { + optional string stringKey = 1; + required OtherMessage value = 2; + optional sint32 intKey = 3; + optional sint64 longKey = 4; + optional OtherMessage otherKey = 5; + } + message Entry { + required ORMapDeltaOp operation = 1; + required ORSet underlying = 2; + required sint32 zeroTag = 3; + optional MapEntry entryData = 4; + } + + repeated Entry entries = 1; +} + +enum ORMapDeltaOp { + ORMapPut = 0; + ORMapRemove = 1; + ORMapRemoveKey = 2; + ORMapUpdate = 3; } message LWWMap { @@ -85,7 +110,7 @@ message LWWMap { } required ORSet keys = 1; - repeated Entry entries = 2; + repeated Entry entries = 2; } message PNCounterMap { @@ -98,21 +123,22 @@ message PNCounterMap { } required ORSet keys = 1; - repeated Entry entries = 2; + repeated Entry entries = 2; } message ORMultiMap { - message Entry { - optional string stringKey = 1; - required ORSet value = 2; - optional sint32 intKey = 3; - optional sint64 longKey = 4; - optional OtherMessage otherKey = 5; - } - - required ORSet keys = 1; - repeated Entry entries = 2; -} + message Entry { + optional string stringKey = 1; + required ORSet value = 2; + optional sint32 intKey = 3; + optional sint64 longKey = 4; + optional OtherMessage otherKey = 5; + } + + required ORSet keys = 1; + repeated Entry entries = 2; + optional bool withValueDeltas = 3; + } diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/LWWMap.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/LWWMap.scala index e36a521757..2af60a8aad 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/LWWMap.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/LWWMap.scala @@ -6,9 +6,10 @@ package akka.cluster.ddata import akka.cluster.Cluster import akka.cluster.UniqueAddress import akka.annotation.InternalApi +import akka.cluster.ddata.ORMap.LWWMapTag object LWWMap { - private val _empty: LWWMap[Any, Any] = new LWWMap(ORMap.empty) + private val _empty: LWWMap[Any, Any] = new LWWMap(ORMap.emptyWithLWWMapTag) def empty[A, B]: LWWMap[A, B] = _empty.asInstanceOf[LWWMap[A, B]] def apply(): LWWMap[Any, Any] = _empty /** @@ -47,10 +48,11 @@ object LWWMap { @SerialVersionUID(1L) final class LWWMap[A, B] private[akka] ( private[akka] val underlying: ORMap[A, LWWRegister[B]]) - extends ReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { + extends DeltaReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { import LWWRegister.{ Clock, defaultClock } type T = LWWMap[A, B] + type D = ORMap.DeltaOp /** * Scala API: All entries of the map. @@ -141,6 +143,14 @@ final class LWWMap[A, B] private[akka] ( @InternalApi private[akka] def remove(node: UniqueAddress, key: A): LWWMap[A, B] = new LWWMap(underlying.remove(node, key)) + override def resetDelta: LWWMap[A, B] = + new LWWMap(underlying.resetDelta) + + override def delta: Option[D] = underlying.delta + + override def mergeDelta(thatDelta: D): LWWMap[A, B] = + new LWWMap(underlying.mergeDelta(thatDelta)) + override def merge(that: LWWMap[A, B]): LWWMap[A, B] = new LWWMap(underlying.merge(that.underlying)) diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMap.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMap.scala index b8cf38edd4..1240e7fdbd 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMap.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMap.scala @@ -7,6 +7,9 @@ import akka.cluster.Cluster import akka.cluster.UniqueAddress import akka.util.HashCode import akka.annotation.InternalApi +import akka.cluster.ddata.ORMap.{ AtomicDeltaOp, ZeroTag } + +import scala.collection.immutable object ORMap { private val _empty: ORMap[Any, ReplicatedData] = new ORMap(ORSet.empty, Map.empty) @@ -22,6 +25,125 @@ object ORMap { */ def unapply[A, B <: ReplicatedData](m: ORMap[A, B]): Option[Map[A, B]] = Some(m.entries) + sealed trait DeltaOp extends ReplicatedDelta with RequiresCausalDeliveryOfDeltas { + type T = DeltaOp + override def zero: DeltaReplicatedData + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] def emptyWithPNCounterMapTag[A, B <: ReplicatedData]: ORMap[A, B] = new ORMap(ORSet.empty, Map.empty, zeroTag = PNCounterMapTag) + + /** + * INTERNAL API + */ + @InternalApi private[akka] def emptyWithORMultiMapTag[A, B <: ReplicatedData]: ORMap[A, B] = new ORMap(ORSet.empty, Map.empty, zeroTag = ORMultiMapTag) + + /** + * INTERNAL API + */ + @InternalApi private[akka] def emptyWithORMultiMapWithValueDeltasTag[A, B <: ReplicatedData]: ORMap[A, B] = new ORMap(ORSet.empty, Map.empty, zeroTag = ORMultiMapWithValueDeltasTag) + + /** + * INTERNAL API + */ + @InternalApi private[akka] def emptyWithLWWMapTag[A, B <: ReplicatedData]: ORMap[A, B] = new ORMap(ORSet.empty, Map.empty, zeroTag = LWWMapTag) + + /** + * INTERNAL API + * Tags for ORMap.DeltaOp's, so that when the Replicator needs to re-create full value from delta, + * the right map type will be used + */ + @InternalApi private[akka] trait ZeroTag { + def zero: DeltaReplicatedData + def value: Int + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] case object VanillaORMapTag extends ZeroTag { + override def zero: DeltaReplicatedData = ORMap.empty + override final val value: Int = 0 + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] case object PNCounterMapTag extends ZeroTag { + override def zero: DeltaReplicatedData = PNCounterMap.empty + override final val value: Int = 1 + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] case object ORMultiMapTag extends ZeroTag { + override def zero: DeltaReplicatedData = ORMultiMap.empty + override final val value: Int = 2 + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] case object ORMultiMapWithValueDeltasTag extends ZeroTag { + override def zero: DeltaReplicatedData = ORMultiMap.emptyWithValueDeltas + override final val value: Int = 3 + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] case object LWWMapTag extends ZeroTag { + override def zero: DeltaReplicatedData = LWWMap.empty + override final val value: Int = 4 + } + + /** + * INTERNAL API + */ + @InternalApi private[akka] sealed abstract class AtomicDeltaOp[A, B <: ReplicatedData] extends DeltaOp { + def underlying: ORSet.DeltaOp + def zeroTag: ZeroTag + override def zero: DeltaReplicatedData = zeroTag.zero + + override def merge(that: DeltaOp): DeltaOp = that match { + case other: AtomicDeltaOp[A, B] ⇒ DeltaGroup(Vector(this, other)) + case DeltaGroup(ops) ⇒ DeltaGroup(this +: ops) + } + } + + // PutDeltaOp contains ORSet delta and full value + /** INTERNAL API */ + @InternalApi private[akka] final case class PutDeltaOp[A, B <: ReplicatedData](underlying: ORSet.DeltaOp, value: (A, B), zeroTag: ZeroTag = VanillaORMapTag) extends AtomicDeltaOp[A, B] { + } + + // UpdateDeltaOp contains ORSet delta and either delta of value (in case where underlying type supports deltas) or full value + /** INTERNAL API */ + @InternalApi private[akka] final case class UpdateDeltaOp[A, X <: ReplicatedDelta](underlying: ORSet.DeltaOp, values: Map[A, X], zeroTag: ZeroTag = VanillaORMapTag) extends AtomicDeltaOp[A, X] { + } + + // RemoveDeltaOp does not contain any value at all - the propagated 'value' map is empty + /** INTERNAL API */ + @InternalApi private[akka] final case class RemoveDeltaOp[A, B <: ReplicatedData](underlying: ORSet.DeltaOp, zeroTag: ZeroTag = VanillaORMapTag) extends AtomicDeltaOp[A, B] { + } + + // RemoveKeyDeltaOp contains a single value - to provide the recipient with the removed key for value map + /** INTERNAL API */ + @InternalApi private[akka] final case class RemoveKeyDeltaOp[A, B <: ReplicatedData](underlying: ORSet.DeltaOp, removedKey: A, zeroTag: ZeroTag = VanillaORMapTag) extends AtomicDeltaOp[A, B] { + } + + // DeltaGroup is effectively a causally ordered list of individual deltas + /** INTERNAL API */ + @InternalApi private[akka] final case class DeltaGroup[A, B <: ReplicatedData](ops: immutable.IndexedSeq[DeltaOp]) extends DeltaOp { + override def merge(that: DeltaOp): DeltaOp = that match { + case DeltaGroup(thatOps) ⇒ DeltaGroup(ops ++ thatOps) + case that: AtomicDeltaOp[A, B] ⇒ DeltaGroup(ops :+ that) + } + + override def zero: DeltaReplicatedData = ops.headOption.fold(ORMap.empty[A, B].asInstanceOf[DeltaReplicatedData])(_.zero) + } } /** @@ -34,11 +156,16 @@ object ORMap { */ @SerialVersionUID(1L) final class ORMap[A, B <: ReplicatedData] private[akka] ( - private[akka] val keys: ORSet[A], - private[akka] val values: Map[A, B]) - extends ReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { + private[akka] val keys: ORSet[A], + private[akka] val values: Map[A, B], + private[akka] val zeroTag: ZeroTag = ORMap.VanillaORMapTag, + override val delta: Option[ORMap.DeltaOp] = None) + extends DeltaReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { + + import ORMap.{ PutDeltaOp, UpdateDeltaOp, RemoveDeltaOp, RemoveKeyDeltaOp } type T = ORMap[A, B] + type D = ORMap.DeltaOp /** * Scala API: All entries of the map. @@ -100,8 +227,11 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( "`ORMap.put` must not be used to replace an existing `ORSet` " + "value, because important history can be lost when replacing the `ORSet` and " + "undesired effects of merging will occur. Use `ORMultiMap` or `ORMap.updated` instead.") - else - new ORMap(keys.add(node, key), values.updated(key, value)) + else { + val putDeltaOp = PutDeltaOp(keys.resetDelta.add(node, key).delta.get, key → value, zeroTag) + // put forcibly damages history, so we propagate full value that will overwrite previous values + new ORMap(keys.add(node, key), values.updated(key, value), zeroTag, Some(newDelta(putDeltaOp))) + } /** * Scala API: Replace a value by applying the `modify` function on the existing value. @@ -124,12 +254,30 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( /** * INTERNAL API */ - @InternalApi private[akka] def updated(node: UniqueAddress, key: A, initial: B)(modify: B ⇒ B): ORMap[A, B] = { - val newValue = values.get(key) match { - case Some(old) ⇒ modify(old) - case _ ⇒ modify(initial) + @InternalApi private[akka] def updated(node: UniqueAddress, key: A, initial: B, valueDeltas: Boolean = false)(modify: B ⇒ B): ORMap[A, B] = { + val (oldValue, hasOldValue) = values.get(key) match { + case Some(old) ⇒ (old, true) + case _ ⇒ (initial, false) + } + // Optimization: for some types - like GSet, GCounter, PNCounter and ORSet - that are delta based + // we can emit (and later merge) their deltas instead of full updates. + // However to avoid necessity of tombstones, the derived map type needs to support this + // with clearing the value (e.g. removing all elements if value is a set) + // before removing the key - like e.g. ORMultiMap does + oldValue match { + case _: DeltaReplicatedData if valueDeltas ⇒ + val newValue = modify(oldValue.asInstanceOf[DeltaReplicatedData].resetDelta.asInstanceOf[B]) + val newValueDelta = newValue.asInstanceOf[DeltaReplicatedData].delta + val deltaOp = newValueDelta match { + case Some(d) if hasOldValue ⇒ UpdateDeltaOp(keys.resetDelta.add(node, key).delta.get, Map(key → d), zeroTag) + case _ ⇒ PutDeltaOp(keys.resetDelta.add(node, key).delta.get, key → newValue, zeroTag) + } + new ORMap(keys.add(node, key), values.updated(key, newValue), zeroTag, Some(newDelta(deltaOp))) + case _ ⇒ + val newValue = modify(oldValue) + val deltaOp = PutDeltaOp(keys.resetDelta.add(node, key).delta.get, key → newValue, zeroTag) + new ORMap(keys.add(node, key), values.updated(key, newValue), zeroTag, Some(newDelta(deltaOp))) } - new ORMap(keys.add(node, key), values.updated(key, newValue)) } /** @@ -150,13 +298,24 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( * INTERNAL API */ @InternalApi private[akka] def remove(node: UniqueAddress, key: A): ORMap[A, B] = { - new ORMap(keys.remove(node, key), values - key) + // for removals the delta values map emitted will be empty + val removeDeltaOp = RemoveDeltaOp(keys.resetDelta.remove(node, key).delta.get, zeroTag) + new ORMap(keys.remove(node, key), values - key, zeroTag, Some(newDelta(removeDeltaOp))) } - override def merge(that: ORMap[A, B]): ORMap[A, B] = { - val mergedKeys = keys.merge(that.keys) + /** + * INTERNAL API + * This function is only to be used by derived maps that avoid remove anomalies + * by keeping the vvector (in form of key -> value pair) for deleted keys + */ + @InternalApi private[akka] def removeKey(node: UniqueAddress, key: A): ORMap[A, B] = { + val removeKeyDeltaOp = RemoveKeyDeltaOp(keys.resetDelta.remove(node, key).delta.get, key, zeroTag) + new ORMap(keys.remove(node, key), values, zeroTag, Some(newDelta(removeKeyDeltaOp))) + } + + private def dryMerge(that: ORMap[A, B], mergedKeys: ORSet[A], valueKeysIterator: Iterator[A]): ORMap[A, B] = { var mergedValues = Map.empty[A, B] - mergedKeys.elementsMap.keysIterator.foreach { key ⇒ + valueKeysIterator.foreach { key ⇒ (this.values.get(key), that.values.get(key)) match { case (Some(thisValue), Some(thatValue)) ⇒ if (thisValue.getClass != thatValue.getClass) { @@ -174,8 +333,110 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( case (None, None) ⇒ throw new IllegalStateException(s"missing value for $key") } } + new ORMap(mergedKeys, mergedValues, zeroTag = zeroTag) + } - new ORMap(mergedKeys, mergedValues) + override def merge(that: ORMap[A, B]): ORMap[A, B] = { + val mergedKeys = keys.merge(that.keys) + dryMerge(that, mergedKeys, mergedKeys.elementsMap.keysIterator) + } + + /** + * INTERNAL API + * This function is only to be used by derived maps that avoid remove anomalies + * by keeping the vvector (in form of key -> value pair) for deleted keys + */ + @InternalApi private[akka] def mergeRetainingDeletedValues(that: ORMap[A, B]): ORMap[A, B] = { + val mergedKeys = keys.merge(that.keys) + dryMerge(that, mergedKeys, (this.values.keySet ++ that.values.keySet).iterator) + } + + override def resetDelta: ORMap[A, B] = + if (delta.isEmpty) this + else new ORMap[A, B](keys, values, zeroTag = zeroTag) + + override def mergeDelta(thatDelta: ORMap.DeltaOp): ORMap[A, B] = { + // helper function to simplify folds below + def foldValues(values: List[(A, ReplicatedData)], initial: B) = + values.foldLeft(initial) { + case (acc: DeltaReplicatedData, (_, value: ReplicatedDelta)) ⇒ + acc.mergeDelta(value.asInstanceOf[acc.D]).asInstanceOf[B] + case (acc, (_, value)) ⇒ + acc.merge(value.asInstanceOf[acc.T]).asInstanceOf[B] + } + + val mergedKeys: ORSet[A] = thatDelta match { + case d: AtomicDeltaOp[A, B] ⇒ keys.mergeDelta(d.underlying) + case ORMap.DeltaGroup(ops) ⇒ + ops.foldLeft(keys)((acc, op) ⇒ acc.mergeDelta(op.asInstanceOf[AtomicDeltaOp[A, B]].underlying)) + } + + var mergedValues = Map.empty[A, B] + var tombstonedVals = Set.empty[A] + var thatValueDeltas: Map[A, List[(A, ReplicatedData)]] = Map.empty + + val processDelta: PartialFunction[ORMap.DeltaOp, Unit] = { + case putOp: PutDeltaOp[A, B] ⇒ + val key = putOp.value._1 + thatValueDeltas += (key → (putOp.value :: Nil)) // put is destructive! + case _: RemoveDeltaOp[A, B] ⇒ + // remove delta is only for the side effect of key being removed + // please note that if it is not preceded by update clearing the value + // anomalies will result + case removeKeyOp: RemoveKeyDeltaOp[A, B] ⇒ + tombstonedVals = tombstonedVals + removeKeyOp.removedKey + case updateOp: UpdateDeltaOp[A, _] ⇒ + val key = updateOp.values.head._1 + val value = (key, updateOp.values.head._2) + if (thatValueDeltas.contains(key)) + thatValueDeltas = thatValueDeltas + (key → (thatValueDeltas(key) :+ value)) + else + thatValueDeltas += (key → (value :: Nil)) + } + + val processNestedDelta: PartialFunction[ORMap.DeltaOp, Unit] = { + case ORMap.DeltaGroup(ops) ⇒ + ops.foreach { + processDelta.orElse { + case ORMap.DeltaGroup(args) ⇒ + throw new IllegalStateException("Cannot nest DeltaGroups") + } + } + } + + (processDelta orElse processNestedDelta)(thatDelta) + + val aggregateValuesForKey: (A ⇒ Unit) = { key ⇒ + (this.values.get(key), thatValueDeltas.get(key)) match { + case (Some(thisValue), Some(thatValues)) ⇒ + val mergedValue = foldValues(thatValues, thisValue) + mergedValues = mergedValues.updated(key, mergedValue) + case (Some(thisValue), None) ⇒ + mergedValues = mergedValues.updated(key, thisValue) + case (None, Some(thatValues)) ⇒ + val (_, initialValue) = thatValues.head + val mergedValue = initialValue match { + case _: ReplicatedDelta ⇒ + foldValues(thatValues, initialValue.asInstanceOf[ReplicatedDelta].zero.asInstanceOf[B]) + case _ ⇒ + foldValues(thatValues.tail, initialValue.asInstanceOf[B]) + } + mergedValues = mergedValues.updated(key, mergedValue) + case (None, None) ⇒ throw new IllegalStateException(s"missing value for $key") + } + } + + mergedKeys.elementsMap.keysIterator.foreach { aggregateValuesForKey } + tombstonedVals.foreach { aggregateValuesForKey } + + new ORMap[A, B](mergedKeys, mergedValues, zeroTag = zeroTag) + } + + private def newDelta(deltaOp: ORMap.DeltaOp) = delta match { + case Some(d) ⇒ + d.merge(deltaOp) + case None ⇒ + deltaOp } override def modifiedByNodes: Set[UniqueAddress] = { @@ -199,7 +460,7 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( acc.updated(key, data.prune(removedNode, collapseInto).asInstanceOf[B]) case (acc, _) ⇒ acc } - new ORMap(prunedKeys, prunedValues) + new ORMap(prunedKeys, prunedValues, zeroTag = zeroTag) } override def pruningCleanup(removedNode: UniqueAddress): ORMap[A, B] = { @@ -209,7 +470,7 @@ final class ORMap[A, B <: ReplicatedData] private[akka] ( acc.updated(key, data.pruningCleanup(removedNode).asInstanceOf[B]) case (acc, _) ⇒ acc } - new ORMap(pruningCleanupedKeys, pruningCleanupedValues) + new ORMap(pruningCleanupedKeys, pruningCleanupedValues, zeroTag = zeroTag) } // this class cannot be a `case class` because we need different `unapply` diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMultiMap.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMultiMap.scala index d95d04409b..5c7d00e907 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMultiMap.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORMultiMap.scala @@ -3,22 +3,26 @@ */ package akka.cluster.ddata -import akka.cluster.{ UniqueAddress, Cluster } +import akka.cluster.{ Cluster, UniqueAddress } import akka.annotation.InternalApi +import akka.cluster.ddata.ORMap._ object ORMultiMap { - val _empty: ORMultiMap[Any, Any] = new ORMultiMap(ORMap.empty) + val _empty: ORMultiMap[Any, Any] = new ORMultiMap(ORMap.emptyWithORMultiMapTag, false) + val _emptyWithValueDeltas: ORMultiMap[Any, Any] = new ORMultiMap(ORMap.emptyWithORMultiMapTag, true) /** * Provides an empty multimap. */ def empty[A, B]: ORMultiMap[A, B] = _empty.asInstanceOf[ORMultiMap[A, B]] + def emptyWithValueDeltas[A, B]: ORMultiMap[A, B] = _emptyWithValueDeltas.asInstanceOf[ORMultiMap[A, B]] def apply(): ORMultiMap[Any, Any] = _empty /** * Java API */ def create[A, B](): ORMultiMap[A, B] = empty[A, B] + def createWithDeltaDelta[A, B](): ORMultiMap[A, B] = emptyWithValueDeltas[A, B] /** * Extract the [[ORMultiMap#entries]]. @@ -41,18 +45,28 @@ object ORMultiMap { * This class is immutable, i.e. "modifying" methods return a new instance. */ @SerialVersionUID(1L) -final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[A, ORSet[B]]) - extends ReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { +final class ORMultiMap[A, B] private[akka] ( + private[akka] val underlying: ORMap[A, ORSet[B]], + private[akka] val withValueDeltas: Boolean) + extends DeltaReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { override type T = ORMultiMap[A, B] + override type D = ORMap.DeltaOp override def merge(that: T): T = - new ORMultiMap(underlying.merge(that.underlying)) + if (withValueDeltas == that.withValueDeltas) { + if (withValueDeltas) + new ORMultiMap(underlying.mergeRetainingDeletedValues(that.underlying), withValueDeltas) + else + new ORMultiMap(underlying.merge(that.underlying), withValueDeltas) + } else throw new IllegalArgumentException("Trying to merge two ORMultiMaps of different map sub-type") /** * Scala API: All entries of a multimap where keys are strings and values are sets. */ - def entries: Map[A, Set[B]] = + def entries: Map[A, Set[B]] = if (withValueDeltas) + underlying.entries.collect { case (k, v) if underlying.keys.elements.contains(k) ⇒ k → v.elements } + else underlying.entries.map { case (k, v) ⇒ k → v.elements } /** @@ -61,9 +75,10 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ def getEntries(): java.util.Map[A, java.util.Set[B]] = { import scala.collection.JavaConverters._ val result = new java.util.HashMap[A, java.util.Set[B]] - underlying.entries.foreach { - case (k, v) ⇒ result.put(k, v.elements.asJava) - } + if (withValueDeltas) + underlying.entries.foreach { case (k, v) ⇒ if (underlying.keys.elements.contains(k)) result.put(k, v.elements.asJava) } + else + underlying.entries.foreach { case (k, v) ⇒ result.put(k, v.elements.asJava) } result } @@ -71,7 +86,10 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ * Get the set associated with the key if there is one. */ def get(key: A): Option[Set[B]] = - underlying.get(key).map(_.elements) + if (withValueDeltas && !underlying.keys.elements.contains(key)) + None + else + underlying.get(key).map(_.elements) /** * Scala API: Get the set associated with the key if there is one, @@ -80,11 +98,11 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ def getOrElse(key: A, default: ⇒ Set[B]): Set[B] = get(key).getOrElse(default) - def contains(key: A): Boolean = underlying.contains(key) + def contains(key: A): Boolean = underlying.keys.elements.contains(key) - def isEmpty: Boolean = underlying.isEmpty + def isEmpty: Boolean = underlying.keys.elements.isEmpty - def size: Int = underlying.size + def size: Int = underlying.keys.elements.size /** * Convenience for put. Requires an implicit Cluster. @@ -115,10 +133,10 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ * INTERNAL API */ @InternalApi private[akka] def put(node: UniqueAddress, key: A, value: Set[B]): ORMultiMap[A, B] = { - val newUnderlying = underlying.updated(node, key, ORSet.empty[B]) { existing ⇒ + val newUnderlying = underlying.updated(node, key, ORSet.empty[B], valueDeltas = withValueDeltas) { existing ⇒ value.foldLeft(existing.clear(node)) { (s, element) ⇒ s.add(node, element) } } - new ORMultiMap(newUnderlying) + new ORMultiMap(newUnderlying, withValueDeltas) } /** @@ -137,8 +155,14 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ /** * INTERNAL API */ - @InternalApi private[akka] def remove(node: UniqueAddress, key: A): ORMultiMap[A, B] = - new ORMultiMap(underlying.remove(node, key)) + @InternalApi private[akka] def remove(node: UniqueAddress, key: A): ORMultiMap[A, B] = { + if (withValueDeltas) { + val u = underlying.updated(node, key, ORSet.empty[B], valueDeltas = true) { existing ⇒ existing.clear(node) } + new ORMultiMap(u.removeKey(node, key), withValueDeltas) + } else { + new ORMultiMap(underlying.remove(node, key), withValueDeltas) + } + } /** * Scala API: Add an element to a set associated with a key. If there is no existing set then one will be initialised. @@ -156,8 +180,8 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ * INTERNAL API */ @InternalApi private[akka] def addBinding(node: UniqueAddress, key: A, element: B): ORMultiMap[A, B] = { - val newUnderlying = underlying.updated(node, key, ORSet.empty[B])(_.add(node, element)) - new ORMultiMap(newUnderlying) + val newUnderlying = underlying.updated(node, key, ORSet.empty[B], valueDeltas = withValueDeltas)(_.add(node, element)) + new ORMultiMap(newUnderlying, withValueDeltas) } /** @@ -179,13 +203,17 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ */ @InternalApi private[akka] def removeBinding(node: UniqueAddress, key: A, element: B): ORMultiMap[A, B] = { val newUnderlying = { - val u = underlying.updated(node, key, ORSet.empty[B])(_.remove(node, element)) + val u = underlying.updated(node, key, ORSet.empty[B], valueDeltas = withValueDeltas)(_.remove(node, element)) u.get(key) match { - case Some(s) if s.isEmpty ⇒ u.remove(node, key) - case _ ⇒ u + case Some(s) if s.isEmpty ⇒ + if (withValueDeltas) + u.removeKey(node, key) + else + u.remove(node, key) + case _ ⇒ u } } - new ORMultiMap(newUnderlying) + new ORMultiMap(newUnderlying, withValueDeltas) } /** @@ -205,6 +233,14 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ else this + override def resetDelta: ORMultiMap[A, B] = + new ORMultiMap(underlying.resetDelta, withValueDeltas) + + override def delta: Option[D] = underlying.delta + + override def mergeDelta(thatDelta: D): ORMultiMap[A, B] = + new ORMultiMap(underlying.mergeDelta(thatDelta), withValueDeltas) + override def modifiedByNodes: Set[UniqueAddress] = underlying.modifiedByNodes @@ -212,10 +248,10 @@ final class ORMultiMap[A, B] private[akka] (private[akka] val underlying: ORMap[ underlying.needPruningFrom(removedNode) override def pruningCleanup(removedNode: UniqueAddress): T = - new ORMultiMap(underlying.pruningCleanup(removedNode)) + new ORMultiMap(underlying.pruningCleanup(removedNode), withValueDeltas) override def prune(removedNode: UniqueAddress, collapseInto: UniqueAddress): T = - new ORMultiMap(underlying.prune(removedNode, collapseInto)) + new ORMultiMap(underlying.prune(removedNode, collapseInto), withValueDeltas) // this class cannot be a `case class` because we need different `unapply` diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORSet.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORSet.scala index 2f1637dfe8..fa3eacd744 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORSet.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/ORSet.scala @@ -91,7 +91,10 @@ object ORSet { } } - final case class DeltaGroup[A](ops: immutable.IndexedSeq[DeltaOp]) extends DeltaOp { + /** + * INTERNAL API + */ + @InternalApi private[akka] final case class DeltaGroup[A](ops: immutable.IndexedSeq[DeltaOp]) extends DeltaOp { override def merge(that: DeltaOp): DeltaOp = that match { case thatAdd: AddDeltaOp[A] ⇒ // merge AddDeltaOp into last AddDeltaOp in the group, if possible diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/PNCounterMap.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/PNCounterMap.scala index 6fed4cc47c..694616edb2 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/PNCounterMap.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/PNCounterMap.scala @@ -6,10 +6,12 @@ package akka.cluster.ddata import akka.cluster.Cluster import akka.cluster.UniqueAddress import java.math.BigInteger + import akka.annotation.InternalApi +import akka.cluster.ddata.ORMap._ object PNCounterMap { - def empty[A]: PNCounterMap[A] = new PNCounterMap(ORMap.empty) + def empty[A]: PNCounterMap[A] = new PNCounterMap(ORMap.emptyWithPNCounterMapTag) def apply[A](): PNCounterMap[A] = empty /** * Java API @@ -30,9 +32,10 @@ object PNCounterMap { @SerialVersionUID(1L) final class PNCounterMap[A] private[akka] ( private[akka] val underlying: ORMap[A, PNCounter]) - extends ReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { + extends DeltaReplicatedData with ReplicatedDataSerialization with RemovedNodePruning { type T = PNCounterMap[A] + type D = ORMap.DeltaOp /** Scala API */ def entries: Map[A, BigInt] = underlying.entries.map { case (k, c) ⇒ k → c.value } @@ -124,6 +127,14 @@ final class PNCounterMap[A] private[akka] ( override def merge(that: PNCounterMap[A]): PNCounterMap[A] = new PNCounterMap(underlying.merge(that.underlying)) + override def resetDelta: PNCounterMap[A] = + new PNCounterMap(underlying.resetDelta) + + override def delta: Option[D] = underlying.delta + + override def mergeDelta(thatDelta: D): PNCounterMap[A] = + new PNCounterMap(underlying.mergeDelta(thatDelta)) + override def modifiedByNodes: Set[UniqueAddress] = underlying.modifiedByNodes diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala index d65c372c26..cd9eff03b5 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala @@ -149,6 +149,22 @@ private object ReplicatedDataSerializer { override def getValue(entry: rd.ORMultiMap.Entry): rd.ORSet = entry.getValue } + implicit object ORMapDeltaGroupEntry extends ProtoMapEntryWriter[rd.ORMapDeltaGroup.MapEntry, rd.ORMapDeltaGroup.MapEntry.Builder, dm.OtherMessage] with ProtoMapEntryReader[rd.ORMapDeltaGroup.MapEntry, dm.OtherMessage] { + override def setStringKey(builder: rd.ORMapDeltaGroup.MapEntry.Builder, key: String, value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry = builder.setStringKey(key).setValue(value).build() + override def setLongKey(builder: rd.ORMapDeltaGroup.MapEntry.Builder, key: Long, value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry = builder.setLongKey(key).setValue(value).build() + override def setIntKey(builder: rd.ORMapDeltaGroup.MapEntry.Builder, key: Int, value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry = builder.setIntKey(key).setValue(value).build() + override def setOtherKey(builder: rd.ORMapDeltaGroup.MapEntry.Builder, key: dm.OtherMessage, value: dm.OtherMessage): rd.ORMapDeltaGroup.MapEntry = builder.setOtherKey(key).setValue(value).build() + 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 + } + } /** @@ -178,6 +194,11 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) private val PNCounterKeyManifest = "g" private val ORMapManifest = "H" private val ORMapKeyManifest = "h" + 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" @@ -198,6 +219,11 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) GCounterManifest → gcounterFromBinary, PNCounterManifest → pncounterFromBinary, ORMapManifest → ormapFromBinary, + ORMapPutManifest → ormapPutFromBinary, + ORMapRemoveManifest → ormapRemoveFromBinary, + ORMapRemoveKeyManifest → ormapRemoveKeyFromBinary, + ORMapUpdateManifest → ormapUpdateFromBinary, + ORMapDeltaGroupManifest → ormapDeltaGroupFromBinary, LWWMapManifest → lwwmapFromBinary, PNCounterMapManifest → pncountermapFromBinary, ORMultiMapManifest → multimapFromBinary, @@ -216,57 +242,67 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) 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 _: LWWMap[_, _] ⇒ LWWMapManifest - case _: PNCounterMap[_] ⇒ PNCounterMapManifest - case _: ORMultiMap[_, _] ⇒ ORMultiMapManifest - case DeletedData ⇒ DeletedDataManifest - case _: VersionVector ⇒ VersionVectorManifest + 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 - 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 _: ORSet.DeltaGroup[_] ⇒ ORSetDeltaGroupManifest - case _: ORSet.FullStateDeltaOp[_] ⇒ ORSetFullManifest + 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: 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: ORSet.FullStateDeltaOp[_] ⇒ orsetToProto(m.underlying).toByteArray + 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}]") } @@ -512,8 +548,9 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) } def ormapToProto(ormap: ORMap[_, _]): rd.ORMap = { + val ormapBuilder = rd.ORMap.newBuilder() 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() + ormapBuilder.setKeys(orsetToProto(ormap.keys)).addAllEntries(entries).build() } def ormapFromBinary(bytes: Array[Byte]): ORMap[Any, ReplicatedData] = @@ -536,9 +573,144 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) entries) } + def singleMapEntryFromProto[PEntry <: GeneratedMessage, A <: GeneratedMessage, B <: ReplicatedData](entry: PEntry, valueCreator: A ⇒ B)(implicit eh: ProtoMapEntryReader[PEntry, A]): Map[Any, B] = { + val elem = if (eh.hasStringKey(entry)) Some(eh.getStringKey(entry) → valueCreator(eh.getValue(entry))) + else if (eh.hasIntKey(entry)) Some(eh.getIntKey(entry) → valueCreator(eh.getValue(entry))) + else if (eh.hasLongKey(entry)) Some(eh.getLongKey(entry) → valueCreator(eh.getValue(entry))) + else if (eh.hasOtherKey(entry)) Some(otherMessageFromProto(eh.getOtherKey(entry)) → valueCreator(eh.getValue(entry))) + else None + elem match { + case Some(e) ⇒ Map(e) + case _ ⇒ Map.empty[Any, B] + } + } + + // wire protocol is always DeltaGroup + private def ormapPutFromBinary(bytes: Array[Byte]): ORMap.PutDeltaOp[Any, ReplicatedData] = { + val group = ormapDeltaGroupFromBinary(bytes) + if (group.ops.size == 1 && group.ops.head.isInstanceOf[ORMap.PutDeltaOp[_, _]]) + group.ops.head.asInstanceOf[ORMap.PutDeltaOp[Any, ReplicatedData]] + 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 group = ormapDeltaGroupFromBinary(bytes) + if (group.ops.size == 1 && group.ops.head.isInstanceOf[ORMap.RemoveDeltaOp[_, _]]) + group.ops.head.asInstanceOf[ORMap.RemoveDeltaOp[Any, ReplicatedData]] + 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 group = ormapDeltaGroupFromBinary(bytes) + if (group.ops.size == 1 && group.ops.head.isInstanceOf[ORMap.RemoveKeyDeltaOp[_, _]]) + group.ops.head.asInstanceOf[ORMap.RemoveKeyDeltaOp[Any, ReplicatedData]] + 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 group = ormapDeltaGroupFromBinary(bytes) + if (group.ops.size == 1 && group.ops.head.isInstanceOf[ORMap.UpdateDeltaOp[_, _]]) + group.ops.head.asInstanceOf[ORMap.UpdateDeltaOp[Any, ReplicatedDelta]] + 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 { + case ORMap.VanillaORMapTag.value ⇒ ORMap.VanillaORMapTag + case ORMap.PNCounterMapTag.value ⇒ ORMap.PNCounterMapTag + case ORMap.ORMultiMapTag.value ⇒ ORMap.ORMultiMapTag + case ORMap.ORMultiMapWithValueDeltasTag.value ⇒ ORMap.ORMultiMapWithValueDeltasTag + case ORMap.LWWMapTag.value ⇒ ORMap.LWWMapTag + case _ ⇒ throw new IllegalArgumentException("Invalid ZeroTag code") + } + + private def ormapDeltaGroupFromBinary(bytes: Array[Byte]): ORMap.DeltaGroup[Any, ReplicatedData] = { + val deltaGroup = rd.ORMapDeltaGroup.parseFrom(bytes) + val ops: Vector[ORMap.DeltaOp] = + deltaGroup.getEntriesList.asScala.map { entry ⇒ + if (entry.getOperation == rd.ORMapDeltaOp.ORMapPut) { + val map = singleMapEntryFromProto(entry.getEntryData, (v: dm.OtherMessage) ⇒ otherMessageFromProto(v).asInstanceOf[ReplicatedData]) + ORMap.PutDeltaOp(ORSet.AddDeltaOp(orsetFromProto(entry.getUnderlying)), map.head, zeroTagFromCode(entry.getZeroTag)) + } else if (entry.getOperation == rd.ORMapDeltaOp.ORMapRemove) { + val map = singleMapEntryFromProto(entry.getEntryData, (v: dm.OtherMessage) ⇒ otherMessageFromProto(v).asInstanceOf[ReplicatedData]) + ORMap.RemoveDeltaOp(ORSet.RemoveDeltaOp(orsetFromProto(entry.getUnderlying)), zeroTagFromCode(entry.getZeroTag)) + } else if (entry.getOperation == rd.ORMapDeltaOp.ORMapRemoveKey) { + val map = singleMapEntryFromProto(entry.getEntryData, (v: dm.OtherMessage) ⇒ otherMessageFromProto(v).asInstanceOf[ReplicatedData]) + ORMap.RemoveKeyDeltaOp(ORSet.RemoveDeltaOp(orsetFromProto(entry.getUnderlying)), map.keySet.head, zeroTagFromCode(entry.getZeroTag)) + } else if (entry.getOperation == rd.ORMapDeltaOp.ORMapUpdate) { + val map = singleMapEntryFromProto(entry.getEntryData, (v: dm.OtherMessage) ⇒ otherMessageFromProto(v).asInstanceOf[ReplicatedDelta]) + ORMap.UpdateDeltaOp(ORSet.AddDeltaOp(orsetFromProto(entry.getUnderlying)), map, zeroTagFromCode(entry.getZeroTag)) + } else + throw new NotSerializableException(s"Unknown ORMap delta operation ${entry.getOperation}") + }(collection.breakOut) + ORMap.DeltaGroup(ops) + } + + private def ormapPutToProto(addDelta: ORMap.PutDeltaOp[_, _]): rd.ORMapDeltaGroup = { + ormapDeltaGroupToProto(ORMap.DeltaGroup(scala.collection.immutable.IndexedSeq(addDelta.asInstanceOf[ORMap.DeltaOp]))) + } + + private def ormapRemoveToProto(addDelta: ORMap.RemoveDeltaOp[_, _]): rd.ORMapDeltaGroup = { + ormapDeltaGroupToProto(ORMap.DeltaGroup(scala.collection.immutable.IndexedSeq(addDelta.asInstanceOf[ORMap.DeltaOp]))) + } + + private def ormapRemoveKeyToProto(addDelta: ORMap.RemoveKeyDeltaOp[_, _]): rd.ORMapDeltaGroup = { + ormapDeltaGroupToProto(ORMap.DeltaGroup(scala.collection.immutable.IndexedSeq(addDelta.asInstanceOf[ORMap.DeltaOp]))) + } + + private def ormapUpdateToProto(addDelta: ORMap.UpdateDeltaOp[_, _]): rd.ORMapDeltaGroup = { + ormapDeltaGroupToProto(ORMap.DeltaGroup(scala.collection.immutable.IndexedSeq(addDelta.asInstanceOf[ORMap.DeltaOp]))) + } + + private def ormapDeltaGroupToProto(deltaGroup: ORMap.DeltaGroup[_, _]): rd.ORMapDeltaGroup = { + def createEntry(opType: rd.ORMapDeltaOp, u: ORSet[_], m: Map[_, _], zt: Int) = { + if (m.size > 1) + throw new IllegalArgumentException("Invalid size of ORMap delta map") + else { + val entryDataBuilder = rd.ORMapDeltaGroup.MapEntry.newBuilder() + m.headOption.map { + case (key: String, value) ⇒ entryDataBuilder.setStringKey(key).setValue(otherMessageToProto(value)) + case (key: Int, value) ⇒ entryDataBuilder.setIntKey(key).setValue(otherMessageToProto(value)) + case (key: Long, value) ⇒ entryDataBuilder.setLongKey(key).setValue(otherMessageToProto(value)) + case (key, value) ⇒ entryDataBuilder.setOtherKey(otherMessageToProto(key)).setValue(otherMessageToProto(value)) + } + val builder = rd.ORMapDeltaGroup.Entry.newBuilder() + .setOperation(opType) + .setUnderlying(orsetToProto(u)) + .setZeroTag(zt) + if (m.size > 0) + builder.setEntryData(entryDataBuilder.build()) + builder + } + } + + val b = rd.ORMapDeltaGroup.newBuilder() + deltaGroup.ops.foreach { + case ORMap.PutDeltaOp(op, pair, zt) ⇒ + b.addEntries(createEntry(rd.ORMapDeltaOp.ORMapPut, op.asInstanceOf[ORSet.AddDeltaOp[_]].underlying, Map(pair), zt.value)) + case ORMap.RemoveDeltaOp(op, zt) ⇒ + b.addEntries(createEntry(rd.ORMapDeltaOp.ORMapRemove, op.asInstanceOf[ORSet.RemoveDeltaOp[_]].underlying, Map.empty, zt.value)) + case ORMap.RemoveKeyDeltaOp(op, k, zt) ⇒ + b.addEntries(createEntry(rd.ORMapDeltaOp.ORMapRemove, op.asInstanceOf[ORSet.RemoveDeltaOp[_]].underlying, Map(k → k), zt.value)) + case ORMap.UpdateDeltaOp(op, m, zt) ⇒ + b.addEntries(createEntry(rd.ORMapDeltaOp.ORMapUpdate, op.asInstanceOf[ORSet.AddDeltaOp[_]].underlying, m, zt.value)) + case ORMap.DeltaGroup(u) ⇒ + throw new IllegalArgumentException("ORMap.DeltaGroup should not be nested") + } + b.build() + } + def lwwmapToProto(lwwmap: LWWMap[_, _]): rd.LWWMap = { + val lwwmapBuilder = rd.LWWMap.newBuilder() 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() + lwwmapBuilder.setKeys(orsetToProto(lwwmap.underlying.keys)).addAllEntries(entries).build() } def lwwmapFromBinary(bytes: Array[Byte]): LWWMap[Any, Any] = @@ -548,12 +720,13 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) val entries = mapTypeFromProto(lwwmap.getEntriesList, lwwRegisterFromProto) new LWWMap(new ORMap( keys = orsetFromProto(lwwmap.getKeys), - entries)) + entries, ORMap.LWWMapTag)) } def pncountermapToProto(pncountermap: PNCounterMap[_]): rd.PNCounterMap = { + val pncountermapBuilder = rd.PNCounterMap.newBuilder() 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() + pncountermapBuilder.setKeys(orsetToProto(pncountermap.underlying.keys)).addAllEntries(entries).build() } def pncountermapFromBinary(bytes: Array[Byte]): PNCounterMap[_] = @@ -563,12 +736,16 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) val entries = mapTypeFromProto(pncountermap.getEntriesList, pncounterFromProto) new PNCounterMap(new ORMap( keys = orsetFromProto(pncountermap.getKeys), - entries)) + entries, ORMap.PNCounterMapTag)) } def multimapToProto(multimap: ORMultiMap[_, _]): rd.ORMultiMap = { + val ormultimapBuilder = rd.ORMultiMap.newBuilder() 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() + ormultimapBuilder.setKeys(orsetToProto(multimap.underlying.keys)).addAllEntries(entries) + if (multimap.withValueDeltas) + ormultimapBuilder.setWithValueDeltas(true) + ormultimapBuilder.build() } def multimapFromBinary(bytes: Array[Byte]): ORMultiMap[Any, Any] = @@ -576,9 +753,18 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) def multimapFromProto(multimap: rd.ORMultiMap): ORMultiMap[Any, Any] = { val entries = mapTypeFromProto(multimap.getEntriesList, orsetFromProto) - new ORMultiMap(new ORMap( - keys = orsetFromProto(multimap.getKeys), - entries)) + val withValueDeltas = if (multimap.hasWithValueDeltas) + multimap.getWithValueDeltas + else false + new ORMultiMap( + new ORMap( + keys = orsetFromProto(multimap.getKeys), + entries, + if (withValueDeltas) + ORMap.ORMultiMapWithValueDeltasTag + else + ORMap.ORMultiMapTag), + withValueDeltas) } def keyIdToBinary(id: String): Array[Byte] = diff --git a/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorMapDeltaSpec.scala b/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorMapDeltaSpec.scala new file mode 100644 index 0000000000..f083fdbf30 --- /dev/null +++ b/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorMapDeltaSpec.scala @@ -0,0 +1,281 @@ +/** + * Copyright (C) 2009-2016 Lightbend Inc. + */ +package akka.cluster.ddata + +import java.util.concurrent.ThreadLocalRandom + +import scala.concurrent.duration._ + +import akka.cluster.Cluster +import akka.cluster.ddata.Replicator._ +import akka.remote.testconductor.RoleName +import akka.remote.testkit.MultiNodeConfig +import akka.remote.testkit.MultiNodeSpec +import akka.testkit._ +import com.typesafe.config.ConfigFactory + +object ReplicatorMapDeltaSpec extends MultiNodeConfig { + val first = role("first") + val second = role("second") + val third = role("third") + val fourth = role("fourth") + + commonConfig(ConfigFactory.parseString(""" + akka.loglevel = DEBUG + akka.actor.provider = "cluster" + akka.log-dead-letters-during-shutdown = off + """)) + + testTransport(on = true) + + sealed trait Op + final case class Delay(n: Int) extends Op + final case class Incr(ki: (PNCounterMapKey[String], String), n: Int, consistency: WriteConsistency) extends Op + final case class Decr(ki: (PNCounterMapKey[String], String), n: Int, consistency: WriteConsistency) extends Op + final case class Add(ki: (ORMultiMapKey[String, String], String), elem: String, consistency: WriteConsistency) extends Op + final case class Remove(ki: (ORMultiMapKey[String, String], String), elem: String, consistency: WriteConsistency) extends Op + + val timeout = 5.seconds + val writeTwo = WriteTo(2, timeout) + val writeMajority = WriteMajority(timeout) + + val KeyPN = PNCounterMapKey[String]("A") + val KeyMM = ORMultiMapKey[String, String]("D") + val KeyA: (PNCounterMapKey[String], String) = (KeyPN, "a") + val KeyB: (PNCounterMapKey[String], String) = (KeyPN, "b") + val KeyC: (PNCounterMapKey[String], String) = (KeyPN, "c") + val KeyD: (ORMultiMapKey[String, String], String) = (KeyMM, "d") + val KeyE: (ORMultiMapKey[String, String], String) = (KeyMM, "e") + val KeyF: (ORMultiMapKey[String, String], String) = (KeyMM, "f") + + def generateOperations(onNode: RoleName): Vector[Op] = { + val rnd = ThreadLocalRandom.current() + + def consistency(): WriteConsistency = { + rnd.nextInt(100) match { + case n if n < 90 ⇒ WriteLocal + case n if n < 95 ⇒ writeTwo + case n if n < 100 ⇒ writeMajority + } + } + + def rndPnCounterkey(): (PNCounterMapKey[String], String) = { + rnd.nextInt(3) match { + case 0 ⇒ KeyA + case 1 ⇒ KeyB + case 2 ⇒ KeyC + } + } + + def rndOrSetkey(): (ORMultiMapKey[String, String], String) = { + rnd.nextInt(3) match { + case 0 ⇒ KeyD + case 1 ⇒ KeyE + case 2 ⇒ KeyF + } + } + + var availableForRemove = Set.empty[String] + + def rndAddElement(): String = { + // lower case a - j + val s = (97 + rnd.nextInt(10)).toChar.toString + availableForRemove += s + s + } + + def rndRemoveElement(): String = { + if (availableForRemove.isEmpty) + "a" + else + availableForRemove.toVector(rnd.nextInt(availableForRemove.size)) + } + + (0 to (30 + rnd.nextInt(10))).map { _ ⇒ + rnd.nextInt(4) match { + case 0 ⇒ Delay(rnd.nextInt(500)) + case 1 ⇒ Incr(rndPnCounterkey(), rnd.nextInt(100), consistency()) + case 2 ⇒ Decr(rndPnCounterkey(), rnd.nextInt(10), consistency()) + case 3 ⇒ + // ORSet + val key = rndOrSetkey() + // only removals for KeyF on node first + if (key == KeyF && onNode == first && rnd.nextBoolean()) + Remove(key, rndRemoveElement(), consistency()) + else + Add(key, rndAddElement(), consistency()) + } + }.toVector + } + +} + +class ReplicatorMapDeltaSpecMultiJvmNode1 extends ReplicatorMapDeltaSpec +class ReplicatorMapDeltaSpecMultiJvmNode2 extends ReplicatorMapDeltaSpec +class ReplicatorMapDeltaSpecMultiJvmNode3 extends ReplicatorMapDeltaSpec +class ReplicatorMapDeltaSpecMultiJvmNode4 extends ReplicatorMapDeltaSpec + +class ReplicatorMapDeltaSpec extends MultiNodeSpec(ReplicatorMapDeltaSpec) with STMultiNodeSpec with ImplicitSender { + import Replicator._ + import ReplicatorMapDeltaSpec._ + + override def initialParticipants = roles.size + + implicit val cluster = Cluster(system) + val fullStateReplicator = system.actorOf(Replicator.props( + ReplicatorSettings(system).withGossipInterval(1.second).withDeltaCrdtEnabled(false)), "fullStateReplicator") + val deltaReplicator = { + val r = system.actorOf(Replicator.props(ReplicatorSettings(system)), "deltaReplicator") + r ! Replicator.Internal.TestFullStateGossip(enabled = false) + r + } + + var afterCounter = 0 + def enterBarrierAfterTestStep(): Unit = { + afterCounter += 1 + enterBarrier("after-" + afterCounter) + } + + def join(from: RoleName, to: RoleName): Unit = { + runOn(from) { + cluster join node(to).address + } + enterBarrier(from.name + "-joined") + } + + "delta-CRDT" must { + "join cluster" in { + join(first, first) + join(second, first) + join(third, first) + join(fourth, first) + + within(15.seconds) { + awaitAssert { + fullStateReplicator ! GetReplicaCount + expectMsg(ReplicaCount(4)) + } + } + + enterBarrierAfterTestStep() + } + + "propagate delta" in { + join(first, first) + join(second, first) + join(third, first) + join(fourth, first) + + within(15.seconds) { + awaitAssert { + fullStateReplicator ! GetReplicaCount + expectMsg(ReplicaCount(4)) + } + } + enterBarrier("ready") + + runOn(first) { + // by setting something for each key we don't have to worry about NotFound + List(KeyA, KeyB, KeyC).foreach { key ⇒ + fullStateReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ increment key._2) + deltaReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ increment key._2) + } + List(KeyD, KeyE, KeyF).foreach { key ⇒ + fullStateReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ + (key._2, Set("a"))) + deltaReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ + (key._2, Set("a"))) + } + } + enterBarrier("updated-1") + + within(5.seconds) { + awaitAssert { + val p = TestProbe() + List(KeyA, KeyB, KeyC).foreach { key ⇒ + fullStateReplicator.tell(Get(key._1, ReadLocal), p.ref) + p.expectMsgType[GetSuccess[PNCounterMap[String]]].dataValue.get(key._2).get.intValue should be(1) + } + } + awaitAssert { + val p = TestProbe() + List(KeyD, KeyE, KeyF).foreach { key ⇒ + fullStateReplicator.tell(Get(key._1, ReadLocal), p.ref) + p.expectMsgType[GetSuccess[ORMultiMap[String, String]]].dataValue.get(key._2) should ===(Some(Set("a"))) + } + } + } + + enterBarrierAfterTestStep() + } + + "be eventually consistent" in { + val operations = generateOperations(onNode = myself) + log.debug(s"random operations on [${myself.name}]: ${operations.mkString(", ")}") + try { + // perform random operations with both delta and full-state replicators + // and compare that the end result is the same + + for (op ← operations) { + log.debug("operation: {}", op) + op match { + case Delay(d) ⇒ Thread.sleep(d) + case Incr(key, n, consistency) ⇒ + fullStateReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ increment (key._2, n)) + deltaReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ increment (key._2, n)) + case Decr(key, n, consistency) ⇒ + fullStateReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ decrement (key._2, n)) + deltaReplicator ! Update(key._1, PNCounterMap.empty[String], WriteLocal)(_ decrement (key._2, n)) + case Add(key, elem, consistency) ⇒ + // to have an deterministic result when mixing add/remove we can only perform + // the ORSet operations from one node + runOn((if (key == KeyF) List(first) else List(first, second, third)): _*) { + fullStateReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ addBinding (key._2, elem)) + deltaReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ addBinding (key._2, elem)) + } + case Remove(key, elem, consistency) ⇒ + runOn(first) { + fullStateReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ removeBinding (key._2, elem)) + deltaReplicator ! Update(key._1, ORMultiMap.emptyWithValueDeltas[String, String], WriteLocal)(_ removeBinding (key._2, elem)) + } + } + } + + enterBarrier("updated-2") + + List(KeyA, KeyB, KeyC).foreach { key ⇒ + within(5.seconds) { + awaitAssert { + val p = TestProbe() + fullStateReplicator.tell(Get(key._1, ReadLocal), p.ref) + val fullStateValue = p.expectMsgType[GetSuccess[PNCounterMap[String]]].dataValue.get(key._2).get.intValue + deltaReplicator.tell(Get(key._1, ReadLocal), p.ref) + val deltaValue = p.expectMsgType[GetSuccess[PNCounterMap[String]]].dataValue.get(key._2).get.intValue + deltaValue should ===(fullStateValue) + } + } + } + + List(KeyD, KeyE, KeyF).foreach { key ⇒ + within(5.seconds) { + awaitAssert { + val p = TestProbe() + fullStateReplicator.tell(Get(key._1, ReadLocal), p.ref) + val fullStateValue = p.expectMsgType[GetSuccess[ORMultiMap[String, String]]].dataValue.get(key._2) + deltaReplicator.tell(Get(key._1, ReadLocal), p.ref) + val deltaValue = p.expectMsgType[GetSuccess[ORMultiMap[String, String]]].dataValue.get(key._2) + deltaValue should ===(fullStateValue) + } + } + } + + enterBarrierAfterTestStep() + } catch { + case e: Throwable ⇒ + info(s"random operations on [${myself.name}]: ${operations.mkString(", ")}") + throw e + } + } + } + +} + diff --git a/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorPruningSpec.scala b/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorPruningSpec.scala index 33154a59b0..da67a36434 100644 --- a/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorPruningSpec.scala +++ b/akka-distributed-data/src/multi-jvm/scala/akka/cluster/ddata/ReplicatorPruningSpec.scala @@ -47,6 +47,8 @@ class ReplicatorPruningSpec extends MultiNodeSpec(ReplicatorPruningSpec) with ST val KeyA = GCounterKey("A") val KeyB = ORSetKey[String]("B") val KeyC = PNCounterMapKey[String]("C") + val KeyD = ORMultiMapKey[String, String]("D") + val KeyE = ORMapKey[String, GSet[String]]("E") def join(from: RoleName, to: RoleName): Unit = { runOn(from) { @@ -89,6 +91,12 @@ class ReplicatorPruningSpec extends MultiNodeSpec(ReplicatorPruningSpec) with ST replicator ! Update(KeyC, PNCounterMap.empty[String], WriteAll(timeout)) { _ increment "x" increment "y" } expectMsg(UpdateSuccess(KeyC, None)) + replicator ! Update(KeyD, ORMultiMap.empty[String, String], WriteAll(timeout)) { _ + ("a", Set("A")) } + expectMsg(UpdateSuccess(KeyD, None)) + + replicator ! Update(KeyE, ORMap.empty[String, GSet[String]], WriteAll(timeout)) { _ + ("a", GSet.empty[String].add("A")) } + expectMsg(UpdateSuccess(KeyE, None)) + enterBarrier("updates-done") replicator ! Get(KeyA, ReadLocal) @@ -104,8 +112,24 @@ class ReplicatorPruningSpec extends MultiNodeSpec(ReplicatorPruningSpec) with ST oldMap.get("x") should be(Some(3)) oldMap.get("y") should be(Some(3)) + replicator ! Get(KeyD, ReadLocal) + val oldMultiMap = expectMsgType[GetSuccess[ORMultiMap[String, String]]].dataValue + oldMultiMap.get("a") should be(Some(Set("A"))) + + replicator ! Get(KeyE, ReadLocal) + val oldORMap = expectMsgType[GetSuccess[ORMap[String, GSet[String]]]].dataValue + val GSet(d) = oldORMap.entries("a") + d should be(Set("A")) + enterBarrier("get-old") + runOn(third) { + replicator ! Update(KeyE, ORMap.empty[String, GSet[String]], WriteLocal) { _ - "a" } + expectMsg(UpdateSuccess(KeyE, None)) + } + + enterBarrier("remove-element") + runOn(first) { cluster.leave(node(third).address) } @@ -155,6 +179,25 @@ class ReplicatorPruningSpec extends MultiNodeSpec(ReplicatorPruningSpec) with ST } } } + within(5.seconds) { + awaitAssert { + replicator ! Get(KeyD, ReadLocal) + expectMsgPF() { + case g @ GetSuccess(KeyD, _) ⇒ + g.get(KeyD).entries("a") should be(Set("A")) + g.get(KeyD).needPruningFrom(thirdUniqueAddress) should be(false) + } + } + } + within(5.seconds) { + awaitAssert { + replicator ! Get(KeyE, ReadLocal) + expectMsgPF() { + case g @ GetSuccess(KeyE, _) ⇒ + g.get(KeyE).needPruningFrom(thirdUniqueAddress) should be(false) + } + } + } } enterBarrier("pruning-done") diff --git a/akka-distributed-data/src/test/scala/akka/cluster/ddata/LWWMapSpec.scala b/akka-distributed-data/src/test/scala/akka/cluster/ddata/LWWMapSpec.scala index fd83e035af..37f364d393 100644 --- a/akka-distributed-data/src/test/scala/akka/cluster/ddata/LWWMapSpec.scala +++ b/akka-distributed-data/src/test/scala/akka/cluster/ddata/LWWMapSpec.scala @@ -47,6 +47,27 @@ class LWWMapSpec extends WordSpec with Matchers { (m3 merge m4).entries should be(Map("a" → 1, "b" → 22, "c" → 3)) } + "be able to work with deltas" in { + val m1 = LWWMap.empty.put(node1, "a", 1, defaultClock[Int]).put(node1, "b", 2, defaultClock[Int]) + val m2 = LWWMap.empty.put(node2, "c", 3, defaultClock[Int]) + + val expected = Map("a" → 1, "b" → 2, "c" → 3) + (m1 merge m2).entries should be(expected) + (m2 merge m1).entries should be(expected) + + LWWMap.empty.mergeDelta(m1.delta.get).mergeDelta(m2.delta.get).entries should be(expected) + LWWMap.empty.mergeDelta(m2.delta.get).mergeDelta(m1.delta.get).entries should be(expected) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + (merged1 mergeDelta m3.delta.get).entries should be(Map("a" → 1, "c" → 3)) + + // but if there is a conflicting update the entry is not removed + val m4 = merged1.resetDelta.put(node2, "b", 22, defaultClock[Int]) + (m3 mergeDelta m4.delta.get).entries should be(Map("a" → 1, "b" → 22, "c" → 3)) + } + "have unapply extractor" in { val m1 = LWWMap.empty.put(node1, "a", 1L, defaultClock[Long]) val LWWMap(entries1) = m1 diff --git a/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMapSpec.scala b/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMapSpec.scala index 3b25721794..a9d245d1c4 100644 --- a/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMapSpec.scala +++ b/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMapSpec.scala @@ -30,12 +30,43 @@ class ORMapSpec extends WordSpec with Matchers { } + "be able to add entries with deltas" in { + val m = ORMap().put(node1, "a", GSet() + "A").put(node1, "b", GSet() + "B") + val md = m.delta.get + + val m1 = ORMap().mergeDelta(md) + + val GSet(a) = m1.entries("a") + a should be(Set("A")) + val GSet(b) = m1.entries("b") + b should be(Set("B")) + + val m2 = m1.put(node1, "a", GSet() + "C") + val GSet(a2) = m2.entries("a") + a2 should be(Set("C")) + + } + "be able to remove entry" in { val m = ORMap().put(node1, "a", GSet() + "A").put(node1, "b", GSet() + "B").remove(node1, "a") m.entries.keySet should not contain ("a") m.entries.keySet should contain("b") } + "be able to remove entry using a delta" in { + val m = ORMap().put(node1, "a", GSet() + "A").put(node1, "b", GSet() + "B") + val addDelta = m.delta.get + + val removeDelta = m.resetDelta.remove(node1, "a").delta.get + + val m1 = ORMap().mergeDelta(addDelta) + m1.entries.keySet should contain("a") + + val m2 = m1.mergeDelta(removeDelta) + m2.entries.keySet should not contain ("a") + m2.entries.keySet should contain("b") + } + "be able to add removed" in { val m = ORMap().put(node1, "a", GSet() + "A").put(node1, "b", GSet() + "B").remove(node1, "a") m.entries.keySet should not contain ("a") @@ -110,6 +141,330 @@ class ORMapSpec extends WordSpec with Matchers { merged2.entries("c").elements should be(Set("C")) } + "not have anomalies for remove+updated scenario and deltas" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A").put(node1, "b", GSet.empty + "B") + val m2 = ORMap.empty.put(node2, "c", GSet.empty + "C") + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.updated(node1, "b", GSet.empty[String])(_.add("B2")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is included, because GSet("B") is merged with GSet("B2") + merged2.entries("b").elements should be(Set("B", "B2")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is included, because GSet("B") is merged with GSet("B2") + merged3.entries("b").elements should be(Set("B", "B2")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 2" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B")) + val m2 = ORMap.empty.put(node2, "c", ORSet.empty.add(node2, "C")) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.remove(node1, "b").updated(node1, "b", ORSet.empty[String])(_.add(node1, "B2")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged2.entries("b").elements should be(Set("B2")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged3.entries("b").elements should be(Set("B2")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 3" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B")) + val m2 = ORMap.empty.put(node2, "c", ORSet.empty.add(node2, "C")) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.remove(node2, "b").updated(node2, "b", ORSet.empty[String])(_.add(node2, "B2")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged2.entries("b").elements should be(Set("B2")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged3.entries("b").elements should be(Set("B2")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 4" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B")) + val m2 = ORMap.empty.put(node2, "c", ORSet.empty.add(node2, "C")) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.updated(node1, "b", ORSet.empty[String])(_.add(node1, "B2")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is included, because ORSet("B") is merged with ORSet("B2") + merged2.entries("b").elements should be(Set("B", "B2")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is included, because ORSet("B") is merged with ORSet("B2") + merged3.entries("b").elements should be(Set("B", "B2")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 5" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A").put(node1, "b", GSet.empty + "B") + val m2 = ORMap.empty.put(node2, "c", GSet.empty + "C") + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.put(node2, "b", GSet.empty + "B2") + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged2.entries("b").elements should be(Set("B2")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged3.entries("b").elements should be(Set("B2")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 6" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B")) + val m2 = ORMap.empty.put(node2, "b", ORSet.empty.add(node2, "B3")) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.remove(node2, "b").updated(node2, "b", ORSet.empty[String])(_.add(node2, "B1")) + .updated(node2, "b", ORSet.empty[String])(_.add(node2, "B2")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged2.entries("b").elements should be(Set("B1", "B2")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + // note that B is not included, because it was removed in both timelines + merged3.entries("b").elements should be(Set("B1", "B2")) + } + + "not have anomalies for remove+updated scenario and deltas 7" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")) + .put(node1, "b", ORSet.empty.add(node1, "B1")).remove(node1, "b") + val m2 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B2")) + val m2d = m2.resetDelta.remove(node1, "b") + val m2u = m2.resetDelta.updated(node1, "b", ORSet.empty[String])(_.add(node1, "B3")) + .updated(node2, "b", ORSet.empty[String])(_.add(node2, "B4")) + + val merged1 = (m1 merge m2d) mergeDelta m2u.delta.get + + merged1.entries("a").elements should be(Set("A")) + // note that B1 is lost as it was added and removed earlier in timeline than B2 + merged1.entries("b").elements should be(Set("B2", "B3", "B4")) + } + + "not have anomalies for remove+updated scenario and deltas 8" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A") + .put(node1, "b", GSet.empty + "B").put(node2, "b", GSet.empty + "B") + val m2 = ORMap.empty.put(node2, "c", GSet.empty + "C") + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b").remove(node2, "b") + val m4 = merged1.resetDelta.put(node2, "b", GSet.empty + "B2").put(node2, "b", GSet.empty + "B3") + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + merged2.entries("b").elements should be(Set("B3")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = (merged1 mergeDelta m3.delta.get) mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + merged3.entries("b").elements should be(Set("B3")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 9" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A") + .put(node1, "b", GSet.empty + "B").put(node2, "b", GSet.empty + "B") + val m2 = ORMap.empty.put(node2, "c", GSet.empty + "C") + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b").remove(node2, "b") + val m4 = merged1.resetDelta.updated(node2, "b", GSet.empty[String])(_.add("B2")) + .updated(node2, "b", GSet.empty[String])(_.add("B3")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + merged2.entries("b").elements should be(Set("B2", "B3")) + merged2.entries("c").elements should be(Set("C")) + + val merged3 = (merged1 mergeDelta m3.delta.get) mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + merged3.entries("b").elements should be(Set("B2", "B3")) + merged3.entries("c").elements should be(Set("C")) + } + + "not have anomalies for remove+updated scenario and deltas 10" in { + val m1 = ORMap.empty.put(node2, "a", GSet.empty + "A") + .put(node2, "b", GSet.empty + "B") + + val m3 = m1.resetDelta.remove(node2, "b") + val m4 = m3.resetDelta.put(node2, "b", GSet.empty + "B2").updated(node2, "b", GSet.empty[String])(_.add("B3")) + + val merged2 = m3 merge m4 + + merged2.entries("a").elements should be(Set("A")) + merged2.entries("b").elements should be(Set("B2", "B3")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a").elements should be(Set("A")) + merged3.entries("b").elements should be(Set("B2", "B3")) + } + + "have the usual anomalies for remove+updated scenario" in { + // please note that the current ORMultiMap has the same anomaly + // because the condition of keeping global vvector is violated + // by removal of the whole entry for the removed key "b" which results in removal of it's value's vvector + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")).put(node1, "b", ORSet.empty.add(node1, "B")) + val m2 = ORMap.empty.put(node2, "c", ORSet.empty.add(node2, "C")) + + // m1 - node1 gets the update from m2 + val merged1 = m1 merge m2 + // m2 - node2 gets the update from m1 + val merged2 = m2 merge m1 + + // RACE CONDITION ahead! + val m3 = merged1.resetDelta.remove(node1, "b") + // let's imagine that m3 (node1) update gets propagated here (full state or delta - doesn't matter) + // and is in flight, but in the meantime, an element is being added somewhere else (m4 - node2) + // and the update is propagated before the update from node1 is merged + val m4 = merged2.resetDelta.updated(node2, "b", ORSet.empty[String])(_.add(node2, "B2")) + // and later merged on node1 + val merged3 = m3 merge m4 + // and the other way round... + val merged4 = m4 merge m3 + + // result - the element "B" is kept on both sides... + merged3.entries("a").elements should be(Set("A")) + merged3.entries("b").elements should be(Set("B", "B2")) + merged3.entries("c").elements should be(Set("C")) + + merged4.entries("a").elements should be(Set("A")) + merged4.entries("b").elements should be(Set("B", "B2")) + merged4.entries("c").elements should be(Set("C")) + + // but if the timing was slightly different, so that the update from node1 + // would get merged just before update on node2: + val merged5 = (m2 merge m3).resetDelta.updated(node2, "b", ORSet.empty[String])(_.add(node2, "B2")) + // the update propagated ... and merged on node1: + val merged6 = m3 merge merged5 + + // then the outcome is different... because the vvector of value("b") was lost... + merged5.entries("a").elements should be(Set("A")) + // this time it's different... + merged5.entries("b").elements should be(Set("B2")) + merged5.entries("c").elements should be(Set("C")) + + merged6.entries("a").elements should be(Set("A")) + // this time it's different... + merged6.entries("b").elements should be(Set("B2")) + merged6.entries("c").elements should be(Set("C")) + } + + "work with deltas and updated for GSet elements type" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A") + val m2 = m1.resetDelta.updated(node1, "a", GSet.empty[String])(_.add("B")) + val m3 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get) + val GSet(d3) = m3.entries("a") + d3 should be(Set("A", "B")) + } + + "work with deltas and updated for ORSet elements type" in { + val m1 = ORMap.empty.put(node1, "a", ORSet.empty.add(node1, "A")) + val m2 = m1.resetDelta.updated(node1, "a", ORSet.empty[String])(_.add(node1, "B")) + val m3 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get) + + val ORSet(d3) = m3.entries("a") + d3 should be(Set("A", "B")) + } + + "work with aggregated deltas and updated for GSet elements type" in { + val m1 = ORMap.empty.put(node1, "a", GSet.empty + "A") + val m2 = m1.resetDelta.updated(node1, "a", GSet.empty[String])(_.add("B")).updated(node1, "a", GSet.empty[String])(_.add("C")) + val m3 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get) + val GSet(d3) = m3.entries("a") + d3 should be(Set("A", "B", "C")) + } + + "work with deltas and updated for GCounter elements type" in { + val m1 = ORMap.empty.put(node1, "a", GCounter.empty) + val m2 = m1.resetDelta.updated(node1, "a", GCounter.empty)(_.increment(node1, 10)) + val m3 = m2.resetDelta.updated(node2, "a", GCounter.empty)(_.increment(node2, 10)) + val m4 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get).mergeDelta(m3.delta.get) + val GCounter(num) = m4.entries("a") + num should ===(20) + } + + "work with deltas and updated for PNCounter elements type" in { + val m1 = ORMap.empty.put(node1, "a", PNCounter.empty) + val m2 = m1.resetDelta.updated(node1, "a", PNCounter.empty)(_.increment(node1, 10)) + val m3 = m2.resetDelta.updated(node2, "a", PNCounter.empty)(_.decrement(node2, 10)) + val m4 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get).mergeDelta(m3.delta.get) + val PNCounter(num) = m4.entries("a") + num should ===(0) + } + + "work with deltas and updated for Flag elements type" in { + val m1 = ORMap.empty.put(node1, "a", Flag(false)) + val m2 = m1.resetDelta.updated(node1, "a", Flag.empty)(_.switchOn) + val m3 = ORMap().mergeDelta(m1.delta.get).mergeDelta(m2.delta.get) + val Flag(d3) = m3.entries("a") + d3 should be(true) + } + "not allow put for ORSet elements type" in { val m = ORMap().put(node1, "a", ORSet().add(node1, "A")) diff --git a/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMultiMapSpec.scala b/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMultiMapSpec.scala index c3bc3f49c0..f95af2c934 100644 --- a/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMultiMapSpec.scala +++ b/akka-distributed-data/src/test/scala/akka/cluster/ddata/ORMultiMapSpec.scala @@ -77,6 +77,12 @@ class ORMultiMapSpec extends WordSpec with Matchers { val merged2 = m2 merge m1 merged2.entries should be(expectedMerged) + + val merged3 = m1 mergeDelta m2.delta.get + merged3.entries should be(expectedMerged) + + val merged4 = m2 mergeDelta m1.delta.get + merged4.entries should be(expectedMerged) } } @@ -107,6 +113,74 @@ class ORMultiMapSpec extends WordSpec with Matchers { m2.entries should be(Map("b" → Set("B1"))) } + "not have usual anomalies for remove+addBinding scenario and delta-deltas" in { + val m1 = ORMultiMap.emptyWithValueDeltas[String, String].put(node1, "a", Set("A")).put(node1, "b", Set("B")) + val m2 = ORMultiMap.emptyWithValueDeltas[String, String].put(node2, "c", Set("C")) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + val m4 = merged1.resetDelta.addBinding(node1, "b", "B2") + + val merged2 = m3 merge m4 + + merged2.entries("a") should be(Set("A")) + merged2.entries("b") should be(Set("B2")) + merged2.entries("c") should be(Set("C")) + + val merged3 = m3 mergeDelta m4.delta.get + + merged3.entries("a") should be(Set("A")) + merged3.entries("b") should be(Set("B2")) + merged3.entries("c") should be(Set("C")) + } + + "not have usual anomalies for remove+addBinding scenario and delta-deltas 2" in { + // the new delta-delta ORMultiMap is free from this anomaly + val m1 = ORMultiMap.emptyWithValueDeltas[String, String].put(node1, "a", Set("A")).put(node1, "b", Set("B")) + val m2 = ORMultiMap.emptyWithValueDeltas[String, String].put(node2, "c", Set("C")) + + // m1 - node1 gets the update from m2 + val merged1 = m1 merge m2 + // m2 - node2 gets the update from m1 + val merged2 = m2 merge m1 + + // no race condition + val m3 = merged1.resetDelta.remove(node1, "b") + // let's imagine that m3 (node1) update gets propagated here (full state or delta - doesn't matter) + // and is in flight, but in the meantime, an element is being added somewhere else (m4 - node2) + // and the update is propagated before the update from node1 is merged + val m4 = merged2.resetDelta.addBinding(node2, "b", "B2") + // and later merged on node1 + val merged3 = m3 merge m4 + // and the other way round... + val merged4 = m4 merge m3 + + // result - the element "B" is kept on both sides... + merged3.entries("a") should be(Set("A")) + merged3.entries("b") should be(Set("B2")) + merged3.entries("c") should be(Set("C")) + + merged4.entries("a") should be(Set("A")) + merged4.entries("b") should be(Set("B2")) + merged4.entries("c") should be(Set("C")) + + // but if the timing was slightly different, so that the update from node1 + // would get merged just before update on node2: + val merged5 = (m2 merge m3).resetDelta.addBinding(node2, "b", "B2") + // the update propagated ... and merged on node1: + val merged6 = m3 merge merged5 + + // then the outcome would be the same... + merged5.entries("a") should be(Set("A")) + merged5.entries("b") should be(Set("B2")) + merged5.entries("c") should be(Set("C")) + + merged6.entries("a") should be(Set("A")) + merged6.entries("b") should be(Set("B2")) + merged6.entries("c") should be(Set("C")) + } + "have unapply extractor" in { val m1 = ORMultiMap.empty.put(node1, "a", Set(1L, 2L)).put(node2, "b", Set(3L)) val m2: ORMultiMap[String, Long] = m1 diff --git a/akka-distributed-data/src/test/scala/akka/cluster/ddata/PNCounterMapSpec.scala b/akka-distributed-data/src/test/scala/akka/cluster/ddata/PNCounterMapSpec.scala index 3960c3fd99..5ac4915a33 100644 --- a/akka-distributed-data/src/test/scala/akka/cluster/ddata/PNCounterMapSpec.scala +++ b/akka-distributed-data/src/test/scala/akka/cluster/ddata/PNCounterMapSpec.scala @@ -46,6 +46,24 @@ class PNCounterMapSpec extends WordSpec with Matchers { (m3 merge m4).entries should be(Map("a" → 1, "b" → 13, "c" → 7)) } + "be able to work with deltas" in { + val m1 = PNCounterMap().increment(node1, "a", 1).increment(node1, "b", 3).increment(node1, "c", 2) + val m2 = PNCounterMap().increment(node2, "c", 5) + + val expected = Map("a" → 1, "b" → 3, "c" → 7) + (PNCounterMap() mergeDelta m1.delta.get mergeDelta m2.delta.get).entries should be(expected) + (PNCounterMap() mergeDelta m2.delta.get mergeDelta m1.delta.get).entries should be(expected) + + val merged1 = m1 merge m2 + + val m3 = merged1.resetDelta.remove(node1, "b") + (merged1 mergeDelta m3.delta.get).entries should be(Map("a" → 1, "c" → 7)) + + // but if there is a conflicting update the entry is not removed + val m4 = merged1.resetDelta.increment(node2, "b", 10) + (m3 mergeDelta m4.delta.get).entries should be(Map("a" → 1, "b" → 13, "c" → 7)) + } + "have unapply extractor" in { val m1 = PNCounterMap.empty.increment(node1, "a", 1).increment(node2, "b", 2) val PNCounterMap(entries1) = m1 diff --git a/akka-distributed-data/src/test/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializerSpec.scala b/akka-distributed-data/src/test/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializerSpec.scala index 4e53e1045e..b77c363f2b 100644 --- a/akka-distributed-data/src/test/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializerSpec.scala +++ b/akka-distributed-data/src/test/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializerSpec.scala @@ -184,6 +184,23 @@ class ReplicatedDataSerializerSpec extends TestKit(ActorSystem( checkSerialization(ORMap().put(address1, Flag(), GSet() + "A")) } + "serialize ORMap delta" in { + checkSerialization(ORMap().put(address1, "a", GSet() + "A").put(address2, "b", GSet() + "B").delta.get) + checkSerialization(ORMap().put(address1, "a", GSet() + "A").resetDelta.remove(address2, "a").delta.get) + checkSerialization(ORMap().put(address1, "a", GSet() + "A").remove(address2, "a").delta.get) + checkSerialization(ORMap().put(address1, 1, GSet() + "A").delta.get) + checkSerialization(ORMap().put(address1, 1L, GSet() + "A").delta.get) + checkSerialization(ORMap.empty[String, ORSet[String]] + .put(address1, "a", ORSet.empty[String].add(address1, "A")) + .put(address2, "b", ORSet.empty[String].add(address2, "B")) + .updated(address1, "a", ORSet.empty[String])(_.add(address1, "C")).delta.get) + checkSerialization(ORMap.empty[String, ORSet[String]] + .resetDelta + .updated(address1, "a", ORSet.empty[String])(_.add(address1, "C")).delta.get) + // use Flag for this test as object key because it is serializable + checkSerialization(ORMap().put(address1, Flag(), GSet() + "A").delta.get) + } + "be compatible with old ORMap serialization" in { // Below blob was created with previous version of the serializer val oldBlobAsBase64 = "H4sIAAAAAAAAAOOax8jlyaXMJc8lzMWXX5KRWqSXkV9copdflC7wXEWUiYGBQRaIGQQkuJS45LiEuHiL83NTUdQwwtWIC6kQpUqVKAulGBOlGJOE+LkYE4W4uJi5GB0FuJUYnUACSRABJ7AAAOLO3C3DAAAA" @@ -244,6 +261,22 @@ class ReplicatedDataSerializerSpec extends TestKit(ActorSystem( checkCompatibility(oldBlobAsBase64, ORMultiMap()) } + "serialize ORMultiMap withValueDeltas" in { + checkSerialization(ORMultiMap._emptyWithValueDeltas) + checkSerialization(ORMultiMap._emptyWithValueDeltas.addBinding(address1, "a", "A")) + checkSerialization(ORMultiMap._emptyWithValueDeltas.addBinding(address1, 1, "A")) + checkSerialization(ORMultiMap._emptyWithValueDeltas.addBinding(address1, 1L, "A")) + checkSerialization(ORMultiMap._emptyWithValueDeltas.addBinding(address1, Flag(), "A")) + checkSerialization(ORMultiMap.emptyWithValueDeltas[String, String] + .addBinding(address1, "a", "A1") + .put(address2, "b", Set("B1", "B2", "B3")) + .addBinding(address2, "a", "A2")) + + val m1 = ORMultiMap.emptyWithValueDeltas[String, String].addBinding(address1, "a", "A1").addBinding(address2, "a", "A2") + val m2 = ORMultiMap.emptyWithValueDeltas[String, String].put(address2, "b", Set("B1", "B2", "B3")) + checkSameContent(m1.merge(m2), m2.merge(m1)) + } + "serialize DeletedData" in { checkSerialization(DeletedData) }