From d78be3b006a83f4e9e3a83cd76c0c79ee549040c Mon Sep 17 00:00:00 2001 From: ajs6f Date: Wed, 7 Mar 2018 12:25:05 -0500 Subject: [PATCH] JENA-1499: Pruning TIM indexes on tuple deletion --- .../jena/sparql/core/mem/PMapQuadTable.java | 23 ++++++++++++------- .../jena/sparql/core/mem/PMapTripleTable.java | 10 ++++++-- .../mem/TestDatasetGraphInMemoryBasic.java | 19 ++++++++++++++- .../jena/atlas/lib/persistent/PMap.java | 5 ++++ .../jena/atlas/lib/persistent/PSet.java | 5 ++++ .../atlas/lib/persistent/PersistentMap.java | 5 ++++ .../atlas/lib/persistent/PersistentSet.java | 5 ++++ 7 files changed, 61 insertions(+), 11 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapQuadTable.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapQuadTable.java index 8a31f2e48e2..b92986547cf 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapQuadTable.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapQuadTable.java @@ -158,14 +158,21 @@ protected TConsumer4 delete() { final FourTupleMap fourTuples = local().get(); fourTuples.get(first).ifPresent(threeTuples -> threeTuples.get(second) .ifPresent(twoTuples -> twoTuples.get(third).ifPresent(oneTuples -> { - if (oneTuples.contains(fourth)) { - oneTuples = oneTuples.minus(fourth); - final TwoTupleMap newTwoTuples = twoTuples.minus(third).plus(third, oneTuples); - final ThreeTupleMap newThreeTuples = threeTuples.minus(second).plus(second, newTwoTuples); - debug("Setting transactional index to new value."); - local().set(fourTuples.minus(first).plus(first, newThreeTuples)); - } - }))); + if (oneTuples.contains(fourth)) { + oneTuples = oneTuples.minus(fourth); + final TwoTupleMap newTwoTuples = oneTuples.asSet().isEmpty() + ? twoTuples.minus(third) + : twoTuples.minus(third).plus(third, oneTuples); + final ThreeTupleMap newThreeTuples = newTwoTuples.asMap().isEmpty() + ? threeTuples.minus(second) + : threeTuples.minus(second).plus(second, newTwoTuples); + final FourTupleMap newFourTuples = newThreeTuples.asMap().isEmpty() + ? fourTuples.minus(first) + : fourTuples.minus(first).plus(first, newThreeTuples); + debug("Setting transactional index to new value."); + local().set(newFourTuples); + } + }))); }; } } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTripleTable.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTripleTable.java index 16ba258cf7b..73b16df96c3 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTripleTable.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTripleTable.java @@ -144,9 +144,15 @@ protected TConsumer3 delete() { final ThreeTupleMap threeTuples = local().get(); threeTuples.get(first).ifPresent(twoTuples -> twoTuples.get(second).ifPresent(oneTuples -> { if (oneTuples.contains(third)) { - final TwoTupleMap newTwoTuples = twoTuples.minus(second).plus(second, oneTuples.minus(third)); + oneTuples = oneTuples.minus(third); + final TwoTupleMap newTwoTuples = oneTuples.asSet().isEmpty() + ? twoTuples.minus(second) + : twoTuples.minus(second).plus(second, oneTuples); debug("Setting transactional index to new value."); - local().set(threeTuples.minus(first).plus(first, newTwoTuples)); + final ThreeTupleMap newThreeTuples = twoTuples.asMap().isEmpty() + ? threeTuples.minus(first) + : threeTuples.minus(first).plus(first, newTwoTuples); + local().set(newThreeTuples); } })); }; diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryBasic.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryBasic.java index 3eff49e1dab..7401f705d5b 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryBasic.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryBasic.java @@ -101,9 +101,26 @@ public void unionGraphWorksProperly() { // no triples from default graph should appear in union Triple t = Triple.create(createBlankNode(), createBlankNode(), createBlankNode()); dsg.getDefaultGraph().add(t); - assertFalse(iter(dsg.find(unionGraph, ANY, ANY, ANY)).some(Quad::isDefaultGraph)) ; + assertFalse(iter(dsg.find(unionGraph, ANY, ANY, ANY)).some(Quad::isDefaultGraph)); } + @Test + public void listGraphNodesHasNoPhantomEmptyGraphs() { + final DatasetGraph dsg = emptyDataset(); + final Node g = createURI("http://example/g"); + final Node s = createURI("http://example/s"); + final Node p = createURI("http://example/p"); + final Node o = createURI("http://example/o"); + dsg.add(g, s, p, o); + Iterator graphNodes = dsg.listGraphNodes(); + assertTrue("Missing named graph!", graphNodes.hasNext()); + assertEquals("Wrong graph name!", g, graphNodes.next()); + assertFalse("Too many named graphs!", graphNodes.hasNext()); + dsg.delete(g, s, p, o); + graphNodes = dsg.listGraphNodes(); + assertFalse("Too many named graphs!", graphNodes.hasNext()); + } + @Override protected DatasetGraph emptyDataset() { return DatasetGraphFactory.createTxnMem(); diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PMap.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PMap.java index dba7160f965..4c72cf982c1 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PMap.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PMap.java @@ -51,6 +51,11 @@ protected PMap() { this(Maps.of()); } + @Override + public java.util.Map asMap() { + return wrappedMap.asMap(); + } + /** * @param wrapped a map that supplies the internal state to be used * @return a new {@code SelfType} that holds the supplied internal state diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PSet.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PSet.java index 1653c718e45..a01e293f878 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PSet.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PSet.java @@ -65,4 +65,9 @@ public boolean contains(final E e) { public Stream stream() { return wrappedSet.asSet().stream(); } + + @Override + public java.util.Set asSet() { + return wrappedSet.asSet(); + } } diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentMap.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentMap.java index d3f25e38691..788d6bb42ea 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentMap.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentMap.java @@ -76,4 +76,9 @@ default boolean containsKey(final K key) { default Stream flatten(final BiFunction> f) { return entryStream().flatMap(e -> f.apply(e.getKey(), e.getValue())); } + + /** + * An immutable view of this as a {@link java.util.Map}. + */ + java.util.Map asMap(); } diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentSet.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentSet.java index 92e799b3704..cfd9514dbab 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentSet.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/persistent/PersistentSet.java @@ -56,4 +56,9 @@ static PersistentSet empty() { * @return a {@link Stream} of the elements in this set */ Stream stream(); + + /** + * An immutable view of this as a {@code java.util.Set}. + */ + java.util.Set asSet(); }