use of org.apache.ratis.client.RaftClientRpc in project incubator-ratis by apache.
the class RaftReconfigurationBaseTest method testOverlappedSetConfRequests.
/**
* Make sure a setConfiguration request is rejected if a configuration change
* is still in progress (i.e., has not been committed yet).
*/
@Test
public void testOverlappedSetConfRequests() throws Exception {
LOG.info("Start testOverlappedSetConfRequests");
// originally 3 peers
final MiniRaftCluster cluster = getCluster(3);
try {
cluster.start();
RaftTestUtil.waitForLeader(cluster);
final RaftPeerId leaderId = cluster.getLeader().getId();
RaftPeer[] newPeers = cluster.addNewPeers(2, true).allPeersInNewConf;
// delay every peer's logSync so that the setConf request is delayed
cluster.getPeers().forEach(peer -> logSyncDelay.setDelayMs(peer.getId().toString(), 1000));
final CountDownLatch latch = new CountDownLatch(1);
final RaftPeer[] peersInRequest2 = cluster.getPeers().toArray(new RaftPeer[0]);
AtomicBoolean caughtException = new AtomicBoolean(false);
new Thread(() -> {
try (final RaftClient client2 = cluster.createClient(leaderId)) {
latch.await();
LOG.info("client2 starts to change conf");
final RaftClientRpc sender2 = client2.getClientRpc();
sender2.sendRequest(cluster.newSetConfigurationRequest(client2.getId(), leaderId, peersInRequest2));
} catch (ReconfigurationInProgressException e) {
caughtException.set(true);
} catch (Exception e) {
LOG.warn("Got unexpected exception when client2 changes conf", e);
}
}).start();
AtomicBoolean confChanged = new AtomicBoolean(false);
new Thread(() -> {
try (final RaftClient client1 = cluster.createClient(leaderId)) {
LOG.info("client1 starts to change conf");
confChanged.set(client1.setConfiguration(newPeers).isSuccess());
} catch (IOException e) {
LOG.warn("Got unexpected exception when client1 changes conf", e);
}
}).start();
Thread.sleep(100);
latch.countDown();
for (int i = 0; i < 10 && !confChanged.get(); i++) {
Thread.sleep(1000);
}
Assert.assertTrue(confChanged.get());
Assert.assertTrue(caughtException.get());
} finally {
logSyncDelay.clear();
cluster.shutdown();
}
}
use of org.apache.ratis.client.RaftClientRpc in project incubator-ratis by apache.
the class RaftReconfigurationBaseTest method testRevertConfigurationChange.
/**
* Test a scenario where the follower truncates its log entries which causes
* configuration change.
*/
@Test
public void testRevertConfigurationChange() throws Exception {
LOG.info("Start testRevertConfigurationChange");
RaftLog log2 = null;
final MiniRaftCluster cluster = getCluster(5);
try {
cluster.start();
RaftTestUtil.waitForLeader(cluster);
final RaftServerImpl leader = cluster.getLeader();
final RaftPeerId leaderId = leader.getId();
final RaftLog log = leader.getState().getLog();
log2 = log;
Thread.sleep(1000);
// we block the incoming msg for the leader and block its requests to
// followers, so that we force the leader change and the old leader will
// not know
LOG.info("start blocking the leader");
BlockRequestHandlingInjection.getInstance().blockReplier(leaderId.toString());
cluster.setBlockRequestsFrom(leaderId.toString(), true);
PeerChanges change = cluster.removePeers(1, false, new ArrayList<>());
AtomicBoolean gotNotLeader = new AtomicBoolean(false);
final Thread clientThread = new Thread(() -> {
try (final RaftClient client = cluster.createClient(leaderId)) {
LOG.info("client starts to change conf");
final RaftClientRpc sender = client.getClientRpc();
RaftClientReply reply = sender.sendRequest(cluster.newSetConfigurationRequest(client.getId(), leaderId, change.allPeersInNewConf));
if (reply.getNotLeaderException() != null) {
gotNotLeader.set(true);
}
} catch (IOException e) {
LOG.warn("Got unexpected exception when client1 changes conf", e);
}
});
clientThread.start();
// find CONFIGURATIONENTRY, there may be NOOP before and after it.
final long confIndex = JavaUtils.attempt(() -> {
final long last = log.getLastEntryTermIndex().getIndex();
for (long i = 1; i <= last; i++) {
if (log.get(i).getLogEntryBodyCase() == CONFIGURATIONENTRY) {
return i;
}
}
throw new Exception("CONFIGURATIONENTRY not found: last=" + last);
}, 10, 500, "confIndex", LOG);
// wait till the old leader persist the new conf
JavaUtils.attempt(() -> log.getLatestFlushedIndex() >= confIndex, 10, 500L, "FLUSH", LOG);
final long committed = log.getLastCommittedIndex();
Assert.assertTrue(committed < confIndex);
// unblock the old leader
BlockRequestHandlingInjection.getInstance().unblockReplier(leaderId.toString());
cluster.setBlockRequestsFrom(leaderId.toString(), false);
// the client should get NotLeaderException
clientThread.join(5000);
Assert.assertTrue(gotNotLeader.get());
// the old leader should have truncated the setConf from the log
JavaUtils.attempt(() -> log.getLastCommittedIndex() >= confIndex, 10, 500L, "COMMIT", LOG);
Assert.assertEquals(NOOP, log.get(confIndex).getLogEntryBodyCase());
log2 = null;
} finally {
RaftStorageTestUtils.printLog(log2, s -> LOG.info(s));
cluster.shutdown();
}
}
use of org.apache.ratis.client.RaftClientRpc in project incubator-ratis by apache.
the class RaftExceptionBaseTest method testHandleNotLeaderException.
private void testHandleNotLeaderException(boolean killNewLeader) throws Exception {
RaftTestUtil.waitForLeader(cluster);
final RaftPeerId leaderId = cluster.getLeader().getId();
final RaftClient client = cluster.createClient(leaderId);
RaftClientReply reply = client.send(new SimpleMessage("m1"));
Assert.assertTrue(reply.isSuccess());
// enforce leader change
RaftPeerId newLeader = RaftTestUtil.changeLeader(cluster, leaderId);
if (killNewLeader) {
// kill the new leader
cluster.killServer(newLeader);
}
RaftClientRpc rpc = client.getClientRpc();
reply = null;
for (int i = 0; reply == null && i < 10; i++) {
try {
reply = rpc.sendRequest(cluster.newRaftClientRequest(ClientId.randomId(), leaderId, new SimpleMessage("m2")));
} catch (IOException ignored) {
Thread.sleep(1000);
}
}
Assert.assertNotNull(reply);
Assert.assertFalse(reply.isSuccess());
final NotLeaderException nle = reply.getNotLeaderException();
Objects.requireNonNull(nle);
Assert.assertEquals(newLeader, nle.getSuggestedLeader().getId());
reply = client.send(new SimpleMessage("m3"));
Assert.assertTrue(reply.isSuccess());
client.close();
}
use of org.apache.ratis.client.RaftClientRpc in project incubator-ratis by apache.
the class RaftReconfigurationBaseTest method testLeaderNotReadyException.
/**
* Delay the commit of the leader placeholder log entry and see if the client
* can correctly receive and handle the LeaderNotReadyException.
*/
@Test
public void testLeaderNotReadyException() throws Exception {
LOG.info("Start testLeaderNotReadyException");
final MiniRaftCluster cluster = getCluster(1).initServers();
final RaftPeerId leaderId = cluster.getPeers().iterator().next().getId();
try {
// delay 1s for each logSync call
cluster.getPeers().forEach(peer -> leaderPlaceHolderDelay.setDelayMs(peer.getId().toString(), 2000));
cluster.start();
AtomicBoolean caughtNotReady = new AtomicBoolean(false);
AtomicBoolean success = new AtomicBoolean(false);
new Thread(() -> {
final RaftClient client = cluster.createClient(leaderId);
final RaftClientRpc sender = client.getClientRpc();
final RaftClientRequest request = cluster.newRaftClientRequest(client.getId(), leaderId, new SimpleMessage("test"));
while (!success.get()) {
try {
RaftClientReply reply = sender.sendRequest(request);
success.set(reply.isSuccess());
} catch (LeaderNotReadyException e) {
LOG.info("Hit LeaderNotReadyException", e);
caughtNotReady.set(true);
} catch (IOException e) {
LOG.info("Hit other IOException", e);
}
if (!success.get()) {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
}
}
}).start();
RaftTestUtil.waitForLeader(cluster);
for (int i = 0; !success.get() && i < 5; i++) {
Thread.sleep(1000);
}
Assert.assertTrue(success.get());
Assert.assertTrue(caughtNotReady.get());
} finally {
leaderPlaceHolderDelay.clear();
cluster.shutdown();
}
}
use of org.apache.ratis.client.RaftClientRpc in project incubator-ratis by apache.
the class RaftReconfigurationBaseTest method testReconfTimeout.
@Test
public void testReconfTimeout() throws Exception {
LOG.info("Start testReconfTimeout");
// originally 3 peers
final MiniRaftCluster cluster = getCluster(3);
cluster.start();
try {
RaftTestUtil.waitForLeader(cluster);
final RaftPeerId leaderId = cluster.getLeader().getId();
final RaftClient client = cluster.createClient(leaderId);
PeerChanges c1 = cluster.addNewPeers(2, false);
LOG.info("Start changing the configuration: {}", asList(c1.allPeersInNewConf));
Assert.assertFalse(cluster.getLeader().getRaftConf().isTransitional());
final RaftClientRpc sender = client.getClientRpc();
final SetConfigurationRequest request = cluster.newSetConfigurationRequest(client.getId(), leaderId, c1.allPeersInNewConf);
try {
sender.sendRequest(request);
Assert.fail("did not get expected exception");
} catch (IOException e) {
Assert.assertTrue("Got exception " + e, e instanceof ReconfigurationTimeoutException);
}
// the two new peers have not started yet, the bootstrapping must timeout
LOG.info(cluster.printServers());
// state so that we still get timeout instead of in-progress exception
try {
sender.sendRequest(request);
Assert.fail("did not get expected exception");
} catch (IOException e) {
Assert.assertTrue("Got exception " + e, e instanceof ReconfigurationTimeoutException);
}
// start the two new peers
LOG.info("Start new peers");
for (RaftPeer np : c1.newPeers) {
cluster.startServer(np.getId());
}
Assert.assertTrue(client.setConfiguration(c1.allPeersInNewConf).isSuccess());
client.close();
} finally {
cluster.shutdown();
}
}
Aggregations