@Test
  public void testConcurrentConflictMaxRetryCount() throws Exception {
    dropTable(new String[]{"target"});
    driver2 = Mockito.spy(driver2);
    driver2.getConf().setBoolVar(HiveConf.ConfVars.TXN_WRITE_X_LOCK, true);

    final int maxRetries = 4;
    driver2.getConf().setIntVar(HiveConf.ConfVars.HIVE_TXN_MAX_RETRYSNAPSHOT_COUNT, maxRetries);

    driver.run("create table target(i int) stored as orc tblproperties ('transactional'='true')");
    driver.run("insert into target values (1),(1)");

    DbTxnManager txnMgr2 = (DbTxnManager) TxnManagerFactory.getTxnManagerFactory().getTxnManager(conf);
    swapTxnManager(txnMgr2);

    // This run should conflict with the above query and cause the "conflict lambda" to be execute,
    // which will then also conflict with the driver2 query and cause it to retry. The intent here is
    // to cause driver2's query to exceed HIVE_TXN_MAX_RETRYSNAPSHOT_COUNT and throw exception.
    AtomicInteger lockAndRespondCount = new AtomicInteger();
    Mockito.doAnswer((invocation) -> {
      lockAndRespondCount.getAndIncrement();
      // we want to make sure the transaction gets conflicted until it fails.
      // +1 is for the initial lockAndRespond after compilation
      if (lockAndRespondCount.get() <= 1 + maxRetries) {
        swapTxnManager(txnMgr);
        try {
          // this should call a conflict with the current query being ran by driver2
          driver.run("update target set i = 1 where i = 1");
        } catch (Exception e) {
          // do nothing
        }
        swapTxnManager(txnMgr2);
      }
      invocation.callRealMethod();
      return null;
    }).when(driver2).lockAndRespond();

    boolean exceptionThrown = false;
    // Start a query on driver2, we expect this query to never execute because the nature of the test it to conflict
    // until HIVE_TXN_MAX_RETRYSNAPSHOT_COUNT is exceeded.
    // We verify that it is never executed by counting the number of rows returned that have i = 1.
    try {
      driver2.run("update target set i = 2 where i = 1");
    } catch (CommandProcessorException cpe) {
      exceptionThrown = true;
      Assert.assertTrue(
          cpe.getMessage().contains("Operation could not be executed, snapshot was outdated when locks were acquired.")
      );
    }
    Assert.assertTrue(exceptionThrown);
    // +1 for the inital lockAndRespond after compilation, another +1 for the lockAndRespond that caused us
    // to exceed max retries.
    Assert.assertEquals(maxRetries+2, lockAndRespondCount.get());
    swapTxnManager(txnMgr);

    // we expect two rows
    driver.run("select * from target where i = 1");
    List<String> res = new ArrayList<>();
    driver.getFetchTask().fetch(res);
    Assert.assertEquals(2, res.size());
  }
run a merge statement using un-partitioned target table and a concurrent op on the target
Check that proper locks are acquired and Write conflict detection works and the state
of internal table.
@param causeConflict true to make 2 operations such that they update the same entity
ql/src/test/org/apache/hadoop/hive/ql/lockmgr/TestDbTxnManager2.java