SOLR-11670: Use TimeSource's value of NOW consistently when parsing date math.

Add a unit test for TimeSource's epochTime.
This commit is contained in:
Andrzej Bialecki 2018-03-13 13:46:11 +01:00
parent 536e16d3af
commit ed6feded6d
3 changed files with 68 additions and 6 deletions

View File

@ -76,9 +76,11 @@ public class ScheduledTrigger extends TriggerBase {
preferredOp = (String) properties.get(PREFERRED_OP); preferredOp = (String) properties.get(PREFERRED_OP);
// attempt parsing to validate date math strings // attempt parsing to validate date math strings
Instant startTime = parseStartTime(startTimeStr, timeZoneStr); // explicitly set NOW because it may be different for simulated time
DateMathParser.parseMath(null, startTime + everyStr, timeZone); Date now = new Date(TimeUnit.NANOSECONDS.toMillis(cloudManager.getTimeSource().getEpochTime()));
DateMathParser.parseMath(null, startTime + graceDurationStr, timeZone); Instant startTime = parseStartTime(now, startTimeStr, timeZoneStr);
DateMathParser.parseMath(now, startTime + everyStr, timeZone);
DateMathParser.parseMath(now, startTime + graceDurationStr, timeZone);
// We set lastRunAt to be the startTime (which could be a date math expression such as 'NOW') // We set lastRunAt to be the startTime (which could be a date math expression such as 'NOW')
// Ordinarily, NOW will always be evaluated in this constructor so it may seem that // Ordinarily, NOW will always be evaluated in this constructor so it may seem that
@ -88,13 +90,13 @@ public class ScheduledTrigger extends TriggerBase {
this.lastRunAt = startTime; this.lastRunAt = startTime;
} }
private Instant parseStartTime(String startTimeStr, String timeZoneStr) { private Instant parseStartTime(Date now, String startTimeStr, String timeZoneStr) {
if (startTimeStr == null) { if (startTimeStr == null) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'startTime' cannot be null"); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'startTime' cannot be null");
} }
try { try {
// try parsing startTime as an ISO-8601 date time string // try parsing startTime as an ISO-8601 date time string
return DateMathParser.parseMath(null, startTimeStr).toInstant(); return DateMathParser.parseMath(now, startTimeStr).toInstant();
} catch (SolrException e) { } catch (SolrException e) {
if (e.code() != SolrException.ErrorCode.BAD_REQUEST.code) throw e; if (e.code() != SolrException.ErrorCode.BAD_REQUEST.code) throw e;
} }
@ -174,7 +176,7 @@ public class ScheduledTrigger extends TriggerBase {
} }
// Even though we are skipping the event, we need to notify any listeners of the IGNORED stage // Even though we are skipping the event, we need to notify any listeners of the IGNORED stage
// so we create a dummy event with the ignored=true flag and ScheduledTriggers will do the rest // so we create a dummy event with the ignored=true flag and ScheduledTriggers will do the rest
if (processor != null && processor.process(new ScheduledEvent(getEventType(), getName(), nextRunTime.toEpochMilli(), if (processor != null && processor.process(new ScheduledEvent(getEventType(), getName(), timeSource.getTime(),
preferredOp, now.toEpochMilli(), true))) { preferredOp, now.toEpochMilli(), true))) {
lastRunAt = nextRunTime; lastRunAt = nextRunTime;
return; return;

View File

@ -136,6 +136,11 @@ public abstract class TimeSource {
long nano = Math.round((double)TimeUnit.NANOSECONDS.convert(value, fromUnit) / multiplier); long nano = Math.round((double)TimeUnit.NANOSECONDS.convert(value, fromUnit) / multiplier);
return toUnit.convert(nano, TimeUnit.NANOSECONDS); return toUnit.convert(nano, TimeUnit.NANOSECONDS);
} }
@Override
public String toString() {
return super.toString() + ":" + multiplier;
}
} }
/** This instance uses {@link CurrentTimeSource} for generating timestamps. */ /** This instance uses {@link CurrentTimeSource} for generating timestamps. */
@ -196,4 +201,8 @@ public abstract class TimeSource {
public abstract void sleep(long ms) throws InterruptedException; public abstract void sleep(long ms) throws InterruptedException;
public abstract long convertDelay(TimeUnit fromUnit, long value, TimeUnit toUnit); public abstract long convertDelay(TimeUnit fromUnit, long value, TimeUnit toUnit);
public String toString() {
return getClass().getSimpleName();
}
} }

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.common.util;
import org.apache.solr.SolrTestCaseJ4;
import org.junit.Test;
/**
*
*/
public class TestTimeSource extends SolrTestCaseJ4 {
@Test
public void testEpochTime() throws Exception {
doTestEpochTime(TimeSource.CURRENT_TIME);
doTestEpochTime(TimeSource.NANO_TIME);
doTestEpochTime(TimeSource.get("simTime:50"));
}
private void doTestEpochTime(TimeSource ts) throws Exception {
long prevTime = ts.getTime();
long prevEpochTime = ts.getEpochTime();
long delta = 500000000; // 500 ms
for (int i = 0; i < 10; i++) {
ts.sleep(500);
long curTime = ts.getTime();
long curEpochTime = ts.getEpochTime();
long diff = prevTime + delta - curTime;
assertTrue(ts + " time diff=" + diff, diff < 100000);
diff = prevEpochTime + delta - curEpochTime;
assertTrue(ts + " epochTime diff=" + diff, diff < 100000);
prevTime = curTime;
prevEpochTime = curEpochTime;
}
}
}