use of org.corfudb.protocols.wireprotocol.ReadResponse in project CorfuDB by CorfuDB.
the class QuorumReplicationProtocol method peek.
/** {@inheritDoc} */
@Override
public ILogData peek(Layout layout, long address) {
int numUnits = layout.getSegmentLength(address);
log.trace("Peek[{}]: quorum {}/{}", address, numUnits, numUnits);
try {
ReadResponse readResponse = null;
try {
CompletableFuture<ReadResponse>[] futures = new CompletableFuture[numUnits];
for (int i = 0; i < numUnits; i++) {
futures[i] = layout.getLogUnitClient(address, i).read(address);
}
QuorumFuturesFactory.CompositeFuture<ReadResponse> future = QuorumFuturesFactory.getQuorumFuture(new ReadResponseComparator(address), futures);
readResponse = CFUtils.getUninterruptibly(future, QuorumUnreachableException.class);
} catch (QuorumUnreachableException e) {
e.printStackTrace();
log.debug(e.getMessage(), e);
return null;
}
if (readResponse != null) {
LogData result = readResponse.getReadSet().get(address);
if (result != null && !isEmptyType(result.getType())) {
return result;
}
}
return null;
} catch (RuntimeException e) {
throw e;
}
}
use of org.corfudb.protocols.wireprotocol.ReadResponse in project CorfuDB by CorfuDB.
the class QuorumReplicationProtocol method recoveryWrite.
private boolean recoveryWrite(Layout layout, ILogData logData) {
long address = logData.getGlobalAddress();
log.debug("Recovery write at {} " + address);
Holder<ILogData> dh = new Holder<>(logData);
AtomicBoolean otherValueAdopted = new AtomicBoolean(false);
AtomicInteger retryCount = new AtomicInteger(0);
if (logData.getRank() == null) {
logData.setRank(new IMetadata.DataRank(0));
}
try {
IRetry.build(ExponentialBackoffRetry.class, () -> {
QuorumFuturesFactory.CompositeFuture<Boolean> future = null;
try {
log.debug("Recovery write loop for " + log);
// increment the rank
dh.getRef().releaseBuffer();
dh.getRef().setRank(dh.getRef().getRank().buildHigherRank());
// peek for existing
if (retryCount.getAndIncrement() > 0) {
try {
return holeFillPolicy.peekUntilHoleFillRequired(address, a -> peek(layout, a));
} catch (HoleFillRequiredException e) {
log.debug(e.getMessage(), e);
// continuing
}
}
// phase 1
try (ILogData.SerializationHandle ph1 = createEmptyData(dh.getRef().getGlobalAddress(), DataType.RANK_ONLY, dh.getRef().getRank())) {
future = getWriteFuture(layout, ph1.getSerialized());
CFUtils.getUninterruptibly(future, QuorumUnreachableException.class, OverwriteException.class, DataOutrankedException.class);
} catch (LogUnitException | QuorumUnreachableException e) {
e.printStackTrace();
ReadResponse rr = getAdoptedValueWithHighestRankIfPresent(address, future.getThrowables());
if (rr != null) {
// check
LogData logDataExisting = rr.getReadSet().get(address);
logDataExisting.releaseBuffer();
logDataExisting.setRank(dh.getRef().getRank());
dh.setRef(logDataExisting.getSerializedForm().getSerialized());
otherValueAdopted.set(true);
// value adopted - continue on phase 2
} else {
throw e;
}
}
// phase 2 - only if exception is not thrown from phase 1
future = getWriteFuture(layout, dh.getRef());
CFUtils.getUninterruptibly(future, QuorumUnreachableException.class, OverwriteException.class, DataOutrankedException.class);
log.trace("Write done[{}]: {}", address);
return dh.getRef();
} catch (QuorumUnreachableException | DataOutrankedException e) {
e.printStackTrace();
throw new RetryNeededException();
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
}).setOptions(WRITE_RETRY_SETTINGS).run();
return otherValueAdopted.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("interrupted", e);
} catch (RuntimeException e) {
throw e;
}
}
use of org.corfudb.protocols.wireprotocol.ReadResponse in project CorfuDB by CorfuDB.
the class LogUnitClientTest method valueCanBeAdopted.
@Test
public void valueCanBeAdopted() throws ExecutionException, InterruptedException {
byte[] testString = "hello world".getBytes();
client.write(0, Collections.<UUID>emptySet(), new IMetadata.DataRank(1), testString, Collections.emptyMap()).get();
LogData r = client.read(0).get().getReadSet().get(0L);
assertThat(r.getType()).isEqualTo(DataType.DATA);
assertThat(r.getPayload(new CorfuRuntime())).isEqualTo(testString);
try {
ILogData data = createEmptyData(0, DataType.RANK_ONLY, new IMetadata.DataRank(2)).getSerialized();
client.write(data).get();
fail();
} catch (Exception e) {
// expected
assertEquals(ValueAdoptedException.class, e.getCause().getClass());
ValueAdoptedException ex = (ValueAdoptedException) e.getCause();
ReadResponse read = ex.getReadResponse();
LogData log = read.getReadSet().get(0l);
assertThat(log.getType()).isEqualTo(DataType.DATA);
assertThat(log.getPayload(new CorfuRuntime())).isEqualTo(testString);
;
}
r = client.read(0).get().getReadSet().get(0L);
assertThat(r.getType()).isEqualTo(DataType.DATA);
assertThat(r.getPayload(new CorfuRuntime())).isEqualTo(testString);
}
use of org.corfudb.protocols.wireprotocol.ReadResponse in project CorfuDB by CorfuDB.
the class QuorumReplicationProtocol method getAdoptedValueWithHighestRankIfPresent.
private ReadResponse getAdoptedValueWithHighestRankIfPresent(Long position, Set<Throwable> throwables) {
ReadResponse result = null;
IMetadata.DataRank maxRank = null;
for (Throwable t : throwables) {
if (t instanceof ValueAdoptedException) {
ValueAdoptedException ve = (ValueAdoptedException) t;
ReadResponse r = ve.getReadResponse();
LogData ld = r.getReadSet().get(position);
if (maxRank == null || maxRank.compareTo(ld.getRank()) < 0) {
maxRank = ld.getRank();
result = r;
}
}
}
return result;
}
use of org.corfudb.protocols.wireprotocol.ReadResponse in project CorfuDB by CorfuDB.
the class StreamLogWithRankedAddressSpace method assertAppendPermittedUnsafe.
/**
* Check whether the data can be appended to a given log address.
* Note that it is not permitted multiple threads to access the same log address
* concurrently through this method, this method does not lock or synchronize.
* This method needs
* @param address
* @param newEntry
* @throws DataOutrankedException if the log entry cannot be assigned to this log address as there is a data with higher rank
* @throws ValueAdoptedException if the new message is a proposal during the two phase recovery write and there is an existing
* data at this log address already.
* @throw OverwriteException if the new data is with rank 0 (not from recovery write). This can happen only if there is a bug in the client implementation.
*/
default default void assertAppendPermittedUnsafe(long address, LogData newEntry) throws DataOutrankedException, ValueAdoptedException {
LogData oldEntry = read(address);
if (oldEntry.getType() == DataType.EMPTY) {
return;
}
if (newEntry.getRank().getRank() == 0) {
// data consistency in danger
throw new OverwriteException();
}
int compare = newEntry.getRank().compareTo(oldEntry.getRank());
if (compare < 0) {
throw new DataOutrankedException();
}
if (compare > 0) {
if (newEntry.getType() == DataType.RANK_ONLY && oldEntry.getType() != DataType.RANK_ONLY) {
// the new data is a proposal, the other data is not, so the old value should be adopted
ReadResponse resp = new ReadResponse();
resp.put(address, oldEntry);
throw new ValueAdoptedException(resp);
} else {
return;
}
}
}
Aggregations