@After
 public void tearDown() {
   System.out.println("Stm.GlobalConflictCount: " + stm.getGlobalConflictCounter().count());
   for (GammaTxnLong ref : refs) {
     System.out.println(ref.toDebugString());
   }
 }
  @Test
  public void whenReadLockAcquiredByOther_thenIncrementSucceedsButCommitFails() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn otherTx = transactionFactory.newTxn();
    ref.getLock().acquire(otherTx, LockMode.Read);

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);

    ref.increment(5);

    try {
      tx.commit();
      fail();
    } catch (ReadWriteConflict expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
    assertRefHasReadLock(ref, otherTx);
    assertReadLockCount(ref, 1);
  }
    public void doRun() {
      GammaTxnLong ref = new GammaTxnLong(stm);

      // FatArrayTreeGammaTxn tx = new FatArrayTreeGammaTxn(stm);
      // FatArrayGammaTxn tx = new FatArrayGammaTxn(stm,1);
      FatMonoGammaTxn tx =
          new FatMonoGammaTxn(
              new GammaTxnConfig(stm)
                  .setReadLockMode(LockMode.Exclusive)
                  .setDirtyCheckEnabled(false));
      long startMs = System.currentTimeMillis();
      for (long k = 0; k < transactionCount; k++) {
        ref.openForWrite(tx, LOCKMODE_EXCLUSIVE).long_value++;
        tx.commit();
        tx.hardReset();

        // if (k % 100000000 == 0 && k > 0) {
        //    System.out.printf("%s is at %s\n", getName(), k);
        // }
      }

      assertEquals(transactionCount, ref.atomicGet());

      durationMs = System.currentTimeMillis() - startMs;
      System.out.printf("Multiverse> %s is finished in %s ms\n", getName(), durationMs);
    }
  @Test
  public void whenFound() {
    GammaTxnLong ref = new GammaTxnLong(stm);

    GammaTxn tx = newTransaction();
    Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE);

    Tranlocal found = tx.locate(ref);
    assertSame(tranlocal, found);
    assertIsActive(tx);
  }
  @Test
  public void whenNotFound() {
    GammaTxnLong ref = new GammaTxnLong(stm);
    GammaTxnLong otherRef = new GammaTxnLong(stm);

    GammaTxn tx = newTransaction();
    ref.openForRead(tx, LOCKMODE_NONE);

    Tranlocal found = tx.locate(otherRef);
    assertNull(found);
    assertIsActive(tx);
  }
  @Test
  public void whenNoTransaction_thenTxnMandatoryException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    try {
      ref.increment(5);
      fail();
    } catch (TxnMandatoryException expected) {
    }

    assertVersionAndValue(ref, initialVersion, initialValue);
  }
  @Test
  public void whenSuccess() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);

    ref.increment(5);

    tx.commit();

    assertIsCommitted(tx);
    assertVersionAndValue(ref, initialVersion + 1, initialValue + 5);
  }
  @Test
  public void whenPreparedTransactionFound_thenPreparedTxnException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);
    tx.prepare();

    try {
      ref.increment(5);
      fail();
    } catch (PreparedTxnException expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
  }
  @Test
  public void whenListenersAvailable() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    long amount = 4;
    TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount);
    thread.start();

    sleepMs(500);

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);
    ref.increment(amount);
    tx.commit();

    joinAll(thread);

    assertVersionAndValue(ref, initialVersion + 1, initialValue + amount);
  }
  @Test
  public void whenReadonlyTransaction_thenReadonlyException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx =
        stm.newTxnFactoryBuilder()
            .setReadonly(true)
            .setSpeculative(false)
            .newTransactionFactory()
            .newTxn();
    setThreadLocalTxn(tx);

    try {
      ref.increment(5);
      fail();
    } catch (ReadonlyException expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
  }
  @Test
  public void test() {
    final GammaTxnLong ref = new GammaTxnLong(stm);

    WaitThread t = new WaitThread(ref);
    t.start();

    sleepMs(1000);
    assertAlive(t);

    stm.getDefaultTxnExecutor()
        .execute(
            new TxnVoidCallable() {
              @Override
              public void call(Txn tx) throws Exception {
                GammaTxn btx = (GammaTxn) tx;
                Tranlocal write = ref.openForWrite(btx, LOCKMODE_NONE);
                write.long_value = 1;
              }
            });

    joinAll(t);
    assertEquals(2, ref.atomicGet());
  }