mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-20 04:35:32 +00:00
Merge branch 'bug4339' into bug4693
This commit is contained in:
+11
-8
@@ -24,21 +24,24 @@ public class BravoFixRetrievalProcessor extends AbstractRetrievalProcessor<HasTr
|
||||
@Override
|
||||
protected Iterable<HasBravoFixContext> retrieveData(HasTrackedLegOfCompetitorContext element) {
|
||||
Collection<HasBravoFixContext> bravoFixesWithContext = new ArrayList<>();
|
||||
BravoFixTrack<Competitor> bravoFixTrack = element.getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
|
||||
if (bravoFixTrack != null) {
|
||||
bravoFixTrack.lockForRead();
|
||||
try {
|
||||
TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor();
|
||||
if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) {
|
||||
TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor();
|
||||
if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) {
|
||||
BravoFixTrack<Competitor> bravoFixTrack = element.getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
|
||||
if (bravoFixTrack != null) {
|
||||
bravoFixTrack.lockForRead();
|
||||
try {
|
||||
for (BravoFix bravoFix : bravoFixTrack.getFixes(trackedLegOfCompetitor.getStartTime(), true, trackedLegOfCompetitor.getFinishTime(), true)) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
BravoFixWithContext gpsFixWithContext = new BravoFixWithContext(
|
||||
new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
|
||||
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), bravoFix.getTimePoint()), bravoFix);
|
||||
bravoFixesWithContext.add(gpsFixWithContext);
|
||||
}
|
||||
} finally {
|
||||
bravoFixTrack.unlockAfterRead();
|
||||
}
|
||||
} finally {
|
||||
bravoFixTrack.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
return bravoFixesWithContext;
|
||||
|
||||
+2
-6
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.datamining.impl.components;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
|
||||
@@ -28,13 +28,9 @@ public class BravoFixTrackRetrievalProcessor extends AbstractRetrievalProcessor<
|
||||
|
||||
@Override
|
||||
protected Iterable<HasBravoFixTrackContext> retrieveData(HasRaceOfCompetitorContext element) {
|
||||
Collection<HasBravoFixTrackContext> bravoTracksWithContext = new ArrayList<>();
|
||||
final TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
|
||||
final BravoFixTrack<Competitor> bravoFixTrack = trackedRace.getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
|
||||
if (bravoFixTrack != null) {
|
||||
bravoTracksWithContext.add(new BravoFixTrackWithContext(element, bravoFixTrack));
|
||||
}
|
||||
return bravoTracksWithContext;
|
||||
return bravoFixTrack == null ? Collections.emptySet() : Collections.singleton(new BravoFixTrackWithContext(element, bravoFixTrack));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -24,7 +24,13 @@ public class CompetitorOfRaceInLeaderboardRetrievalProcessor extends
|
||||
protected Iterable<HasRaceResultOfCompetitorContext> retrieveData(HasLeaderboardContext element) {
|
||||
Collection<HasRaceResultOfCompetitorContext> raceResultsOfCompetitor = new ArrayList<>();
|
||||
for (RaceColumn raceColumn : element.getLeaderboard().getRaceColumns()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
for (Competitor competitor : element.getLeaderboard().getCompetitors()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
HasRaceResultOfCompetitorContext raceResultOfCompetitorContext = new RaceResultOfCompetitorWithContext(element, raceColumn, competitor,
|
||||
element.getLeaderboardGroupContext().getPolarDataService());
|
||||
raceResultsOfCompetitor.add(raceResultOfCompetitorContext);
|
||||
|
||||
+13
-1
@@ -49,14 +49,26 @@ public class CompleteManeuverCurveWithEstimationDataRetrievalProcessor extends
|
||||
ManeuverDetectorWithEstimationDataSupport maneuverDetector = new ManeuverDetectorWithEstimationDataSupportDecoratorImpl(
|
||||
new ManeuverDetectorImpl(trackedRace, competitor),
|
||||
element.getTrackedRaceContext().getLeaderboardContext().getLeaderboardGroupContext().getPolarDataService());
|
||||
|
||||
Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, false);
|
||||
if (isAborted()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterable<CompleteManeuverCurve> maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers);
|
||||
if (isAborted()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterable<CompleteManeuverCurveWithEstimationData> maneuversWithEstimationData = maneuverDetector
|
||||
.getCompleteManeuverCurvesWithEstimationData(maneuverCurves);
|
||||
|
||||
CompleteManeuverCurveWithEstimationData previousManeuver = null;
|
||||
CompleteManeuverCurveWithEstimationData currentManeuver = null;
|
||||
for (CompleteManeuverCurveWithEstimationData nextManeuver : maneuversWithEstimationData) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentManeuver != null) {
|
||||
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
|
||||
element, currentManeuver, settings, previousManeuver, nextManeuver);
|
||||
|
||||
+3
@@ -50,6 +50,9 @@ public class FoilingSegmentRetrievalProcessor extends AbstractRetrievalProcessor
|
||||
bravoFixTrack.lockForRead();
|
||||
try {
|
||||
for (final BravoFix bravoFix : bravoFixTrack.getFixes(startOfRace, /* fromInclusive */ true, end, /* toInclusive */ false)) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
final boolean currentFixIsFoiling =
|
||||
(bravoFix.isFoiling(settings.getMinimumRideHeight()) &&
|
||||
(settings.getMinimumSpeedForFoiling() == null || settings.getMinimumSpeedForFoiling().compareTo(
|
||||
|
||||
+3
@@ -30,6 +30,9 @@ public class GPSFixRetrievalProcessor extends AbstractRetrievalProcessor<HasTrac
|
||||
TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor();
|
||||
if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) {
|
||||
for (GPSFixMoving gpsFix : competitorTrack.getFixes(trackedLegOfCompetitor.getStartTime(), true, trackedLegOfCompetitor.getFinishTime(), true)) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
HasGPSFixContext gpsFixWithContext = new GPSFixWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
|
||||
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), gpsFix.getTimePoint()), gpsFix);
|
||||
gpsFixesWithContext.add(gpsFixWithContext);
|
||||
|
||||
+12
-7
@@ -1,11 +1,13 @@
|
||||
package com.sap.sailing.datamining.impl.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
@@ -20,12 +22,15 @@ public class LeaderboardGroupRetrievalProcessor extends AbstractRetrievalProcess
|
||||
|
||||
@Override
|
||||
protected Iterable<HasLeaderboardGroupContext> retrieveData(RacingEventService element) {
|
||||
final PolarDataService polarDataService = element.getPolarDataService();
|
||||
return element.getLeaderboardGroups()
|
||||
.values()
|
||||
.stream()
|
||||
.map(lg -> new LeaderboardGroupWithContext(lg, polarDataService))
|
||||
.collect(Collectors.toSet());
|
||||
Set<HasLeaderboardGroupContext> data = new HashSet<>();
|
||||
PolarDataService polarDataService = element.getPolarDataService();
|
||||
for (LeaderboardGroup leaderboardGroup : element.getLeaderboardGroups().values()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
data.add(new LeaderboardGroupWithContext(leaderboardGroup, polarDataService));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ public class LeaderboardRetrievalProcessor extends AbstractRetrievalProcessor<Ha
|
||||
protected Iterable<HasLeaderboardContext> retrieveData(HasLeaderboardGroupContext element) {
|
||||
Collection<HasLeaderboardContext> leaderboardsWithContext = new ArrayList<>();
|
||||
for (Leaderboard leaderboard : element.getLeaderboardGroup().getLeaderboards()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
leaderboardsWithContext.add(new LeaderboardWithContext(leaderboard, element));
|
||||
}
|
||||
return leaderboardsWithContext;
|
||||
|
||||
+4
@@ -48,6 +48,10 @@ public class ManeuverRetrievalProcessor
|
||||
Maneuver previousManeuver = null;
|
||||
Maneuver currentManeuver = null;
|
||||
for (Maneuver nextManeuver : maneuvers) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentManeuver != null) {
|
||||
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
|
||||
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), currentManeuver.getTimePoint()), currentManeuver,
|
||||
|
||||
+7
@@ -87,6 +87,10 @@ public class ManeuverSpeedDetailsRetrievalProcessor
|
||||
|
||||
double directionChangeForAnalysisSignum = Math.signum(directionChangeInDegreesForAnalysis);
|
||||
for (SpeedWithBearingStep bearingStep : maneuverBearingSteps) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentDirectionChangeSumInDegrees += bearingStep.getCourseChangeInDegrees();
|
||||
if (previousRoundedTWA != -1
|
||||
&& Math.signum(currentDirectionChangeSumInDegrees) != directionChangeForAnalysisSignum
|
||||
@@ -123,6 +127,9 @@ public class ManeuverSpeedDetailsRetrievalProcessor
|
||||
for (int step = 1, fillingTWA = twaIterationFunction
|
||||
.apply(previousRoundedTWA); fillingTWA != roundedTWA; fillingTWA = twaIterationFunction
|
||||
.apply(fillingTWA), ++step) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
if (speedPerTWA[fillingTWA] == 0) {
|
||||
speedPerTWA[fillingTWA] = previousSpeed
|
||||
+ diffWithPreviousSpeed * step / diffWithPreviousTWA;
|
||||
|
||||
+3
@@ -29,6 +29,9 @@ public class MarkPassingRetrievalProcessor extends AbstractRetrievalProcessor<Ha
|
||||
try {
|
||||
Iterable<Maneuver> maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
|
||||
for (Maneuver maneuver : maneuvers) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
if (maneuver.isMarkPassing()) {
|
||||
maneuversWithContext.add(new MarkPassingWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
|
||||
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), maneuver.getTimePoint()), maneuver));
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ public class RaceOfCompetitorRetrievalProcessor extends AbstractRetrievalProcess
|
||||
protected Iterable<HasRaceOfCompetitorContext> retrieveData(HasTrackedRaceContext element) {
|
||||
Collection<HasRaceOfCompetitorContext> raceOfCompetitorsWithContext = new ArrayList<>();
|
||||
for (Competitor competitor : element.getTrackedRace().getRace().getCompetitors()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
HasRaceOfCompetitorContext raceOfCompetitorWithContext = new RaceOfCompetitorWithContext(element, competitor);
|
||||
raceOfCompetitorsWithContext.add(raceOfCompetitorWithContext);
|
||||
}
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ public class TrackedLegOfCompetitorRetrievalProcessor extends AbstractRetrievalP
|
||||
protected Iterable<HasTrackedLegOfCompetitorContext> retrieveData(HasTrackedLegContext element) {
|
||||
Collection<HasTrackedLegOfCompetitorContext> trackedLegOfCompetitorsWithContext = new ArrayList<>();
|
||||
for (Competitor competitor : element.getTrackedRaceContext().getTrackedRace().getRace().getCompetitors()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
HasTrackedLegOfCompetitorContext trackedLegOfCompetitorWithContext = new TrackedLegOfCompetitorWithContext(element, element.getTrackedLeg().getTrackedLeg(competitor));
|
||||
trackedLegOfCompetitorsWithContext.add(trackedLegOfCompetitorWithContext);
|
||||
}
|
||||
|
||||
+3
@@ -23,6 +23,9 @@ public class TrackedLegRetrievalProcessor extends AbstractRetrievalProcessor<Has
|
||||
Collection<HasTrackedLegContext> trackedLegsWithContext = new ArrayList<>();
|
||||
int legNumber = 1;
|
||||
for (TrackedLeg trackedLeg : element.getTrackedRace().getTrackedLegs()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
HasTrackedLegContext trackedLegWithContext = new TrackedLegWithContext(element, trackedLeg, legNumber);
|
||||
trackedLegsWithContext.add(trackedLegWithContext);
|
||||
legNumber++;
|
||||
|
||||
+6
@@ -25,7 +25,13 @@ public class TrackedRaceRetrievalProcessor extends AbstractRetrievalProcessor<Ha
|
||||
protected Iterable<HasTrackedRaceContext> retrieveData(HasLeaderboardContext element) {
|
||||
Collection<HasTrackedRaceContext> trackedRacesWithContext = new ArrayList<>();
|
||||
for (RaceColumn raceColumn : element.getLeaderboard().getRaceColumns()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
Regatta regatta = trackedRace.getTrackedRegatta().getRegatta();
|
||||
|
||||
+3
@@ -33,6 +33,9 @@ public class WindFixRetrievalProcessor extends AbstractRetrievalProcessor<HasWin
|
||||
windTrack.lockForRead();
|
||||
try {
|
||||
for (final Wind wind : windTrack.getFixes()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
windFixesWithContext.add(new WindFixWithContext(element.getTrackedRaceContext(), wind, element.getWindSourceType()));
|
||||
}
|
||||
} finally {
|
||||
|
||||
+3
@@ -31,6 +31,9 @@ public class WindTrackRetrievalProcessor extends AbstractRetrievalProcessor<HasT
|
||||
Collection<HasWindTrackContext> windTracksWithContext = new ArrayList<>();
|
||||
final TrackedRace trackedRace = element.getTrackedRace();
|
||||
for (final WindSource windSource : trackedRace.getWindSources()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
if (!trackedRace.getWindSourcesToExclude().contains(windSource)) {
|
||||
final WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
|
||||
windTracksWithContext.add(new WindTrackWithContext(element, windTrack, windSource));
|
||||
|
||||
+3
@@ -64,6 +64,9 @@ public abstract class AbstractParallelAverageAggregationProcessor<T extends Comp
|
||||
Map<GroupKey, T> minAggregation = minAggregationProcessor.getResult();
|
||||
Map<GroupKey, T> maxAggregation = maxAggregationProcessor.getResult();
|
||||
for (Entry<GroupKey, T> sumAggregationEntry : sumAggregation.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new AverageWithStatsImpl<>(
|
||||
/* average */ divide(sumAggregationEntry.getValue(), elementAmountPerKey.get(key).longValue()),
|
||||
|
||||
+2
-2
@@ -19,8 +19,6 @@ public abstract class AbstractParallelSumAggregationProcessor<T> extends
|
||||
super(executor, resultReceivers, "Sum");
|
||||
results = new HashMap<>();
|
||||
}
|
||||
|
||||
protected abstract T add(T t1, T t2);
|
||||
|
||||
@Override
|
||||
protected void handleElement(GroupedDataEntry<T> element) {
|
||||
@@ -31,6 +29,8 @@ public abstract class AbstractParallelSumAggregationProcessor<T> extends
|
||||
results.put(key, add(results.get(key), element.getDataEntry()));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T add(T t1, T t2);
|
||||
|
||||
@Override
|
||||
protected Map<GroupKey, T> getResult() {
|
||||
|
||||
+3
@@ -47,6 +47,9 @@ public class ParallelBearingAverageDegreesAggregationProcessor
|
||||
protected Map<GroupKey, Double> aggregateResult() {
|
||||
Map<GroupKey, Double> result = new HashMap<>();
|
||||
for (Entry<GroupKey, BearingCluster> clusterEntry : results.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
GroupKey key = clusterEntry.getKey();
|
||||
result.put(key, clusterEntry.getValue().getAverage().getDegrees());
|
||||
}
|
||||
|
||||
+3
@@ -50,6 +50,9 @@ public class ParallelDistanceMedianAggregationProcessor
|
||||
protected Map<GroupKey, Distance> aggregateResult() {
|
||||
Map<GroupKey, Distance> result = new HashMap<>();
|
||||
for (Entry<GroupKey, List<Distance>> groupedValuesEntry : groupedValues.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
result.put(groupedValuesEntry.getKey(), getMedianOf(groupedValuesEntry.getValue()));
|
||||
}
|
||||
return result;
|
||||
|
||||
+42
-12
@@ -5,9 +5,11 @@ import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@@ -132,6 +134,8 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
|
||||
private final RaceIdentifierToLeaderboardRaceColumnAndFleetMapper raceIdentifierToLeaderboardRaceColumnAndFleetMapper;
|
||||
protected boolean nonTrackingWarningWasDisplayed;
|
||||
|
||||
private final Set<MarkDTO> marksCurrentlyRequestedViaRemoteCall = new HashSet<>();
|
||||
|
||||
public EditMarkPositionPanel(Component<?> parent, ComponentContext<?> context, final RaceMap raceMap,
|
||||
final SingleRaceLeaderboardPanel leaderboardPanel,
|
||||
RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName, final StringMessages stringMessages,
|
||||
@@ -735,10 +739,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
|
||||
}
|
||||
raceMap.unregisterAllCourseMarkInfoWindowClickHandlers();
|
||||
} else {
|
||||
if (currentFixPositionChooser != null) {
|
||||
currentFixPositionChooser.cancel();
|
||||
currentFixPositionChooser = null;
|
||||
}
|
||||
cancelFixPositionChooserAndNotification();
|
||||
marksPanel.deselectMark();
|
||||
selectedMark = null;
|
||||
if (sideBySideComponentViewer != null) {
|
||||
@@ -754,6 +755,17 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
private void cancelFixPositionChooserAndNotification() {
|
||||
if (currentFixPositionChooser != null) {
|
||||
currentFixPositionChooser.cancel();
|
||||
currentFixPositionChooser = null;
|
||||
if (notificationTimer.isRunning()) {
|
||||
notificationTimer.run();
|
||||
notificationTimer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIfTracking(Runnable continuation) {
|
||||
if (nonTrackingWarningWasDisplayed) {
|
||||
continuation.run();
|
||||
@@ -859,11 +871,10 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
|
||||
}
|
||||
|
||||
private void selectMark(MarkDTO mark) {
|
||||
selectedMark = mark;
|
||||
if (currentFixPositionChooser != null) {
|
||||
currentFixPositionChooser.cancel();
|
||||
currentFixPositionChooser = null;
|
||||
if (selectedMark != mark) {
|
||||
cancelFixPositionChooserAndNotification();
|
||||
}
|
||||
selectedMark = mark;
|
||||
if (selectedMark != null) {
|
||||
if (marksFromToTimes.get(selectedMark) != null) {
|
||||
// For some reason the time slider does not change with this method only if you comment out line 430 and 432 in TimePanel it works
|
||||
@@ -905,24 +916,43 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
|
||||
@Override
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
final MarkDTO mark = marksPanel.getSelectedMark();
|
||||
retrieveAndSelectMarkIfNecessary(mark, null);
|
||||
}
|
||||
|
||||
protected void retrieveAndSelectMarkIfNecessary(final MarkDTO mark, final Runnable callback) {
|
||||
if (mark != null && (marks.get(mark) == null || marks.get(mark).isEmpty())) {
|
||||
if (mark != null) {
|
||||
markPositionService.getMarkTrack(raceIdentifierToLeaderboardRaceColumnAndFleetMapper.getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier),
|
||||
|
||||
if (marksCurrentlyRequestedViaRemoteCall.add(mark)) {
|
||||
markPositionService.getMarkTrack(
|
||||
raceIdentifierToLeaderboardRaceColumnAndFleetMapper
|
||||
.getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier),
|
||||
mark.getIdAsString(), new AsyncCallback<MarkTrackDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorCommunicatingWithServer()+": "+caught.getMessage());
|
||||
marksCurrentlyRequestedViaRemoteCall.remove(mark);
|
||||
errorReporter.reportError(
|
||||
stringMessages.errorCommunicatingWithServer() + ": " + caught.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSuccess(MarkTrackDTO result) {
|
||||
marksCurrentlyRequestedViaRemoteCall.remove(mark);
|
||||
createMarkTrackUi(mark, result.getFixes());
|
||||
selectMark(mark);
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// remote call of the same mark already in progress -> ignore this request
|
||||
}
|
||||
} else {
|
||||
selectMark(mark);
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-15
@@ -85,22 +85,27 @@ public class MarksPanel extends AbstractCompositeComponent<AbstractSettings> {
|
||||
@Override
|
||||
public void update(int index, final MarkDTO mark, String value) {
|
||||
final Date timePoint = parent.timer.getTime();
|
||||
select(mark);
|
||||
if (parent.hasFixAtTimePoint(mark, timePoint)) {
|
||||
parent.showNotification(stringMessages.pleaseSelectOtherTimepoint(), NotificationType.ERROR);
|
||||
} else {
|
||||
parent.createFixPositionChooserToAddFixToMark(mark, new Callback<Position, Exception>() {
|
||||
@Override
|
||||
public void onFailure(Exception reason) {
|
||||
parent.resetCurrentFixPositionChooser();
|
||||
parent.retrieveAndSelectMarkIfNecessary(mark, new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (parent.hasFixAtTimePoint(mark, timePoint)) {
|
||||
parent.showNotification(stringMessages.pleaseSelectOtherTimepoint(), NotificationType.ERROR);
|
||||
} else {
|
||||
parent.createFixPositionChooserToAddFixToMark(mark, new Callback<Position, Exception>() {
|
||||
@Override
|
||||
public void onFailure(final Exception reason) {
|
||||
parent.resetCurrentFixPositionChooser();
|
||||
}
|
||||
@Override
|
||||
public void onSuccess(Position result) {
|
||||
parent.addMarkFix(mark, timePoint, result);
|
||||
parent.resetCurrentFixPositionChooser();
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void onSuccess(Position result) {
|
||||
parent.addMarkFix(mark, timePoint, result);
|
||||
parent.resetCurrentFixPositionChooser();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
markTable.addColumn(addFixColumn);
|
||||
|
||||
+11
-5
@@ -1,9 +1,11 @@
|
||||
package com.sap.sailing.polars.datamining.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.polars.PolarDataService;
|
||||
import com.sap.sailing.polars.datamining.data.HasBackendPolarBoatClassContext;
|
||||
import com.sap.sailing.polars.datamining.data.impl.BoatClassWithBackendPolarContext;
|
||||
@@ -20,11 +22,15 @@ public class BackendPolarsBoatClassRetrievalProcessor extends AbstractRetrievalP
|
||||
|
||||
@Override
|
||||
protected Iterable<HasBackendPolarBoatClassContext> retrieveData(RacingEventService element) {
|
||||
Set<HasBackendPolarBoatClassContext> data = new HashSet<>();
|
||||
PolarDataService polarDataService = element.getPolarDataService();
|
||||
return polarDataService.getAllBoatClassesWithPolarSheetsAvailable()
|
||||
.stream()
|
||||
.map(bc -> new BoatClassWithBackendPolarContext(bc, polarDataService))
|
||||
.collect(Collectors.toSet());
|
||||
for (BoatClass boatClass : polarDataService.getAllBoatClassesWithPolarSheetsAvailable()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
data.add(new BoatClassWithBackendPolarContext(boatClass, polarDataService));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -25,6 +25,9 @@ public class PolarCompetitorRetrievalProcessor extends AbstractRetrievalProcesso
|
||||
TrackedRace trackedRace = element.getTrackedRace();
|
||||
Set<HasCompetitorPolarContext> competitorWithContext = new HashSet<>();
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
competitorWithContext.add(new CompetitorWithPolarContext(competitor, trackedRace, element.getLeg(), element));
|
||||
}
|
||||
return competitorWithContext;
|
||||
|
||||
+3
@@ -25,6 +25,9 @@ public class PolarFleetRetrievalProcessor extends AbstractRetrievalProcessor<Has
|
||||
Set<HasFleetPolarContext> fleetWithContext = new HashSet<>();
|
||||
RaceColumn raceColumn = element.getRaceColumn();
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
fleetWithContext.add(new FleetWithPolarContext(fleet, raceColumn, element));
|
||||
}
|
||||
return fleetWithContext;
|
||||
|
||||
+3
@@ -59,6 +59,9 @@ public class PolarGPSFixRetrievalProcessor extends AbstractRetrievalProcessor<Ha
|
||||
try {
|
||||
Iterable<GPSFixMoving> fixes = track.getFixes(startTime, true, finishTime, false);
|
||||
for (GPSFixMoving fix : fixes) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
WindWithConfidence<Pair<Position, TimePoint>> wind = trackedRace.getWindWithConfidence(
|
||||
fix.getPosition(),
|
||||
fix.getTimePoint(),
|
||||
|
||||
+11
-6
@@ -1,9 +1,11 @@
|
||||
package com.sap.sailing.polars.datamining.components;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.polars.datamining.data.HasLeaderboardGroupPolarContext;
|
||||
import com.sap.sailing.polars.datamining.data.impl.LeaderboardGroupWithPolarContext;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
@@ -19,11 +21,14 @@ public class PolarLeaderboardGroupRetrievalProcessor extends AbstractRetrievalPr
|
||||
|
||||
@Override
|
||||
protected Iterable<HasLeaderboardGroupPolarContext> retrieveData(RacingEventService element) {
|
||||
return element.getLeaderboardGroups()
|
||||
.values()
|
||||
.stream()
|
||||
.map(lg -> new LeaderboardGroupWithPolarContext(lg))
|
||||
.collect(Collectors.toSet());
|
||||
Set<HasLeaderboardGroupPolarContext> data = new HashSet<>();
|
||||
for (LeaderboardGroup leaderboardGroup : element.getLeaderboardGroups().values()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
data.add(new LeaderboardGroupWithPolarContext(leaderboardGroup));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -23,6 +23,9 @@ public class PolarLeaderboardRetrievalProcessor extends AbstractRetrievalProcess
|
||||
protected Iterable<HasLeaderboardPolarContext> retrieveData(HasLeaderboardGroupPolarContext element) {
|
||||
Set<HasLeaderboardPolarContext> leaderboardsWithContext = new HashSet<>();
|
||||
for (Leaderboard leaderboard : element.getLeaderboardGroup().getLeaderboards()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
leaderboardsWithContext.add(new LeaderboardWithPolarContext(leaderboard, element));
|
||||
}
|
||||
return leaderboardsWithContext;
|
||||
|
||||
+3
@@ -35,6 +35,9 @@ public class PolarLegRetrievalProcessor extends AbstractRetrievalProcessor<HasFl
|
||||
if (raceDefinition != null) {
|
||||
Course course = raceDefinition.getCourse();
|
||||
for (Leg leg : course.getLegs()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
legWithContext.add(new LegWithPolarContext(leg, trackedRace, element));
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -25,6 +25,9 @@ public class PolarRaceColumnRetrievalProcessor extends AbstractRetrievalProcesso
|
||||
Set<HasRaceColumnPolarContext> raceColumnWithContext = new HashSet<>();
|
||||
Leaderboard leaderboard = element.getLeaderboard();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
raceColumnWithContext.add(new RaceColumnWithPolarContext(raceColumn, element));
|
||||
}
|
||||
return raceColumnWithContext;
|
||||
|
||||
+10
@@ -100,10 +100,17 @@ public class PolarBackendDataAggregationProcessor extends AbstractParallelGroupe
|
||||
} catch (NotEnoughDataHasBeenAddedException e) {
|
||||
hasDownwindAngleData = false;
|
||||
}
|
||||
|
||||
for (int angleInDeg = 0; angleInDeg < 360; angleInDeg++) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
int convertedAngle = angleInDeg > 180 ? angleInDeg - 360 : angleInDeg ;
|
||||
try {
|
||||
for (int x = 0; x < 30; x++) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
SpeedWithConfidence<Void> speed = polarDataService.getSpeed(boatClass, new KnotSpeedImpl(x), new DegreeBearingImpl(convertedAngle));
|
||||
if (speed.getConfidence() > 0.1) {
|
||||
hasDataForAngle[angleInDeg] = true;
|
||||
@@ -127,6 +134,9 @@ public class PolarBackendDataAggregationProcessor extends AbstractParallelGroupe
|
||||
|
||||
private void setArrayValuesForFunction(PolynomialFunction function, double[] yOverWindSpeed) {
|
||||
for (int x = 0; x < 30; x++) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
yOverWindSpeed[x] = function.value(x);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-12
@@ -71,24 +71,31 @@ public class TestAbortingHeavyLoadQuery {
|
||||
// Test Configuration ----------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Number of threads in the executor. Determines the number of elements (and thus heavy load instructions)
|
||||
* retrieved for each group. This means that each group should have a runtime of {@value #HeavyLoadInstructionDuration}ms,
|
||||
* retrieved for each group. This means that each group should have a runtime of {@value #HeavyLoadInstructionTotalDuration}ms,
|
||||
* since the single instructions are executed concurrently.
|
||||
*/
|
||||
private static final int ExecutorPoolSize = Math.max(3, Runtime.getRuntime().availableProcessors());
|
||||
|
||||
/** The number of groups contained in the initial data source. */
|
||||
private static final int DataSourceSize = 2000;
|
||||
private static final String GroupKeyPrefix = "G";
|
||||
/** The time a heavy load instruction blocks the executing thread using {@link Thread#sleep(long)}. */
|
||||
private static final long HeavyLoadInstructionDuration = 500;
|
||||
|
||||
/** The time a step of a heavy load instruction blocks the executing thread (using {@link Thread#sleep(long)}). */
|
||||
private static final long HeavyLoadInstructionStepDuration = 50;
|
||||
/** The number of steps a heavy load instruction performs */
|
||||
private static final int HeavyLoadInstructionNumberOfSteps = 10;
|
||||
/** The total time a heavy load instruction blocks the executing thread (using {@link Thread#sleep(long)}). */
|
||||
private static final long HeavyLoadInstructionTotalDuration = HeavyLoadInstructionStepDuration * HeavyLoadInstructionNumberOfSteps;
|
||||
|
||||
/** The number of milliseconds to wait before {@link Query#abort()} is called. */
|
||||
private static final long AbortQueryDelay = (long) (HeavyLoadInstructionDuration * 5.45);
|
||||
private static final long AbortQueryDelay = (long) (HeavyLoadInstructionTotalDuration * 5.45);
|
||||
/** The time given to the executor to complete all unfinished instructions */
|
||||
private static final long TerminationTimeout = (long) (HeavyLoadInstructionDuration * 1.5);
|
||||
private static final long TerminationTimeout = HeavyLoadInstructionStepDuration * 2;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Execution Recording Configuration -------------------------------------------------------------------------
|
||||
/** Enables concurrent logging of the query execution and prints the current record before assertions. */
|
||||
private static final boolean RecordExecution = false;
|
||||
private static final boolean RecordExecution = true;
|
||||
private static final SimpleDateFormat DateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
|
||||
private ConcurrentLinkedQueue<String> executionRecord;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
@@ -174,6 +181,10 @@ public class TestAbortingHeavyLoadQuery {
|
||||
for (StatefulProcessorInstruction<?> instruction : runningInstructions) {
|
||||
assertTrue("computeResult() of a running unfinished instruction wasn't called", instruction.computeResultWasCalled());
|
||||
assertTrue("computeResult() of a running unfinished instruction didn't finish", instruction.computeResultWasFinished());
|
||||
if (instruction instanceof StatefulBlockingInstruction) {
|
||||
StatefulBlockingInstruction<?> blockingInstruction = (StatefulBlockingInstruction<?>) instruction;
|
||||
assertTrue("computeResult() of a running heavy load instruction wasn't aborted", blockingInstruction.computeResultWasAborted());
|
||||
}
|
||||
}
|
||||
for (StatefulProcessorInstruction<?> instruction : notStartedInstructions) {
|
||||
assertTrue("run() of an unstarted unfinished instruction wasn't called", instruction.runWasCalled());
|
||||
@@ -216,7 +227,7 @@ public class TestAbortingHeavyLoadQuery {
|
||||
* </li>
|
||||
* <li>
|
||||
* A heavy load instruction for each element is scheduled, which blocks the running thread for
|
||||
* {@value #HeavyLoadInstructionDuration}ms.
|
||||
* {@value #HeavyLoadInstructionTotalDuration}ms.
|
||||
* </li>
|
||||
* <li>
|
||||
* Each element is grouped by its name and its value is used as value for the {@link GroupedDataEntry}.
|
||||
@@ -306,8 +317,8 @@ public class TestAbortingHeavyLoadQuery {
|
||||
@Override
|
||||
protected ProcessorInstruction<Element> createInstruction(Element element) {
|
||||
StatefulProcessorInstruction<Element> instruction = new HeavyLoadInstruction(this,
|
||||
ProcessorInstructionPriority.Extraction, HeavyLoadInstructionDuration, element,
|
||||
TestAbortingHeavyLoadQuery.this::logExecution);
|
||||
ProcessorInstructionPriority.Extraction, HeavyLoadInstructionStepDuration,
|
||||
HeavyLoadInstructionNumberOfSteps, element, TestAbortingHeavyLoadQuery.this::logExecution);
|
||||
unfinishedInstructions.add(instruction);
|
||||
return instruction;
|
||||
}
|
||||
@@ -397,9 +408,9 @@ public class TestAbortingHeavyLoadQuery {
|
||||
|
||||
private final Consumer<String> recorder;
|
||||
|
||||
public HeavyLoadInstruction(ProcessorInstructionHandler<Element> handler,
|
||||
ProcessorInstructionPriority priority, long blockDuration, Element result, Consumer<String> recorder) {
|
||||
super(handler, priority, blockDuration, result);
|
||||
public HeavyLoadInstruction(ProcessorInstructionHandler<Element> handler, ProcessorInstructionPriority priority,
|
||||
long stepDuration, int numberOfSteps, Element result, Consumer<String> recorder) {
|
||||
super(handler, priority, stepDuration, numberOfSteps, result);
|
||||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
@@ -414,6 +425,11 @@ public class TestAbortingHeavyLoadQuery {
|
||||
recorder.accept("Starting work for heavy load instruction for " + result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionBeforeAbort() {
|
||||
recorder.accept("Aborting heavy load instruction for " + result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionAfterBlock() {
|
||||
recorder.accept("Finished heavy load instruction for " + result);
|
||||
|
||||
+62
-34
@@ -1,7 +1,9 @@
|
||||
package com.sap.sse.datamining.impl.components;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -13,6 +15,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.datamining.components.AdditionalResultDataBuilder;
|
||||
import com.sap.sse.datamining.components.Processor;
|
||||
import com.sap.sse.datamining.components.ProcessorInstruction;
|
||||
@@ -22,7 +25,7 @@ import com.sap.sse.datamining.test.util.components.StatefulBlockingInstruction;
|
||||
public class TestAbstractParallelProcessorElementProcessing {
|
||||
|
||||
private ThreadPoolExecutor executor;
|
||||
private Processor<Integer, Object> processor;
|
||||
private Processor<Pair<Long, Integer>, Object> processor;
|
||||
private List<StatefulBlockingInstruction<?>> createdInstructions;
|
||||
|
||||
@Before
|
||||
@@ -30,10 +33,13 @@ public class TestAbstractParallelProcessorElementProcessing {
|
||||
int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||
executor = new ThreadPoolExecutor(corePoolSize, corePoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
createdInstructions = new ArrayList<>();
|
||||
processor = new AbstractParallelProcessor<Integer, Object>(Integer.class, Object.class, executor, Collections.emptySet()) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Pair<Long, Integer>> inputType = (Class<Pair<Long, Integer>>)(Class<?>) Pair.class;
|
||||
processor = new AbstractParallelProcessor<Pair<Long, Integer>, Object>(inputType, Object.class, executor, Collections.emptySet()) {
|
||||
@Override
|
||||
protected ProcessorInstruction<Object> createInstruction(Integer sleepTime) {
|
||||
StatefulBlockingInstruction<Object> instruction = new StatefulBlockingInstruction<>(this, sleepTime);
|
||||
protected ProcessorInstruction<Object> createInstruction(Pair<Long, Integer> sleepTime) {
|
||||
StatefulBlockingInstruction<Object> instruction = new StatefulBlockingInstruction<>(this, sleepTime.getA(), sleepTime.getB());
|
||||
createdInstructions.add(instruction);
|
||||
return instruction;
|
||||
}
|
||||
@@ -44,79 +50,101 @@ public class TestAbstractParallelProcessorElementProcessing {
|
||||
|
||||
@Test
|
||||
public void testSimpleProcessing() throws InterruptedException {
|
||||
long stepDuration = 10;
|
||||
int numberOfSteps = 1;
|
||||
Pair<Long, Integer> input = new Pair<Long, Integer>(stepDuration, numberOfSteps);
|
||||
int elementCount = executor.getMaximumPoolSize() * 2;
|
||||
for (int i = 0; i < elementCount; i++) {
|
||||
processor.processElement(10);
|
||||
processor.processElement(input);
|
||||
}
|
||||
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
double executionTime = Math.ceil((double) elementCount / executor.getMaximumPoolSize()) * stepDuration * numberOfSteps;
|
||||
executor.shutdown();
|
||||
assertThat("Executor couldn't terminate", executor.awaitTermination(1, TimeUnit.SECONDS), is(true));
|
||||
assertTrue("Executor couldn't terminate", executor.awaitTermination((long) (executionTime * 1.2), TimeUnit.SECONDS));
|
||||
for (StatefulBlockingInstruction<?> instruction : createdInstructions) {
|
||||
assertThat("run wasn't called", instruction.runWasCalled(), is(true));
|
||||
assertThat("computeResult wasn't called", instruction.computeResultWasCalled(), is(true));
|
||||
assertThat("computeResult didn't finish", instruction.computeResultWasFinished(), is(true));
|
||||
assertTrue("run wasn't called", instruction.runWasCalled());
|
||||
assertTrue("computeResult wasn't called", instruction.computeResultWasCalled());
|
||||
assertTrue("computeResult didn't finish", instruction.computeResultWasFinished());
|
||||
assertFalse("computeResult was aborted", instruction.computeResultWasAborted());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessingAfterFinish() throws InterruptedException {
|
||||
int instructionDuration = 50;
|
||||
long stepDuration = 10;
|
||||
int numberOfSteps = 5;
|
||||
Pair<Long, Integer> input = new Pair<Long, Integer>(stepDuration, numberOfSteps);
|
||||
int elementCount = executor.getMaximumPoolSize() + 1; // Last instruction will be queued
|
||||
for (int i = 0; i < elementCount; i++) {
|
||||
processor.processElement(instructionDuration);
|
||||
processor.processElement(input);
|
||||
}
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
|
||||
Thread.sleep(instructionDuration / 3); // Giving some time to ensure execution of unqueued instructions
|
||||
Thread.sleep(stepDuration); // Giving some time to ensure execution of unqueued instructions
|
||||
Thread finishingThread = ConcurrencyTestsUtil.tryToFinishTheProcessorInAnotherThread(processor);
|
||||
do {
|
||||
Thread.sleep(1);
|
||||
} while (!finishingThread.isAlive());
|
||||
assertThat("Processor is already finished", processor.isFinished(), is(false));
|
||||
assertFalse("Processor is already finished", processor.isFinished());
|
||||
// Processor not yet finished. New elements will be accepted
|
||||
processor.processElement(instructionDuration);
|
||||
processor.processElement(input);
|
||||
elementCount++;
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
|
||||
finishingThread.join(1000);
|
||||
assertThat("Processor isn't finished", processor.isFinished(), is(true));
|
||||
processor.processElement(instructionDuration);
|
||||
finishingThread.join();
|
||||
assertTrue("Processor isn't finished", processor.isFinished());
|
||||
processor.processElement(input);
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
|
||||
for (StatefulBlockingInstruction<?> instruction : createdInstructions) {
|
||||
assertThat("run wasn't called", instruction.runWasCalled(), is(true));
|
||||
assertThat("computeResult wasn't called", instruction.computeResultWasCalled(), is(true));
|
||||
assertThat("computeResult didn't finish", instruction.computeResultWasFinished(), is(true));
|
||||
assertTrue("run wasn't called", instruction.runWasCalled());
|
||||
assertTrue("computeResult wasn't called", instruction.computeResultWasCalled());
|
||||
assertTrue("computeResult didn't finish", instruction.computeResultWasFinished());
|
||||
assertFalse("computeResult was aborted", instruction.computeResultWasAborted());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessingAfterAbort() throws InterruptedException {
|
||||
int instructionDuration = 50;
|
||||
int elementCount = executor.getMaximumPoolSize() + 1; // Last instruction will be queued
|
||||
long stepDuration = 10;
|
||||
int numberOfSteps = 5;
|
||||
Pair<Long, Integer> input = new Pair<Long, Integer>(stepDuration, numberOfSteps);
|
||||
int elementCount = executor.getMaximumPoolSize() // Set of finished instructions
|
||||
+ executor.getMaximumPoolSize() // Set of started, but not yet finished instructions
|
||||
+ 1; // Scheduled instruction
|
||||
for (int i = 0; i < elementCount; i++) {
|
||||
processor.processElement(instructionDuration);
|
||||
processor.processElement(input);
|
||||
}
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
|
||||
Thread.sleep(instructionDuration / 3); // Giving some time to ensure execution of unqueued instructions
|
||||
|
||||
long instructionDuration = stepDuration * numberOfSteps;
|
||||
Thread.sleep(instructionDuration + stepDuration); // Time to finish first set and start second set
|
||||
processor.abort();
|
||||
processor.processElement(0);
|
||||
processor.processElement(new Pair<>(0L, 0));
|
||||
assertThat("Unexpected amount of created instructions", createdInstructions.size(), is(elementCount));
|
||||
|
||||
executor.shutdown();
|
||||
assertThat("Executor couldn't terminate", executor.awaitTermination(1, TimeUnit.SECONDS), is(true));
|
||||
assertTrue("Executor couldn't terminate", executor.awaitTermination(2 * stepDuration, TimeUnit.MILLISECONDS));
|
||||
for (int i = 0; i < createdInstructions.size(); i++) {
|
||||
StatefulBlockingInstruction<?> instruction = createdInstructions.get(i);
|
||||
assertThat("run wasn't called", instruction.runWasCalled(), is(true));
|
||||
// Last instructions was executed after the processor has been aborted. computeResult() should not be called
|
||||
if (i == createdInstructions.size() - 1) {
|
||||
assertThat("computeResult of last instruction was called", instruction.computeResultWasCalled(), is(false));
|
||||
assertThat("computeResult of last instruction finished", instruction.computeResultWasFinished(), is(false));
|
||||
// run should be called for all instructions
|
||||
assertTrue("run wasn't called", instruction.runWasCalled());
|
||||
if (i < executor.getMaximumPoolSize()) {
|
||||
// First set of instructions should be processed normally
|
||||
assertTrue("computeResult wasn't called", instruction.computeResultWasCalled());
|
||||
assertTrue("computeResult didn't finish", instruction.computeResultWasFinished());
|
||||
assertFalse("computeResult was aborted", instruction.computeResultWasAborted());
|
||||
} else if (i < executor.getMaximumPoolSize() * 2) {
|
||||
// Second set of instructions was running when the processor was aborted. computeResult should be aborted
|
||||
assertTrue("computeResult wasn't called", instruction.computeResultWasCalled());
|
||||
assertTrue("computeResult didn't finish", instruction.computeResultWasFinished());
|
||||
assertTrue("computeResult wasn't aborted", instruction.computeResultWasAborted());
|
||||
} else {
|
||||
assertThat("computeResult wasn't called", instruction.computeResultWasCalled(), is(true));
|
||||
assertThat("computeResult didn't finish", instruction.computeResultWasFinished(), is(true));
|
||||
// Last instructions was still scheduled when the processor was aborted. computeResult should not be called
|
||||
assertFalse("computeResult of last instruction was called", instruction.computeResultWasCalled());
|
||||
assertFalse("computeResult of last instruction finished", instruction.computeResultWasFinished());
|
||||
assertFalse("computeResult was aborted", instruction.computeResultWasAborted());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-14
@@ -5,38 +5,54 @@ import com.sap.sse.datamining.impl.components.ProcessorInstructionPriority;
|
||||
|
||||
public class StatefulBlockingInstruction<ResultType> extends StatefulProcessorInstruction<ResultType> {
|
||||
|
||||
protected final long blockDuration;
|
||||
protected final long stepDuration;
|
||||
protected final int numberOfSteps;
|
||||
protected final ResultType result;
|
||||
|
||||
private boolean computeResultWasAborted;
|
||||
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, long blockDuration) {
|
||||
this(handler, 0, blockDuration, null);
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, long stepDuration, int numberOfSteps) {
|
||||
this(handler, 0, stepDuration, numberOfSteps, null);
|
||||
}
|
||||
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, ProcessorInstructionPriority priority, long blockDuration, ResultType result) {
|
||||
this(handler, priority.asIntValue(), blockDuration, result);
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, ProcessorInstructionPriority priority, long stepDuration, int numberOfSteps, ResultType result) {
|
||||
this(handler, priority.asIntValue(), stepDuration, numberOfSteps, result);
|
||||
}
|
||||
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, int priority, long blockDuration, ResultType result) {
|
||||
public StatefulBlockingInstruction(ProcessorInstructionHandler<ResultType> handler, int priority, long stepDuration, int numberOfSteps, ResultType result) {
|
||||
super(handler, priority);
|
||||
this.blockDuration = blockDuration;
|
||||
this.stepDuration = stepDuration;
|
||||
this.numberOfSteps = numberOfSteps;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResultType internalComputeResult() throws Exception {
|
||||
actionBeforeBlock();
|
||||
if (blockDuration > 0) {
|
||||
Thread.sleep(blockDuration);
|
||||
if (getTotalBlockDuration() > 0) {
|
||||
actionBeforeBlock();
|
||||
for (int i = 0; i < numberOfSteps; i++) {
|
||||
if (isAborted()) {
|
||||
actionBeforeAbort();
|
||||
computeResultWasAborted = true;
|
||||
break;
|
||||
}
|
||||
Thread.sleep(stepDuration);
|
||||
}
|
||||
actionAfterBlock();
|
||||
}
|
||||
actionAfterBlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
protected void actionBeforeBlock() { }
|
||||
protected void actionBeforeAbort() { }
|
||||
protected void actionAfterBlock() { }
|
||||
|
||||
public long getBlockDuration() {
|
||||
return blockDuration;
|
||||
public long getTotalBlockDuration() {
|
||||
return stepDuration * numberOfSteps;
|
||||
}
|
||||
|
||||
public boolean computeResultWasAborted() {
|
||||
return computeResultWasAborted;
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -69,6 +69,9 @@ public abstract class AbstractParallelMultiDimensionalNestingGroupingProcessor<D
|
||||
} else {
|
||||
List<GroupKey> keys = new ArrayList<>();
|
||||
for (ParameterizedFunction<?> parameterizedDimension : parameterizedDimensions) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
keys.add(createGroupKeyFor(input, parameterizedDimension.getFunction(), parameterizedDimension.getParameterProvider()));
|
||||
}
|
||||
return new CompoundGroupKey(keys);
|
||||
|
||||
+5
-1
@@ -52,7 +52,7 @@ public abstract class AbstractProcessorInstruction<ResultType> implements Proces
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (!handler.isAborted()) {
|
||||
if (!isAborted()) {
|
||||
ResultType result = computeResult();
|
||||
handler.instructionSucceeded(result);
|
||||
}
|
||||
@@ -62,6 +62,10 @@ public abstract class AbstractProcessorInstruction<ResultType> implements Proces
|
||||
handler.afterInstructionFinished(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAborted() {
|
||||
return handler.isAborted();
|
||||
}
|
||||
|
||||
protected abstract ResultType computeResult() throws Exception;
|
||||
|
||||
|
||||
+3
@@ -38,6 +38,9 @@ public abstract class AbstractRetrievalProcessor<InputType, ResultType> extends
|
||||
@Override
|
||||
public ResultType computeResult() {
|
||||
for (ResultType retrievedElement : retrieveData(element)) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
retrievedDataAmount.incrementAndGet();
|
||||
forwardResultToReceivers(retrievedElement);
|
||||
}
|
||||
|
||||
+3
@@ -82,6 +82,9 @@ public class ParallelGroupedNumberDataAverageAggregationProcessor
|
||||
protected Map<GroupKey, AverageWithStats<Number>> aggregateResult() {
|
||||
Map<GroupKey, AverageWithStats<Number>> result = new HashMap<>();
|
||||
for (Entry<GroupKey, DoubleHolder> sumAggregationEntry : sumPerKey.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new AverageWithStatsImpl<Number>(sumAggregationEntry.getValue().value / elementAmountPerKey.get(key).get(),
|
||||
minPerKey.get(key), maxPerKey.get(key),
|
||||
|
||||
+3
@@ -47,6 +47,9 @@ public class ParallelGroupedNumberDataMedianAggregationProcessor
|
||||
protected Map<GroupKey, Number> aggregateResult() {
|
||||
Map<GroupKey, Number> result = new HashMap<>();
|
||||
for (Entry<GroupKey, List<Number>> groupedValuesEntry : groupedValues.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
result.put(groupedValuesEntry.getKey(), getMedianOf(groupedValuesEntry.getValue()));
|
||||
}
|
||||
return result;
|
||||
|
||||
+3
@@ -90,6 +90,9 @@ public class ParallelGroupedNumberPairAverageAggregationProcessor
|
||||
protected Map<GroupKey, PairWithStats<Number>> aggregateResult() {
|
||||
Map<GroupKey, PairWithStats<Number>> result = new HashMap<>();
|
||||
for (Entry<GroupKey, Pair<Number, Number>> sumAggregationEntry : sumPerKey.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new PairWithStatsImpl<Number>(new Pair<>(sumAggregationEntry.getValue().getA() != null ? sumAggregationEntry.getValue().getA().doubleValue() / elementAmountPerKey.get(key).get() : null, sumAggregationEntry.getValue().getB() != null ? sumAggregationEntry.getValue().getB().doubleValue() / elementAmountPerKey.get(key).get() : null) ,
|
||||
minPerKey.get(key), maxPerKey.get(key),
|
||||
|
||||
+3
@@ -81,6 +81,9 @@ public class ParallelGroupedNumberPairCollectingProcessor
|
||||
protected Map<GroupKey, PairWithStats<Number>> aggregateResult() {
|
||||
Map<GroupKey, PairWithStats<Number>> result = new HashMap<>();
|
||||
for (Entry<GroupKey, HashSet<Pair<Number, Number>>> sumAggregationEntry : individualPairs.entrySet()) {
|
||||
if (isAborted()) {
|
||||
break;
|
||||
}
|
||||
GroupKey key = sumAggregationEntry.getKey();
|
||||
result.put(key, new PairWithStatsImpl<Number>(null,
|
||||
/* min */ null,
|
||||
|
||||
Reference in New Issue
Block a user