use of org.corfudb.protocols.wireprotocol.ILogData in project CorfuDB by CorfuDB.
the class AbstractContextStreamView method nextUpTo.
/**
* {@inheritDoc}
*/
@Override
public final synchronized ILogData nextUpTo(final long maxGlobal) {
// pointer.
if (getCurrentContext().globalPointer > maxGlobal) {
return null;
}
// Pop the context if it has changed.
if (getCurrentContext().globalPointer >= getCurrentContext().maxGlobalAddress) {
final T last = streamContexts.pollFirst();
log.trace("Completed context {}@{}, removing.", last.id, last.maxGlobalAddress);
}
// Get the next entry from the underlying implementation.
final ILogData entry = getNextEntry(getCurrentContext(), maxGlobal);
if (entry != null) {
// Update the pointer.
updatePointer(entry);
// context.
if (processEntryForContext(entry)) {
return nextUpTo(maxGlobal);
}
}
// Return the entry.
return entry;
}
use of org.corfudb.protocols.wireprotocol.ILogData in project CorfuDB by CorfuDB.
the class AbstractQueuedStreamView method getNextEntry.
/**
* {@inheritDoc}
*/
@Override
protected ILogData getNextEntry(QueuedStreamContext context, long maxGlobal) {
// Return if the queue is still empty.
if (context.readQueue.isEmpty() && context.readCpQueue.isEmpty() && !fillReadQueue(maxGlobal, context)) {
return null;
}
// If checkpoint data is available, get from readCpQueue first
NavigableSet<Long> getFrom;
if (context.readCpQueue.size() > 0) {
getFrom = context.readCpQueue;
if (context.readQueue.isEmpty()) {
// readQueue is empty, readCpQueue is not.
// This is a case where we have had 2 checkpoints
// adjacent to each other, and no non-checkpoint
// entries in the stream in between the checkpoints
// or during the 2nd checkpoint. Processing of
// checkpoint entries will not advance our context
// globalPointer, only regular entries in readQueue.
// However, we know that readQueue is *empty*, so
// we advance globalPointer here.
context.globalPointer = maxGlobal;
}
} else {
getFrom = context.readQueue;
}
// to return.
if (context.readCpQueue.isEmpty() && context.readQueue.first() > maxGlobal) {
return null;
}
// have to perform several reads.
while (getFrom.size() > 0) {
final long thisRead = getFrom.pollFirst();
ILogData ld = read(thisRead);
if (ld.containsStream(context.id)) {
// Only add to resolved if ld is from readQueue
if (getFrom == context.readQueue) {
addToResolvedQueue(context, thisRead, ld);
}
return ld;
}
}
// stream, so we return null.
return null;
}
use of org.corfudb.protocols.wireprotocol.ILogData in project CorfuDB by CorfuDB.
the class BackpointerStreamView method fillReadQueue.
/**
* {@inheritDoc}
*/
@Override
protected boolean fillReadQueue(final long maxGlobal, final QueuedStreamContext context) {
log.trace("Read_Fill_Queue[{}] Max: {}, Current: {}, Resolved: {} - {}", this, maxGlobal, context.globalPointer, context.maxResolution, context.minResolution);
// considerCheckpoint: Use context.globalPointer as a signal of caller's intent:
// if globalPointer == -1, then the caller needs to replay the stream from the
// beginning because the caller has never read anything from the stream before.
// Thus, it could be a significant time & I/O saving for the client to playback
// from the latest checkpoint.
// On the other hand, if not -1, then we assume that the caller has already
// found the stream head and replayed some/all of it.
//
// We assume a "typical" case where the client probably needs to discover & replay
// just a few log entries, whereas the checkpoint data that this method may discover
// may be "huge" ... thus we favor ignoring the checkpoint data. Such an assumption
// may be invalid for very small SMR objects, such as a simple counter, where
// checkpoint size would always be small enough to use checkpoint data instead of
// continuing backward to find individual updates.
boolean considerCheckpoint = context.globalPointer == -1;
// The maximum address we will fill to.
final long maxAddress = Long.min(maxGlobal, context.maxGlobalAddress);
// we return since there is nothing left to do.
if (context.globalPointer > maxAddress) {
return false;
}
// queue, use it
if (context.maxResolution > maxAddress && context.minResolution < context.globalPointer) {
return fillFromResolved(maxGlobal, context);
}
Long latestTokenValue = null;
// If the max has been resolved, use it.
if (maxGlobal != Address.MAX) {
latestTokenValue = context.resolvedQueue.ceiling(maxGlobal);
}
// a linearized read, fetch the token from the sequencer.
if (latestTokenValue == null || maxGlobal == Address.MAX) {
latestTokenValue = runtime.getSequencerView().nextToken(Collections.singleton(context.id), 0).getToken().getTokenValue();
}
// If there is no infomation on the tail of the stream, return, there is nothing to do
if (Address.nonAddress(latestTokenValue)) {
// curretly, the only possible non-address return value for a token-query is Address.NON_EXIST
if (latestTokenValue != Address.NON_EXIST)
log.warn("TOKEN[{}] unexpected return value", latestTokenValue);
return false;
}
// queue, use it
if (context.maxResolution > latestTokenValue && context.minResolution < context.globalPointer) {
return fillFromResolved(latestTokenValue, context);
}
// Now we start traversing backpointers, if they are available. We
// start at the latest token and go backward, until we reach the
// log pointer. For each address which is less than
// maxGlobalAddress, we insert it into the read queue.
long currentRead = latestTokenValue;
while (currentRead > context.globalPointer && Address.isAddress(currentRead)) {
// We've somehow reached a read we already know about.
if (context.readQueue.contains(currentRead)) {
break;
}
log.trace("Read_Fill_Queue[{}] Read {}", this, currentRead);
// Read the entry in question.
ILogData currentEntry = runtime.getAddressSpaceView().read(currentRead);
// we add it to the read queue.
if (currentEntry.containsStream(context.id)) {
if (currentEntry.hasCheckpointMetadata()) {
examineCheckpointRecord(context, currentEntry, considerCheckpoint, currentRead);
} else {
context.readQueue.add(currentRead);
}
}
// that the caller wants us to us, then we're done here.
if (considerCheckpoint && currentRead <= context.checkpointSuccessStartAddr) {
log.trace("Read_Fill_Queue[{}]: currentRead {} checkpointSuccessStartAddr {}", this, currentRead, context.checkpointSuccessStartAddr);
break;
}
// queue, use it
if (context.maxResolution > currentRead && context.minResolution < context.globalPointer) {
return fillFromResolved(latestTokenValue, context);
}
// use it.
if (context.minResolution <= context.globalPointer) {
fillFromResolved(maxGlobal, context);
}
// If we have a backpointer, we'll use that for our next read.
if (!runtime.backpointersDisabled && currentEntry.hasBackpointer(context.id)) {
log.trace("Read_Fill_Queue[{}] Backpointer {}->{}", this, currentRead, currentEntry.getBackpointer(context.id));
currentRead = currentEntry.getBackpointer(context.id);
} else // Otherwise, our next read is the previous entry.
{
currentRead = currentRead - 1L;
}
// we need to stop.
if (context.maxResolution >= currentRead) {
break;
}
}
log.debug("Read_Fill_Queue[{}] Filled CP queue with {}", this, context.readCpQueue);
log.debug("Read_Fill_Queue[{}] Filled queue with {}", this, context.readQueue);
return !context.readCpQueue.isEmpty() || !context.readQueue.isEmpty();
}
use of org.corfudb.protocols.wireprotocol.ILogData in project CorfuDB by CorfuDB.
the class StreamSpliterator method tryAdvance.
/** {@inheritDoc} */
@Override
public boolean tryAdvance(Consumer<? super ILogData> action) {
// Get the next entry in the stream.
ILogData next = streamView.nextUpTo(maxGlobal);
// If null, end.
if (next == null) {
return false;
}
// Otherwise, apply
action.accept(next);
return true;
}
use of org.corfudb.protocols.wireprotocol.ILogData in project CorfuDB by CorfuDB.
the class AbstractReplicationProtocolTest method canWriteRead.
/** Check if we can write and then read the value
* that was written.
*/
@Test
@SuppressWarnings("unchecked")
public void canWriteRead() throws Exception {
setupNodes();
//begin tests
final CorfuRuntime r = getDefaultRuntime();
final IReplicationProtocol rp = getProtocol();
final Layout layout = r.getLayoutView().getLayout();
LogData data = getLogData(0, "hello world".getBytes());
rp.write(layout, data);
ILogData read = rp.read(layout, 0);
assertThat(read.getType()).isEqualTo(DataType.DATA);
assertThat(read.getGlobalAddress()).isEqualTo(0);
assertThat(read.getPayload(r)).isEqualTo("hello world".getBytes());
}
Aggregations