package org.corfudb.runtime.view.replication; import org.corfudb.infrastructure.TestLayoutBuilder; import org.corfudb.protocols.wireprotocol.ILogData; import org.corfudb.protocols.wireprotocol.LogData; import org.corfudb.runtime.CorfuRuntime; import org.corfudb.runtime.clients.LogUnitClient; import org.corfudb.runtime.exceptions.OverwriteException; import org.corfudb.runtime.view.Layout; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** Test the chain replication protocol. * * Created by mwei on 4/11/17. */ public class ChainReplicationProtocolTest extends AbstractReplicationProtocolTest { /** {@inheritDoc} */ @Override IReplicationProtocol getProtocol() { return new ChainReplicationProtocol(new AlwaysHoleFillPolicy()); } /** {@inheritDoc} */ @Override void setupNodes() { addServer(SERVERS.PORT_0); addServer(SERVERS.PORT_1); addServer(SERVERS.PORT_2); bootstrapAllServers(new TestLayoutBuilder() .addLayoutServer(SERVERS.PORT_0) .addSequencer(SERVERS.PORT_0) .buildSegment() .setReplicationMode(Layout.ReplicationMode.CHAIN_REPLICATION) .buildStripe() .addLogUnit(SERVERS.PORT_0) .addLogUnit(SERVERS.PORT_1) .addLogUnit(SERVERS.PORT_2) .addToSegment() .addToLayout() .build()); } /** Check to see that a writer correctly * completes a failed write from another client. */ @Test public void failedWriteIsPropagated() throws Exception { setupNodes(); //begin tests final CorfuRuntime r = getDefaultRuntime(); final IReplicationProtocol rp = getProtocol(); final Layout layout = r.getLayoutView().getLayout(); LogData failedWrite = getLogData(0, "failed".getBytes()); LogData incompleteWrite = getLogData(0, "incomplete".getBytes()); // Write the incomplete write to the head of the chain r.getRouter(SERVERS.ENDPOINT_0).getClient(LogUnitClient.class) .write(incompleteWrite); // Attempt to write using the replication protocol. // Should result in an overwrite exception assertThatThrownBy(() -> rp.write(layout, failedWrite)) .isInstanceOf(OverwriteException.class); // At this point, a direct read of the tail should // reflect the -other- clients value ILogData readResult = r.getRouter(SERVERS.ENDPOINT_0).getClient(LogUnitClient.class) .read(0).get().getReadSet().get(0L); assertThat(readResult.getPayload(r)) .isEqualTo("incomplete".getBytes()); } /** Check to see that a read correctly * completes a failed write from another client. */ @Test public void failedWriteCanBeRead() throws Exception { setupNodes(); //begin tests final CorfuRuntime r = getDefaultRuntime(); final IReplicationProtocol rp = getProtocol(); final Layout layout = r.getLayoutView().getLayout(); LogData incompleteWrite = getLogData(0, "incomplete".getBytes()); // Write the incomplete write to the head of the chain r.getRouter(SERVERS.ENDPOINT_0).getClient(LogUnitClient.class) .write(incompleteWrite); // At this point, a read // reflect the -other- clients value ILogData readResult = rp.read(layout, 0); assertThat(readResult.getPayload(r)) .isEqualTo("incomplete".getBytes()); } }