use of org.corfudb.runtime.view.Layout in project CorfuDB by CorfuDB.
the class ChainReplicationProtocolTest method failedWriteCanBeRead.
/** 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());
}
use of org.corfudb.runtime.view.Layout in project CorfuDB by CorfuDB.
the class FailureHandlerDispatcher method dispatchHandler.
/**
* Takes in the existing layout and a set of failed nodes.
* It first generates a new layout by removing the failed nodes from the existing layout.
* It then seals the epoch to prevent any client from accessing the stale layout.
* Finally we run paxos to update all servers with the new layout.
*
* @param currentLayout The current layout
* @param corfuRuntime Connected corfu runtime instance
* @param failedServers Set of failed server addresses
*/
public void dispatchHandler(IFailureHandlerPolicy failureHandlerPolicy, Layout currentLayout, CorfuRuntime corfuRuntime, Set<String> failedServers) {
try {
// Generates a new layout by removing the failed nodes from the existing layout
Layout newLayout = failureHandlerPolicy.generateLayout(currentLayout, corfuRuntime, failedServers);
// Seals and increments the epoch.
currentLayout.setRuntime(corfuRuntime);
sealEpoch(currentLayout);
// Reconfigure servers if required
reconfigureServers(corfuRuntime, currentLayout, newLayout, false);
// Attempts to update all the layout servers with the modified layout.
try {
corfuRuntime.getLayoutView().updateLayout(newLayout, prepareRank);
prepareRank++;
} catch (OutrankedException oe) {
// Update rank since outranked.
log.error("Conflict in updating layout by failureHandlerDispatcher: {}", oe);
// Update rank to be able to outrank other competition and complete paxos.
prepareRank = oe.getNewRank() + 1;
}
// Check if our proposed layout got selected and committed.
corfuRuntime.invalidateLayout();
if (corfuRuntime.getLayoutView().getLayout().equals(newLayout)) {
log.info("Failed node removed. New Layout committed = {}", newLayout);
}
} catch (Exception e) {
log.error("Error: dispatchHandler: {}", e);
}
}
use of org.corfudb.runtime.view.Layout in project CorfuDB by CorfuDB.
the class LayoutServer method handleMessageLayoutPrepare.
/**
* Accepts a prepare message if the rank is higher than any accepted so far.
* @param msg
* @param ctx
* @param r
*/
// TODO this can work under a separate lock for this step as it does not change the global components
@ServerHandler(type = CorfuMsgType.LAYOUT_PREPARE, opTimer = metricsPrefix + "prepare")
public synchronized void handleMessageLayoutPrepare(CorfuPayloadMsg<LayoutPrepareRequest> msg, ChannelHandlerContext ctx, IServerRouter r, boolean isMetricsEnabled) {
// Check if the prepare is for the correct epoch
if (!checkBootstrap(msg, ctx, r)) {
return;
}
Rank prepareRank = new Rank(msg.getPayload().getRank(), msg.getClientID());
Rank phase1Rank = getPhase1Rank();
Layout proposedLayout = getProposedLayout();
long serverEpoch = getServerEpoch();
if (msg.getPayload().getEpoch() != serverEpoch) {
r.sendResponse(ctx, msg, new CorfuPayloadMsg<>(CorfuMsgType.WRONG_EPOCH, serverEpoch));
log.trace("Incoming message with wrong epoch, got {}, expected {}, message was: {}", msg.getPayload().getEpoch(), serverEpoch, msg);
return;
}
// This is a prepare. If the rank is less than or equal to the phase 1 rank, reject.
if (phase1Rank != null && prepareRank.lessThanEqualTo(phase1Rank)) {
log.debug("Rejected phase 1 prepare of rank={}, phase1Rank={}", prepareRank, phase1Rank);
r.sendResponse(ctx, msg, CorfuMsgType.LAYOUT_PREPARE_REJECT.payloadMsg(new LayoutPrepareResponse(phase1Rank.getRank(), proposedLayout)));
} else {
setPhase1Rank(prepareRank);
log.debug("New phase 1 rank={}", getPhase1Rank());
r.sendResponse(ctx, msg, CorfuMsgType.LAYOUT_PREPARE_ACK.payloadMsg(new LayoutPrepareResponse(prepareRank.getRank(), proposedLayout)));
}
}
use of org.corfudb.runtime.view.Layout in project CorfuDB by CorfuDB.
the class CorfuRuntime method fetchLayout.
/**
* Return a completable future which is guaranteed to contain a layout.
* This future will continue retrying until it gets a layout. If you need this completable future to fail,
* you should chain it with a timeout.
*
* @return A completable future containing a layout.
*/
private CompletableFuture<Layout> fetchLayout() {
return CompletableFuture.<Layout>supplyAsync(() -> {
while (true) {
List<String> layoutServersCopy = layoutServers.stream().collect(Collectors.toList());
Collections.shuffle(layoutServersCopy);
// Iterate through the layout servers, attempting to connect to one
for (String s : layoutServersCopy) {
log.debug("Trying connection to layout server {}", s);
try {
IClientRouter router = getRouter(s);
// Try to get a layout.
CompletableFuture<Layout> layoutFuture = router.getClient(LayoutClient.class).getLayout();
// Wait for layout
Layout l = layoutFuture.get();
l.setRuntime(this);
// this.layout should only be assigned to the new layout future once it has been
// completely constructed and initialized. For example, assigning this.layout = l
// before setting the layout's runtime can result in other threads trying to access a layout
// with a null runtime.
//FIXME Synchronization START
// We are updating multiple variables and we need the update to be synchronized across all variables.
// Since the variable layoutServers is used only locally within the class it is acceptable
// (at least the code on 10/13/2016 does not have issues)
// but setEpoch of routers needs to be synchronized as those variables are not local.
l.getAllServers().stream().map(getRouterFunction).forEach(x -> x.setEpoch(l.getEpoch()));
layoutServers = l.getLayoutServers();
layout = layoutFuture;
//FIXME Synchronization END
log.debug("Layout server {} responded with layout {}", s, l);
return l;
} catch (Exception e) {
log.warn("Tried to get layout from {} but failed with exception:", s, e);
}
}
log.warn("Couldn't connect to any layout servers, retrying in {}s.", retryRate);
try {
Thread.sleep(retryRate * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (isShutdown) {
return null;
}
}
});
}
use of org.corfudb.runtime.view.Layout in project CorfuDB by CorfuDB.
the class LayoutClientTest method canGetNewLayoutInDifferentEpoch.
@Test
public void canGetNewLayoutInDifferentEpoch() throws Exception {
Layout l = TestLayoutBuilder.single(SERVERS.PORT_0);
final long NEW_EPOCH = 42L;
l.setEpoch(NEW_EPOCH);
assertThat(client.bootstrapLayout(l).get()).isEqualTo(true);
assertThat(client.getLayout().get().getEpoch()).isEqualTo(NEW_EPOCH);
}
Aggregations