bug 3533: deadlock in CompetitorDeregistrator: fixed by separating finding the events from revoking them

Change-Id: I52a0d149edcb89914e6847fd4c81f3796eb6f318
This commit is contained in:
Axel Uhl committed 2016-03-23 15:18:03 +01:00
1 parent 5ece6b257a
commit b59db4943d
2 files changed
+29 -15

No files matched your search

@@ -28,7 +28,8 @@ public class CompetitorDeregistrationTest extends AbstractRegattaLogTrackingTest
log.add(new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), author, competitor2));
final CompetitorDeregistrator<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor> deregistrator = new CompetitorDeregistrator<>(log,
Collections.singleton(competitor2), author);
deregistrator.analyze();
final Set<RegattaLogEvent> events = deregistrator.analyze();
deregistrator.deregister(events);
final Set<Competitor> competitors = new CompetitorsInLogAnalyzer<>(log).analyze();
assertEquals(1, competitors.size());
assertSame(competitor, competitors.iterator().next());
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -14,14 +15,21 @@ import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sse.common.Util;
/**
* Generates events that close the events that are responsible for the {@link #mapping} that is passed to the
* constructor.
* Finds the competitor registration events for a given set of {@link Competitor competitors} that must be
* {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent) revoked} in order to deregister the
* competitors. Note that the de-registration cannot be performed during analysis because
* {@link BaseLogAnalyzer#analyze()} obtains a read lock on the log whereas
* {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent)} requires a write lock, and upgrading from a
* read to a write lock is not possible.<p>
*
* Clients must call {@link #deregister} with the result of {@link #analyze()} in order to actually perform the
* deregistration.
*
* @author Jan Bross
*
*/
public class CompetitorDeregistrator<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Void> {
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Set<EventT>> {
private static final Logger logger = Logger.getLogger(CompetitorDeregistrator.class.getName());
protected final Iterable<Competitor> competitorsToDeregister;
@@ -34,24 +42,29 @@ extends BaseLogAnalyzer<LogT, EventT, VisitorT, Void> {
}
@Override
protected Void performAnalysis() {
HashSet<Competitor> competitorSet = new HashSet<Competitor>();
protected Set<EventT> performAnalysis() {
final Set<EventT> result = new HashSet<>();
final HashSet<Competitor> competitorSet = new HashSet<Competitor>();
Util.addAll(competitorsToDeregister, competitorSet);
for (EventT event : log.getUnrevokedEventsDescending()) {
if (event instanceof RegisterCompetitorEvent) {
RegisterCompetitorEvent<?> registerEvent = (RegisterCompetitorEvent<?>) event;
if (competitorSet.contains(registerEvent.getCompetitor())) {
try {
log.revokeEvent(eventAuthor, event,
"unregistering competitor because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
}
result.add(event);
}
}
}
return null;
return result;
}
public void deregister(final Set<EventT> competitorRegistrationEvents) {
for (final EventT event : competitorRegistrationEvents) {
try {
log.revokeEvent(eventAuthor, event,
"unregistering competitor because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e);
}
}
}
}