@Override public Map<ThreadIdentifier, EventSequenceNumberHolder> getState() { Map<ThreadIdentifier, EventSequenceNumberHolder> result = new HashMap<>(recordedEvents.size()); for (Map.Entry<ThreadIdentifier, EventSequenceNumberHolder> entry : recordedEvents.entrySet()) { EventSequenceNumberHolder holder = entry.getValue(); // don't transfer version tags - adds too much bulk just so we can do client tag recovery result.put(entry.getKey(), new EventSequenceNumberHolder(holder.getLastSequenceNumber(), null)); } return result; }
@Override public void recordBulkOpStart(EventID eventID, ThreadIdentifier tid) { if (logger.isDebugEnabled()) { logger.debug("recording bulkOp start for {}", tid.expensiveToString()); } EventSequenceNumberHolder evh = recordedEvents.get(tid); if (evh == null) { return; } synchronized (evh) { // only remove it when a new bulk op occurs if (eventID.getSequenceID() > evh.getLastSequenceNumber()) { this.recordedBulkOpVersionTags.remove(tid); } } }
@Override public boolean hasSeenEvent(EventID eventID, InternalCacheEvent tagHolder) { if (eventID == null) { return false; } EventSequenceNumberHolder evh = getSequenceHolderForEvent(eventID); if (evh == null) { return false; } synchronized (evh) { if (evh.isRemoved() || evh.getLastSequenceNumber() < eventID.getSequenceID()) { return false; } // log at fine because partitioned regions can send event multiple times // during normal operation during bucket region initialization if (logger.isTraceEnabled(LogMarker.DISTRIBUTION_BRIDGE_SERVER_VERBOSE)) { logger.trace(LogMarker.DISTRIBUTION_BRIDGE_SERVER_VERBOSE, "Cache encountered replay of event with ID {}. Highest recorded for this source is {}", eventID, evh.getLastSequenceNumber()); } // bug #44956 - recover version tag for duplicate event if (evh.getLastSequenceNumber() == eventID.getSequenceID() && tagHolder != null && evh.getVersionTag() != null) { ((EntryEventImpl) tagHolder).setVersionTag(evh.getVersionTag()); } return true; } }
if (oldEvh.getLastSequenceNumber() < evh.getLastSequenceNumber()) { oldEvh.setLastSequenceNumber(evh.getLastSequenceNumber()); oldEvh.setVersionTag(evh.getVersionTag());
@Override public VersionTag findVersionTagForSequence(EventID eventID) { EventSequenceNumberHolder evh = getSequenceHolderForEvent(eventID); if (evh == null) { if (logger.isDebugEnabled()) { logger.debug("search for version tag failed as no event is recorded for {}", createThreadIDFromEvent(eventID).expensiveToString()); } return null; } synchronized (evh) { if (logger.isDebugEnabled()) { logger.debug("search for version tag located last event for {}: {}", createThreadIDFromEvent(eventID).expensiveToString(), evh); } if (evh.getLastSequenceNumber() != eventID.getSequenceID()) { return null; } // log at fine because partitioned regions can send event multiple times // during normal operation during bucket region initialization if (logger.isTraceEnabled(LogMarker.DISTRIBUTION_BRIDGE_SERVER_VERBOSE) && evh.getVersionTag() == null) { logger.trace(LogMarker.DISTRIBUTION_BRIDGE_SERVER_VERBOSE, "Could not recover version tag. Found event holder with no version tag for {}", eventID); } return evh.getVersionTag(); } }
@Test public void entryInRecordedStateStoredWhenNotInCurrentState() { EventSequenceNumberHolder sequenceIdHolder = new EventSequenceNumberHolder(0L, null); ThreadIdentifier threadId = new ThreadIdentifier(new byte[0], 0L); Map<ThreadIdentifier, EventSequenceNumberHolder> state = Collections.singletonMap(threadId, sequenceIdHolder); eventTracker.recordState(null, state); Map<ThreadIdentifier, EventSequenceNumberHolder> storedState = eventTracker.getState(); assertEquals(storedState.get(threadId).getLastSequenceNumber(), sequenceIdHolder.getLastSequenceNumber()); }
@Test public void entryInRecordedStateNotStoredIfAlreadyInCurrentState() { EventSequenceNumberHolder originalSequenceIdHolder = new EventSequenceNumberHolder(0L, null); ThreadIdentifier threadId = new ThreadIdentifier(new byte[0], 0L); Map<ThreadIdentifier, EventSequenceNumberHolder> state = Collections.singletonMap(threadId, originalSequenceIdHolder); eventTracker.recordState(null, state); EventSequenceNumberHolder newSequenceIdHolder = new EventSequenceNumberHolder(1L, null); Map<ThreadIdentifier, EventSequenceNumberHolder> newState = Collections.singletonMap(threadId, newSequenceIdHolder); eventTracker.recordState(null, newState); Map<ThreadIdentifier, EventSequenceNumberHolder> storedState = eventTracker.getState(); assertEquals(storedState.get(threadId).getLastSequenceNumber(), originalSequenceIdHolder.getLastSequenceNumber()); }
@Test public void returnsMapContainingSequenceIdHoldersCurrentlyPresent() { EventSequenceNumberHolder sequenceIdHolder = new EventSequenceNumberHolder(0L, null); ThreadIdentifier threadId = new ThreadIdentifier(new byte[0], 0L); eventTracker.recordSequenceNumber(threadId, sequenceIdHolder); Map<ThreadIdentifier, EventSequenceNumberHolder> state = eventTracker.getState(); assertEquals(1, state.size()); EventSequenceNumberHolder returnedHolder = state.get(threadId); assertNotNull(returnedHolder); // the version tag is stripped out on purpose, so passed in object and returned one are not // equal to each other assertNull(returnedHolder.getVersionTag()); assertEquals(sequenceIdHolder.getLastSequenceNumber(), returnedHolder.getLastSequenceNumber()); }