You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gossip.apache.org by ec...@apache.org on 2017/07/17 22:58:10 UTC
[1/2] incubator-gossip git commit: GOSSIP-66 Implement Crdt 2P-Set
Repository: incubator-gossip
Updated Branches:
refs/heads/master 6ef0eb788 -> 95cce48a8
GOSSIP-66 Implement Crdt 2P-Set
Project: http://git-wip-us.apache.org/repos/asf/incubator-gossip/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-gossip/commit/89af0ac1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-gossip/tree/89af0ac1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-gossip/diff/89af0ac1
Branch: refs/heads/master
Commit: 89af0ac11289e7448a00382a0a93c460d9bfce5c
Parents: f71460a
Author: Maxim Rusak <ma...@yandex.ru>
Authored: Fri Jun 30 10:15:26 2017 +0300
Committer: Maxim Rusak <ma...@yandex.ru>
Committed: Fri Jun 30 10:16:22 2017 +0300
----------------------------------------------------------------------
.../java/org/apache/gossip/crdt/CrdtModule.java | 8 ++
.../org/apache/gossip/crdt/TwoPhaseSet.java | 115 ++++++++++++++++
.../gossip/crdt/AbstractCRDTStringSetTest.java | 133 ------------------
.../gossip/crdt/AddRemoveStringSetTest.java | 137 +++++++++++++++++++
.../java/org/apache/gossip/crdt/LwwSetTest.java | 2 +-
.../apache/gossip/crdt/MaxChangeSetTest.java | 2 +-
.../java/org/apache/gossip/crdt/OrSetTest.java | 2 +-
.../org/apache/gossip/crdt/TwoPhaseSetTest.java | 101 ++++++++++++++
.../test/java/org/apache/gossip/DataTest.java | 6 +
.../gossip/protocol/json/JacksonTest.java | 12 +-
10 files changed, 379 insertions(+), 139 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/main/java/org/apache/gossip/crdt/CrdtModule.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/main/java/org/apache/gossip/crdt/CrdtModule.java b/gossip-base/src/main/java/org/apache/gossip/crdt/CrdtModule.java
index 7ec96e7..ab5cefa 100644
--- a/gossip-base/src/main/java/org/apache/gossip/crdt/CrdtModule.java
+++ b/gossip-base/src/main/java/org/apache/gossip/crdt/CrdtModule.java
@@ -54,6 +54,13 @@ abstract class MaxChangeSetMixin<E> {
@JsonProperty("data") abstract Map<E, Integer> getStruct();
}
+abstract class TwoPhaseSetMixin<E> {
+ @JsonCreator
+ TwoPhaseSetMixin(@JsonProperty("added") Set<E> added, @JsonProperty("removed") Set<E> removed) { }
+ @JsonProperty("added") abstract Set<E> getAdded();
+ @JsonProperty("removed") abstract Set<E> getRemoved();
+}
+
abstract class GrowOnlySetMixin<E>{
@JsonCreator
GrowOnlySetMixin(@JsonProperty("elements") Set<E> elements){ }
@@ -93,6 +100,7 @@ public class CrdtModule extends SimpleModule {
context.setMixInAnnotations(LwwSet.class, LWWSetMixin.class);
context.setMixInAnnotations(LwwSet.Timestamps.class, LWWSetTimestampsMixin.class);
context.setMixInAnnotations(MaxChangeSet.class, MaxChangeSetMixin.class);
+ context.setMixInAnnotations(TwoPhaseSet.class, TwoPhaseSetMixin.class);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/main/java/org/apache/gossip/crdt/TwoPhaseSet.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/main/java/org/apache/gossip/crdt/TwoPhaseSet.java b/gossip-base/src/main/java/org/apache/gossip/crdt/TwoPhaseSet.java
new file mode 100644
index 0000000..a1f44a9
--- /dev/null
+++ b/gossip-base/src/main/java/org/apache/gossip/crdt/TwoPhaseSet.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gossip.crdt;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/*
+ Two-Phase CrdtSet.
+ You can add element only once and remove only once.
+ You cannot remove element which is not present.
+
+ Read more: https://github.com/aphyr/meangirls#2p-set
+ You can view examples of usage in tests:
+ TwoPhaseSetTest - unit tests
+ DataTest - integration test with 2 nodes, TwoPhaseSet was serialized/deserialized, sent between nodes, merged
+*/
+
+public class TwoPhaseSet<ElementType> implements CrdtAddRemoveSet<ElementType, Set<ElementType>, TwoPhaseSet<ElementType>> {
+ private final Set<ElementType> added;
+ private final Set<ElementType> removed;
+
+ public TwoPhaseSet(){
+ added = new HashSet<>();
+ removed = new HashSet<>();
+ }
+
+ @SafeVarargs
+ public TwoPhaseSet(ElementType... elements){
+ this(new HashSet<>(Arrays.asList(elements)));
+ }
+
+ public TwoPhaseSet(Set<ElementType> set){
+ this();
+ for (ElementType e : set){
+ added.add(e);
+ }
+ }
+
+ public TwoPhaseSet(TwoPhaseSet<ElementType> first, TwoPhaseSet<ElementType> second){
+ BiFunction<Set<ElementType>, Set<ElementType>, Set<ElementType>> mergeSets = (f, s) ->
+ Stream.concat(f.stream(), s.stream()).collect(Collectors.toSet());
+
+ added = mergeSets.apply(first.added, second.added);
+ removed = mergeSets.apply(first.removed, second.removed);
+ }
+
+ TwoPhaseSet(Set<ElementType> added, Set<ElementType> removed){
+ this.added = added;
+ this.removed = removed;
+ }
+
+ Set<ElementType> getAdded(){
+ return added;
+ }
+
+ Set<ElementType> getRemoved(){
+ return removed;
+ }
+
+ public TwoPhaseSet<ElementType> add(ElementType e){
+ if (removed.contains(e) || added.contains(e)){
+ return this;
+ }
+ return this.merge(new TwoPhaseSet<>(e));
+ }
+
+ public TwoPhaseSet<ElementType> remove(ElementType e){
+ if (removed.contains(e) || !added.contains(e)){
+ return this;
+ }
+ Set<ElementType> eSet = new HashSet<>(Collections.singletonList(e));
+ return this.merge(new TwoPhaseSet<>(eSet, eSet));
+ }
+
+ @Override
+ public TwoPhaseSet<ElementType> merge(TwoPhaseSet<ElementType> other){
+ return new TwoPhaseSet<>(this, other);
+ }
+
+ @Override
+ public Set<ElementType> value(){
+ return added.stream().filter(e -> !removed.contains(e)).collect(Collectors.toSet());
+ }
+
+ @Override
+ public TwoPhaseSet<ElementType> optimize(){
+ return new TwoPhaseSet<>(value(), removed);
+ }
+
+ @Override
+ public boolean equals(Object obj){
+ return this == obj || (obj != null && getClass() == obj.getClass() && value().equals(((TwoPhaseSet) obj).value()));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/AbstractCRDTStringSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/AbstractCRDTStringSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/AbstractCRDTStringSetTest.java
deleted file mode 100644
index d4db4ce..0000000
--- a/gossip-base/src/test/java/org/apache/gossip/crdt/AbstractCRDTStringSetTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unle<F4>ss required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.gossip.crdt;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.Ignore;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/*
- Abstract test suit to test CrdtSets with Add and Remove operations.
- It compares them with simple sets, validates add, remove, equals, value, etc. operations
- To use it you should:
- 1. subclass this and implement constructors
- 2. implement CrdtAddRemoveSet in your CrdtSet
- 3. make your CrdtSet immutable
-*/
-
-@Ignore
-public abstract class AbstractCRDTStringSetTest<SetType extends CrdtAddRemoveSet<String, Set<String>, SetType>> {
- abstract SetType construct(Set<String> set);
-
- abstract SetType construct();
-
- private Set<String> sampleSet;
-
- @Before
- public void setup(){
- sampleSet = new HashSet<>();
- sampleSet.add("4");
- sampleSet.add("5");
- sampleSet.add("12");
- }
-
- @Test
- public void abstractSetConstructorTest(){
- Assert.assertEquals(construct(sampleSet).value(), sampleSet);
- }
-
- @Test
- public void abstractStressWithSetTest(){
- Set<String> hashSet = new HashSet<>();
- SetType set = construct();
- for (int it = 0; it < 40; it++){
- SetType newSet;
- if (it % 5 == 1){
- //deleting existing
- String forDelete = hashSet.stream().skip((long) (hashSet.size() * Math.random())).findFirst().get();
- newSet = set.remove(forDelete);
- Assert.assertEquals(set.value(), hashSet); // check old version is immutable
- hashSet.remove(forDelete);
- } else {
- //adding
- String forAdd = String.valueOf((int) (10000 * Math.random()));
- newSet = set.add(forAdd);
- Assert.assertEquals(set.value(), hashSet); // check old version is immutable
- hashSet.add(forAdd);
- }
- set = newSet;
- Assert.assertEquals(set.value(), hashSet);
- }
- }
-
- @Test
- public void abstractEqualsTest(){
- SetType set = construct(sampleSet);
- Assert.assertFalse(set.equals(sampleSet));
- SetType newSet = set.add("25");
- sampleSet.add("25");
- Assert.assertFalse(newSet.equals(set));
- Assert.assertEquals(construct(sampleSet), newSet);
- }
-
- @Test
- public void abstractRemoveMissingTest(){
- SetType set = construct(sampleSet);
- set = set.add("25");
- set = set.remove("25");
- Assert.assertEquals(set.value(), sampleSet);
- set = set.remove("25");
- set = set.add("25");
- sampleSet.add("25");
- Assert.assertEquals(set.value(), sampleSet);
- }
-
- @Test
- public void abstractStressMergeTest(){
- // in one-process context, add, remove and merge operations of lww are equal to operations of Set
- // we've already checked it. Now just check merge
- Set<String> hashSet1 = new HashSet<>(), hashSet2 = new HashSet<>();
- SetType set1 = construct(), set2 = construct();
-
- for (int it = 0; it < 100; it++){
- String forAdd = String.valueOf((int) (10000 * Math.random()));
- if (it % 2 == 0){
- hashSet1.add(forAdd);
- set1 = set1.add(forAdd);
- } else {
- hashSet2.add(forAdd);
- set2 = set2.add(forAdd);
- }
- }
- Assert.assertEquals(set1.value(), hashSet1);
- Assert.assertEquals(set2.value(), hashSet2);
- Set<String> mergedSet = Stream.concat(hashSet1.stream(), hashSet2.stream()).collect(Collectors.toSet());
- Assert.assertEquals(set1.merge(set2).value(), mergedSet);
- }
-
- @Test
- public void abstractOptimizeTest(){
- Assert.assertEquals(construct(sampleSet).value(), sampleSet);
- Assert.assertEquals(construct(sampleSet).optimize().value(), sampleSet);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/AddRemoveStringSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/AddRemoveStringSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/AddRemoveStringSetTest.java
new file mode 100644
index 0000000..6dac9df
--- /dev/null
+++ b/gossip-base/src/test/java/org/apache/gossip/crdt/AddRemoveStringSetTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unle<F4>ss required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gossip.crdt;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/*
+ Abstract test suit to test CrdtSets with Add and Remove operations.
+ You can use this suite only if your set supports multiple additions/deletions
+ and has behavior similar to Set in single-threaded environment.
+ It compares them with simple sets, validates add, remove, equals, value, etc. operations
+ To use it you should:
+ 1. subclass this and implement constructors
+ 2. implement CrdtAddRemoveSet in your CrdtSet
+ 3. make your CrdtSet immutable
+*/
+
+@Ignore
+public abstract class AddRemoveStringSetTest<SetType extends CrdtAddRemoveSet<String, Set<String>, SetType>> {
+
+ abstract SetType construct(Set<String> set);
+
+ abstract SetType construct();
+
+ private Set<String> sampleSet;
+
+ @Before
+ public void setup(){
+ sampleSet = new HashSet<>();
+ sampleSet.add("4");
+ sampleSet.add("5");
+ sampleSet.add("12");
+ }
+
+ @Test
+ public void abstractSetConstructorTest(){
+ Assert.assertEquals(construct(sampleSet).value(), sampleSet);
+ }
+
+ @Test
+ public void abstractStressWithSetTest(){
+ Set<String> hashSet = new HashSet<>();
+ SetType set = construct();
+ for (int it = 0; it < 40; it++){
+ SetType newSet;
+ if (it % 5 == 1){
+ //deleting existing
+ String forDelete = hashSet.stream().skip((long) (hashSet.size() * Math.random())).findFirst().get();
+ newSet = set.remove(forDelete);
+ Assert.assertEquals(set.value(), hashSet); // check old version is immutable
+ hashSet.remove(forDelete);
+ } else {
+ //adding
+ String forAdd = String.valueOf((int) (10000 * Math.random()));
+ newSet = set.add(forAdd);
+ Assert.assertEquals(set.value(), hashSet); // check old version is immutable
+ hashSet.add(forAdd);
+ }
+ set = newSet;
+ Assert.assertEquals(set.value(), hashSet);
+ }
+ }
+
+ @Test
+ public void abstractEqualsTest(){
+ SetType set = construct(sampleSet);
+ Assert.assertFalse(set.equals(sampleSet));
+ SetType newSet = set.add("25");
+ sampleSet.add("25");
+ Assert.assertFalse(newSet.equals(set));
+ Assert.assertEquals(construct(sampleSet), newSet);
+ }
+
+ @Test
+ public void abstractRemoveMissingTest(){
+ SetType set = construct(sampleSet);
+ set = set.add("25");
+ set = set.remove("25");
+ Assert.assertEquals(set.value(), sampleSet);
+ set = set.remove("25");
+ set = set.add("25");
+ sampleSet.add("25");
+ Assert.assertEquals(set.value(), sampleSet);
+ }
+
+ @Test
+ public void abstractStressMergeTest(){
+ // in one-process context, add, remove and merge operations of lww are equal to operations of Set
+ // we've already checked it. Now just check merge
+ Set<String> hashSet1 = new HashSet<>(), hashSet2 = new HashSet<>();
+ SetType set1 = construct(), set2 = construct();
+
+ for (int it = 0; it < 100; it++){
+ String forAdd = String.valueOf((int) (10000 * Math.random()));
+ if (it % 2 == 0){
+ hashSet1.add(forAdd);
+ set1 = set1.add(forAdd);
+ } else {
+ hashSet2.add(forAdd);
+ set2 = set2.add(forAdd);
+ }
+ }
+ Assert.assertEquals(set1.value(), hashSet1);
+ Assert.assertEquals(set2.value(), hashSet2);
+ Set<String> mergedSet = Stream.concat(hashSet1.stream(), hashSet2.stream()).collect(Collectors.toSet());
+ Assert.assertEquals(set1.merge(set2).value(), mergedSet);
+ }
+
+ @Test
+ public void abstractOptimizeTest(){
+ Assert.assertEquals(construct(sampleSet).value(), sampleSet);
+ Assert.assertEquals(construct(sampleSet).optimize().value(), sampleSet);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/LwwSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/LwwSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/LwwSetTest.java
index 8200b15..c4da83d 100644
--- a/gossip-base/src/test/java/org/apache/gossip/crdt/LwwSetTest.java
+++ b/gossip-base/src/test/java/org/apache/gossip/crdt/LwwSetTest.java
@@ -27,7 +27,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-public class LwwSetTest extends AbstractCRDTStringSetTest<LwwSet<String>> {
+public class LwwSetTest extends AddRemoveStringSetTest<LwwSet<String>> {
static private Clock clock = new SystemClock();
LwwSet<String> construct(Set<String> set){
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/MaxChangeSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/MaxChangeSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/MaxChangeSetTest.java
index 2ba3f09..3828747 100644
--- a/gossip-base/src/test/java/org/apache/gossip/crdt/MaxChangeSetTest.java
+++ b/gossip-base/src/test/java/org/apache/gossip/crdt/MaxChangeSetTest.java
@@ -25,7 +25,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-public class MaxChangeSetTest extends AbstractCRDTStringSetTest<MaxChangeSet<String>> {
+public class MaxChangeSetTest extends AddRemoveStringSetTest<MaxChangeSet<String>> {
MaxChangeSet<String> construct(Set<String> set){
return new MaxChangeSet<>(set);
}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/OrSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/OrSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/OrSetTest.java
index bdaada9..8b21360 100644
--- a/gossip-base/src/test/java/org/apache/gossip/crdt/OrSetTest.java
+++ b/gossip-base/src/test/java/org/apache/gossip/crdt/OrSetTest.java
@@ -25,7 +25,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
-public class OrSetTest extends AbstractCRDTStringSetTest<OrSet<String>> {
+public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> {
OrSet<String> construct(){
return new OrSet<>();
}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-base/src/test/java/org/apache/gossip/crdt/TwoPhaseSetTest.java
----------------------------------------------------------------------
diff --git a/gossip-base/src/test/java/org/apache/gossip/crdt/TwoPhaseSetTest.java b/gossip-base/src/test/java/org/apache/gossip/crdt/TwoPhaseSetTest.java
new file mode 100644
index 0000000..3af1920
--- /dev/null
+++ b/gossip-base/src/test/java/org/apache/gossip/crdt/TwoPhaseSetTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gossip.crdt;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+public class TwoPhaseSetTest {
+
+ private Set<String> sampleSet;
+
+ @Before
+ public void setup(){
+ sampleSet = new HashSet<>();
+ sampleSet.add("a");
+ sampleSet.add("b");
+ sampleSet.add("d");
+ }
+
+ @Test
+ public void setConstructorTest(){
+ Assert.assertEquals(new TwoPhaseSet<>(sampleSet).value(), sampleSet);
+ }
+
+ @Test
+ public void valueTest(){
+ Set<Character> added = new HashSet<>();
+ added.add('a');
+ added.add('b');
+ Set<Character> removed = new HashSet<>();
+ removed.add('b');
+ Assert.assertEquals(new TwoPhaseSet<>(added, removed), new TwoPhaseSet<>('a'));
+ }
+
+ @Test
+ public void optimizeTest(){
+ TwoPhaseSet<String> set = new TwoPhaseSet<>(sampleSet);
+ set = set.remove("b");
+ Assert.assertEquals(set.optimize(), set);
+ // check that optimize in this case actually works
+ Assert.assertTrue(set.optimize().getAdded().size() < set.getAdded().size());
+ }
+
+ @Test
+ public void immutabilityTest(){
+ TwoPhaseSet<String> set = new TwoPhaseSet<>(sampleSet);
+ TwoPhaseSet<String> newSet = set.remove("b");
+ Assert.assertNotEquals(set, newSet);
+ Assert.assertEquals(set, new TwoPhaseSet<>(sampleSet));
+ }
+
+ @Test
+ public void removeMissingAddExistingLimitsTest(){
+ BiConsumer<TwoPhaseSet<?>, TwoPhaseSet<?>> checkInternals = (f, s) -> {
+ Assert.assertEquals(s, f);
+ Assert.assertEquals(s.getRemoved(), f.getRemoved());
+ Assert.assertEquals(s.getAdded(), f.getAdded());
+ };
+ TwoPhaseSet<String> set = new TwoPhaseSet<>(sampleSet);
+ // remove missing
+ checkInternals.accept(set, set.remove("e"));
+ // add existing
+ checkInternals.accept(set, set.add("a"));
+ // limits
+ TwoPhaseSet<String> newSet = set.remove("a"); // allow this remove
+ Assert.assertEquals(newSet.add("a"), new TwoPhaseSet<>("b", "d")); // discard this add, "a" was added and removed
+ }
+
+ @Test
+ public void mergeTest(){
+ TwoPhaseSet<String> f = new TwoPhaseSet<>(sampleSet);
+ TwoPhaseSet<String> s = new TwoPhaseSet<>("a", "c");
+ s = s.remove("a");
+ TwoPhaseSet<String> res = f.merge(s);
+ Assert.assertEquals(res, new TwoPhaseSet<>(f, s)); // check two-sets constructor
+
+ // "a" was both added and deleted in second set => it's deleted in result
+ // "b" and "d" comes from first set and "c" comes from second
+ Assert.assertEquals(res, new TwoPhaseSet<>("b", "c", "d"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-itest/src/test/java/org/apache/gossip/DataTest.java
----------------------------------------------------------------------
diff --git a/gossip-itest/src/test/java/org/apache/gossip/DataTest.java b/gossip-itest/src/test/java/org/apache/gossip/DataTest.java
index df078aa..c16174f 100644
--- a/gossip-itest/src/test/java/org/apache/gossip/DataTest.java
+++ b/gossip-itest/src/test/java/org/apache/gossip/DataTest.java
@@ -25,6 +25,7 @@ import org.apache.gossip.crdt.LwwSet;
import org.apache.gossip.crdt.MaxChangeSet;
import org.apache.gossip.crdt.OrSet;
import org.apache.gossip.crdt.PNCounter;
+import org.apache.gossip.crdt.TwoPhaseSet;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.model.PerNodeDataMessage;
@@ -148,6 +149,11 @@ public class DataTest {
}
@Test
+ public void TwoPhaseSetTest(){
+ crdtSetTest("crtps", TwoPhaseSet::new);
+ }
+
+ @Test
public void GrowOnlyCounterTest(){
Consumer<Long> assertCountUpdated = count -> {
for (GossipManager client : clients){
http://git-wip-us.apache.org/repos/asf/incubator-gossip/blob/89af0ac1/gossip-protocol-jackson/src/test/java/org/apache/gossip/protocol/json/JacksonTest.java
----------------------------------------------------------------------
diff --git a/gossip-protocol-jackson/src/test/java/org/apache/gossip/protocol/json/JacksonTest.java b/gossip-protocol-jackson/src/test/java/org/apache/gossip/protocol/json/JacksonTest.java
index d391fa1..2a5239c 100644
--- a/gossip-protocol-jackson/src/test/java/org/apache/gossip/protocol/json/JacksonTest.java
+++ b/gossip-protocol-jackson/src/test/java/org/apache/gossip/protocol/json/JacksonTest.java
@@ -25,6 +25,7 @@ import org.apache.gossip.Member;
import org.apache.gossip.crdt.LwwSet;
import org.apache.gossip.crdt.MaxChangeSet;
import org.apache.gossip.crdt.OrSet;
+import org.apache.gossip.crdt.TwoPhaseSet;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.protocol.ProtocolManager;
@@ -98,17 +99,22 @@ public class JacksonTest {
@Test
public void jacksonOrSetTest(){
- jacksonCrdtSeDeTest(new OrSet<>("1", "2", "3"), OrSet.class);
+ jacksonCrdtSeDeTest(new OrSet<>("1", "2", "3").remove("2"), OrSet.class);
}
@Test
public void jacksonLWWSetTest(){
- jacksonCrdtSeDeTest(new LwwSet<>("1", "2", "3"), LwwSet.class);
+ jacksonCrdtSeDeTest(new LwwSet<>("1", "2", "3").remove("2"), LwwSet.class);
}
@Test
public void jacksonMaxChangeSetTest(){
- jacksonCrdtSeDeTest(new MaxChangeSet<>("1", "2", "3"), MaxChangeSet.class);
+ jacksonCrdtSeDeTest(new MaxChangeSet<>("1", "2", "3").remove("2"), MaxChangeSet.class);
+ }
+
+ @Test
+ public void jacksonTwoPhaseSetTest(){
+ jacksonCrdtSeDeTest(new TwoPhaseSet<>("1", "2", "3").remove("2"), TwoPhaseSet.class);
}
@Test
[2/2] incubator-gossip git commit: Merge branch 'GOSSIP-66' of
https://github.com/makrusak/incubator-gossip
Posted by ec...@apache.org.
Merge branch 'GOSSIP-66' of https://github.com/makrusak/incubator-gossip
Project: http://git-wip-us.apache.org/repos/asf/incubator-gossip/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-gossip/commit/95cce48a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-gossip/tree/95cce48a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-gossip/diff/95cce48a
Branch: refs/heads/master
Commit: 95cce48a8e5a9e685d654a79ef082c47dd485df1
Parents: 6ef0eb7 89af0ac
Author: edward <ed...@hollywood.ian>
Authored: Mon Jul 17 18:54:26 2017 -0400
Committer: edward <ed...@hollywood.ian>
Committed: Mon Jul 17 18:54:26 2017 -0400
----------------------------------------------------------------------
.../java/org/apache/gossip/crdt/CrdtModule.java | 8 ++
.../org/apache/gossip/crdt/TwoPhaseSet.java | 115 ++++++++++++++++
.../gossip/crdt/AbstractCRDTStringSetTest.java | 133 ------------------
.../gossip/crdt/AddRemoveStringSetTest.java | 137 +++++++++++++++++++
.../java/org/apache/gossip/crdt/LwwSetTest.java | 2 +-
.../apache/gossip/crdt/MaxChangeSetTest.java | 2 +-
.../java/org/apache/gossip/crdt/OrSetTest.java | 2 +-
.../org/apache/gossip/crdt/TwoPhaseSetTest.java | 101 ++++++++++++++
.../test/java/org/apache/gossip/DataTest.java | 6 +
.../gossip/protocol/json/JacksonTest.java | 12 +-
10 files changed, 379 insertions(+), 139 deletions(-)
----------------------------------------------------------------------