Skip to content

Commit 7392bb8

Browse files
authored
diffgraph: ensure we don't crash if a node get's deleted twice (#414)
1 parent 6c0c492 commit 7392bb8

File tree

3 files changed

+85
-8
lines changed

3 files changed

+85
-8
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package overflowdb;
2+
3+
import org.junit.Test;
4+
import overflowdb.testdomains.simple.SimpleDomain;
5+
import overflowdb.testdomains.simple.TestEdge;
6+
import overflowdb.testdomains.simple.TestNode;
7+
8+
import static org.junit.Assert.assertEquals;
9+
10+
public class DiffGraphTest {
11+
12+
@Test
13+
public void nodeRemovalTest() {
14+
try (Graph graph = SimpleDomain.newGraph()) {
15+
BatchedUpdate.DiffGraphBuilder diff1 = new BatchedUpdate.DiffGraphBuilder();
16+
DetachedNodeData newNode = new DetachedNodeGeneric(TestNode.LABEL, TestNode.STRING_PROPERTY, "node 1");
17+
diff1.addNode(newNode);
18+
BatchedUpdate.applyDiff(graph, diff1);
19+
assertNodeCount(1, graph);
20+
Node node = graph.nodes().next();
21+
22+
BatchedUpdate.DiffGraphBuilder diff2 = new BatchedUpdate.DiffGraphBuilder();
23+
diff2.removeNode(node);
24+
// it shouldn't matter (and especially not error) if we remove the same node twice
25+
diff2.removeNode(node);
26+
BatchedUpdate.applyDiff(graph, diff2);
27+
assertNodeCount(0, graph);
28+
}
29+
}
30+
31+
@Test
32+
public void edgeRemovalTest() {
33+
try (Graph graph = SimpleDomain.newGraph()) {
34+
BatchedUpdate.DiffGraphBuilder diff1 = new BatchedUpdate.DiffGraphBuilder();
35+
DetachedNodeData n1D = new DetachedNodeGeneric(TestNode.LABEL, TestNode.STRING_PROPERTY, "node 1");
36+
DetachedNodeData n2D = new DetachedNodeGeneric(TestNode.LABEL, TestNode.STRING_PROPERTY, "node 2");
37+
diff1.addEdge(n1D, n2D,TestEdge.LABEL, TestEdge.LONG_PROPERTY, 99L);
38+
39+
BatchedUpdate.applyDiff(graph, diff1);
40+
assertNodeCount(2, graph);
41+
assertEdgeCount(1, graph);
42+
Edge edge = graph.edges().next();
43+
44+
BatchedUpdate.DiffGraphBuilder diff2 = new BatchedUpdate.DiffGraphBuilder();
45+
diff2.removeEdge(edge);
46+
// it shouldn't matter (and especially not error) if we remove the same edge twice
47+
diff2.removeEdge(edge);
48+
BatchedUpdate.applyDiff(graph, diff2);
49+
assertNodeCount(2, graph);
50+
assertEdgeCount(0, graph);
51+
}
52+
}
53+
54+
private void assertNodeCount(int expected, Graph graph) {
55+
assertEquals("node count different to expected", expected, graph.nodeCount());
56+
}
57+
58+
private void assertEdgeCount(int expected, Graph graph) {
59+
assertEquals("edge count different to expected", expected, graph.edgeCount());
60+
}
61+
62+
}

core/src/main/java/overflowdb/BatchedUpdate.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
import overflowdb.util.IteratorUtils;
44

5-
import java.util.ArrayDeque;
6-
import java.util.Iterator;
5+
import java.util.*;
76

87
public class BatchedUpdate {
98

@@ -199,6 +198,16 @@ public static class RemoveNode implements Change {
199198
public RemoveNode(Node node) {
200199
this.node = node;
201200
}
201+
202+
@Override
203+
public boolean equals(Object obj) {
204+
return (obj instanceof RemoveNode) && ((RemoveNode) obj).node.id() == node.id();
205+
}
206+
207+
@Override
208+
public int hashCode() {
209+
return Objects.hash(node.id());
210+
}
202211
}
203212

204213
public static class CreateEdge implements Change {
@@ -235,6 +244,10 @@ private static class DiffGraphApplier {
235244
private final Graph graph;
236245
private int nChanges = 0;
237246

247+
/** We keep track of already removed nodes to ensure we don't fail to load them from storage when they are
248+
* removed multiple times in the same Diff. */
249+
private Set<RemoveNode> removedNodes = new HashSet<>();
250+
238251
DiffGraphApplier(Graph graph, DiffOrBuilder diff, KeyPool keyPool, ModificationListener listener) {
239252
this.diff = diff;
240253
this.keyPool = keyPool;
@@ -311,11 +324,13 @@ private void applyChange(Change change) {
311324
remove.edge.removeInternal();
312325
} else if (change instanceof RemoveNode) {
313326
nChanges += 1;
314-
RemoveNode remove = (RemoveNode) change;
315-
if (listener != null)
316-
listener.onBeforeRemoveNode(remove.node);
317-
remove.node.removeInternal();
318-
327+
if (!removedNodes.contains(change)) {
328+
RemoveNode remove = (RemoveNode) change;
329+
if (listener != null)
330+
listener.onBeforeRemoveNode(remove.node);
331+
remove.node.removeInternal();
332+
removedNodes.add(remove);
333+
}
319334
} else if (change instanceof SetNodeProperty) {
320335
nChanges += 1;
321336
SetNodeProperty setProp = (SetNodeProperty) change;

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.9.0
1+
sbt.version=1.9.8

0 commit comments

Comments
 (0)