diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index ba1fb22d59e..413ed9fe889 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -230,12 +230,28 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { public DBCollection getGPSFixCollection() { DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name()); + + // Removes an old index not needed anymore + dropIndexSafe(gpsFixCollection, "DEVICE_ID.DEVICE_TYPE_SPECIFIC_ID_1_GPSFIX.TIME_AS_MILLIS_1"); + DBObject index = new BasicDBObject(); - index.put(FieldNames.DEVICE_ID.name()+"."+FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), 1); + index.put(FieldNames.DEVICE_ID.name(), 1); index.put(FieldNames.GPSFIX.name()+"."+FieldNames.TIME_AS_MILLIS.name(), 1); gpsFixCollection.createIndex(index); return gpsFixCollection; } + + /** + * Dropping an index that does not exist causes an exception. This method first checks if the index exist to prevent + * an exception from occurring. + */ + private void dropIndexSafe(DBCollection collection, String indexName) { + collection.getIndexInfo().forEach(indexInfo -> { + if (indexName.equals(indexInfo.get("name"))) { + collection.dropIndex(indexName); + } + }); + } public DBCollection getGPSFixMetadataCollection() { DBCollection collection = database.getCollection(CollectionNames.GPS_FIXES_METADATA.name()); diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java index cecb5e7ae62..d9cf59b0009 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java @@ -11,7 +11,6 @@ import java.util.Map; import java.util.Set; import java.util.function.BooleanSupplier; import java.util.function.Consumer; -import java.util.function.UnaryOperator; import java.util.logging.Level; import java.util.logging.Logger; @@ -32,6 +31,7 @@ import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler; import com.sap.sailing.domain.persistence.racelog.tracking.MongoSensorFixStore; import com.sap.sailing.domain.racelog.tracking.FixReceivedListener; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; +import com.sap.sse.common.Duration; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimeRange; @@ -94,13 +94,13 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore { @Override public boolean loadOldestFix(Consumer consumer, DeviceIdentifier device, TimeRange timeRangeToLoad) throws NoCorrespondingServiceRegisteredException, TransformationException { return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, () -> false, (d) -> { - }, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* ascending */ 1)).limit(1)); + }, true, true); } @Override public boolean loadYoungestFix(Consumer consumer, DeviceIdentifier device, TimeRange timeRangeToLoad) throws NoCorrespondingServiceRegisteredException, TransformationException { return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, () -> false, (d) -> { - }, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* descending */ -1)).limit(1)); + }, false, true); } @Override @@ -115,19 +115,19 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore { TimePoint to, boolean inclusive, BooleanSupplier isPreemptiveStopped, Consumer progressConsumer) throws NoCorrespondingServiceRegisteredException, TransformationException { loadFixes(consumer, device, from, to, inclusive, isPreemptiveStopped, progressConsumer, - UnaryOperator.identity()); + true, false); } private boolean loadFixes(Consumer consumer, DeviceIdentifier device, TimePoint from, TimePoint to, boolean inclusive, BooleanSupplier isPreemptiveStopped, Consumer progressConsumer, - UnaryOperator dbCursorCallback) + boolean ascending, boolean onlyOneResult) throws NoCorrespondingServiceRegisteredException, TransformationException { progressConsumer.accept(0d); final TimePoint loadFixesFrom = from == null ? TimePoint.BeginningOfTime : from; final TimePoint loadFixesTo = to == null ? TimePoint.EndOfTime : to; - Object dbDeviceId = storeDeviceId(deviceServiceFinder, device); + DBObject dbDeviceId = storeDeviceId(deviceServiceFinder, device); final QueryBuilder queryBuilder = QueryBuilder.start(FieldNames.DEVICE_ID.name()).is(dbDeviceId) .and(FieldNames.TIME_AS_MILLIS.name()); if (inclusive) { @@ -138,27 +138,35 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore { .lessThan(loadFixesTo.asMillis()); } DBObject query = queryBuilder.get(); - DBCursor result = dbCursorCallback.apply(fixesCollection.find(query)); + DBCursor result = fixesCollection.find(query); + result.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), ascending ? 1 : -1)); + if (onlyOneResult) { + result.limit(1); + } boolean fixLoaded = false; - double max = result.size(); - // update roughly every percent, but at not more often than every 100th entry - int reportIncrement = (int) Math.max(max / 100, 100); - int current = 0; + final Duration totalDurationToLoad = loadFixesFrom.until(loadFixesTo); + // Given that fixes are recorded with a rate of 10/s we update the progress every 10*60*5=3000 fixes. + final Duration minimumDurationBetweenProgressUpdates = Util.max(totalDurationToLoad.divide(20), Duration.ONE_MINUTE.times(5)); + TimePoint nextProgressUpdateAt = ascending + ? loadFixesFrom.plus(minimumDurationBetweenProgressUpdates) + : loadFixesTo.minus(minimumDurationBetweenProgressUpdates); for (DBObject fixObject : result) { - current++; - - if (current % reportIncrement == 0) { - progressConsumer.accept(current / max); - if (isPreemptiveStopped.getAsBoolean()) { - logger.log(Level.WARNING, "Exiting because of preemtive stop requested " + fixObject); - return fixLoaded; - } - } try { - @SuppressWarnings("unchecked") - FixT fix = (FixT) loadFix(fixObject); + FixT fix = loadFix(fixObject); consumer.accept(fix); fixLoaded = true; + TimePoint fixTimePoint = fix.getTimePoint(); + if (ascending ? fixTimePoint.after(nextProgressUpdateAt) : fixTimePoint.before(nextProgressUpdateAt)) { + final Duration durationAlreadyLoaded = ascending ? loadFixesFrom.until(fixTimePoint) : fixTimePoint.until(loadFixesTo); + progressConsumer.accept(durationAlreadyLoaded.divide(totalDurationToLoad)); + nextProgressUpdateAt = ascending + ? fixTimePoint.plus(minimumDurationBetweenProgressUpdates) + : fixTimePoint.minus(minimumDurationBetweenProgressUpdates); + if (isPreemptiveStopped.getAsBoolean()) { + logger.log(Level.WARNING, "Exiting because of preemtive stop requested " + fixObject); + return fixLoaded; + } + } } catch (TransformationException e) { logger.log(Level.WARNING, "Could not read fix from MongoDB: " + fixObject); } catch (ClassCastException e) { diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java index e924a000a45..50f0204d706 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java @@ -106,17 +106,17 @@ public class SensorFixStoreTest { } @Test - public void testFew() throws Exception { + public void testProgressFew() throws Exception { testProgress(80); } @Test - public void testLittle() throws Exception { + public void testProgressLittle() throws Exception { testProgress(109); } @Test - public void testProgressMay() throws Exception { + public void testProgressMany() throws Exception { testProgress(2000); }