updateCache methods in MediaLibrary are updating now also mediaTracksByRace

This commit is contained in:
Nils committed 2014-09-08 13:51:42 +02:00
1 parent 377a6e90ae
commit 9b4fb1ac6b
6 files changed
+86 -79

No files matched your search

@@ -81,7 +81,7 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
@Override
public void updateRace(MediaTrack mediaTrack) {
racingEventService().mediaTrackRaceChanged(mediaTrack);
racingEventService().mediaTrackRacesChanged(mediaTrack);
}
@@ -174,7 +174,7 @@ public class MediaLibaryTest {
mediaLibary.addMediaTrack(originalMediaTrack);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(queryStartTime, queryEndTime, null);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(firstQueryResult.size(), is(1));
MediaTrack changedMediaTrack = new MediaTrack();
@@ -183,10 +183,10 @@ public class MediaLibaryTest {
changedMediaTrack.duration = new MillisecondsDurationImpl(100);
mediaLibary.startTimeChanged(changedMediaTrack);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(queryStartTime, queryEndTime, null);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(secondQueryResult.size(), is(0));
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(changedMediaTrack.startTime, changedMediaTrack.deriveEndTime(), null);
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(thirdQueryResult.size(), is(1));
@@ -204,12 +204,12 @@ public class MediaLibaryTest {
mediaLibary.addMediaTrack(mediaTrack);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(originalStartTime, originalEndTime, null);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(firstQueryResult.size(), is(1));
mediaLibary.deleteMediaTrack(mediaTrack);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(originalStartTime, originalEndTime, null);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(secondQueryResult.size(), is(0));
}
@@ -225,7 +225,7 @@ public class MediaLibaryTest {
TimePoint queryStartTime = firstMediaTrack.startTime.plus(1);
TimePoint queryEndTime = firstMediaTrack.deriveEndTime().minus(1);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(queryStartTime, queryEndTime, null);
Set<MediaTrack> firstQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(firstQueryResult.size(), is(1));
MediaTrack secondMediaTrack = new MediaTrack();
@@ -234,13 +234,13 @@ public class MediaLibaryTest {
secondMediaTrack.duration = firstMediaTrack.duration;
mediaLibary.addMediaTrack(secondMediaTrack);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(queryStartTime, queryEndTime, null);
Set<MediaTrack> secondQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(secondQueryResult.size(), is(2));
TimePoint uncachedStartTime = firstMediaTrack.startTime.plus(2);
TimePoint uncachedEndTime = firstMediaTrack.deriveEndTime().minus(2);
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksForRaceInTimeRange(uncachedStartTime, uncachedEndTime, null);
Set<MediaTrack> thirdQueryResult = mediaLibary.findMediaTracksForRace(null);
assertThat(thirdQueryResult.size(), is(2));
}
@@ -255,7 +255,7 @@ public class MediaLibaryTest {
MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, duration, mimeType, regattasAndRaces);
mediaLibary.addMediaTrack(mediaTrack);
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksForRaceInTimeRange(rangeStart, rangeEnd, null);
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksForRace(null);
assertThat(mediaTracks.size(), is(1));
assertThat(mediaTracks.iterator().next().dbId, is(dbId));
}
@@ -271,7 +271,7 @@ public class MediaLibaryTest {
MediaTrack mediaTrack = new MediaTrack(dbId, title, url, startTime, duration, mimeType, regattasAndRaces);
mediaLibary.addMediaTrack(mediaTrack);
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksForRaceInTimeRange(rangeStart, rangeEnd, null);
Collection<MediaTrack> mediaTracks = mediaLibary.findMediaTracksForRace(null);
assertThat(mediaTracks.size(), is(0));
}
@@ -426,7 +426,7 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
void mediaTrackDurationChanged(MediaTrack mediaTrack);
void mediaTrackRaceChanged(MediaTrack mediaTrack);
void mediaTrackRacesChanged(MediaTrack mediaTrack);
void mediaTrackDeleted(MediaTrack mediaTrack);
@@ -9,14 +9,11 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.TimeRange;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.util.impl.LockUtil;
import com.sap.sailing.util.impl.NamedReentrantReadWriteLock;
@@ -35,28 +32,28 @@ class MediaLibrary {
* result in case a MediaTrack is being removed from the library or changes values such that it needs to be removed
* from the cache.
*/
private final ConcurrentMap<TimeRange, Set<MediaTrack>> cacheByInterval = new ConcurrentHashMap<TimeRange, Set<MediaTrack>>();
private final ConcurrentMap<RegattaAndRaceIdentifier, Set<MediaTrack>> cacheByRace = new ConcurrentHashMap<RegattaAndRaceIdentifier, Set<MediaTrack>>();
private final NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock(MediaLibrary.class.getName(), /* fair */ false);
private final ConcurrentMap<RegattaAndRaceIdentifier, Set<MediaTrack>> mediaTrackByRace = new ConcurrentHashMap<RegattaAndRaceIdentifier, Set<MediaTrack>>();
// /**
// * Sort in reverse order of start time! For equal start times compare dbId to distinguish different instances.
// */
// private static final Comparator<MediaTrack> COMPARATOR_BY_REVERSE_STARTTIME = new Comparator<MediaTrack>() {
//
// @Override
// public int compare(MediaTrack mediaTrack1, MediaTrack mediaTrack2) {
// int result = compareDatesAllowingNull(mediaTrack2.startTime, mediaTrack1.startTime);
// if (result == 0) {
// return mediaTrack1.dbId.compareTo(mediaTrack2.dbId);
// } else {
// return result;
// }
// }
//
// };
private final NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock(MediaLibrary.class.getName(), /* fair */
false);
// /**
// * Sort in reverse order of start time! For equal start times compare dbId to distinguish different instances.
// */
// private static final Comparator<MediaTrack> COMPARATOR_BY_REVERSE_STARTTIME = new Comparator<MediaTrack>() {
//
// @Override
// public int compare(MediaTrack mediaTrack1, MediaTrack mediaTrack2) {
// int result = compareDatesAllowingNull(mediaTrack2.startTime, mediaTrack1.startTime);
// if (result == 0) {
// return mediaTrack1.dbId.compareTo(mediaTrack2.dbId);
// } else {
// return result;
// }
// }
//
// };
/**
* NOTE: The implementation of this lookup using simple linear search is a trade off between development effort and
@@ -68,44 +65,44 @@ class MediaLibrary {
* However, considering the expected low number of media entries and the expected high rate of cache hits doesn't
* justify providing a dedicated interval tree implementation (given that there's none readily available).
*
* TODO: A slight performance gain might be achieved assuming that more recent media tracks are requested more frequently
* than older ones. Thus, sorting the list of media tracks by start time and starting linear search from the more
* recent end might reduce loop cycles during linear search. E.g. use a SortedMap with COMPARATOR_BY_REVERSE_STARTTIME commented out above.
* TODO: A slight performance gain might be achieved assuming that more recent media tracks are requested more
* frequently than older ones. Thus, sorting the list of media tracks by start time and starting linear search from
* the more recent end might reduce loop cycles during linear search. E.g. use a SortedMap with
* COMPARATOR_BY_REVERSE_STARTTIME commented out above.
* @param race
* TODO
*
* @param startTime
* @param endTime
* @param race TODO
* @return
*/
Set<MediaTrack> findMediaTracksForRaceInTimeRange(TimePoint startTime, TimePoint endTime, RegattaAndRaceIdentifier race) {
Set<MediaTrack> findMediaTracksForRace(RegattaAndRaceIdentifier race) {
if(race != null){
if (race != null) {
LockUtil.lockForRead(lock);
try{
Set<MediaTrack> cachedMediaTracks = cacheByRace.get(race);
if(cachedMediaTracks == null){
try {
Set<MediaTrack> cachedMediaTracks = mediaTrackByRace.get(race);
if (cachedMediaTracks == null) {
Set<MediaTrack> result = new HashSet<MediaTrack>();
for (MediaTrack mediaTrack : mediaTracksByDbId.values()) {
if(mediaTrack.isConnectedTo(race) && mediaTrack.overlapsWith(startTime, endTime)){
if (mediaTrack.isConnectedTo(race)) {
result.add(mediaTrack);
}
}
cachedMediaTracks = cacheByRace.putIfAbsent(race, result);
if(cachedMediaTracks != null){
cachedMediaTracks = mediaTrackByRace.putIfAbsent(race, result);
if (cachedMediaTracks != null) {
return cachedMediaTracks;
}else{
} else {
return result;
}
}else{
} else {
return cachedMediaTracks;
}
}finally{
} finally {
LockUtil.unlockAfterRead(lock);
}
}
}
//else
// else
return Collections.emptySet();
}
@@ -212,13 +209,13 @@ class MediaLibrary {
LockUtil.unlockAfterWrite(lock);
}
}
void racesChanged(MediaTrack changedMediaTrack) {
LockUtil.lockForWrite(lock);
try {
MediaTrack mediaTrack = mediaTracksByDbId.get(changedMediaTrack);
if (mediaTrack != null) {
mediaTrack.regattasAndRaces.clear();
mediaTrack.regattasAndRaces.clear();
mediaTrack.regattasAndRaces.addAll(changedMediaTrack.regattasAndRaces);
updateCache_Change(mediaTrack);
}
@@ -231,10 +228,16 @@ class MediaLibrary {
* To be called only under write lock!
*/
private void updateCache_Add(MediaTrack mediaTrack) {
for (Entry<TimeRange, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
TimeRange interval = cacheEntry.getKey();
if (mediaTrack.overlapsWith(interval.from(), interval.to())) {
cacheEntry.getValue().add(mediaTrack);
mediaTracksByDbId.put(mediaTrack, mediaTrack);
for (RegattaAndRaceIdentifier regattasAndRaces : mediaTrack.regattasAndRaces) {
if (mediaTrackByRace.containsKey(regattasAndRaces)) {
mediaTrackByRace.get(regattasAndRaces).add(mediaTrack);
} else {
Set<MediaTrack> mediaTracks = new HashSet<MediaTrack>();
mediaTracks.add(mediaTrack);
mediaTrackByRace.put(regattasAndRaces, mediaTracks);
}
}
}
@@ -243,21 +246,25 @@ class MediaLibrary {
* To be called only under write lock!
*/
private void updateCache_Change(MediaTrack mediaTrack) {
for (Entry<TimeRange, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
cacheEntry.getValue().remove(mediaTrack);
TimeRange interval = cacheEntry.getKey();
if (mediaTrack.overlapsWith(interval.from(), interval.to())) {
cacheEntry.getValue().add(mediaTrack);
}
}
updateCache_Remove(mediaTrack);
updateCache_Add(mediaTrack);
}
/**
* To be called only under write lock!
*/
private void updateCache_Remove(MediaTrack mediaTrack) {
for (Entry<TimeRange, Set<MediaTrack>> cacheEntry : cacheByInterval.entrySet()) {
cacheEntry.getValue().remove(mediaTrack);
mediaTracksByDbId.remove(mediaTrack);
for (RegattaAndRaceIdentifier regattaAndRace : mediaTrack.regattasAndRaces) {
Set<MediaTrack> mediaTracks = mediaTrackByRace.get(regattaAndRace);
if(mediaTracks != null){
mediaTracks.remove(mediaTrack);
if(mediaTracks.size()==0){
mediaTrackByRace.remove(regattaAndRace);
}
}
}
}
@@ -291,7 +298,7 @@ class MediaLibrary {
LockUtil.lockForWrite(lock);
try {
mediaTracksByDbId.clear();
cacheByInterval.clear();
mediaTrackByRace.clear();
} finally {
LockUtil.unlockAfterWrite(lock);
}
@@ -175,7 +175,7 @@ import com.sap.sailing.server.operationaltransformation.TrackRegatta;
import com.sap.sailing.server.operationaltransformation.UpdateCompetitor;
import com.sap.sailing.server.operationaltransformation.UpdateMarkPassings;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackDurationOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackRaceOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackRacesOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackStartTimeOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackTitleOperation;
import com.sap.sailing.server.operationaltransformation.UpdateMediaTrackUrlOperation;
@@ -2470,10 +2470,10 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
}
@Override
public void mediaTrackRaceChanged(MediaTrack mediaTrack) {
public void mediaTrackRacesChanged(MediaTrack mediaTrack) {
mediaDB.updateRace(mediaTrack.dbId, mediaTrack.regattasAndRaces);
mediaLibrary.racesChanged(mediaTrack);
replicate(new UpdateMediaTrackRaceOperation(mediaTrack));
replicate(new UpdateMediaTrackRacesOperation(mediaTrack));
}
@Override
@@ -2525,7 +2525,7 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
} else {
TimePoint raceStart = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace();
TimePoint raceEnd = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace();
return mediaLibrary.findMediaTracksForRaceInTimeRange(raceStart, raceEnd, trackedRace.getRaceIdentifier());
return mediaLibrary.findMediaTracksForRace(trackedRace.getRaceIdentifier());
}
} else {
return Collections.emptyList();
@@ -3,17 +3,17 @@ package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.server.RacingEventService;
public class UpdateMediaTrackRaceOperation extends AbstractMediaTrackOperation {
public class UpdateMediaTrackRacesOperation extends AbstractMediaTrackOperation {
private static final long serialVersionUID = 1L;
public UpdateMediaTrackRaceOperation(MediaTrack mediaTrack) {
public UpdateMediaTrackRacesOperation(MediaTrack mediaTrack) {
super(mediaTrack);
}
@Override
public Void internalApplyTo(RacingEventService toState) throws Exception {
toState.mediaTrackRaceChanged(this.mediaTrack);
toState.mediaTrackRacesChanged(this.mediaTrack);
return null;
}