Skip to content

Commit db36986

Browse files
authored
Transaction reads should not interfere with add/update/delete (#3163)
https://issues.apache.org/jira/browse/TINKERPOP-3142 Changed TinkerElementContainer to no longer consider element reads as being 'used in a transaction' which should be reserved for element add/update/delete only. This is appropriate for TinkerTransactionGraph because the isolation level is 'read committed'. With this isolation level, we do not need to protect against 'unrepeatable reads' or 'phantom reads'. Prior to this change, a read-only thread could cause a 'Conflict: element modified in another transaction' error in a separate thread which was attempting add/drop/update.
1 parent 16255f5 commit db36986

File tree

4 files changed

+190
-40
lines changed

4 files changed

+190
-40
lines changed

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
5757
* Increased default `max_content_length`/`max_msg_size` in `gremlin-python` from 4MB to 10MB.
5858
* Added the `PopContaining` interface designed to get label and `Pop` combinations held in a `PopInstruction` object.
5959
* Fixed bug preventing a vertex from being dropped and then re-added in the same `TinkerTransaction`
60+
* Fixed bug which could cause a 'Conflict: element modified in another transaction' when a transaction is attempting to add/drop/update a vertex or edge while another transaction is reading the same vertex or edge.
6061
6162
[[release-3-7-3]]
6263
=== TinkerPop 3.7.3 (October 23, 2024)

docs/src/reference/implementations-tinkergraph.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ supported. You can think of the transaction as belonging to a thread, any traver
221221
will share the same transaction even if you attempt to start a new transaction.
222222
223223
`TinkerTransactionGraph` provides the `read committed` transaction isolation level. This means that it will always try to
224-
guard against dirty reads. While you may notice stricter isolation semantics in some cases, you should not depend on
225-
this behavior as it may change in the future.
224+
guard against dirty reads but will not prevent non-repeatable reads or phantom reads. While you may notice stricter
225+
isolation semantics in some cases, you should not depend on this behavior as it may change in the future.
226226
227227
`TinkerTransactionGraph` employs optimistic locking as its locking strategy. This reduces complexity in the design as
228228
there are fewer timeouts that the user needs to manage. However, a consequence of this approach is that a transaction

tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerElementContainer.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ final class TinkerElementContainer<T extends TinkerElement> {
5959
private final ThreadLocal<Boolean> isReadInTx = ThreadLocal.withInitial(() -> false);
6060

6161
/**
62-
* Count of usages of container in different transactions.
62+
* Count of modification/deletion/addition usages of container in different transactions (reads do not contribute to this count).
6363
* Needed to understand whether this element is used in other transactions or it can be deleted during rollback.
6464
*/
6565
private final AtomicInteger usesInTransactions = new AtomicInteger(0);
@@ -97,7 +97,6 @@ public T getWithClone(final TinkerTransaction tx) {
9797

9898
if (!isReadInTx.get()) {
9999
isReadInTx.set(true);
100-
usesInTransactions.incrementAndGet();
101100
tx.markRead(this);
102101
}
103102

@@ -205,7 +204,7 @@ public boolean updatedOutsideTransaction() {
205204
}
206205

207206
/**
208-
* Used to understand if element is in use by any transaction.
207+
* Used to understand if element is in use (added, modified, or deleted) by any transaction.
209208
*/
210209
public boolean inUse() {
211210
return usesInTransactions.get() > 0;
@@ -246,8 +245,6 @@ private void updateUsesCount() {
246245
usesInTransactions.decrementAndGet();
247246
if (isModifiedInTx.get())
248247
usesInTransactions.decrementAndGet();
249-
if (isReadInTx.get())
250-
usesInTransactions.decrementAndGet();
251248
}
252249

253250
/**

0 commit comments

Comments
 (0)