added synchronization to fix bug 1046 (ConcurrentModificationException while loading score corrections and at the same time attaching a tracked race)

This commit is contained in:
Axel Uhl
2012-11-15 15:38:51 +01:00
parent 34e40fa4bd
commit 1416fbd0d6
3 changed files with 95 additions and 49 deletions
@@ -67,29 +67,35 @@ public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorr
@Override
public void setCarriedPoints(String competitorName, double carriedPoints) {
assertNoTrackedRaceAssociatedYet();
carriedPointsByCompetitorName.put(competitorName, carriedPoints);
synchronized (carriedPointsByCompetitorName) {
carriedPointsByCompetitorName.put(competitorName, carriedPoints);
}
}
@Override
public void setMaxPointsReason(String competitorName, RaceColumn raceColumn, MaxPointsReason maxPointsReason) {
assertNoTrackedRaceAssociatedYet();
Map<RaceColumn, MaxPointsReason> map = maxPointsReasonsByCompetitorName.get(competitorName);
if (map == null) {
map = new HashMap<RaceColumn, MaxPointsReason>();
maxPointsReasonsByCompetitorName.put(competitorName, map);
synchronized (maxPointsReasonsByCompetitorName) {
Map<RaceColumn, MaxPointsReason> map = maxPointsReasonsByCompetitorName.get(competitorName);
if (map == null) {
map = new HashMap<RaceColumn, MaxPointsReason>();
maxPointsReasonsByCompetitorName.put(competitorName, map);
}
map.put(raceColumn, maxPointsReason);
}
map.put(raceColumn, maxPointsReason);
}
@Override
public void correctScore(String competitorName, RaceColumn raceColumn, double correctedScore) {
assertNoTrackedRaceAssociatedYet();
Map<RaceColumn, Double> map = correctedScoresByCompetitorName.get(competitorName);
if (map == null) {
map = new HashMap<RaceColumn, Double>();
correctedScoresByCompetitorName.put(competitorName, map);
synchronized (correctedScoresByCompetitorName) {
Map<RaceColumn, Double> map = correctedScoresByCompetitorName.get(competitorName);
if (map == null) {
map = new HashMap<RaceColumn, Double>();
correctedScoresByCompetitorName.put(competitorName, map);
}
map.put(raceColumn, correctedScore);
}
map.put(raceColumn, correctedScore);
}
/**
@@ -105,48 +111,67 @@ public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorr
for (Competitor competitor : race.getRace().getCompetitors()) {
competitorsByName.put(competitor.getName(), competitor);
}
for (Iterator<Map.Entry<String, Double>> carryEntryIter = carriedPointsByCompetitorName.entrySet().iterator(); carryEntryIter.hasNext(); ) {
Map.Entry<String, Double> carryEntry = carryEntryIter.next();
if (competitorsByName.containsKey(carryEntry.getKey())) {
leaderboard.setCarriedPoints(competitorsByName.get(carryEntry.getKey()), carryEntry.getValue());
carryEntryIter.remove();
}
}
for (Iterator<java.util.Map.Entry<String, Map<RaceColumn, MaxPointsReason>>> maxPointsReasonsEntryIter =
maxPointsReasonsByCompetitorName.entrySet().iterator(); maxPointsReasonsEntryIter.hasNext();) {
java.util.Map.Entry<String, Map<RaceColumn, MaxPointsReason>> maxPointsReasonEntries = maxPointsReasonsEntryIter.next();
if (competitorsByName.containsKey(maxPointsReasonEntries.getKey())) {
for (Map.Entry<RaceColumn, MaxPointsReason> maxPointsReasonEntry : maxPointsReasonEntries.getValue().entrySet()) {
leaderboard.getScoreCorrection().setMaxPointsReason(competitorsByName.get(maxPointsReasonEntries.getKey()),
maxPointsReasonEntry.getKey(), maxPointsReasonEntry.getValue());
synchronized (carriedPointsByCompetitorName) {
for (Iterator<Map.Entry<String, Double>> carryEntryIter = carriedPointsByCompetitorName.entrySet()
.iterator(); carryEntryIter.hasNext();) {
Map.Entry<String, Double> carryEntry = carryEntryIter.next();
if (competitorsByName.containsKey(carryEntry.getKey())) {
leaderboard.setCarriedPoints(competitorsByName.get(carryEntry.getKey()), carryEntry.getValue());
carryEntryIter.remove();
}
maxPointsReasonsEntryIter.remove();
}
}
for (Iterator<java.util.Map.Entry<String, Map<RaceColumn, Double>>> correctedScoresEntryIter =
correctedScoresByCompetitorName.entrySet().iterator(); correctedScoresEntryIter.hasNext();) {
java.util.Map.Entry<String, Map<RaceColumn, Double>> correctedScoresEntries = correctedScoresEntryIter.next();
if (competitorsByName.containsKey(correctedScoresEntries.getKey())) {
for (java.util.Map.Entry<RaceColumn, Double> correctedScoreEntry : correctedScoresEntries.getValue().entrySet()) {
leaderboard.getScoreCorrection().correctScore(competitorsByName.get(correctedScoresEntries.getKey()),
correctedScoreEntry.getKey(), correctedScoreEntry.getValue());
synchronized (maxPointsReasonsByCompetitorName) {
for (Iterator<java.util.Map.Entry<String, Map<RaceColumn, MaxPointsReason>>> maxPointsReasonsEntryIter = maxPointsReasonsByCompetitorName
.entrySet().iterator(); maxPointsReasonsEntryIter.hasNext();) {
java.util.Map.Entry<String, Map<RaceColumn, MaxPointsReason>> maxPointsReasonEntries = maxPointsReasonsEntryIter
.next();
if (competitorsByName.containsKey(maxPointsReasonEntries.getKey())) {
for (Map.Entry<RaceColumn, MaxPointsReason> maxPointsReasonEntry : maxPointsReasonEntries
.getValue().entrySet()) {
leaderboard.getScoreCorrection().setMaxPointsReason(
competitorsByName.get(maxPointsReasonEntries.getKey()), maxPointsReasonEntry.getKey(),
maxPointsReasonEntry.getValue());
}
maxPointsReasonsEntryIter.remove();
}
correctedScoresEntryIter.remove();
}
}
for (Iterator<java.util.Map.Entry<String, String>> displayNamesEntryIter =
displayNamesByCompetitorName.entrySet().iterator(); displayNamesEntryIter.hasNext();) {
java.util.Map.Entry<String, String> displayNamesEntry = displayNamesEntryIter.next();
if (competitorsByName.containsKey(displayNamesEntry.getKey())) {
leaderboard.setDisplayName(competitorsByName.get(displayNamesEntry.getKey()), displayNamesEntry.getValue());
displayNamesEntryIter.remove();
synchronized (correctedScoresByCompetitorName) {
for (Iterator<java.util.Map.Entry<String, Map<RaceColumn, Double>>> correctedScoresEntryIter = correctedScoresByCompetitorName
.entrySet().iterator(); correctedScoresEntryIter.hasNext();) {
java.util.Map.Entry<String, Map<RaceColumn, Double>> correctedScoresEntries = correctedScoresEntryIter
.next();
if (competitorsByName.containsKey(correctedScoresEntries.getKey())) {
for (java.util.Map.Entry<RaceColumn, Double> correctedScoreEntry : correctedScoresEntries
.getValue().entrySet()) {
leaderboard.getScoreCorrection().correctScore(
competitorsByName.get(correctedScoresEntries.getKey()), correctedScoreEntry.getKey(),
correctedScoreEntry.getValue());
}
correctedScoresEntryIter.remove();
}
}
}
for (Iterator<String> suppressedCompetitorNameIter=suppressedCompetitorNames.iterator(); suppressedCompetitorNameIter.hasNext(); ) {
String next = suppressedCompetitorNameIter.next();
if (competitorsByName.containsKey(next)) {
leaderboard.setSuppressed(competitorsByName.get(next), true);
suppressedCompetitorNameIter.remove();
synchronized (displayNamesByCompetitorName) {
for (Iterator<java.util.Map.Entry<String, String>> displayNamesEntryIter = displayNamesByCompetitorName
.entrySet().iterator(); displayNamesEntryIter.hasNext();) {
java.util.Map.Entry<String, String> displayNamesEntry = displayNamesEntryIter.next();
if (competitorsByName.containsKey(displayNamesEntry.getKey())) {
leaderboard.setDisplayName(competitorsByName.get(displayNamesEntry.getKey()),
displayNamesEntry.getValue());
displayNamesEntryIter.remove();
}
}
}
synchronized (suppressedCompetitorNames) {
for (Iterator<String> suppressedCompetitorNameIter = suppressedCompetitorNames.iterator(); suppressedCompetitorNameIter
.hasNext();) {
String next = suppressedCompetitorNameIter.next();
if (competitorsByName.containsKey(next)) {
leaderboard.setSuppressed(competitorsByName.get(next), true);
suppressedCompetitorNameIter.remove();
}
}
}
removeAsListenerIfNoLeftOvers();
@@ -163,13 +188,17 @@ public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorr
@Override
public void setDisplayName(String competitorName, String displayName) {
assertNoTrackedRaceAssociatedYet();
displayNamesByCompetitorName.put(competitorName, displayName);
synchronized (displayNamesByCompetitorName) {
displayNamesByCompetitorName.put(competitorName, displayName);
}
}
@Override
public void suppressCompetitor(String competitorName) {
assertNoTrackedRaceAssociatedYet();
suppressedCompetitorNames.add(competitorName);
synchronized (suppressedCompetitorNames) {
suppressedCompetitorNames.add(competitorName);
}
}
@Override
@@ -9,4 +9,5 @@
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.sap.sailing.domain.swisstimingadapter.persistence.StoreAndForward"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="3500 3501"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.domain.swisstimingadapter.persistence"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties"/>
</launchConfiguration>
@@ -280,11 +280,27 @@ public class StoreAndForward implements Runnable {
SailMasterMessage message = swissTimingFactory.createMessage(messageAndOptionalSequenceNumber.getA(), lastMessageCount);
swissTimingAdapterPersistence.storeSailMasterMessage(message);
synchronized (this) {
for (OutputStream os : streamsToForwardTo) {
for (OutputStream os : new ArrayList<OutputStream>(streamsToForwardTo)) {
// write the sequence number of the message into the stream before actually writing the
// SwissTiming message
try {
// TODO if forwarding to os doesn't work, e.g., because the socket was closed or the client died, remove os from streamsToForwardTo and the socket from socketsToForwardTo
transceiver.sendMessage(message, os);
transceiver.sendMessage(message, os);
} catch (Throwable e) {
int i=streamsToForwardTo.indexOf(os);
try {
os.close();
} catch (Throwable t) {
logger.throwing(StoreAndForward.class.getName(), "run", t);
}
streamsToForwardTo.remove(os);
Socket s = socketsToForwardTo.remove(i);
try {
s.close();
} catch (Throwable t) {
logger.throwing(StoreAndForward.class.getName(), "run", t);
}
}
}
}
if (!stopped) {