curState.getEventsIterator().hasNext() &&
!checkForShutdownRequest() &&
//exit the event processing loop if there are other queued notifications
!hasMessages())
{
DbusEventInternalReadable nextEvent = curState.getEventsIterator().next();
_currentWindowSizeInBytes += nextEvent.size();
if (traceEnabled) _log.trace("Got event:" + nextEvent);
Long eventSrcId = (long)nextEvent.srcId();
if (curState.isSCNRegress())
{
SingleSourceSCN scn = new SingleSourceSCN(nextEvent.physicalPartitionId(),
nextEvent.sequence());
_log.info("We are regressing to SCN: " + scn);
curState.switchToRollback();
doRollback(curState, scn, false, false);
curState.setSCNRegress(false);
curState.switchToExpectEventWindow();
}
if (null != getAsyncCallback().getStats())
getAsyncCallback().getStats().registerWindowSeen(nextEvent.timestampInNanos(),
nextEvent.sequence());
if (nextEvent.isControlMessage())
{
//control event
if (nextEvent.isEndOfPeriodMarker())
{
if (curState.isEventsSeen())
{
if (null != curState.getCurrentSource())
{
curState.switchToEndStreamSource();
success = doEndStreamSource(curState);
}
SCN endWinScn = null;
if (success)
{
_lastWindowScn = nextEvent.sequence();
_lastEowTsNsecs = nextEvent.timestampInNanos();
endWinScn = new SingleSourceSCN(nextEvent.physicalPartitionId(),
_lastWindowScn);
curState.switchToEndStreamEventWindow(endWinScn);
success = doEndStreamEventWindow(curState);
}
if (success)
{
try
{
//end of period event
Checkpoint cp = createCheckpoint(curState, nextEvent);
success = doStoreCheckpoint(curState, nextEvent, cp, endWinScn);
}
catch (SharedCheckpointException e)
{
//shutdown
return;
}
}
}
else
{
//empty window
success = true;
if (_log.isDebugEnabled())
{
_log.debug("skipping empty window: " + nextEvent.sequence());
}
//write a checkpoint; takes care of slow sources ; but skip storing the first control eop with 0 scn
if (nextEvent.sequence() > 0)
{
_lastWindowScn = nextEvent.sequence();
//the first window (startEvents()) can have a eop whose sequence() is non-zero but timestamp 0 e.g. in chained relay .
//The reason is that the eop's timestamp is the max timestamp of all data events seen so far.
if (nextEvent.timestampInNanos() > 0)
{
_lastEowTsNsecs = nextEvent.timestampInNanos();
}
Checkpoint ckpt = createCheckpoint(curState, nextEvent);
try
{
success = doStoreCheckpoint(curState, nextEvent, ckpt,
new SingleSourceSCN(nextEvent.physicalPartitionId(),nextEvent.sequence()));
}
catch (SharedCheckpointException e)
{
//shutdown
return;
}
}
else
{
_log.warn("EOP with scn=" + nextEvent.sequence());
}
}
if (success)
{
curState.switchToExpectEventWindow();
//we have recovered from the error and it's not the dummy window
if (nextEvent.sequence() > 0)
{
if (! getStatus().isRunningStatus()) getStatus().resume();
}
}
}
else if (nextEvent.isErrorEvent())
{
_log.info("Error event: " + nextEvent.sequence());
success = processErrorEvent(curState, nextEvent);
}
else
{
//control event
success = processSysEvent(curState, nextEvent);
if (success)
{
if (nextEvent.isCheckpointMessage())
{
Checkpoint sysCheckpt = createCheckpoint(curState, nextEvent);
try
{
long scn = sysCheckpt.getConsumptionMode() == DbusClientMode.ONLINE_CONSUMPTION ?
nextEvent.sequence() : sysCheckpt.getBootstrapSinceScn();
//ensure that control event with 0 scn doesn't get saved unless it is during snapshot of bootstrap
if (scn > 0 || sysCheckpt.getConsumptionMode()==DbusClientMode.BOOTSTRAP_SNAPSHOT)
{
success = doStoreCheckpoint(curState, nextEvent, sysCheckpt,
new SingleSourceSCN(nextEvent.physicalPartitionId(),scn));
}
}
catch (SharedCheckpointException e)
{
//shutdown
return;
}
}
}
}
}
else
{
curState.setEventsSeen(true);
//not a control event
if (curState.getStateId().equals(StateId.EXPECT_EVENT_WINDOW) ||
curState.getStateId().equals(StateId.REPLAY_DATA_EVENTS))
{
SCN startScn = new SingleSourceSCN(nextEvent.physicalPartitionId(),
nextEvent.sequence());
curState.switchToStartStreamEventWindow(startScn);
success = doStartStreamEventWindow(curState);
if (success && (eventSrcId.longValue() >= 0))
{
success = doCheckStartSource(curState, eventSrcId,new SchemaId(nextEvent.schemaId()));
}
}
else
{
if (null != curState.getCurrentSource() &&
!eventSrcId.equals(curState.getCurrentSource().getId()))
{
curState.switchToEndStreamSource();
success = doEndStreamSource(curState);
}
if (success)
{
//Check if schemas of the source exist.
//Also check if the exact schema id present in event exists in the client. This is worthwhile if there's a
//guarantee that the entire window is written with the same schemaId, which is the case if the relay does not use a new schema
//mid-window
success = doCheckStartSource(curState, eventSrcId,new SchemaId(nextEvent.schemaId()));
}
}
if (success)
{
//finally: process data event
success = processDataEvent(curState, nextEvent);
if (success)
{
hasQueuedEvents = true;
if (hasCheckpointThresholdBeenExceeded())
{
_log.info("Attempting to checkpoint (only if the consumer callback for onCheckpoint returns SUCCESS), because " + getCurrentWindowSizeInBytes() + " bytes reached without checkpoint ");
success = processDataEventsBatch(curState);
if (success)
{
hasQueuedEvents = false;
//checkpoint: for bootstrap it's the right checkpoint; that has been lazily created by a checkpoint event
// checkpoint: for relay: create a checkpoint that has the prevScn
Checkpoint cp = createCheckpoint(curState, nextEvent);
// DDSDBUS-1889 : scn for bootstrap is bootstrapSinceSCN
// scn for online consumption is : currentWindow
SCN lastScn = cp.getConsumptionMode() == DbusClientMode.ONLINE_CONSUMPTION ?
curState.getStartWinScn()
: new SingleSourceSCN(
nextEvent.physicalPartitionId(),
cp.getBootstrapSinceScn());
try
{
// Even if storeCheckpoint fails, we
// should continue (hoping for the best)
success = doStoreCheckpoint(curState,
nextEvent, cp, lastScn);
}
catch (SharedCheckpointException e)
{
// shutdown
return;
}
curState.switchToExpectStreamDataEvents();
if (!getStatus().isRunningStatus()) getStatus().resume();
}
}
}
}
}
if (success)
{
// check if threshold has been exceeded for control events;
// DDSDBUS-1776
// this condition will take care of cases where checkpoint
// persistence failed or onCheckpoint returned false
// and the buffer was still left with events, at this juncture
// we clear the buffer to make progress at the risk
// of not being able to rollback should an error be encountered
// before next successful checkpoint
if (hasCheckpointThresholdBeenExceeded())
{
//drain events just in case it hasn't been drained before; mainly control events that are not checkpoint events
success = processDataEventsBatch(curState);
if (success)
{
_log.warn("Checkpoint not stored, but removing older events from buffer to guarantee progress (checkpoint threshold has" +
" exceeded), consider checkpointing more frequently. Triggered on control-event=" + nextEvent.isControlMessage());
// guarantee progress: risk being unable to rollback by
// removing events, but hope for the best
removeEvents(curState);
}
}