Skip to content

Commit f6480f5

Browse files
greenrobot-teamgreenrobot
authored andcommitted
Transaction: destroy checks must call nativeIsActive() #282
isActive() also considered closed flag, which must be ignored here
1 parent 96763d5 commit f6480f5

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

objectbox-java/src/main/java/io/objectbox/Transaction.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public synchronized void close() {
103103

104104
boolean isOwnerThread = nativeIsOwnerThread(transaction);
105105
if (!isOwnerThread) {
106+
// Note: don't use isActive(), it returns false here because closed == true already
106107
boolean isActive = nativeIsActive(transaction);
107108
boolean isRecycled = nativeIsRecycled(transaction);
108109
if (isActive || isRecycled) {
@@ -128,23 +129,31 @@ public synchronized void close() {
128129
if (!store.isNativeStoreClosed()) {
129130
nativeDestroy(transaction);
130131
} else {
131-
String threadType = isOwnerThread ? "owner thread" : "non-owner thread";
132-
String activeInfo = isActive() ? " (active TX)" : " (inactive TX)";
132+
// Note: don't use isActive(), it returns false here because closed == true already
133+
boolean isActive = nativeIsActive(transaction);
133134
if (readOnly) {
134-
// Minor leak if TX is active, but still log so we can check logs that it only happens occasionally.
135-
// We cannot rely on the native and Java stores waiting briefly for read transactions.
136-
System.out.println("Info: closing read transaction after store was closed (should be avoided) in " +
137-
threadType + activeInfo);
135+
// Minor leak if TX is active, but still log so the ObjectBox team can check that it only happens
136+
// occasionally.
137+
// Note this cannot assume the store isn't destroyed, yet. The native and Java stores may at best
138+
// briefly wait for read transactions.
139+
System.out.printf(
140+
"Info: closing read transaction after store was closed (isActive=%s, isOwnerThread=%s), this should be avoided.%n",
141+
isActive, isOwnerThread);
138142
System.out.flush();
139143

140-
if (!isActive()) { // Note: call "isActive()" for fresh value (do not cache it)
144+
// Note: get fresh active state
145+
if (!nativeIsActive(transaction)) {
141146
nativeDestroy(transaction);
142147
}
143-
} else { // write transaction
144-
System.out.println("WARN: closing write transaction after store was closed (must be avoided) in " +
145-
threadType + activeInfo);
148+
} else {
149+
// write transaction
150+
System.out.printf(
151+
"WARN: closing write transaction after store was closed (isActive=%s, isOwnerThread=%s), this must be avoided.%n",
152+
isActive, isOwnerThread);
146153
System.out.flush();
147-
if (isActive() && store.isNativeStoreDestroyed()) { // Note: call "isActive()" for fresh value
154+
155+
// Note: get fresh active state
156+
if (nativeIsActive(transaction) && store.isNativeStoreDestroyed()) {
148157
// This is an internal validation: if this is an active write-TX,
149158
// the (native) store will always wait for it, so it must not be destroyed yet.
150159
// If this ever happens, the above assumption is wrong, and throwing likely prevents a SIGSEGV.

0 commit comments

Comments
 (0)