This is an automated email from the ASF dual-hosted git repository.
colegreer pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.7-dev by this push:
new 818a1b32a2 Fix Bug in TinkerTransactionGraph transaction used counts
(#2992)
818a1b32a2 is described below
commit 818a1b32a243aff9c3a0eea5f8f520bfb612b685
Author: Cole Greer <[email protected]>
AuthorDate: Wed Jan 29 11:12:57 2025 -0800
Fix Bug in TinkerTransactionGraph transaction used counts (#2992)
Fixed bug where elements which are read in a transaction end up with
incorrect usedInTransaction counts which may trigger unintended
TransactionExceptions
---
CHANGELOG.asciidoc | 1 +
.../structure/TinkerElementContainer.java | 16 +++++++-
.../tinkergraph/structure/TinkerTransaction.java | 2 +-
.../structure/TinkerTransactionGraphTest.java | 46 ++++++++++++++++++++++
4 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 79c6ce8c9c..447a9b33e3 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Changed `IdentityRemovalStrategy` to omit `IdentityStep` if only with
`RepeatEndStep` under `RepeatStep`.
* Changed Gremlin grammar to make use of `g` to spawn child traversals a
syntax error.
* Added `unexpected-response` handler to `ws` for `gremlin-javascript`
+* Fixed bug in `TinkerTransactionGraph` where a read-only transaction may
leave elements trapped in a "zombie transaction".
[[release-3-7-3]]
=== TinkerPop 3.7.3 (October 23, 2024)
diff --git
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerElementContainer.java
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerElementContainer.java
index a74337926c..4d7216d21b 100644
---
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerElementContainer.java
+++
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerElementContainer.java
@@ -133,10 +133,15 @@ final class TinkerElementContainer<T extends
TinkerElement> {
}
/**
- * Used to understand if the element has deleted in the current transaction
+ * Used to understand if the element has been deleted in the current
transaction
*/
public boolean isDeleted() { return isDeleted || isDeletedInTx.get(); }
+ /**
+ * Used to understand if the element has been read in the current
transaction
+ */
+ public boolean isRead() { return isReadInTx.get(); }
+
/**
* Mark element as deleted in the current transaction.
*/
@@ -185,6 +190,13 @@ final class TinkerElementContainer<T extends
TinkerElement> {
element != null && updatedValue != null &&
updatedValue.version() != element.version();
}
+ /**
+ * Used to understand if element is in use by any transaction.
+ */
+ public boolean inUse() {
+ return usesInTransactions.get() > 0;
+ }
+
/**
* Commit changes for the stored element.
* @param txVersion version of transaction
@@ -197,7 +209,7 @@ final class TinkerElementContainer<T extends TinkerElement>
{
element.removed = true;
element = null;
isDeleted = true;
- } else {
+ } else if (isModifiedInTx.get()){
element = transactionUpdatedValue.get();
element.currentVersion = txVersion;
}
diff --git
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransaction.java
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransaction.java
index 077b6adbc0..4e4cde497c 100644
---
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransaction.java
+++
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransaction.java
@@ -203,7 +203,7 @@ final class TinkerTransaction extends
AbstractThreadLocalTransaction {
final Set<TinkerElementContainer> readElements =
txReadElements.get();
if (readElements != null)
- readElements.stream().forEach(e -> e.reset());
+ readElements.stream().forEach(e -> e.commit(txVersion));
txChangedVertices.remove();
txChangedEdges.remove();
diff --git
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraphTest.java
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraphTest.java
index 9d240625bb..88b52413b6 100644
---
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraphTest.java
+++
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraphTest.java
@@ -32,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -1457,4 +1458,49 @@ public class TinkerTransactionGraphTest {
countElementsInNewThreadTx(g, 1, 0);
}
+
+ @Test
+ public void shouldHandleSequenceOfCreateReadDeleteCreateSameVertex() {
+ final TinkerTransactionGraph graph = TinkerTransactionGraph.open();
+ final GraphTraversalSource g = graph.traversal();
+
+ g.addV().property(T.id, 1).next();
+ graph.tx().commit();
+ g.V().next();
+ graph.tx().commit();
+ g.V().drop().iterate();
+ graph.tx().commit();
+
+ assertEquals(false, graph.hasVertex(1));
+
+ g.addV().property(T.id, 1).next();
+ graph.tx().commit();
+
+ assertFalse(graph.getVertices().get(1).inUse());
+ assertEquals(true, graph.hasVertex(1));
+ }
+
+ @Test
+ public void shouldHandleCorrectlyHandleCountForChangedAndReadElement() {
+ final TinkerTransactionGraph graph = TinkerTransactionGraph.open();
+ final GraphTraversalSource g = graph.traversal();
+
+ g.addV().property(T.id, 1).next();
+ graph.tx().commit();
+ TinkerElementContainer vertex = graph.getVertices().get(1);
+
+ g.V().next();
+ g.V().property("prop", 5).next();
+ g.V().next();
+ g.V().property("prop2", "foo").next();
+ assertTrue(vertex.isChanged());
+ assertTrue(vertex.isRead());
+ assertTrue(vertex.inUse());
+
+ graph.tx().commit();
+ assertFalse(vertex.isChanged());
+ assertFalse(vertex.isRead());
+
+ assertFalse(vertex.inUse());
+ }
}