diff options
49 files changed, 365 insertions, 839 deletions
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java index 6b40577b1b0..56fe679fc6a 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java @@ -882,11 +882,11 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd */ private void scheduleVersionDependentTasksForFutureCompletion(int completeAtVersion) { // TODO expose and use monotonic clock instead of system clock - final long deadlineTimePointMs = timer.getCurrentTimeInMillis() + options.getMaxDeferredTaskVersionWaitTime().toMillis(); + final long maxDeadlineTimePointMs = timer.getCurrentTimeInMillis() + options.getMaxDeferredTaskVersionWaitTime().toMillis(); for (RemoteClusterControllerTask task : tasksPendingStateRecompute) { log.finest(() -> String.format("Adding task of type '%s' to be completed at version %d", task.getClass().getName(), completeAtVersion)); - taskCompletionQueue.add(new VersionDependentTaskCompletion(completeAtVersion, task, deadlineTimePointMs)); + taskCompletionQueue.add(new VersionDependentTaskCompletion(completeAtVersion, task, maxDeadlineTimePointMs)); } tasksPendingStateRecompute.clear(); } diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java index e96209c083a..8382e127e13 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java @@ -5,6 +5,9 @@ import com.yahoo.vdslib.state.ClusterState; import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener; import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler; +import java.time.Instant; +import java.util.Optional; + public abstract class RemoteClusterControllerTask { public static class Context { @@ -65,6 +68,10 @@ public abstract class RemoteClusterControllerTask { */ public void handleFailure(FailureCondition condition) {} + public Optional<Instant> getDeadline() { + return Optional.empty(); + } + public boolean isCompleted() { synchronized (monitor) { return completed; diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/VersionDependentTaskCompletion.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/VersionDependentTaskCompletion.java index 5d6a4f66467..28df5a8e35a 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/VersionDependentTaskCompletion.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/VersionDependentTaskCompletion.java @@ -16,10 +16,12 @@ class VersionDependentTaskCompletion { private final RemoteClusterControllerTask task; private final long deadlineTimePointMs; - VersionDependentTaskCompletion(long minimumVersion, RemoteClusterControllerTask task, long deadlineTimePointMs) { + VersionDependentTaskCompletion(long minimumVersion, RemoteClusterControllerTask task, long maxDeadlineTimePointMs) { this.minimumVersion = minimumVersion; this.task = task; - this.deadlineTimePointMs = deadlineTimePointMs; + this.deadlineTimePointMs = task.getDeadline().map(deadline -> + Math.max(0, Math.min(deadline.toEpochMilli(), maxDeadlineTimePointMs))) + .orElse(maxDeadlineTimePointMs); } long getMinimumVersion() { @@ -30,7 +32,9 @@ class VersionDependentTaskCompletion { return task; } - long getDeadlineTimePointMs() { return deadlineTimePointMs; } + long getDeadlineTimePointMs() { + return deadlineTimePointMs; + } @Override public boolean equals(Object o) { diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java index 849d8cc6e7b..4d6738940a8 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.clustercontroller.core.restapiv2.requests; import com.yahoo.log.LogLevel; +import com.yahoo.time.TimeBudget; import com.yahoo.vdslib.state.ClusterState; import com.yahoo.vdslib.state.Node; import com.yahoo.vdslib.state.NodeState; @@ -21,8 +22,10 @@ import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStat import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse; import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; +import java.time.Instant; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.logging.Logger; public class SetNodeStateRequest extends Request<SetResponse> { @@ -33,6 +36,7 @@ public class SetNodeStateRequest extends Request<SetResponse> { private final SetUnitStateRequest.Condition condition; private final SetUnitStateRequest.ResponseWait responseWait; private final WantedStateSetter wantedState; + private final TimeBudget timeBudget; public SetNodeStateRequest(Id.Node id, SetUnitStateRequest setUnitStateRequest) { this(id, setUnitStateRequest, SetNodeStateRequest::setWantedState); @@ -46,6 +50,7 @@ public class SetNodeStateRequest extends Request<SetResponse> { this.condition = setUnitStateRequest.getCondition(); this.responseWait = setUnitStateRequest.getResponseWait(); this.wantedState = wantedState; + this.timeBudget = setUnitStateRequest.timeBudget(); } @Override @@ -79,6 +84,11 @@ public class SetNodeStateRequest extends Request<SetResponse> { } @Override + public Optional<Instant> getDeadline() { + return timeBudget.deadline(); + } + + @Override public boolean isFailed() { // Failure to set a node state is propagated as a 200 with wasModified false. return super.isFailed() || (resultSet && !result.getWasModified()); diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java index 1246ba62313..b4d189bcd55 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.core.restapiv2.requests; +import com.yahoo.time.TimeBudget; import com.yahoo.vdslib.distribution.ConfiguredNode; import com.yahoo.vdslib.state.Node; import com.yahoo.vdslib.state.NodeType; @@ -14,7 +15,9 @@ import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStat import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse; import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; +import java.time.Instant; import java.util.Map; +import java.util.Optional; import java.util.logging.Logger; public class SetNodeStatesForClusterRequest extends Request<SetResponse> { @@ -23,6 +26,7 @@ public class SetNodeStatesForClusterRequest extends Request<SetResponse> { private final Id.Cluster cluster; private final Map<String, UnitState> newStates; private final SetUnitStateRequest.Condition condition; + private final TimeBudget timeBudget; public SetNodeStatesForClusterRequest(Id.Cluster cluster, SetUnitStateRequest request) { @@ -30,6 +34,7 @@ public class SetNodeStatesForClusterRequest extends Request<SetResponse> { this.cluster = cluster; this.newStates = request.getNewState(); this.condition = request.getCondition(); + this.timeBudget = request.timeBudget(); } @Override @@ -80,6 +85,11 @@ public class SetNodeStatesForClusterRequest extends Request<SetResponse> { } @Override + public Optional<Instant> getDeadline() { + return timeBudget.deadline(); + } + + @Override public boolean isFailed() { // Failure to set a node state is propagated as a 200 with wasModified false. return super.isFailed() || (resultSet && !result.getWasModified()); diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/SetNodeStateTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/SetNodeStateTest.java index 3f977273054..f3a4be5ac2f 100644 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/SetNodeStateTest.java +++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/SetNodeStateTest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.core.restapiv2; +import com.yahoo.time.TimeBudget; import com.yahoo.vdslib.state.NodeType; import com.yahoo.vespa.clustercontroller.core.MasterInterface; import com.yahoo.vespa.clustercontroller.core.RemoteClusterControllerTask; @@ -20,6 +21,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import java.time.Clock; +import java.time.Duration; import java.util.LinkedHashMap; import java.util.Map; @@ -42,6 +45,7 @@ public class SetNodeStateTest extends StateRestApiTest { private Map<String, UnitState> newStates = new LinkedHashMap<>(); private Condition condition = Condition.FORCE; private ResponseWait responseWait = ResponseWait.WAIT_UNTIL_CLUSTER_ACKED; + private TimeBudget timeBudget = TimeBudget.fromNow(Clock.systemUTC(), Duration.ofSeconds(10)); public SetUnitStateRequestImpl(String req) { super(req, 0); @@ -89,6 +93,11 @@ public class SetNodeStateTest extends StateRestApiTest { public ResponseWait getResponseWait() { return responseWait; } + + @Override + public TimeBudget timeBudget() { + return timeBudget; + } } private void verifyStateSet(String state, String reason) throws Exception { diff --git a/clustercontroller-utils/pom.xml b/clustercontroller-utils/pom.xml index ecfc6df3bd0..e176ce9d1e5 100644 --- a/clustercontroller-utils/pom.xml +++ b/clustercontroller-utils/pom.xml @@ -40,6 +40,11 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <scope>provided</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java index d583e4ecc27..a28ddb3539b 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/requests/SetUnitStateRequest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.utils.staterestapi.requests; +import com.yahoo.time.TimeBudget; import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidContentException; import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; @@ -62,4 +63,5 @@ public interface SetUnitStateRequest extends UnitRequest { } ResponseWait getResponseWait(); + TimeBudget timeBudget(); } diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java index 3d0856669f1..d871a8ed6bc 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/JsonReader.java @@ -12,7 +12,6 @@ import java.util.HashMap; import java.util.Map; public class JsonReader { - private static class UnitStateImpl implements UnitState { private final String id; private final String reason; @@ -37,7 +36,9 @@ public class JsonReader { final Map<String, UnitState> stateMap; final SetUnitStateRequest.Condition condition; final SetUnitStateRequest.ResponseWait responseWait; - public SetRequestData(Map<String, UnitState> stateMap, SetUnitStateRequest.Condition condition, + + public SetRequestData(Map<String, UnitState> stateMap, + SetUnitStateRequest.Condition condition, SetUnitStateRequest.ResponseWait responseWait) { this.stateMap = stateMap; this.condition = condition; @@ -98,7 +99,7 @@ public class JsonReader { } stateMap.put(type, new UnitStateImpl(code, reason)); } + return new SetRequestData(stateMap, condition, responseWait); } - } diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java index 71e6bc36de1..d3cab74c66f 100644 --- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java +++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandler.java @@ -1,33 +1,52 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.utils.staterestapi.server; +import com.google.common.util.concurrent.UncheckedTimeoutException; import com.yahoo.log.LogLevel; -import com.yahoo.yolean.Exceptions; +import com.yahoo.time.TimeBudget; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequestHandler; import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; import com.yahoo.vespa.clustercontroller.utils.communication.http.JsonHttpResult; import com.yahoo.vespa.clustercontroller.utils.staterestapi.StateRestAPI; -import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.*; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.DeadlineExceededException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidContentException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidOptionValueException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.OtherMasterException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.StateRestApiException; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.UnknownMasterException; import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStateRequest; import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.UnitStateRequest; -import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.*; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitResponse; +import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.UnitState; +import com.yahoo.yolean.Exceptions; -import java.util.*; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; public class RestApiHandler implements HttpRequestHandler { + public static final Duration MAX_TIMEOUT = Duration.ofHours(1); private final static Logger log = Logger.getLogger(RestApiHandler.class.getName()); private final StateRestAPI restApi; private final JsonWriter jsonWriter; private final JsonReader jsonReader = new JsonReader(); + private final Clock clock; public RestApiHandler(StateRestAPI restApi) { this.restApi = restApi; this.jsonWriter = new JsonWriter(); + this.clock = Clock.systemUTC(); } public RestApiHandler setDefaultPathPrefix(String defaultPathPrefix) { @@ -43,6 +62,8 @@ public class RestApiHandler implements HttpRequestHandler { @Override public HttpResult handleRequest(HttpRequest request) { + Instant start = clock.instant(); + try{ final String[] unitPath = createUnitPath(request); if (request.getHttpOperation().equals(HttpRequest.HttpOp.GET)) { @@ -60,6 +81,7 @@ public class RestApiHandler implements HttpRequestHandler { return new JsonHttpResult().setJson(jsonWriter.createJson(data)); } else { final JsonReader.SetRequestData setRequestData = jsonReader.getStateRequestData(request); + final Optional<Duration> timeout = parseTimeout(request.getOption("timeout", null)); SetResponse setResponse = restApi.setUnitState(new SetUnitStateRequest() { @Override public Map<String, UnitState> getNewState() { @@ -73,6 +95,8 @@ public class RestApiHandler implements HttpRequestHandler { public Condition getCondition() { return setRequestData.condition; } @Override public ResponseWait getResponseWait() { return setRequestData.responseWait; } + @Override + public TimeBudget timeBudget() { return TimeBudget.from(clock, start, timeout); } }); return new JsonHttpResult().setJson(jsonWriter.createJson(setResponse)); } @@ -89,7 +113,7 @@ public class RestApiHandler implements HttpRequestHandler { result.setHttpCode(503, "Service Unavailable"); result.setJson(jsonWriter.createErrorJson(exception.getMessage())); return result; - } catch (DeadlineExceededException exception) { + } catch (DeadlineExceededException | UncheckedTimeoutException exception) { logRequestException(request, exception, Level.WARNING); JsonHttpResult result = new JsonHttpResult(); result.setHttpCode(504, "Gateway Timeout"); @@ -172,4 +196,24 @@ public class RestApiHandler implements HttpRequestHandler { return value; } + static Optional<Duration> parseTimeout(String timeoutOption) throws InvalidContentException { + if (timeoutOption == null) { + return Optional.empty(); + } + + float timeoutSeconds; + try { + timeoutSeconds = Float.parseFloat(timeoutOption); + } catch (NumberFormatException e) { + throw new InvalidContentException("value of timeout->" + timeoutOption + " is not a float"); + } + + if (timeoutSeconds <= 0.0) { + return Optional.of(Duration.ZERO); + } else if (timeoutSeconds <= MAX_TIMEOUT.getSeconds()) { + return Optional.of(Duration.ofMillis(Math.round(timeoutSeconds * 1000))); + } else { + throw new InvalidContentException("value of timeout->" + timeoutOption + " exceeds max timeout " + MAX_TIMEOUT); + } + } } diff --git a/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandlerTest.java b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandlerTest.java new file mode 100644 index 00000000000..f7f109fffc8 --- /dev/null +++ b/clustercontroller-utils/src/test/java/com/yahoo/vespa/clustercontroller/utils/staterestapi/server/RestApiHandlerTest.java @@ -0,0 +1,20 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.clustercontroller.utils.staterestapi.server; + +import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.InvalidContentException; +import org.junit.Test; + +import java.time.Duration; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; + +public class RestApiHandlerTest { + @Test + public void testParsingOfTimeout() throws InvalidContentException { + assertEquals(Optional.empty(), RestApiHandler.parseTimeout(null)); + assertEquals(Optional.of(Duration.ofMillis(12500)), RestApiHandler.parseTimeout("12.5")); + assertEquals(Optional.of(Duration.ofMillis(0)), RestApiHandler.parseTimeout("-1")); + assertEquals(Optional.of(Duration.ofMillis(0)), RestApiHandler.parseTimeout("0.0001")); + } +}
\ No newline at end of file diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java index e182b11522b..4738249b420 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java @@ -11,7 +11,7 @@ import java.util.logging.Level; * and {@link com.yahoo.config.provision.Provisioner}, is that this interface only exposes methods needed * to build the model. * - * @author lulf + * @author Ulf Lilleengen */ public interface HostProvisioner { diff --git a/config-model/src/main/java/com/yahoo/vespa/documentmodel/SummaryTransform.java b/config-model/src/main/java/com/yahoo/vespa/documentmodel/SummaryTransform.java index 082265c7694..4f85dd0c84e 100644 --- a/config-model/src/main/java/com/yahoo/vespa/documentmodel/SummaryTransform.java +++ b/config-model/src/main/java/com/yahoo/vespa/documentmodel/SummaryTransform.java @@ -24,7 +24,7 @@ public enum SummaryTransform { private String name; - private SummaryTransform(String name) { + SummaryTransform(String name) { this.name=name; } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ReloadHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ReloadHandler.java index b493e2c7bc6..93af4b1d593 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ReloadHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ReloadHandler.java @@ -9,8 +9,7 @@ import java.util.Set; /** * Interface representing a reload handler. * - * @author lulf - * @since 5.1.24 + * @author Ulf Lilleengen */ public interface ReloadHandler { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java index 68704eeb66a..f9f84de1cfb 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java @@ -360,8 +360,8 @@ public class ZooKeeperClient { } } - public void write(AllocatedHosts info) throws IOException { - configCurator.putData(rootPath.append(ZKApplicationPackage.allocatedHostsNode).getAbsolute(), info.toJson()); + public void write(AllocatedHosts hosts) throws IOException { + configCurator.putData(rootPath.append(ZKApplicationPackage.allocatedHostsNode).getAbsolute(), hosts.toJson()); } public void write(Map<Version, FileRegistry> fileRegistryMap) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java index 9374d68a6ac..bc7c428833b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java @@ -62,7 +62,7 @@ public class RemoteSession extends Session { return ApplicationSet.fromList(applicationLoader.buildModels(zooKeeperClient.readApplicationId(), zooKeeperClient.readVespaVersion(), - zooKeeperClient.loadApplicationPackage(), + applicationPackage, new SettableOptional<>(allocatedHosts), clock.instant())); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java index 8d7023fef5b..f30a58cffea 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandler.java @@ -123,7 +123,7 @@ public class TenantRequestHandler implements RequestHandler, ReloadHandler, Host private void setLiveApp(ApplicationSet applicationSet) { ApplicationId id = applicationSet.getId(); - final Collection<String> hostsForApp = applicationSet.getAllHosts(); + Collection<String> hostsForApp = applicationSet.getAllHosts(); hostRegistry.update(id, hostsForApp); applicationSet.updateHostMetrics(); tenantMetricUpdater.setApplications(applicationMapper.numApplications()); diff --git a/container-dependencies-enforcer/pom.xml b/container-dependencies-enforcer/pom.xml index fa55908befe..f693517c844 100644 --- a/container-dependencies-enforcer/pom.xml +++ b/container-dependencies-enforcer/pom.xml @@ -88,6 +88,7 @@ <include>com.google.inject.extensions:guice-assistedinject:[${guice.version}]:jar:provided</include> <include>com.google.inject.extensions:guice-multibindings:[${guice.version}]:jar:provided</include> <include>com.google.inject:guice:[${guice.version}]:jar:provided:no_aop</include> + <include>com.sun.activation:javax.activation:jar[1.2.0]:jar:provided</include> <include>commons-codec:commons-codec:[1.4]:jar:provided</include> <include>commons-daemon:commons-daemon:[1.0.3]:jar:provided</include> <include>commons-logging:commons-logging:[1.1.1]:jar:provided</include> @@ -96,6 +97,7 @@ <include>javax.servlet:javax.servlet-api:[3.1.0]:jar:provided</include> <include>javax.validation:validation-api:[${javax.validation-api.version}]:jar:provided</include> <include>javax.ws.rs:javax.ws.rs-api:[${javax.ws.rs-api.version}]:jar:provided</include> + <include>javax.xml.bind:jaxb-api:[${jaxb.version}]:jar:provided</include> <include>net.jcip:jcip-annotations:[1.0]:jar:provided</include> <include>net.jpountz.lz4:lz4:[1.3.0]:jar:provided</include> <include>org.apache.felix:org.apache.felix.framework:[${felix.version}]:jar:provided</include> diff --git a/container-dependency-versions/pom.xml b/container-dependency-versions/pom.xml index 4d9c1e94ed9..195e66902db 100644 --- a/container-dependency-versions/pom.xml +++ b/container-dependency-versions/pom.xml @@ -186,7 +186,7 @@ <version>${javax.ws.rs-api.version}</version> </dependency> - <!-- TODO: upgrade jaxb-api artifacts to >=2.3.0. Note that from 2.3, these are OSGi bundles. + <!-- TODO: upgrade jaxb-api artifacts to >=2.3.0. See https://stackoverflow.com/questions/50237516/proper-fix-for-java-10-complaining-about-illegal-reflection-access-by-jaxb-impl --> <dependency> <groupId>javax.xml.bind</groupId> @@ -204,10 +204,11 @@ <version>${jaxb.version}</version> </dependency> <dependency> - <groupId>javax.activation</groupId> - <artifactId>javax.activation-api</artifactId> + <groupId>com.sun.activation</groupId> + <artifactId>javax.activation</artifactId> <version>1.2.0</version> </dependency> + <!-- jaxb end --> <dependency> <groupId>net.jcip</groupId> @@ -456,7 +457,7 @@ <findbugs.version>1.3.9</findbugs.version> <guava.version>18.0</guava.version> <guice.version>3.0</guice.version> - <jaxb.version>2.2.7</jaxb.version> + <jaxb.version>2.3.0</jaxb.version> <jetty.version>9.4.10.v20180503</jetty.version> <slf4j.version>1.7.5</slf4j.version> diff --git a/container-search/src/main/java/com/yahoo/search/federation/vespa/ResultBuilder.java b/container-search/src/main/java/com/yahoo/search/federation/vespa/ResultBuilder.java index 71971b56ef1..dd20472474d 100644 --- a/container-search/src/main/java/com/yahoo/search/federation/vespa/ResultBuilder.java +++ b/container-search/src/main/java/com/yahoo/search/federation/vespa/ResultBuilder.java @@ -10,7 +10,6 @@ import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.Relevance; import com.yahoo.text.XML; -import com.yahoo.text.DoubleParser; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; @@ -472,7 +471,7 @@ public class ResultBuilder extends DefaultHandler { //We try to get either uri or documentID and use that as id Object docId = extractDocumentID(); Hit newHit = new Hit(docId.toString()); - if (hitRelevance != null) newHit.setRelevance(new Relevance(DoubleParser.parse(hitRelevance))); + if (hitRelevance != null) newHit.setRelevance(new Relevance(Double.parseDouble(hitRelevance))); if(hitSource != null) newHit.setSource(hitSource); if(hitType != null) { for(String type: hitType.split(" ")) { diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java index 410f10edda8..1af78982b9c 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java @@ -42,23 +42,23 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber } public static QueryProfileRegistry createFromConfig(QueryProfilesConfig config) { - QueryProfileRegistry registry=new QueryProfileRegistry(); + QueryProfileRegistry registry = new QueryProfileRegistry(); // Pass 1: Create all profiles and profile types for (QueryProfilesConfig.Queryprofiletype profileTypeConfig : config.queryprofiletype()) { - createProfileType(profileTypeConfig,registry.getTypeRegistry()); + createProfileType(profileTypeConfig, registry.getTypeRegistry()); } for (QueryProfilesConfig.Queryprofile profileConfig : config.queryprofile()) { - createProfile(profileConfig,registry); + createProfile(profileConfig, registry); } // Pass 2: Resolve references and add content for (QueryProfilesConfig.Queryprofiletype profileTypeConfig : config.queryprofiletype()) { - fillProfileType(profileTypeConfig,registry.getTypeRegistry()); + fillProfileType(profileTypeConfig, registry.getTypeRegistry()); } - // To ensure topological sorting, using DPS. This will _NOT_ detect cycles (but it will not fail if they - // exist either) + // To ensure topological sorting, using DPS. This will _NOT_ detect cycles + // (but it will not fail if they exist) Set<ComponentId> filled = new HashSet<>(); for (QueryProfilesConfig.Queryprofile profileConfig : config.queryprofile()) { fillProfile(profileConfig, config, registry, filled); @@ -73,29 +73,29 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber subscriber.close(); } - private static void createProfile(QueryProfilesConfig.Queryprofile config,QueryProfileRegistry registry) { - QueryProfile profile=new QueryProfile(config.id()); + private static void createProfile(QueryProfilesConfig.Queryprofile config, QueryProfileRegistry registry) { + QueryProfile profile = new QueryProfile(config.id()); try { - String typeId=config.type(); - if (typeId!=null && !typeId.isEmpty()) + String typeId = config.type(); + if (typeId != null && ! typeId.isEmpty()) profile.setType(registry.getType(typeId)); if (config.dimensions().size()>0) { - String[] dimensions=new String[config.dimensions().size()]; - for (int i=0; i<config.dimensions().size(); i++) - dimensions[i]=config.dimensions().get(i); + String[] dimensions = new String[config.dimensions().size()]; + for (int i = 0; i < config.dimensions().size(); i++) + dimensions[i] = config.dimensions().get(i); profile.setDimensions(dimensions); } registry.register(profile); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid " + profile,e); + throw new IllegalArgumentException("Invalid " + profile, e); } } private static void createProfileType(QueryProfilesConfig.Queryprofiletype config, QueryProfileTypeRegistry registry) { - QueryProfileType type=new QueryProfileType(config.id()); + QueryProfileType type = new QueryProfileType(config.id()); type.setStrict(config.strict()); type.setMatchAsPath(config.matchaspath()); registry.register(type); @@ -105,46 +105,46 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber QueryProfilesConfig queryProfilesConfig, QueryProfileRegistry registry, Set<ComponentId> filled) { - QueryProfile profile=registry.getComponent(new ComponentSpecification(config.id()).toId()); + QueryProfile profile = registry.getComponent(new ComponentSpecification(config.id()).toId()); if (filled.contains(profile.getId())) return; filled.add(profile.getId()); try { for (String inheritedId : config.inherit()) { - QueryProfile inherited=registry.getComponent(inheritedId); - if (inherited==null) + QueryProfile inherited = registry.getComponent(inheritedId); + if (inherited == null) throw new IllegalArgumentException("Inherited query profile '" + inheritedId + "' in " + profile + " was not found"); fillProfile(inherited, queryProfilesConfig, registry, filled); profile.addInherited(inherited); } for (QueryProfilesConfig.Queryprofile.Reference referenceConfig : config.reference()) { - QueryProfile referenced=registry.getComponent(referenceConfig.value()); - if (referenced==null) + QueryProfile referenced = registry.getComponent(referenceConfig.value()); + if (referenced == null) throw new IllegalArgumentException("Query profile '" + referenceConfig.value() + "' referenced as '" + referenceConfig.name() + "' in " + profile + " was not found"); - profile.set(referenceConfig.name(),referenced, registry); - if (referenceConfig.overridable()!=null && !referenceConfig.overridable().isEmpty()) - profile.setOverridable(referenceConfig.name(),BooleanParser.parseBoolean(referenceConfig.overridable()),null); + profile.set(referenceConfig.name(), referenced, registry); + if (referenceConfig.overridable() != null && !referenceConfig.overridable().isEmpty()) + profile.setOverridable(referenceConfig.name(), BooleanParser.parseBoolean(referenceConfig.overridable()), null); } for (QueryProfilesConfig.Queryprofile.Property propertyConfig : config.property()) { - profile.set(propertyConfig.name(),propertyConfig.value(), registry); - if (propertyConfig.overridable()!=null && !propertyConfig.overridable().isEmpty()) - profile.setOverridable(propertyConfig.name(),BooleanParser.parseBoolean(propertyConfig.overridable()),null); + profile.set(propertyConfig.name(), propertyConfig.value(), registry); + if (propertyConfig.overridable() != null && ! propertyConfig.overridable().isEmpty()) + profile.setOverridable(propertyConfig.name(), BooleanParser.parseBoolean(propertyConfig.overridable()), null); } for (QueryProfilesConfig.Queryprofile.Queryprofilevariant variantConfig : config.queryprofilevariant()) { - String[] forDimensionValueArray=new String[variantConfig.fordimensionvalues().size()]; - for (int i=0; i<variantConfig.fordimensionvalues().size(); i++) { - forDimensionValueArray[i]=variantConfig.fordimensionvalues().get(i).trim(); + String[] forDimensionValueArray = new String[variantConfig.fordimensionvalues().size()]; + for (int i = 0; i<variantConfig.fordimensionvalues().size(); i++) { + forDimensionValueArray[i] = variantConfig.fordimensionvalues().get(i).trim(); if ("*".equals(forDimensionValueArray[i])) - forDimensionValueArray[i]=null; + forDimensionValueArray[i] = null; } - DimensionValues forDimensionValues=DimensionValues.createFrom(forDimensionValueArray); + DimensionValues forDimensionValues = DimensionValues.createFrom(forDimensionValueArray); for (String inheritedId : variantConfig.inherit()) { - QueryProfile inherited=registry.getComponent(inheritedId); - if (inherited==null) + QueryProfile inherited = registry.getComponent(inheritedId); + if (inherited == null) throw new IllegalArgumentException("Inherited query profile '" + inheritedId + "' in " + profile + " for '" + forDimensionValues + "' was not found"); fillProfile(inherited, queryProfilesConfig, registry, filled); @@ -153,7 +153,7 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber for (QueryProfilesConfig.Queryprofile.Queryprofilevariant.Reference referenceConfig : variantConfig.reference()) { QueryProfile referenced=registry.getComponent(referenceConfig.value()); - if (referenced==null) + if (referenced == null) throw new IllegalArgumentException("Query profile '" + referenceConfig.value() + "' referenced as '" + referenceConfig.name() + "' in " + profile + " for '" + forDimensionValues + "' was not found"); profile.set(referenceConfig.name(), referenced, forDimensionValues, registry); @@ -167,7 +167,7 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid " + profile,e); + throw new IllegalArgumentException("Invalid " + profile, e); } } @@ -218,7 +218,7 @@ public class QueryProfileConfigurer implements ConfigSubscriber.SingleSubscriber type.addField(field, registry); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid field '" + fieldConfig.name() + "' in " + type,e); + throw new IllegalArgumentException("Invalid field '" + fieldConfig.name() + "' in " + type, e); } } diff --git a/container-search/src/main/java/com/yahoo/search/result/Relevance.java b/container-search/src/main/java/com/yahoo/search/result/Relevance.java index 7737b01cc14..69d49dc33ed 100644 --- a/container-search/src/main/java/com/yahoo/search/result/Relevance.java +++ b/container-search/src/main/java/com/yahoo/search/result/Relevance.java @@ -1,8 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.result; -import com.yahoo.text.DoubleFormatter; - /** * A relevance double value. These values should always be normalized between 0 and 1 (where 1 means perfect), * however, this is not enforced. @@ -47,7 +45,7 @@ public class Relevance implements Comparable<Relevance> { */ @Override public String toString() { - return DoubleFormatter.stringValue(score); + return String.valueOf(score); } /** Compares relevancy values with */ diff --git a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSectionsToSectionsResult.xml b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSectionsToSectionsResult.xml index cb63af526a0..4272e54aeec 100644 --- a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSectionsToSectionsResult.xml +++ b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSectionsToSectionsResult.xml @@ -64,10 +64,10 @@ <hit relevance="0.2" source="source5"> <id>source5-5</id> </hit> - <hit relevance="0.1666666666666667" source="source5"> + <hit relevance="0.16666666666666666" source="source5"> <id>source5-6</id> </hit> - <hit relevance="0.1428571428571428" source="source5"> + <hit relevance="0.14285714285714285" source="source5"> <id>source5-7</id> </hit> </section> @@ -87,7 +87,7 @@ <hit relevance="0.2" source="source4"> <id>source4-5</id> </hit> - <hit relevance="0.1666666666666667" source="source4"> + <hit relevance="0.16666666666666666" source="source4"> <id>source4-6</id> </hit> </section> diff --git a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSourcesToSectionsResult.xml b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSourcesToSectionsResult.xml index 1b8b5a71e35..623918c8739 100644 --- a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSourcesToSectionsResult.xml +++ b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/MapSourcesToSectionsResult.xml @@ -64,7 +64,7 @@ <hit relevance="0.2" source="source4"> <id>source4-5</id> </hit> - <hit relevance="0.1666666666666667" source="source4"> + <hit relevance="0.16666666666666666" source="source4"> <id>source4-6</id> </hit> </section> diff --git a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/TwoSectionsFourSourcesResult.xml b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/TwoSectionsFourSourcesResult.xml index eb2e458ac6d..73b62afd6c1 100644 --- a/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/TwoSectionsFourSourcesResult.xml +++ b/container-search/src/test/java/com/yahoo/search/pagetemplates/engine/test/TwoSectionsFourSourcesResult.xml @@ -57,7 +57,7 @@ <hit relevance="0.2" source="source4"> <id>source4-5</id> </hit> - <hit relevance="0.1666666666666667" source="source4"> + <hit relevance="0.16666666666666666" source="source4"> <id>source4-6</id> </hit> </section> diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json index 2ce9d69472a..b790cec3912 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json @@ -25,12 +25,12 @@ "cost": { "tco": 74, "waste": 0, - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "cluster": { "cluster1": { "count": 2, "resource": "cpu", - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "tco": 74, "waste": 0, "flavor": "flavor1", @@ -40,7 +40,7 @@ "flavorDisk":50.0, "type": "content", "util": { - "cpu": 2.999999999999999, + "cpu": 2.9999999999999996, "mem": 0.4285714285714286, "disk": 0.5714285714285715, "diskBusy": 1.0 diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json index ab86b891fae..f6eae19337a 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json @@ -24,12 +24,12 @@ "cost": { "tco": 74, "waste": 0, - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "cluster": { "cluster1": { "count": 2, "resource": "cpu", - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "tco": 74, "waste": 0, "flavor": "flavor1", @@ -39,7 +39,7 @@ "flavorDisk": 50.0, "type": "content", "util": { - "cpu": 2.999999999999999, + "cpu": 2.9999999999999996, "mem": 0.4285714285714286, "disk": 0.5714285714285715, "diskBusy": 1.0 diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json index 902bda472cf..b35a53eb1a4 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json @@ -31,12 +31,12 @@ "cost": { "tco": 74, "waste": 0, - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "cluster": { "cluster1": { "count": 2, "resource": "cpu", - "utilization": 2.999999999999999, + "utilization": 2.9999999999999996, "tco": 74, "waste": 0, "flavor": "flavor1", @@ -46,7 +46,7 @@ "flavorDisk": 50.0, "type": "content", "util": { - "cpu": 2.999999999999999, + "cpu": 2.9999999999999996, "mem": 0.4285714285714286, "disk": 0.5714285714285715, "diskBusy": 1.0 diff --git a/fat-model-dependencies/pom.xml b/fat-model-dependencies/pom.xml index 68abc36c678..0421f0bbd01 100644 --- a/fat-model-dependencies/pom.xml +++ b/fat-model-dependencies/pom.xml @@ -26,6 +26,13 @@ <groupId>com.yahoo.vespa</groupId> <artifactId>provided-dependencies</artifactId> <version>${project.version}</version> + <exclusions> + <exclusion> + <!-- Not needed runtime, and a multi-release jar which is currently not supported by maven-bundle-plugin (really bndtools) --> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>commons-io</groupId> diff --git a/jdisc_core/pom.xml b/jdisc_core/pom.xml index 246265203cb..6b22aa4a985 100644 --- a/jdisc_core/pom.xml +++ b/jdisc_core/pom.xml @@ -16,6 +16,17 @@ <packaging>jar</packaging> <name>${project.artifactId}</name> <dependencies> + <!-- Necessary for jaxb support from java 9. (Could be deployed as bundles since 2.2.11.) --> + <dependency> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + </dependency> + <dependency> + <groupId>com.sun.activation</groupId> + <artifactId>javax.activation</artifactId> + </dependency> + <!-- jaxb end --> + <dependency> <!-- Newer version than the one in rt.jar, including the ElementTraversal class needed by Xerces (Aug 2015, still valid Sep 2017) --> <groupId>xml-apis</groupId> @@ -228,6 +239,8 @@ <argument>${project.build.directory}/dependency/log4j-over-slf4j.jar</argument> <argument>${project.build.directory}/dependency/config-lib.jar</argument> <argument>${project.build.directory}/dependency/yolean.jar</argument> + <argument>${project.build.directory}/dependency/jaxb-api.jar</argument> + <argument>${project.build.directory}/dependency/javax.activation.jar</argument> </arguments> </configuration> </execution> diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ExportPackages.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ExportPackages.java index 8da1a4fad99..86ab016bded 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/ExportPackages.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/ExportPackages.java @@ -38,9 +38,11 @@ public class ExportPackages { .append("javax.inject;version=1.0.0,") // Included in guice, but not exported. Needed by container-jersey. .append("org.aopalliance.intercept,") .append("org.aopalliance.aop,") + .append("sun.misc,") + .append("sun.net.util,") + .append("sun.security.krb5,") - // xml-apis:xml-apis:1.4.01 is not a bundle - .append("org.w3c.dom,") + // TODO: remove for Vespa 7 (xml-apis:xml-apis:1.4.01 is not a bundle, but exposed from system classpath on Java 9) .append("org.w3c.dom.bootstrap,") .append("org.w3c.dom.css,") .append("org.w3c.dom.events,") @@ -49,11 +51,8 @@ public class ExportPackages { .append("org.w3c.dom.ranges,") .append("org.w3c.dom.stylesheets,") .append("org.w3c.dom.traversal,") - .append("org.w3c.dom.views,") + .append("org.w3c.dom.views"); - .append("sun.misc,") - .append("sun.net.util,") - .append("sun.security.krb5"); for (int i = 1; i < args.length; ++i) { out.append(",").append(getExportedPackages(args[i])); } diff --git a/jdisc_core_test/integration_test/pom.xml b/jdisc_core_test/integration_test/pom.xml index d68d6e2966b..e31fa122232 100644 --- a/jdisc_core_test/integration_test/pom.xml +++ b/jdisc_core_test/integration_test/pom.xml @@ -230,14 +230,34 @@ <scope>test</scope> </dependency> </dependencies> + <profiles> + <profile> + <id>java9-surefire</id> + <activation> + <jdk>[9, )</jdk> + </activation> + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <!-- Allow installing fragment bundles, see felix.framework:ExtensionManager.addExtensionBundle --> + <argLine> + --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED + </argLine> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> + </profile> + </profiles> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> diff --git a/jdisc_core_test/test_bundles/cert-k-pkgs/pom.xml b/jdisc_core_test/test_bundles/cert-k-pkgs/pom.xml index f0e16644a41..37e8469afdc 100644 --- a/jdisc_core_test/test_bundles/cert-k-pkgs/pom.xml +++ b/jdisc_core_test/test_bundles/cert-k-pkgs/pom.xml @@ -14,13 +14,6 @@ <version>6-SNAPSHOT</version> <packaging>bundle</packaging> <name>${project.artifactId}</name> - <dependencies> - <dependency> - <groupId>javax.xml.bind</groupId> - <artifactId>jaxb-api</artifactId> - <scope>provided</scope> - </dependency> - </dependencies> <build> <plugins> <plugin> diff --git a/jdisc_core_test/test_bundles/cert-k-pkgs/src/main/java/com/yahoo/jdisc/bundle/k/CertificateK.java b/jdisc_core_test/test_bundles/cert-k-pkgs/src/main/java/com/yahoo/jdisc/bundle/k/CertificateK.java index 44ec6a2ff6c..ea371eb632b 100644 --- a/jdisc_core_test/test_bundles/cert-k-pkgs/src/main/java/com/yahoo/jdisc/bundle/k/CertificateK.java +++ b/jdisc_core_test/test_bundles/cert-k-pkgs/src/main/java/com/yahoo/jdisc/bundle/k/CertificateK.java @@ -112,12 +112,6 @@ public class CertificateK { private final javax.tools.FileObject fileObject = null; private final javax.transaction.xa.XAException xaException = null; private final javax.xml.XMLConstants xmlConstants = null; - private final javax.xml.bind.DataBindingException dataBindingException = null; - private final javax.xml.bind.annotation.DomHandler<?,?> domHandler = null; - private final javax.xml.bind.annotation.adapters.CollapsedStringAdapter collapsedStringAdapter = null; - private final javax.xml.bind.attachment.AttachmentMarshaller attachmentMarshaller = null; - private final javax.xml.bind.helpers.AbstractMarshallerImpl abstractMarshaller = null; - private final javax.xml.bind.util.JAXBResult jaxbResult = null; private final javax.xml.crypto.AlgorithmMethod algorithmMethod = null; private final javax.xml.crypto.dom.DOMCryptoContext domCryptoContext = null; private final javax.xml.crypto.dsig.CanonicalizationMethod canonicalizationMethod = null; @@ -174,8 +168,23 @@ public class CertificateK { private final org.xml.sax.ext.Attributes2Impl attributes2 = null; private final org.xml.sax.helpers.AttributesImpl attributes = null; + // Packages made invisible from Java 9 -// private final javax.activation.CommandInfo commandInfo = null; + + // Added as dep in jdisc_core: com.sun.activation:javax.activation (OSGi bundle) + private final javax.activation.CommandInfo commandInfo = null; + + // Added as dep in jdisc_core: javax.xml.bind:jaxb-api (OSGi bundle) + private final javax.xml.bind.DataBindingException dataBindingException = null; + private final javax.xml.bind.annotation.DomHandler<?,?> domHandler = null; + private final javax.xml.bind.annotation.adapters.CollapsedStringAdapter collapsedStringAdapter = null; + private final javax.xml.bind.attachment.AttachmentMarshaller attachmentMarshaller = null; + private final javax.xml.bind.helpers.AbstractMarshallerImpl abstractMarshaller = null; + private final javax.xml.bind.util.JAXBResult jaxbResult = null; + + + // Packages that most likely won't be provided from JDisc from Vespa 7 + // private final javax.activity.ActivityCompletedException activityCompletedException = null; // private final javax.jws.HandlerChain handlerChain = null; // private final javax.jws.soap.SOAPBinding soapBinding = null; diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java index 880eab0c755..6577b4b96cc 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java @@ -6,7 +6,6 @@ import com.yahoo.time.TimeBudget; import java.time.Clock; import java.time.Duration; -import java.util.Optional; /** * Context for the Orchestrator, e.g. timeout management. @@ -24,14 +23,18 @@ public class OrchestratorContext { /** Get the original timeout in seconds. */ public long getOriginalTimeoutInSeconds() { - return timeBudget.originalTimeout().getSeconds(); + return timeBudget.originalTimeout().get().getSeconds(); } /** - * Get number of seconds until the deadline, or empty if there's no deadline, or throw - * an {@link UncheckedTimeoutException} if timed out. + * Get timeout for a suboperation that should take up {@code shareOfRemaining} of the + * remaining time, or throw an {@link UncheckedTimeoutException} if timed out. */ - public Optional<Float> getSuboperationTimeoutInSeconds() { - return Optional.of((float) (timeBudget.timeLeftOrThrow().toMillis() / 1000.0)); + public float getSuboperationTimeoutInSeconds(float shareOfRemaining) { + if (!(0f <= shareOfRemaining && shareOfRemaining <= 1.0f)) { + throw new IllegalArgumentException("Share of remaining time must be between 0 and 1: " + shareOfRemaining); + } + + return shareOfRemaining * timeBudget.timeLeftOrThrow().get().toMillis() / 1000.0f; } } diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientImpl.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientImpl.java index 7d7a9b36ff9..467b534f809 100644 --- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientImpl.java +++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientImpl.java @@ -15,6 +15,23 @@ public class ClusterControllerClientImpl implements ClusterControllerClient{ public static final String REQUEST_REASON = "Orchestrator"; + // On setNodeState calls against the CC ensemble. + // + // We'd like to set a timeout for the request to the first CC such that if the first + // CC is faulty, there's sufficient time to send the request to the second and third CC. + // The timeouts would be: + // timeout(1. request) = SHARE_REMAINING_TIME * T + // timeout(2. request) = SHARE_REMAINING_TIME * T * (1 - SHARE_REMAINING_TIME) + // timeout(3. request) = SHARE_REMAINING_TIME * T * (1 - SHARE_REMAINING_TIME)^2 + // + // Using a share of 50% gives approximately: + // timeout(1. request) = T * 0.5 + // timeout(2. request) = T * 0.25 + // timeout(3. request) = T * 0.125 + // + // which seems fine + public static final float SHARE_REMAINING_TIME = 0.5f; + private final JaxRsStrategy<ClusterControllerJaxRsApi> clusterControllerApi; private final String clusterName; @@ -40,7 +57,7 @@ public class ClusterControllerClientImpl implements ClusterControllerClient{ return clusterControllerApi.apply(api -> api.setNodeState( clusterName, storageNodeIndex, - context.getSuboperationTimeoutInSeconds().orElse(null), + context.getSuboperationTimeoutInSeconds(SHARE_REMAINING_TIME), stateRequest) ); } catch (IOException e) { @@ -69,7 +86,7 @@ public class ClusterControllerClientImpl implements ClusterControllerClient{ try { return clusterControllerApi.apply(api -> api.setClusterState( clusterName, - context.getSuboperationTimeoutInSeconds().orElse(null), + context.getSuboperationTimeoutInSeconds(SHARE_REMAINING_TIME), stateRequest)); } catch (IOException e) { final String message = String.format( diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientTest.java index b3f80b5129f..228174a9b3d 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientTest.java @@ -6,8 +6,7 @@ import com.yahoo.vespa.jaxrs.client.LocalPassThroughJaxRsStrategy; import com.yahoo.vespa.orchestrator.OrchestratorContext; import org.junit.Test; -import java.util.Optional; - +import static org.mockito.Matchers.anyFloat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -29,7 +28,7 @@ public class ClusterControllerClientTest { final ClusterControllerNodeState wantedState = ClusterControllerNodeState.MAINTENANCE; OrchestratorContext context = mock(OrchestratorContext.class); - when(context.getSuboperationTimeoutInSeconds()).thenReturn(Optional.of(1.0f)); + when(context.getSuboperationTimeoutInSeconds(anyFloat())).thenReturn(1.0f); clusterControllerClient.setNodeState(context, STORAGE_NODE_INDEX, wantedState); final ClusterControllerStateRequest expectedNodeStateRequest = new ClusterControllerStateRequest( diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java index c3dbe5c8a92..4dabae14add 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java @@ -10,13 +10,13 @@ import org.junit.Test; import java.util.Arrays; import java.util.List; -import java.util.Optional; import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyFloat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; @@ -67,7 +67,7 @@ public class SingleInstanceClusterControllerClientFactoryTest { public void testCreateClientWithSingleClusterControllerInstance() throws Exception { final List<HostName> clusterControllers = Arrays.asList(HOST_NAME_1); - when(context.getSuboperationTimeoutInSeconds()).thenReturn(Optional.of(1.0f)); + when(context.getSuboperationTimeoutInSeconds(anyFloat())).thenReturn(1.0f); clientFactory.createClient(clusterControllers, "clusterName") .setNodeState(context, 0, ClusterControllerNodeState.MAINTENANCE); @@ -95,7 +95,7 @@ public class SingleInstanceClusterControllerClientFactoryTest { public void testCreateClientWithThreeClusterControllerInstances() throws Exception { final List<HostName> clusterControllers = Arrays.asList(HOST_NAME_1, HOST_NAME_2, HOST_NAME_3); - when(context.getSuboperationTimeoutInSeconds()).thenReturn(Optional.of(1.0f)); + when(context.getSuboperationTimeoutInSeconds(anyFloat())).thenReturn(1.0f); clientFactory.createClient(clusterControllers, "clusterName") .setNodeState(context, 0, ClusterControllerNodeState.MAINTENANCE); diff --git a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/integration/ml/VariableConverterTestCase.java b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/integration/ml/VariableConverterTestCase.java index f94098e6255..4e3f722fabd 100644 --- a/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/integration/ml/VariableConverterTestCase.java +++ b/searchlib/src/test/java/com/yahoo/searchlib/rankingexpression/integration/ml/VariableConverterTestCase.java @@ -13,7 +13,7 @@ public class VariableConverterTestCase { byte[] converted = VariableConverter.importVariable("src/test/files/integration/tensorflow/mnist_softmax/saved", "Variable_1", "tensor(d0[10],d1[1])"); - assertEquals("{\"cells\":[{\"address\":{\"d0\":\"0\",\"d1\":\"0\"},\"value\":-0.3546536862850189},{\"address\":{\"d0\":\"1\",\"d1\":\"0\"},\"value\":0.3759574592113495},{\"address\":{\"d0\":\"2\",\"d1\":\"0\"},\"value\":0.06054411828517914},{\"address\":{\"d0\":\"3\",\"d1\":\"0\"},\"value\":-0.251544713973999},{\"address\":{\"d0\":\"4\",\"d1\":\"0\"},\"value\":0.01795101352035999},{\"address\":{\"d0\":\"5\",\"d1\":\"0\"},\"value\":1.289906740188599},{\"address\":{\"d0\":\"6\",\"d1\":\"0\"},\"value\":-0.1038961559534073},{\"address\":{\"d0\":\"7\",\"d1\":\"0\"},\"value\":0.6367976665496826},{\"address\":{\"d0\":\"8\",\"d1\":\"0\"},\"value\":-1.413674473762512},{\"address\":{\"d0\":\"9\",\"d1\":\"0\"},\"value\":-0.2573896050453186}]}", + assertEquals("{\"cells\":[{\"address\":{\"d0\":\"0\",\"d1\":\"0\"},\"value\":-0.3546536862850189},{\"address\":{\"d0\":\"1\",\"d1\":\"0\"},\"value\":0.3759574592113495},{\"address\":{\"d0\":\"2\",\"d1\":\"0\"},\"value\":0.06054411828517914},{\"address\":{\"d0\":\"3\",\"d1\":\"0\"},\"value\":-0.251544713973999},{\"address\":{\"d0\":\"4\",\"d1\":\"0\"},\"value\":0.017951013520359993},{\"address\":{\"d0\":\"5\",\"d1\":\"0\"},\"value\":1.2899067401885986},{\"address\":{\"d0\":\"6\",\"d1\":\"0\"},\"value\":-0.10389615595340729},{\"address\":{\"d0\":\"7\",\"d1\":\"0\"},\"value\":0.6367976665496826},{\"address\":{\"d0\":\"8\",\"d1\":\"0\"},\"value\":-1.4136744737625122},{\"address\":{\"d0\":\"9\",\"d1\":\"0\"},\"value\":-0.2573896050453186}]}", new String(converted, StandardCharsets.UTF_8)); } diff --git a/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java b/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java index bc4543011b3..53be6a82dd2 100644 --- a/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java +++ b/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java @@ -1,7 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.data.access.simple; -import com.yahoo.text.DoubleFormatter; import com.yahoo.data.access.*; /** @@ -52,10 +51,10 @@ public final class JsonRender } private void encodeDOUBLE(double value) { - if (Double.isNaN(value) || Double.isInfinite(value)) { - out.append("null"); + if (Double.isFinite(value)) { + out.append(String.valueOf(value)); } else { - out.append(DoubleFormatter.stringValue(value)); + out.append("null"); } } diff --git a/vespajlib/src/main/java/com/yahoo/geo/BoundingBoxParser.java b/vespajlib/src/main/java/com/yahoo/geo/BoundingBoxParser.java index 5cb8c1db2de..69baa119fde 100644 --- a/vespajlib/src/main/java/com/yahoo/geo/BoundingBoxParser.java +++ b/vespajlib/src/main/java/com/yahoo/geo/BoundingBoxParser.java @@ -1,9 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.geo; -import com.yahoo.text.DoubleParser; - - /** * Class for parsing a bounding box in text format: * "n=37.44899,s=37.3323,e=-121.98241,w=-122.06566" @@ -102,7 +99,7 @@ public class BoundingBoxParser { if (nsew != 0 && lastNumStartPos > 0) { String sub = parseString.substring(lastNumStartPos, pos-1); try { - double v = DoubleParser.parse(sub); + double v = Double.parseDouble(sub); if (nsew == 'n') { if (doneN) { throw new IllegalArgumentException("multiple limits for 'n' boundary"); diff --git a/vespajlib/src/main/java/com/yahoo/slime/JsonFormat.java b/vespajlib/src/main/java/com/yahoo/slime/JsonFormat.java index d908359df19..c4c82609df7 100644 --- a/vespajlib/src/main/java/com/yahoo/slime/JsonFormat.java +++ b/vespajlib/src/main/java/com/yahoo/slime/JsonFormat.java @@ -6,7 +6,6 @@ import com.yahoo.io.ByteWriter; import com.yahoo.text.AbstractUtf8Array; import com.yahoo.text.Utf8; import com.yahoo.text.Utf8String; -import com.yahoo.text.DoubleFormatter; import java.io.*; @@ -107,10 +106,10 @@ public final class JsonFormat implements SlimeFormat } private void encodeDOUBLE(double value) throws IOException { - if (Double.isNaN(value) || Double.isInfinite(value)) { - out.write(NULL); + if (Double.isFinite(value)) { + out.write(String.valueOf(value)); } else { - out.write(DoubleFormatter.stringValue(value)); + out.write(NULL); } } diff --git a/vespajlib/src/main/java/com/yahoo/text/DoubleFormatter.java b/vespajlib/src/main/java/com/yahoo/text/DoubleFormatter.java index 29f038a4cd3..7281f3cd9d6 100644 --- a/vespajlib/src/main/java/com/yahoo/text/DoubleFormatter.java +++ b/vespajlib/src/main/java/com/yahoo/text/DoubleFormatter.java @@ -1,532 +1,35 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.text; -import com.google.common.annotations.Beta; - /** * Utility class to format a double into a String. * <p> - * This is intended as a lower-cost replacement for the standard - * String.valueOf(double) since that method will cause lock - * contention if it's used too often. - * <p> - * Note that this implementation won't always produce the same results - * as java.lang.* formatting. + * This was intended as a lower-cost replacement for the standard + * String.valueOf(double) since that method used to cause contention. * <p> - * Also, this implementation is very poorly tested at the moment, so - * it should be used carefully, only in cases where you know the input - * will be well-defined and you don't need full precision. + * The contention issue is fixed in Java 8u96 so this class is now obsolete. * * @author arnej27959 */ -@Beta +@Deprecated public final class DoubleFormatter { - private static void tooSmall(StringBuilder target, long mantissa, int exponent) { - double carry = 0; - int prExp = 0; - while (exponent < 0) { - while (mantissa < (1L << 53)) { - carry *= 10.0; - mantissa *= 10; - ++prExp; - } - carry *= 0.5; - carry += 0.5*(mantissa & 1); - mantissa >>= 1; - ++exponent; - } - while (mantissa < (1L << 53)) { - carry *= 10.0; - mantissa *= 10; - ++prExp; - } - mantissa += (long)(carry+0.5); - - int[] befor = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int b = 0; - for (int i = 0; mantissa > 0; i++) { - befor[i] = (int)(mantissa % 10); - mantissa /= 10; - ++b; - } - --b; - target.append((char)('0'+befor[b])); - target.append('.'); - if (b == 0) { - target.append('0'); - } else { - for (int i = b; i-- > 0; ) { - target.append((char)('0'+befor[i])); - } - } - prExp -= b; - target.append("E-"); - target.append(String.valueOf(prExp)); - } - public static StringBuilder fmt(StringBuilder target, double v) { - append(target, v); + target.append(v); return target; } public static String stringValue(double v) { - return fmt(new StringBuilder(), v).toString(); + return String.valueOf(v); } - - //Hardcode some byte arrays to make them quickly available - public static final char[] INFINITY = {'I','n','f','i','n','i','t','y'}; - public static final char[] NaN = {'N','a','N'}; - public static final char[][] ZEROS = { - {}, - {'0'}, - {'0','0'}, - {'0','0','0'}, - {'0','0','0','0'}, - {'0','0','0','0','0'}, - {'0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}, - }; - - private static final char[] charForDigit = { - '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h', - 'i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' - }; - - //And required double related constants. - private static final long DoubleSignMask = 0x8000000000000000L; - private static final long DoubleExpMask = 0x7ff0000000000000L; - private static final long DoubleFractMask= ~(DoubleSignMask|DoubleExpMask); - private static final int DoubleExpShift = 52; - private static final int DoubleExpBias = 1023; - - private static final double[] d_tenthPowers = { - 1e-323D, 1e-322D, 1e-321D, 1e-320D, 1e-319D, 1e-318D, 1e-317D, 1e-316D, 1e-315D, 1e-314D, - 1e-313D, 1e-312D, 1e-311D, 1e-310D, 1e-309D, 1e-308D, 1e-307D, 1e-306D, 1e-305D, 1e-304D, - 1e-303D, 1e-302D, 1e-301D, 1e-300D, 1e-299D, 1e-298D, 1e-297D, 1e-296D, 1e-295D, 1e-294D, - 1e-293D, 1e-292D, 1e-291D, 1e-290D, 1e-289D, 1e-288D, 1e-287D, 1e-286D, 1e-285D, 1e-284D, - 1e-283D, 1e-282D, 1e-281D, 1e-280D, 1e-279D, 1e-278D, 1e-277D, 1e-276D, 1e-275D, 1e-274D, - 1e-273D, 1e-272D, 1e-271D, 1e-270D, 1e-269D, 1e-268D, 1e-267D, 1e-266D, 1e-265D, 1e-264D, - 1e-263D, 1e-262D, 1e-261D, 1e-260D, 1e-259D, 1e-258D, 1e-257D, 1e-256D, 1e-255D, 1e-254D, - 1e-253D, 1e-252D, 1e-251D, 1e-250D, 1e-249D, 1e-248D, 1e-247D, 1e-246D, 1e-245D, 1e-244D, - 1e-243D, 1e-242D, 1e-241D, 1e-240D, 1e-239D, 1e-238D, 1e-237D, 1e-236D, 1e-235D, 1e-234D, - 1e-233D, 1e-232D, 1e-231D, 1e-230D, 1e-229D, 1e-228D, 1e-227D, 1e-226D, 1e-225D, 1e-224D, - 1e-223D, 1e-222D, 1e-221D, 1e-220D, 1e-219D, 1e-218D, 1e-217D, 1e-216D, 1e-215D, 1e-214D, - 1e-213D, 1e-212D, 1e-211D, 1e-210D, 1e-209D, 1e-208D, 1e-207D, 1e-206D, 1e-205D, 1e-204D, - 1e-203D, 1e-202D, 1e-201D, 1e-200D, 1e-199D, 1e-198D, 1e-197D, 1e-196D, 1e-195D, 1e-194D, - 1e-193D, 1e-192D, 1e-191D, 1e-190D, 1e-189D, 1e-188D, 1e-187D, 1e-186D, 1e-185D, 1e-184D, - 1e-183D, 1e-182D, 1e-181D, 1e-180D, 1e-179D, 1e-178D, 1e-177D, 1e-176D, 1e-175D, 1e-174D, - 1e-173D, 1e-172D, 1e-171D, 1e-170D, 1e-169D, 1e-168D, 1e-167D, 1e-166D, 1e-165D, 1e-164D, - 1e-163D, 1e-162D, 1e-161D, 1e-160D, 1e-159D, 1e-158D, 1e-157D, 1e-156D, 1e-155D, 1e-154D, - 1e-153D, 1e-152D, 1e-151D, 1e-150D, 1e-149D, 1e-148D, 1e-147D, 1e-146D, 1e-145D, 1e-144D, - 1e-143D, 1e-142D, 1e-141D, 1e-140D, 1e-139D, 1e-138D, 1e-137D, 1e-136D, 1e-135D, 1e-134D, - 1e-133D, 1e-132D, 1e-131D, 1e-130D, 1e-129D, 1e-128D, 1e-127D, 1e-126D, 1e-125D, 1e-124D, - 1e-123D, 1e-122D, 1e-121D, 1e-120D, 1e-119D, 1e-118D, 1e-117D, 1e-116D, 1e-115D, 1e-114D, - 1e-113D, 1e-112D, 1e-111D, 1e-110D, 1e-109D, 1e-108D, 1e-107D, 1e-106D, 1e-105D, 1e-104D, - 1e-103D, 1e-102D, 1e-101D, 1e-100D, 1e-99D, 1e-98D, 1e-97D, 1e-96D, 1e-95D, 1e-94D, - 1e-93D, 1e-92D, 1e-91D, 1e-90D, 1e-89D, 1e-88D, 1e-87D, 1e-86D, 1e-85D, 1e-84D, - 1e-83D, 1e-82D, 1e-81D, 1e-80D, 1e-79D, 1e-78D, 1e-77D, 1e-76D, 1e-75D, 1e-74D, - 1e-73D, 1e-72D, 1e-71D, 1e-70D, 1e-69D, 1e-68D, 1e-67D, 1e-66D, 1e-65D, 1e-64D, - 1e-63D, 1e-62D, 1e-61D, 1e-60D, 1e-59D, 1e-58D, 1e-57D, 1e-56D, 1e-55D, 1e-54D, - 1e-53D, 1e-52D, 1e-51D, 1e-50D, 1e-49D, 1e-48D, 1e-47D, 1e-46D, 1e-45D, 1e-44D, - 1e-43D, 1e-42D, 1e-41D, 1e-40D, 1e-39D, 1e-38D, 1e-37D, 1e-36D, 1e-35D, 1e-34D, - 1e-33D, 1e-32D, 1e-31D, 1e-30D, 1e-29D, 1e-28D, 1e-27D, 1e-26D, 1e-25D, 1e-24D, - 1e-23D, 1e-22D, 1e-21D, 1e-20D, 1e-19D, 1e-18D, 1e-17D, 1e-16D, 1e-15D, 1e-14D, - 1e-13D, 1e-12D, 1e-11D, 1e-10D, 1e-9D, 1e-8D, 1e-7D, 1e-6D, 1e-5D, 1e-4D, - 1e-3D, 1e-2D, 1e-1D, 1e0D, 1e1D, 1e2D, 1e3D, 1e4D, - 1e5D, 1e6D, 1e7D, 1e8D, 1e9D, 1e10D, 1e11D, 1e12D, 1e13D, 1e14D, - 1e15D, 1e16D, 1e17D, 1e18D, 1e19D, 1e20D, 1e21D, 1e22D, 1e23D, 1e24D, - 1e25D, 1e26D, 1e27D, 1e28D, 1e29D, 1e30D, 1e31D, 1e32D, 1e33D, 1e34D, - 1e35D, 1e36D, 1e37D, 1e38D, 1e39D, 1e40D, 1e41D, 1e42D, 1e43D, 1e44D, - 1e45D, 1e46D, 1e47D, 1e48D, 1e49D, 1e50D, 1e51D, 1e52D, 1e53D, 1e54D, - 1e55D, 1e56D, 1e57D, 1e58D, 1e59D, 1e60D, 1e61D, 1e62D, 1e63D, 1e64D, - 1e65D, 1e66D, 1e67D, 1e68D, 1e69D, 1e70D, 1e71D, 1e72D, 1e73D, 1e74D, - 1e75D, 1e76D, 1e77D, 1e78D, 1e79D, 1e80D, 1e81D, 1e82D, 1e83D, 1e84D, - 1e85D, 1e86D, 1e87D, 1e88D, 1e89D, 1e90D, 1e91D, 1e92D, 1e93D, 1e94D, - 1e95D, 1e96D, 1e97D, 1e98D, 1e99D, 1e100D, 1e101D, 1e102D, 1e103D, 1e104D, - 1e105D, 1e106D, 1e107D, 1e108D, 1e109D, 1e110D, 1e111D, 1e112D, 1e113D, 1e114D, - 1e115D, 1e116D, 1e117D, 1e118D, 1e119D, 1e120D, 1e121D, 1e122D, 1e123D, 1e124D, - 1e125D, 1e126D, 1e127D, 1e128D, 1e129D, 1e130D, 1e131D, 1e132D, 1e133D, 1e134D, - 1e135D, 1e136D, 1e137D, 1e138D, 1e139D, 1e140D, 1e141D, 1e142D, 1e143D, 1e144D, - 1e145D, 1e146D, 1e147D, 1e148D, 1e149D, 1e150D, 1e151D, 1e152D, 1e153D, 1e154D, - 1e155D, 1e156D, 1e157D, 1e158D, 1e159D, 1e160D, 1e161D, 1e162D, 1e163D, 1e164D, - 1e165D, 1e166D, 1e167D, 1e168D, 1e169D, 1e170D, 1e171D, 1e172D, 1e173D, 1e174D, - 1e175D, 1e176D, 1e177D, 1e178D, 1e179D, 1e180D, 1e181D, 1e182D, 1e183D, 1e184D, - 1e185D, 1e186D, 1e187D, 1e188D, 1e189D, 1e190D, 1e191D, 1e192D, 1e193D, 1e194D, - 1e195D, 1e196D, 1e197D, 1e198D, 1e199D, 1e200D, 1e201D, 1e202D, 1e203D, 1e204D, - 1e205D, 1e206D, 1e207D, 1e208D, 1e209D, 1e210D, 1e211D, 1e212D, 1e213D, 1e214D, - 1e215D, 1e216D, 1e217D, 1e218D, 1e219D, 1e220D, 1e221D, 1e222D, 1e223D, 1e224D, - 1e225D, 1e226D, 1e227D, 1e228D, 1e229D, 1e230D, 1e231D, 1e232D, 1e233D, 1e234D, - 1e235D, 1e236D, 1e237D, 1e238D, 1e239D, 1e240D, 1e241D, 1e242D, 1e243D, 1e244D, - 1e245D, 1e246D, 1e247D, 1e248D, 1e249D, 1e250D, 1e251D, 1e252D, 1e253D, 1e254D, - 1e255D, 1e256D, 1e257D, 1e258D, 1e259D, 1e260D, 1e261D, 1e262D, 1e263D, 1e264D, - 1e265D, 1e266D, 1e267D, 1e268D, 1e269D, 1e270D, 1e271D, 1e272D, 1e273D, 1e274D, - 1e275D, 1e276D, 1e277D, 1e278D, 1e279D, 1e280D, 1e281D, 1e282D, 1e283D, 1e284D, - 1e285D, 1e286D, 1e287D, 1e288D, 1e289D, 1e290D, 1e291D, 1e292D, 1e293D, 1e294D, - 1e295D, 1e296D, 1e297D, 1e298D, 1e299D, 1e300D, 1e301D, 1e302D, 1e303D, 1e304D, - 1e305D, 1e306D, 1e307D, 1e308D - }; - - - /** - * Assumes i is positive. Returns the magnitude of i in base 10. - */ - private static long tenthPower(long i) - { - if (i < 10L) return 1; - else if (i < 100L) return 10L; - else if (i < 1000L) return 100L; - else if (i < 10000L) return 1000L; - else if (i < 100000L) return 10000L; - else if (i < 1000000L) return 100000L; - else if (i < 10000000L) return 1000000L; - else if (i < 100000000L) return 10000000L; - else if (i < 1000000000L) return 100000000L; - else if (i < 10000000000L) return 1000000000L; - else if (i < 100000000000L) return 10000000000L; - else if (i < 1000000000000L) return 100000000000L; - else if (i < 10000000000000L) return 1000000000000L; - else if (i < 100000000000000L) return 10000000000000L; - else if (i < 1000000000000000L) return 100000000000000L; - else if (i < 10000000000000000L) return 1000000000000000L; - else if (i < 100000000000000000L) return 10000000000000000L; - else if (i < 1000000000000000000L) return 100000000000000000L; - else return 1000000000000000000L; + public static void append(StringBuilder s, double d) { + s.append(d); } - - private static int magnitude(double d) - { - //It works. What else can I say. - long doubleToLongBits = Double.doubleToLongBits(d); - int magnitude = - (int) ((((doubleToLongBits & DoubleExpMask) >> DoubleExpShift) - DoubleExpBias) * 0.301029995663981); - - if (magnitude < -323) - magnitude = -323; - else if (magnitude > 308) - magnitude = 308; - - if (d >= d_tenthPowers[magnitude+323]) - { - while(magnitude < 309 && d >= d_tenthPowers[magnitude+323]) - magnitude++; - magnitude--; - return magnitude; - } - else - { - while(magnitude > -324 && d < d_tenthPowers[magnitude+323]) - magnitude--; - return magnitude; - } + public static void append(StringBuilder s, int i) { + s.append(i); } - static long[] l_tenthPowers = { - 1, - 10L, - 100L, - 1000L, - 10000L, - 100000L, - 1000000L, - 10000000L, - 100000000L, - 1000000000L, - 10000000000L, - 100000000000L, - 1000000000000L, - 10000000000000L, - 100000000000000L, - 1000000000000000L, - 10000000000000000L, - 100000000000000000L, - 1000000000000000000L, - }; - - public static long getNthDigit(long l, int n) - { - return (l/(tenthPower(l)/l_tenthPowers[n-1]))%10; - } - - - - - public static void append(StringBuilder s, double d) - { - if (d == Double.NEGATIVE_INFINITY) - s.append(NEGATIVE_INFINITY); - else if (d == Double.POSITIVE_INFINITY) - s.append(POSITIVE_INFINITY); - else if (d != d) - s.append(NaN); - else if (d == 0.0) - { - if ( (Double.doubleToLongBits(d) & DoubleSignMask) != 0) - s.append('-'); - s.append(DOUBLE_ZERO); - } - else - { - if (d < 0) - { - s.append('-'); - d = -d; - } - - if (d >= 0.001 && d < 0.01) - { - long i = (long) (d * 1E20); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - s.append(DOUBLE_ZERO2); - appendFractDigits(s, i,-1); - } - else if (d >= 0.01 && d < 0.1) - { - long i = (long) (d * 1E19); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - s.append(DOUBLE_ZERO); - appendFractDigits(s, i,-1); - } - else if (d >= 0.1 && d < 1) - { - long i = (long) (d * 1E18); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - s.append(DOUBLE_ZERO0); - appendFractDigits(s, i,-1); - } - else if (d >= 1 && d < 10) - { - long i = (long) (d * 1E17); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,1); - } - else if (d >= 10 && d < 100) - { - long i = (long) (d * 1E16); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,2); - } - else if (d >= 100 && d < 1000) - { - long i = (long) (d * 1E15); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,3); - } - else if (d >= 1000 && d < 10000) - { - long i = (long) (d * 1E14); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,4); - } - else if (d >= 10000 && d < 100000) - { - long i = (long) (d * 1E13); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,5); - } - else if (d >= 100000 && d < 1000000) - { - long i = (long) (d * 1E12); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,6); - } - else if (d >= 1000000 && d < 10000000) - { - long i = (long) (d * 1E11); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i,7); - } - else - { - int magnitude = magnitude(d); - long i; - if (magnitude < -280) { - long valueBits = Double.doubleToRawLongBits(d); - long mantissa = valueBits & 0x000fffffffffffffL; - int exponent = (int)((valueBits >> 52) & 0x7ff); - if (exponent == 0) { - tooSmall(s, mantissa, -1074); - } else { - mantissa |= 0x0010000000000000L; - exponent -= 1075; - tooSmall(s, mantissa, exponent); - } - } else { - i = (long) (d / d_tenthPowers[magnitude + 323 - 17]); - i = i%100 >= 50 ? (i/100) + 1 : i/100; - appendFractDigits(s, i, 1); - s.append('E'); - append(s, magnitude); - } - } - } - } - public static void append(StringBuilder s, int i) - { - if (i < 0) - { - if (i == Integer.MIN_VALUE) - { - //cannot make this positive due to integer overflow - s.append("-2147483648"); - } - s.append('-'); - i = -i; - } - int mag; - int c; - if (i < 10) - { - //one digit - s.append(charForDigit[i]); - } - else if (i < 100) - { - //two digits - s.append(charForDigit[i/10]); - s.append(charForDigit[i%10]); - } - else if (i < 1000) - { - //three digits - s.append(charForDigit[i/100]); - s.append(charForDigit[(c=i%100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 10000) - { - //four digits - s.append(charForDigit[i/1000]); - s.append(charForDigit[(c=i%1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 100000) - { - //five digits - s.append(charForDigit[i/10000]); - s.append(charForDigit[(c=i%10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 1000000) - { - //six digits - s.append(charForDigit[i/100000]); - s.append(charForDigit[(c=i%100000)/10000]); - s.append(charForDigit[(c%=10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 10000000) - { - //seven digits - s.append(charForDigit[i/1000000]); - s.append(charForDigit[(c=i%1000000)/100000]); - s.append(charForDigit[(c%=100000)/10000]); - s.append(charForDigit[(c%=10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 100000000) - { - //eight digits - s.append(charForDigit[i/10000000]); - s.append(charForDigit[(c=i%10000000)/1000000]); - s.append(charForDigit[(c%=1000000)/100000]); - s.append(charForDigit[(c%=100000)/10000]); - s.append(charForDigit[(c%=10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else if (i < 1000000000) - { - //nine digits - s.append(charForDigit[i/100000000]); - s.append(charForDigit[(c=i%100000000)/10000000]); - s.append(charForDigit[(c%=10000000)/1000000]); - s.append(charForDigit[(c%=1000000)/100000]); - s.append(charForDigit[(c%=100000)/10000]); - s.append(charForDigit[(c%=10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - else - { - //ten digits - s.append(charForDigit[i/1000000000]); - s.append(charForDigit[(c=i%1000000000)/100000000]); - s.append(charForDigit[(c%=100000000)/10000000]); - s.append(charForDigit[(c%=10000000)/1000000]); - s.append(charForDigit[(c%=1000000)/100000]); - s.append(charForDigit[(c%=100000)/10000]); - s.append(charForDigit[(c%=10000)/1000]); - s.append(charForDigit[(c%=1000)/100]); - s.append(charForDigit[(c%=100)/10]); - s.append(charForDigit[c%10]); - } - } - private static void appendFractDigits(StringBuilder s, long i, int decimalOffset) - { - long mag = tenthPower(i); - long c; - while ( i > 0 ) - { - c = i/mag; - s.append(charForDigit[(int) c]); - decimalOffset--; - if (decimalOffset == 0) - s.append('.'); - c *= mag; - if ( c <= i) - i -= c; - mag = mag/10; - } - if (i != 0) - s.append(charForDigit[(int) i]); - else if (decimalOffset > 0) - { - s.append(ZEROS[decimalOffset]); - decimalOffset = 1; - } - - decimalOffset--; - if (decimalOffset == 0) - s.append(DOT_ZERO); - else if (decimalOffset == -1) - s.append('0'); - } - - public static final char[] NEGATIVE_INFINITY = {'-','I','n','f','i','n','i','t','y'}; - public static final char[] POSITIVE_INFINITY = {'I','n','f','i','n','i','t','y'}; - public static final char[] DOUBLE_ZERO = {'0','.','0'}; - public static final char[] DOUBLE_ZERO2 = {'0','.','0','0'}; - public static final char[] DOUBLE_ZERO0 = {'0','.'}; - public static final char[] DOT_ZERO = {'.','0'}; - } diff --git a/vespajlib/src/main/java/com/yahoo/text/DoubleParser.java b/vespajlib/src/main/java/com/yahoo/text/DoubleParser.java index 6a1fd8e170c..0a777f3000f 100644 --- a/vespajlib/src/main/java/com/yahoo/text/DoubleParser.java +++ b/vespajlib/src/main/java/com/yahoo/text/DoubleParser.java @@ -4,20 +4,15 @@ package com.yahoo.text; /** * Utility class to parse a String into a double. * <p> - * This is intended as a lower-cost replacement for the standard - * Double.parseDouble(String) since that method will cause lock - * contention if it's used too often. + * This was intended as a lower-cost replacement for the standard + * Double.parseDouble(String) since that method used to cause lock + * contention. * <p> - * Note that this implementation won't always produce the same results - * as java.lang.Double (low-order bits may differ), and it doesn't - * properly support denormalized numbers. - * <p> - * Also, this implementation is very poorly tested at the moment, so - * it should be used carefully, only in cases where you know the input - * will be well-defined and you don't need full precision. + * The contention issue is fixed in Java 8u96 so this class is now obsolete. * * @author arnej27959 */ +@Deprecated public final class DoubleParser { /** @@ -29,171 +24,6 @@ public final class DoubleParser { * @throws NullPointerException if the string is a null pointer */ public static double parse(String data) { - final int len = data.length(); - double result = 0; - boolean negative = false; - int beforePoint = 0; - int exponent = 0; - byte[] digits = new byte[25]; - int numDigits = 0; - - int i = 0; - while (i < len && Character.isWhitespace(data.charAt(i))) { - i++; - } - if (data.charAt(i) == '+') { - i++; - } else if (data.charAt(i) == '-') { - negative = true; - i++; - } - if (i + 3 <= len && data.substring(i, i+3).equals("NaN")) { - i += 3; - result = Double.NaN; - } else if (i + 8 <= len && data.substring(i, i+8).equals("Infinity")) { - i += 8; - if (negative) { - result = Double.NEGATIVE_INFINITY; - } else { - result = Double.POSITIVE_INFINITY; - } - } else { - while (i < len && Character.isDigit(data.charAt(i))) { - int dval = Character.digit(data.charAt(i), 10); - assert dval >= 0; - assert dval < 10; - if (numDigits < 25) { - digits[numDigits++] = (byte)dval; - } - ++beforePoint; - i++; - } - if (i < len && data.charAt(i) == '.') { - i++; - while (i < len && Character.isDigit(data.charAt(i))) { - int dval = Character.digit(data.charAt(i), 10); - assert dval >= 0; - assert dval < 10; - if (numDigits < 25) { - digits[numDigits++] = (byte)dval; - } - i++; - } - } - if (numDigits == 0) { - throw new NumberFormatException("No digits in number: '"+data+"'"); - } - if (i < len && (data.charAt(i) == 'e' || data.charAt(i) == 'E')) { - i++; - boolean expNeg = false; - int expDigits = 0; - if (data.charAt(i) == '+') { - i++; - } else if (data.charAt(i) == '-') { - expNeg = true; - i++; - } - while (i < len && Character.isDigit(data.charAt(i))) { - int dval = Character.digit(data.charAt(i), 10); - assert dval >= 0; - assert dval < 10; - exponent *= 10; - exponent += dval; - ++expDigits; - i++; - } - if (expDigits == 0) { - throw new NumberFormatException("Missing digits in exponent part: "+data); - } - if (expNeg) { - exponent = -exponent; - } - } - // System.out.println("parsed exp: "+exponent); - // System.out.println("before pt: "+beforePoint); - exponent += beforePoint; - exponent -= numDigits; - // System.out.println("adjusted exp: "+exponent); - for (int d = numDigits; d > 0; d--) { - double dv = digits[d-1]; - dv *= powTen(numDigits - d); - result += dv; - } - // System.out.println("digits sum: "+result); - while (exponent < -99) { - result *= powTen(-99); - exponent += 99; - } - while (exponent > 99) { - result *= powTen(99); - exponent -= 99; - } - // System.out.println("digits sum: "+result); - // System.out.println("exponent multiplier: "+powTen(exponent)); - result *= powTen(exponent); - - if (negative) { - result = -result; - } - } - while (i < len && Character.isWhitespace(data.charAt(i))) { - i++; - } - if (i < len) { - throw new NumberFormatException("Extra characters after number: "+data.substring(i)); - } - return result; - } - - private static double[] tens = { - 1.0e00, 1.0e01, 1.0e02, 1.0e03, 1.0e04, 1.0e05, 1.0e06, - 1.0e07, 1.0e08, 1.0e09, 1.0e10, 1.0e11, 1.0e12, 1.0e13, - 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, - 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, - 1.0e28, 1.0e29, 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, - 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, 1.0e40, 1.0e41, - 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, - 1.0e49, 1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, - 1.0e56, 1.0e57, 1.0e58, 1.0e59, 1.0e60, 1.0e61, 1.0e62, - 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, - 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, - 1.0e77, 1.0e78, 1.0e79, 1.0e80, 1.0e81, 1.0e82, 1.0e83, - 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, 1.0e90, - 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, - 1.0e98, 1.0e99 - }; - - private static double[] tenths = { - 1.0e-00, 1.0e-01, 1.0e-02, 1.0e-03, 1.0e-04, 1.0e-05, - 1.0e-06, 1.0e-07, 1.0e-08, 1.0e-09, 1.0e-10, 1.0e-11, - 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16, 1.0e-17, - 1.0e-18, 1.0e-19, 1.0e-20, 1.0e-21, 1.0e-22, 1.0e-23, - 1.0e-24, 1.0e-25, 1.0e-26, 1.0e-27, 1.0e-28, 1.0e-29, - 1.0e-30, 1.0e-31, 1.0e-32, 1.0e-33, 1.0e-34, 1.0e-35, - 1.0e-36, 1.0e-37, 1.0e-38, 1.0e-39, 1.0e-40, 1.0e-41, - 1.0e-42, 1.0e-43, 1.0e-44, 1.0e-45, 1.0e-46, 1.0e-47, - 1.0e-48, 1.0e-49, 1.0e-50, 1.0e-51, 1.0e-52, 1.0e-53, - 1.0e-54, 1.0e-55, 1.0e-56, 1.0e-57, 1.0e-58, 1.0e-59, - 1.0e-60, 1.0e-61, 1.0e-62, 1.0e-63, 1.0e-64, 1.0e-65, - 1.0e-66, 1.0e-67, 1.0e-68, 1.0e-69, 1.0e-70, 1.0e-71, - 1.0e-72, 1.0e-73, 1.0e-74, 1.0e-75, 1.0e-76, 1.0e-77, - 1.0e-78, 1.0e-79, 1.0e-80, 1.0e-81, 1.0e-82, 1.0e-83, - 1.0e-84, 1.0e-85, 1.0e-86, 1.0e-87, 1.0e-88, 1.0e-89, - 1.0e-90, 1.0e-91, 1.0e-92, 1.0e-93, 1.0e-94, 1.0e-95, - 1.0e-96, 1.0e-97, 1.0e-98, 1.0e-99 - }; - - private static double powTen(int exponent) { - if (exponent > 0) { - assert exponent < 100; - return tens[exponent]; - } - if (exponent < 0) { - exponent = -exponent; - assert exponent < 100; - return tenths[exponent]; - } - return 1.0; + return Double.parseDouble(data); } - } diff --git a/vespajlib/src/main/java/com/yahoo/time/TimeBudget.java b/vespajlib/src/main/java/com/yahoo/time/TimeBudget.java index fa18cb5e467..a7963df0208 100644 --- a/vespajlib/src/main/java/com/yahoo/time/TimeBudget.java +++ b/vespajlib/src/main/java/com/yahoo/time/TimeBudget.java @@ -6,26 +6,31 @@ import com.google.common.util.concurrent.UncheckedTimeoutException; import java.time.Clock; import java.time.Duration; import java.time.Instant; +import java.util.Optional; /** - * A TimeBudget can be used to track the time of an ongoing operation with a timeout. + * A TimeBudget can be used to track the time of an ongoing operation, possibly with a timeout. * * @author hakon */ public class TimeBudget { private final Clock clock; private final Instant start; - private final Duration timeout; + private final Optional<Duration> timeout; /** Returns a TimeBudget with a start time of now, and with the given timeout. */ public static TimeBudget fromNow(Clock clock, Duration timeout) { - return new TimeBudget(clock, clock.instant(), timeout); + return new TimeBudget(clock, clock.instant(), Optional.of(timeout)); } - private TimeBudget(Clock clock, Instant start, Duration timeout) { + public static TimeBudget from(Clock clock, Instant start, Optional<Duration> timeout) { + return new TimeBudget(clock, start, timeout); + } + + private TimeBudget(Clock clock, Instant start, Optional<Duration> timeout) { this.clock = clock; this.start = start; - this.timeout = makeNonNegative(timeout); + this.timeout = timeout.map(TimeBudget::makeNonNegative); } /** Returns time since start. */ @@ -33,26 +38,32 @@ public class TimeBudget { return nonNegativeBetween(start, clock.instant()); } - /** Returns the original timeout. */ - public Duration originalTimeout() { + /** Returns the original timeout, if any. */ + public Optional<Duration> originalTimeout() { return timeout; } + /** Returns the deadline, if present. */ + public Optional<Instant> deadline() { + return timeout.map(start::plus); + } + /** - * Returns the time until deadline. + * Returns the time until deadline, if there is one. * * @return time until deadline. It's toMillis() is guaranteed to be positive. * @throws UncheckedTimeoutException if the deadline has been reached or passed. */ - public Duration timeLeftOrThrow() { - Instant now = clock.instant(); - Duration left = Duration.between(now, start.plus(timeout)); - if (left.toMillis() <= 0) { - throw new UncheckedTimeoutException("Time since start " + nonNegativeBetween(start, now) + - " exceeds timeout " + timeout); - } + public Optional<Duration> timeLeftOrThrow() { + return timeout.map(timeout -> { + Duration passed = timePassed(); + Duration left = timeout.minus(passed); + if (left.toMillis() <= 0) { + throw new UncheckedTimeoutException("Time since start " + passed + " exceeds timeout " + this.timeout); + } - return left; + return left; + }); } private static Duration nonNegativeBetween(Instant start, Instant end) { diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java b/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java index 9299c96d902..3d0c623bbf4 100644 --- a/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java @@ -4,6 +4,7 @@ package com.yahoo.text; import org.junit.Test; import static org.junit.Assert.assertEquals; +@SuppressWarnings("deprecation") /** * @author arnej27959 */ @@ -73,19 +74,19 @@ public class DoubleFormatterTestCase { assertEquals("1.0737418255E9", s); s = DoubleFormatter.stringValue(1.23456789012345669); - assertEquals("1.234567890123457", s); + assertEquals("1.2345678901234567", s); s = DoubleFormatter.stringValue(12.3456789012345673); - assertEquals("12.34567890123457", s); + assertEquals("12.345678901234567", s); s = DoubleFormatter.stringValue(123.456789012345666); - assertEquals("123.4567890123457", s); + assertEquals("123.45678901234567", s); s = DoubleFormatter.stringValue(1234.56789012345666); - assertEquals("1234.567890123457", s); + assertEquals("1234.5678901234567", s); s = DoubleFormatter.stringValue(12345.6789012345670); - assertEquals("12345.67890123457", s); + assertEquals("12345.678901234567", s); s = DoubleFormatter.stringValue(123456.789012345674); - assertEquals("123456.7890123457", s); + assertEquals("123456.78901234567", s); s = DoubleFormatter.stringValue(1234567.89012345671); - assertEquals("1234567.890123457", s); + assertEquals("1234567.8901234567", s); s = DoubleFormatter.stringValue(0.99); // assertEquals("0.99", s); diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java b/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java index 7f20b9b89ec..a48a1b6a943 100644 --- a/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java @@ -4,6 +4,7 @@ package com.yahoo.text; import org.junit.Test; import static org.junit.Assert.assertEquals; +@SuppressWarnings("deprecation") /** * @author arnej27959 */ diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java b/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java index ec3eae50aa7..a5925df2caf 100644 --- a/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java @@ -12,6 +12,7 @@ import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +@SuppressWarnings("deprecation") /** * @author arnej27959 */ diff --git a/vespajlib/src/test/java/com/yahoo/time/TimeBudgetTest.java b/vespajlib/src/test/java/com/yahoo/time/TimeBudgetTest.java index a51081067b7..f197cc34b32 100644 --- a/vespajlib/src/test/java/com/yahoo/time/TimeBudgetTest.java +++ b/vespajlib/src/test/java/com/yahoo/time/TimeBudgetTest.java @@ -8,8 +8,10 @@ import org.junit.Test; import java.time.Clock; import java.time.Duration; import java.time.Instant; +import java.util.Optional; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; @@ -23,12 +25,12 @@ public class TimeBudgetTest { TimeBudget timeBudget = TimeBudget.fromNow(clock, Duration.ofSeconds(10)); clock.advance(Duration.ofSeconds(7)); - assertEquals(Duration.ofSeconds(3), timeBudget.timeLeftOrThrow()); + assertEquals(Duration.ofSeconds(3), timeBudget.timeLeftOrThrow().get()); // Verify that toMillis() of >=1 is fine, but 0 is not. clock.setInstant(Instant.ofEpochSecond(9, 999000000)); - assertEquals(1, timeBudget.timeLeftOrThrow().toMillis()); + assertEquals(1, timeBudget.timeLeftOrThrow().get().toMillis()); clock.setInstant(Instant.ofEpochSecond(9, 999000001)); try { timeBudget.timeLeftOrThrow(); @@ -37,4 +39,15 @@ public class TimeBudgetTest { // OK } } + + @Test + public void noDeadline() { + ManualClock clock = new ManualClock(); + clock.setInstant(Instant.ofEpochSecond(0)); + TimeBudget timeBudget = TimeBudget.from(clock, clock.instant(), Optional.empty()); + + assertFalse(timeBudget.originalTimeout().isPresent()); + assertFalse(timeBudget.timeLeftOrThrow().isPresent()); + assertFalse(timeBudget.deadline().isPresent()); + } }
\ No newline at end of file |