@Override
    protected void preLogCommitHook() {
      super.preLogCommitHook();
      RepNode rmMasterNode = repEnvInfo[0].getRepNode();
      int size = rmMasterNode.getGroup().getAllElectableMembers().size();
      int delNodes = ((size & 1) == 1) ? 2 : 1;
      int closeNodeIndex = (size - delNodes) - 1;

      /*
       * The loop below simulates the concurrent removal of a node while
       * a transaction is in progress. It deletes a sufficient number of
       * nodes so as to get a lower simple nodes to get to a new lower
       * simple majority.
       */
      for (int i = repEnvInfo.length - 1; delNodes-- > 0; i--) {
        repEnvInfo[i].closeEnv();
        rmMasterNode.removeMember(repEnvInfo[i].getRepConfig().getNodeName(), delete);
      }

      /*
       * Shut down an additional undeleted Replica to provoke a
       * lack of acks based on the old simple majority.
       */
      repEnvInfo[closeNodeIndex].closeEnv();
    }
  private void testMemberRemoveAckInteraction(final boolean delete) {
    createGroup(groupSize);
    Transaction txn;
    Database db;
    try {
      MasterTxn.setFactory(new TxnFactory(delete));
      ReplicatedEnvironment master = repEnvInfo[0].getEnv();

      txn = master.beginTransaction(null, null);
      /* Write to the environment. */
      db = master.openDatabase(txn, "random", dbconfig);
      db.close();
      txn.commit();
    } catch (InsufficientAcksException e) {
      fail("No exception expected.");
    } finally {
      MasterTxn.setFactory(null);
    }
  }
  /**
   * Test that a timeout in the feeder while attempting to read the group database because other
   * feeders have it write locked causes the feeder (and replica) to fail, but allows the master to
   * continue operating. [#23822]
   */
  @Test
  public void testJoinGroupReadGroupTimeout() throws DatabaseException, InterruptedException {

    /* Start first node as master */
    ReplicatedEnvironment repEnv = repEnvInfo[0].openEnv();
    assertEquals("Master node state", State.MASTER, repEnv.getState());

    RepImpl repImpl = RepInternal.getRepImpl(repEnv);

    for (int i = 1; i <= 2; i++) {

      /* Get a write lock on the RepGroupDB */
      final MasterTxn txn =
          new MasterTxn(
              repImpl,
              new TransactionConfig()
                  .setDurability(
                      new Durability(
                          SyncPolicy.SYNC, SyncPolicy.SYNC, ReplicaAckPolicy.SIMPLE_MAJORITY)),
              repImpl.getNameIdPair());
      final DatabaseImpl groupDbImpl = repImpl.getGroupDb();
      final DatabaseEntry value = new DatabaseEntry();
      final Cursor cursor = DbInternal.makeCursor(groupDbImpl, txn, new CursorConfig());
      final OperationStatus status = cursor.getNext(RepGroupDB.groupKeyEntry, value, LockMode.RMW);
      assertEquals(i + ": Lock group result", OperationStatus.SUCCESS, status);

      /* Wait longer than the default 500 ms read timeout */
      Thread.sleep(600);

      /* Test both electable and secondary nodes */
      if (i == 2) {
        repEnvInfo[i].getRepConfig().setNodeType(NodeType.SECONDARY);
      }

      /* Create a thread that attempts to join another environment */
      RepNodeThread repNodeThread = new RepNodeThread(i, i != 1);
      repNodeThread.start();

      /* Wait for attempt to complete */
      repNodeThread.join(30000);
      assertEquals("RN thread alive", false, repNodeThread.isAlive());

      if (i == 1) {

        /* Join attempt should fail for primary */
        assertNotNull("Expected RN thread exception", repNodeThread.te);

        /* Release write lock on RepGroupDB */
        cursor.close();
        txn.abort();

        /* Second join attempt should succeed */
        repNodeThread = new RepNodeThread(1);
        repNodeThread.start();
        repNodeThread.join(30000);
        assertEquals("RN thread alive", false, repNodeThread.isAlive());
        assertEquals("RN thread exception", null, repNodeThread.te);
      } else {

        /* Join attempt should succeed for secondary */
        assertEquals("RN thread exception", null, repNodeThread.te);

        /* Release write lock on RepGroupDB */
        cursor.close();
        txn.abort();
      }
    }
  }