3030import java .util .concurrent .LinkedBlockingQueue ;
3131import java .util .concurrent .ThreadPoolExecutor ;
3232import java .util .concurrent .TimeUnit ;
33+ import java .util .concurrent .atomic .AtomicBoolean ;
3334import java .util .concurrent .atomic .AtomicInteger ;
3435import java .util .concurrent .atomic .AtomicReference ;
3536
@@ -421,20 +422,67 @@ public void testCallInReadTx() {
421422 assertEquals (1 , counts [1 ]);
422423 }
423424
425+ @ Test
426+ public void testRunInTx_closesActiveTxCursor () {
427+ final Box <TestEntity > box = getTestEntityBox ();
428+ AtomicBoolean hasCursorInTx = new AtomicBoolean (false );
429+ store .runInTx (() -> {
430+ box .count (); // Call Box API that creates a reader/activeTxCursor
431+ hasCursorInTx .set (box .hasActiveTxCursorForCurrentThread ());
432+ });
433+ // Verify a cursor for the active tx was created
434+ assertTrue (hasCursorInTx .get ());
435+ // Check it was released
436+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
437+
438+ // Verify the same in case the runnable throws
439+ try {
440+ store .runInTx (() -> {
441+ box .count ();
442+ throw new IllegalStateException ("Throw in transaction" );
443+ });
444+ } catch (IllegalStateException ignored ) {}
445+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
446+ }
447+
448+ @ Test
449+ public void testCallInTx_closesActiveTxCursor () throws Exception {
450+ final Box <TestEntity > box = getTestEntityBox ();
451+ Boolean hasCursorInTx = store .callInTx (() -> {
452+ box .count (); // Call Box API that creates a reader/activeTxCursor
453+ return box .hasActiveTxCursorForCurrentThread ();
454+ });
455+ // Verify a cursor for the active tx was created
456+ assertTrue (hasCursorInTx );
457+ // Check it was released
458+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
459+
460+ // Verify the same in case the callable throws
461+ try {
462+ store .callInTx (() -> {
463+ box .count ();
464+ throw new IllegalStateException ("Throw in transaction" );
465+ });
466+ } catch (IllegalStateException ignored ) {}
467+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
468+ }
469+
424470 @ Test
425471 public void testRunInReadTx_closesActiveTxCursor () {
426472 final Box <TestEntity > box = getTestEntityBox ();
427473 store .runInReadTx (box ::count ); // Call Box API that creates a reader/activeTxCursor
428474 // Verify that box does not hang on to the read-only TX: if it would, count() would re-use the cursor/tx from
429475 // above and not see the put object.
430476 putTestEntityAndExpectCount (1 );
477+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
431478
432479 // Verify the same in case the runnable throws
433480 assertThrows (IllegalStateException .class , () -> store .runInReadTx (() -> {
434481 box .count ();
435482 throw new IllegalStateException ("Throw in transaction" );
436483 }));
437484 putTestEntityAndExpectCount (2 );
485+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
438486 }
439487
440488 @ Test
@@ -444,13 +492,15 @@ public void testCallInReadTx_closesActiveTxCursor() {
444492 // Verify that box does not hang on to the read-only TX: if it would, count() would re-use the cursor/tx from
445493 // above and not see the put object.
446494 putTestEntityAndExpectCount (1 );
495+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
447496
448497 // Verify the same in case the callable throws
449498 assertThrows (IllegalStateException .class , () -> store .callInReadTx (() -> {
450499 box .count ();
451500 throw new IllegalStateException ("Throw in transaction" );
452501 }));
453502 putTestEntityAndExpectCount (2 );
503+ assertFalse (box .hasActiveTxCursorForCurrentThread ());
454504 }
455505
456506 private void putTestEntityAndExpectCount (int expectedCount ) {
0 commit comments