summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/python.yml35
-rw-r--r--CMakeLists.txt2
-rw-r--r--ERRATA.md38
-rw-r--r--application/abi-spec.json2
-rw-r--r--build_settings.cmake5
-rw-r--r--clustercontroller-apps/pom.xml6
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterController.java41
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurer.java23
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/DummyZooKeeperProvider.java10
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/StandaloneZooKeeperProvider.java16
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ZooKeeperProvider.java10
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java (renamed from clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java)0
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java (renamed from clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java)0
-rw-r--r--clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java (renamed from clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java)0
-rw-r--r--clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurerTest.java15
-rw-r--r--clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerTest.java26
-rw-r--r--clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java (renamed from clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java)0
-rw-r--r--clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java (renamed from clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java)0
-rw-r--r--clustercontroller-apputil/.gitignore2
-rw-r--r--clustercontroller-apputil/OWNERS2
-rw-r--r--clustercontroller-apputil/pom.xml60
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java4
-rw-r--r--clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java53
-rw-r--r--clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingCurator.java28
-rw-r--r--clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java61
-rw-r--r--clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMetrics.java11
-rw-r--r--clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/http/ReindexingV1ApiHandler.java30
-rw-r--r--clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java91
-rw-r--r--clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingCuratorTest.java14
-rw-r--r--clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingMaintainerTest.java12
-rw-r--r--clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/http/ReindexingV1ApiTest.java36
-rw-r--r--clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/util/MetricReporter.java4
-rw-r--r--component/abi-spec.json16
-rw-r--r--component/src/main/java/com/yahoo/component/AbstractComponent.java5
-rw-r--r--component/src/main/java/com/yahoo/component/Deconstructable.java13
-rw-r--r--config-lib/abi-spec.json4
-rw-r--r--config-lib/pom.xml6
-rw-r--r--config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java1
-rw-r--r--config-lib/src/main/java/com/yahoo/config/ConfigInstance.java6
-rw-r--r--config-lib/src/main/java/com/yahoo/config/Node.java4
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/Model.java42
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java113
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/Reindexing.java2
-rw-r--r--config-model-fat/pom.xml2
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java2
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java20
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java2
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/document/SDField.java10
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/ExpressionTransforms.java1
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/TokenTransformer.java300
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java29
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerCluster.java14
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java100
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java20
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java41
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV2Builder.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java14
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java34
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/Container.java23
-rwxr-xr-xconfig-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/docproc/MbusClient.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java102
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java10
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/Distributor.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java6
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java68
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java12
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorVisitorProducer.java10
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java21
-rw-r--r--config-model/src/main/resources/schema/containercluster.rnc5
-rw-r--r--config-model/src/test/derived/advanced/index-info.cfg34
-rw-r--r--config-model/src/test/derived/array_of_struct_attribute/index-info.cfg6
-rw-r--r--config-model/src/test/derived/arrays/index-info.cfg10
-rw-r--r--config-model/src/test/derived/attributeprefetch/index-info.cfg36
-rw-r--r--config-model/src/test/derived/attributes/index-info.cfg42
-rw-r--r--config-model/src/test/derived/combinedattributeandindexsearch/index-info.cfg8
-rw-r--r--config-model/src/test/derived/emptydefault/index-info.cfg4
-rw-r--r--config-model/src/test/derived/exactmatch/index-info.cfg26
-rw-r--r--config-model/src/test/derived/fieldset/index-info.cfg4
-rw-r--r--config-model/src/test/derived/id/index-info.cfg16
-rw-r--r--config-model/src/test/derived/imported_position_field/index-info.cfg52
-rw-r--r--config-model/src/test/derived/imported_position_field_summary/index-info.cfg6
-rw-r--r--config-model/src/test/derived/imported_struct_fields/index-info.cfg26
-rw-r--r--config-model/src/test/derived/importedfields/index-info.cfg16
-rw-r--r--config-model/src/test/derived/indexinfo_fieldsets/index-info.cfg12
-rw-r--r--config-model/src/test/derived/indexinfo_lowercase/index-info.cfg18
-rw-r--r--config-model/src/test/derived/indexschema/index-info.cfg74
-rw-r--r--config-model/src/test/derived/indexswitches/index-info.cfg8
-rw-r--r--config-model/src/test/derived/inheritance/index-info.cfg10
-rw-r--r--config-model/src/test/derived/inheritstruct/index-info.cfg4
-rw-r--r--config-model/src/test/derived/map_attribute/index-info.cfg12
-rw-r--r--config-model/src/test/derived/map_of_struct_attribute/index-info.cfg20
-rw-r--r--config-model/src/test/derived/music/index-info.cfg76
-rw-r--r--config-model/src/test/derived/newrank/index-info.cfg64
-rw-r--r--config-model/src/test/derived/position_array/index-info.cfg8
-rw-r--r--config-model/src/test/derived/position_attribute/index-info.cfg8
-rw-r--r--config-model/src/test/derived/position_extra/index-info.cfg6
-rw-r--r--config-model/src/test/derived/predicate_attribute/index-info.cfg2
-rw-r--r--config-model/src/test/derived/prefixexactattribute/index-info.cfg10
-rw-r--r--config-model/src/test/derived/ranktypes/index-info.cfg10
-rw-r--r--config-model/src/test/derived/structanyorder/index-info.cfg200
-rw-r--r--config-model/src/test/derived/tensor/index-info.cfg49
-rw-r--r--config-model/src/test/derived/types/index-info.cfg252
-rw-r--r--config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java140
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/processing/NGramTestCase.java4
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/processing/RankingExpressionWithTransformerTokensTestCase.java95
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/admin/ClusterControllerTestCase.java45
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java15
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java10
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java55
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/configserver/ConfigserverClusterTest.java14
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java61
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java26
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java2
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java19
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java40
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterResources.java7
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java57
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java4
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java5
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java30
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/HostFilterTest.java46
-rw-r--r--config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java5
-rw-r--r--config-proxy/src/main/java/com/yahoo/vespa/config/proxy/Subscriber.java2
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java12
-rw-r--r--config/abi-spec.json5
-rw-r--r--config/src/apps/vespa-get-config/getconfig.cpp10
-rw-r--r--config/src/apps/vespa-ping-configproxy/pingproxy.cpp11
-rwxr-xr-xconfig/src/main/java/com/yahoo/config/subscription/ConfigGetter.java2
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/ConfigHandle.java2
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java72
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java32
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java9
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java4
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java2
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java1
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/GenericConfig.java2
-rwxr-xr-xconfig/src/main/java/com/yahoo/vespa/config/RawConfig.java49
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/CompilationTask.java44
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/CompiledBuilder.java13
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigCompiler.java13
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java12
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinitionClass.java27
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/LazyConfigCompiler.java85
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/buildergen/StringSourceObject.java23
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java2
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java4
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java6
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java12
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java10
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java16
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java6
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/AppService.java7
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/BasicTest.java4
-rwxr-xr-xconfig/src/test/java/com/yahoo/config/subscription/ConfigApiTest.java10
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java3
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/ConfigSetSubscriptionTest.java16
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/ConfigSubscriptionTest.java2
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/DefaultConfigTest.java7
-rw-r--r--config/src/test/java/com/yahoo/config/subscription/GenericConfigSubscriberTest.java4
-rw-r--r--config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java2
-rw-r--r--config/src/test/java/com/yahoo/vespa/config/buildergen/ConfigBuilderGeneratorTest.java49
-rw-r--r--config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java8
-rw-r--r--config/src/tests/configagent/configagent.cpp2
-rw-r--r--config/src/tests/failover/failover.cpp4
-rw-r--r--config/src/tests/file_acquirer/file_acquirer_test.cpp3
-rw-r--r--config/src/tests/frt/frt.cpp5
-rw-r--r--config/src/vespa/config/common/configstate.h8
-rw-r--r--config/src/vespa/config/frt/frtconfigrequestfactory.cpp5
-rw-r--r--config/src/vespa/config/frt/frtconfigrequestfactory.h2
-rw-r--r--config/src/vespa/config/frt/frtconfigresponsev3.cpp2
-rw-r--r--config/src/vespa/config/frt/frtsourcefactory.cpp4
-rw-r--r--config/src/vespa/config/frt/frtsourcefactory.h2
-rw-r--r--config/src/vespa/config/frt/protocol.cpp2
-rw-r--r--config/src/vespa/config/frt/protocol.h2
-rw-r--r--config/src/vespa/config/frt/slimeconfigrequest.cpp2
-rw-r--r--config/src/vespa/config/frt/slimeconfigresponse.cpp6
-rw-r--r--config/src/vespa/config/subscription/sourcespec.cpp2
-rw-r--r--configd/src/apps/sentinel/cmdq.cpp2
-rw-r--r--configd/src/apps/sentinel/rpchooks.cpp3
-rw-r--r--configdefinitions/src/vespa/CMakeLists.txt2
-rw-r--r--configdefinitions/src/vespa/reindexing.def10
-rw-r--r--configdefinitions/src/vespa/stor-filestor.def7
-rw-r--r--configdefinitions/src/vespa/zookeeper-server.def2
-rw-r--r--configgen/CMakeLists.txt (renamed from clustercontroller-apputil/CMakeLists.txt)2
-rw-r--r--configgen/pom.xml32
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java42
-rw-r--r--configgen/src/main/java/com/yahoo/config/codegen/CppClassBuilder.java77
-rw-r--r--configgen/src/test/resources/allfeatures.reference14
-rw-r--r--configserver-flags/src/main/java/com/yahoo/vespa/configserver/flags/http/DefinedFlag.java7
-rw-r--r--configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/ConfigServerFlagSourceTest.java3
-rw-r--r--configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java11
-rw-r--r--configserver/pom.xml18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java54
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexing.java72
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexingStatusClient.java25
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java4
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java117
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClient.java166
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java1
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java154
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java51
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java12
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java27
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java16
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java11
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java4
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java4
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java10
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java30
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java10
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java7
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationMapperTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationSetTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationTest.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ConfigConvergenceCheckerTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClientTest.java127
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/FileDistributionStatusTest.java1
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java8
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java1
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java34
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java17
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java11
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java11
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcServerTest.java1
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRepositoryTest.java1
-rw-r--r--configutil/src/lib/configstatus.cpp1
-rw-r--r--container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java15
-rw-r--r--container-core/abi-spec.json2
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java6
-rw-r--r--container-di/abi-spec.json7
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java16
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java4
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java28
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/Container.java29
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java5
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java1
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java2
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java3
-rw-r--r--container-di/src/test/java/com/yahoo/container/di/ConfigRetrieverTest.java32
-rw-r--r--container-di/src/test/java/com/yahoo/container/di/ContainerTest.java36
-rw-r--r--container-di/src/test/java/com/yahoo/container/di/ContainerTestBase.java4
-rw-r--r--container-disc/pom.xml1
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java37
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java70
-rw-r--r--container-disc/src/test/java/com/yahoo/container/jdisc/component/DeconstructorTest.java60
-rw-r--r--container-messagebus/src/main/java/com/yahoo/container/jdisc/messagebus/SessionCache.java1
-rw-r--r--container-messagebus/src/main/resources/configdefinitions/container.jdisc.container-mbus.def3
-rw-r--r--container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java2
-rw-r--r--container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js2
-rwxr-xr-xcontainer-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js2
-rw-r--r--container-search/abi-spec.json24
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/Index.java91
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/IndexFacts.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java8
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/HasIndexItem.java5
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/IndexedItem.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/ToolBox.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java12
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java1
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchers/QueryValidator.java59
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java4
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/searcher/test/ValidatePredicateSearcherTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/searchers/test/QueryValidatorTestCase.java51
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/ApplicationId.java1
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/InstanceId.java1
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/TenantId.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java6
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java44
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java19
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ApplicationReindexing.java12
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/FlagsV1Api.java16
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java17
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/EntityService.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/MemoryEntityService.java14
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/NodeRepositoryNode.java12
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/HostRepairClient.java23
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/MockRepairClient.java33
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MeteringClient.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMeteringClient.java10
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java20
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java11
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java27
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java28
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java43
-rw-r--r--controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json8
-rw-r--r--controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json8
-rw-r--r--controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json8
-rw-r--r--controller-server/pom.xml5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java82
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java46
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java15
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java8
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java22
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java106
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainer.java66
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdater.java80
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java79
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java21
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java20
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/JobControlFlags.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java79
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java48
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java22
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java30
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java22
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java11
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainerTest.java44
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdaterTest.java110
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java78
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java32
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java41
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json31
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java19
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-invoices2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java21
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java35
-rw-r--r--default_build_settings.cmake19
-rw-r--r--dist/vespa.spec23
-rw-r--r--docproc/src/main/java/com/yahoo/docproc/jdisc/RequestContext.java5
-rw-r--r--docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java14
-rw-r--r--document/CMakeLists.txt3
-rw-r--r--document/abi-spec.json2
-rw-r--r--document/src/main/java/com/yahoo/document/BucketIdFactory.java4
-rw-r--r--document/src/main/java/com/yahoo/document/datatypes/Array.java19
-rw-r--r--document/src/main/java/com/yahoo/document/datatypes/MapFieldValue.java5
-rw-r--r--document/src/main/java/com/yahoo/document/datatypes/WeightedSet.java17
-rwxr-xr-xdocument/src/test/java/com/yahoo/document/datatypes/ArrayTestCase.java4
-rw-r--r--document/src/tests/documentselectparsertest.cpp30
-rw-r--r--document/src/tests/documentupdatetestcase.cpp7
-rw-r--r--document/src/tests/serialization/vespadocumentserializer_test.cpp11
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_add/CMakeLists.txt (renamed from eval/src/tests/tensor/partial_add/CMakeLists.txt)6
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_add/partial_add_test.cpp (renamed from eval/src/tests/tensor/partial_add/partial_add_test.cpp)28
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_modify/CMakeLists.txt (renamed from eval/src/tests/tensor/partial_modify/CMakeLists.txt)6
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_modify/partial_modify_test.cpp (renamed from eval/src/tests/tensor/partial_modify/partial_modify_test.cpp)32
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_remove/CMakeLists.txt (renamed from eval/src/tests/tensor/partial_remove/CMakeLists.txt)6
-rw-r--r--document/src/tests/tensor_fieldvalue/partial_remove/partial_remove_test.cpp (renamed from eval/src/tests/tensor/partial_remove/partial_remove_test.cpp)29
-rw-r--r--document/src/tests/tensor_fieldvalue/tensor_fieldvalue_test.cpp14
-rw-r--r--document/src/vespa/document/annotation/span.h4
-rw-r--r--document/src/vespa/document/bucket/bucketid.cpp12
-rw-r--r--document/src/vespa/document/bucket/bucketselector.cpp5
-rw-r--r--document/src/vespa/document/datatype/documenttype.h1
-rw-r--r--document/src/vespa/document/datatype/referencedatatype.h1
-rw-r--r--document/src/vespa/document/datatype/structureddatatype.h1
-rw-r--r--document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp19
-rw-r--r--document/src/vespa/document/fieldvalue/tensorfieldvalue.h1
-rw-r--r--document/src/vespa/document/serialization/vespadocumentdeserializer.cpp7
-rw-r--r--document/src/vespa/document/serialization/vespadocumentserializer.cpp4
-rw-r--r--document/src/vespa/document/update/CMakeLists.txt1
-rw-r--r--document/src/vespa/document/update/tensor_add_update.cpp12
-rw-r--r--document/src/vespa/document/update/tensor_modify_update.cpp16
-rw-r--r--document/src/vespa/document/update/tensor_partial_update.cpp (renamed from eval/src/vespa/eval/tensor/partial_update.cpp)66
-rw-r--r--document/src/vespa/document/update/tensor_partial_update.h (renamed from eval/src/vespa/eval/tensor/partial_update.h)13
-rw-r--r--document/src/vespa/document/update/tensor_remove_update.cpp17
-rw-r--r--documentapi/CMakeLists.txt2
-rw-r--r--documentapi/abi-spec.json2
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusDocumentAccess.java2
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java2
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java2
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocolRoutingPolicy.java3
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LoadBalancerPolicy.java2
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java2
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/StoragePolicy.java1
-rw-r--r--documentapi/src/tests/loadtypes/.gitignore3
-rw-r--r--documentapi/src/tests/loadtypes/CMakeLists.txt10
-rw-r--r--documentapi/src/tests/loadtypes/loadtypetest.cpp74
-rw-r--r--documentapi/src/tests/messagebus/messagebus_test.cpp9
-rw-r--r--documentapi/src/tests/messages/testbase.cpp4
-rw-r--r--documentapi/src/tests/messages/testbase.h5
-rw-r--r--documentapi/src/tests/policies/policies_test.cpp31
-rw-r--r--documentapi/src/tests/policies/testframe.cpp3
-rw-r--r--documentapi/src/tests/policies/testframe.h2
-rw-r--r--documentapi/src/tests/policyfactory/policyfactory.cpp4
-rw-r--r--documentapi/src/tests/routablefactory/routablefactory.cpp7
-rw-r--r--documentapi/src/vespa/documentapi/CMakeLists.txt1
-rw-r--r--documentapi/src/vespa/documentapi/loadtypes/CMakeLists.txt7
-rw-r--r--documentapi/src/vespa/documentapi/loadtypes/loadtype.cpp16
-rw-r--r--documentapi/src/vespa/documentapi/loadtypes/loadtype.h41
-rw-r--r--documentapi/src/vespa/documentapi/loadtypes/loadtypeset.cpp84
-rw-r--r--documentapi/src/vespa/documentapi/loadtypes/loadtypeset.h69
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/documentprotocol.cpp6
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/documentprotocol.h5
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/iroutablefactory.h4
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/policies/externpolicy.cpp9
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/policies/externslobrokpolicy.cpp4
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/routablefactories60.cpp7
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/routablefactories60.h4
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/routablerepository.cpp9
-rw-r--r--documentapi/src/vespa/documentapi/messagebus/routablerepository.h5
-rw-r--r--eval/CMakeLists.txt46
-rw-r--r--eval/src/apps/eval_expr/eval_expr.cpp16
-rw-r--r--eval/src/apps/tensor_conformance/tensor_conformance.cpp63
-rw-r--r--eval/src/apps/tensor_conformance/test_spec.json1988
-rw-r--r--eval/src/tests/eval/engine_or_factory/CMakeLists.txt17
-rw-r--r--eval/src/tests/eval/engine_or_factory/engine_or_factory_override_test.cpp25
-rw-r--r--eval/src/tests/eval/engine_or_factory/engine_or_factory_test.cpp24
-rw-r--r--eval/src/tests/eval/fast_sparse_map/fast_sparse_map_test.cpp2
-rw-r--r--eval/src/tests/eval/function/function_test.cpp3
-rw-r--r--eval/src/tests/eval/function_speed/function_speed_test.cpp10
-rw-r--r--eval/src/tests/eval/gbdt/gbdt_test.cpp5
-rw-r--r--eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp27
-rw-r--r--eval/src/tests/eval/multiply_add/multiply_add_test.cpp6
-rw-r--r--eval/src/tests/eval/reference_evaluation/CMakeLists.txt10
-rw-r--r--eval/src/tests/eval/reference_evaluation/reference_evaluation_test.cpp209
-rw-r--r--eval/src/tests/eval/reference_operations/CMakeLists.txt10
-rw-r--r--eval/src/tests/eval/reference_operations/reference_operations_test.cpp530
-rw-r--r--eval/src/tests/eval/simple_tensor/.gitignore1
-rw-r--r--eval/src/tests/eval/simple_tensor/CMakeLists.txt8
-rw-r--r--eval/src/tests/eval/simple_tensor/simple_tensor_test.cpp370
-rw-r--r--eval/src/tests/eval/simple_value/simple_value_test.cpp16
-rw-r--r--eval/src/tests/eval/tensor_function/tensor_function_test.cpp123
-rw-r--r--eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp114
-rw-r--r--eval/src/tests/eval/typed_cells/CMakeLists.txt (renamed from eval/src/tests/tensor/typed_cells/CMakeLists.txt)0
-rw-r--r--eval/src/tests/eval/typed_cells/typed_cells_test.cpp (renamed from eval/src/tests/tensor/typed_cells/typed_cells_test.cpp)0
-rw-r--r--eval/src/tests/eval/value_cache/tensor_loader_test.cpp29
-rw-r--r--eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_add_dimension_optimizer/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp (renamed from eval/src/tests/tensor/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp)16
-rw-r--r--eval/src/tests/instruction/dense_dot_product_function/dense_dot_product_function_test.cpp19
-rw-r--r--eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_fast_rename_optimizer/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp (renamed from eval/src/tests/tensor/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp)15
-rw-r--r--eval/src/tests/instruction/dense_inplace_join_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_inplace_join_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_inplace_join_function/dense_inplace_join_function_test.cpp (renamed from eval/src/tests/tensor/dense_inplace_join_function/dense_inplace_join_function_test.cpp)11
-rw-r--r--eval/src/tests/instruction/dense_matmul_function/dense_matmul_function_test.cpp22
-rw-r--r--eval/src/tests/instruction/dense_multi_matmul_function/dense_multi_matmul_function_test.cpp23
-rw-r--r--eval/src/tests/instruction/dense_pow_as_map_optimizer/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_pow_as_map_optimizer/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp (renamed from eval/src/tests/tensor/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp)15
-rw-r--r--eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_remove_dimension_optimizer/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp (renamed from eval/src/tests/tensor/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp)15
-rw-r--r--eval/src/tests/instruction/dense_replace_type_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_replace_type_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp (renamed from eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp)19
-rw-r--r--eval/src/tests/instruction/dense_simple_expand_function/dense_simple_expand_function_test.cpp23
-rw-r--r--eval/src/tests/instruction/dense_simple_join_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_simple_join_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_simple_join_function/dense_simple_join_function_test.cpp (renamed from eval/src/tests/tensor/dense_simple_join_function/dense_simple_join_function_test.cpp)18
-rw-r--r--eval/src/tests/instruction/dense_simple_map_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_simple_map_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_simple_map_function/dense_simple_map_function_test.cpp (renamed from eval/src/tests/tensor/dense_simple_map_function/dense_simple_map_function_test.cpp)16
-rw-r--r--eval/src/tests/instruction/dense_single_reduce_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_single_reduce_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_single_reduce_function/dense_single_reduce_function_test.cpp (renamed from eval/src/tests/tensor/dense_single_reduce_function/dense_single_reduce_function_test.cpp)18
-rw-r--r--eval/src/tests/instruction/dense_tensor_create_function/CMakeLists.txt (renamed from eval/src/tests/tensor/dense_tensor_create_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/dense_tensor_create_function/dense_tensor_create_function_test.cpp (renamed from eval/src/tests/tensor/dense_tensor_create_function/dense_tensor_create_function_test.cpp)11
-rw-r--r--eval/src/tests/instruction/dense_tensor_peek_function/dense_tensor_peek_function_test.cpp11
-rw-r--r--eval/src/tests/instruction/dense_xw_product_function/dense_xw_product_function_test.cpp20
-rw-r--r--eval/src/tests/instruction/generic_concat/generic_concat_test.cpp40
-rw-r--r--eval/src/tests/instruction/generic_create/generic_create_test.cpp7
-rw-r--r--eval/src/tests/instruction/generic_join/generic_join_test.cpp21
-rw-r--r--eval/src/tests/instruction/generic_map/generic_map_test.cpp20
-rw-r--r--eval/src/tests/instruction/generic_merge/generic_merge_test.cpp21
-rw-r--r--eval/src/tests/instruction/generic_peek/generic_peek_test.cpp9
-rw-r--r--eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp40
-rw-r--r--eval/src/tests/instruction/generic_rename/generic_rename_test.cpp25
-rw-r--r--eval/src/tests/instruction/vector_from_doubles_function/CMakeLists.txt (renamed from eval/src/tests/tensor/vector_from_doubles_function/CMakeLists.txt)0
-rw-r--r--eval/src/tests/instruction/vector_from_doubles_function/vector_from_doubles_function_test.cpp (renamed from eval/src/tests/tensor/vector_from_doubles_function/vector_from_doubles_function_test.cpp)11
-rw-r--r--eval/src/tests/streamed/value/streamed_value_test.cpp16
-rw-r--r--eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt9
-rw-r--r--eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp185
-rw-r--r--eval/src/tests/tensor/dense_generic_join/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp127
-rw-r--r--eval/src/tests/tensor/dense_number_join_function/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/dense_number_join_function/dense_number_join_function_test.cpp119
-rw-r--r--eval/src/tests/tensor/direct_dense_tensor_builder/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp192
-rw-r--r--eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp119
-rw-r--r--eval/src/tests/tensor/instruction_benchmark/.gitignore2
-rw-r--r--eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp154
-rw-r--r--eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp46
-rw-r--r--eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt9
-rw-r--r--eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp85
-rw-r--r--eval/src/tests/tensor/tensor_address/.gitignore1
-rw-r--r--eval/src/tests/tensor/tensor_address/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/tensor_address/tensor_address_test.cpp39
-rw-r--r--eval/src/tests/tensor/tensor_conformance/.gitignore2
-rw-r--r--eval/src/tests/tensor/tensor_conformance/tensor_conformance_test.cpp50
-rw-r--r--eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt9
-rw-r--r--eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp111
-rw-r--r--eval/src/tests/tensor/tensor_remove_operation/CMakeLists.txt9
-rw-r--r--eval/src/tests/tensor/tensor_remove_operation/tensor_remove_operation_test.cpp95
-rw-r--r--eval/src/tests/tensor/tensor_serialization/.gitignore1
-rw-r--r--eval/src/tests/tensor/tensor_serialization/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/tensor_serialization/tensor_serialization_test.cpp243
-rw-r--r--eval/src/vespa/eval/CMakeLists.txt7
-rw-r--r--eval/src/vespa/eval/eval/CMakeLists.txt6
-rw-r--r--eval/src/vespa/eval/eval/basic_nodes.cpp5
-rw-r--r--eval/src/vespa/eval/eval/binary_format.txt (renamed from eval/src/vespa/eval/tensor/serialization/format.txt)2
-rw-r--r--eval/src/vespa/eval/eval/cell_type.h4
-rw-r--r--eval/src/vespa/eval/eval/compile_tensor_function.cpp16
-rw-r--r--eval/src/vespa/eval/eval/compile_tensor_function.h4
-rw-r--r--eval/src/vespa/eval/eval/dense_cells_value.cpp19
-rw-r--r--eval/src/vespa/eval/eval/dense_cells_value.h30
-rw-r--r--eval/src/vespa/eval/eval/engine_or_factory.cpp178
-rw-r--r--eval/src/vespa/eval/eval/engine_or_factory.h64
-rw-r--r--eval/src/vespa/eval/eval/interpreted_function.cpp28
-rw-r--r--eval/src/vespa/eval/eval/interpreted_function.h34
-rw-r--r--eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp24
-rw-r--r--eval/src/vespa/eval/eval/make_tensor_function.cpp25
-rw-r--r--eval/src/vespa/eval/eval/make_tensor_function.h5
-rw-r--r--eval/src/vespa/eval/eval/node_types.cpp9
-rw-r--r--eval/src/vespa/eval/eval/node_types.h1
-rw-r--r--eval/src/vespa/eval/eval/optimize_tensor_function.cpp28
-rw-r--r--eval/src/vespa/eval/eval/optimize_tensor_function.h5
-rw-r--r--eval/src/vespa/eval/eval/param_usage.cpp6
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor.cpp788
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor.h103
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor_engine.cpp150
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor_engine.h37
-rw-r--r--eval/src/vespa/eval/eval/simple_value.cpp20
-rw-r--r--eval/src/vespa/eval/eval/simple_value.h10
-rw-r--r--eval/src/vespa/eval/eval/tensor.cpp26
-rw-r--r--eval/src/vespa/eval/eval/tensor.h44
-rw-r--r--eval/src/vespa/eval/eval/tensor_engine.cpp9
-rw-r--r--eval/src/vespa/eval/eval/tensor_engine.h62
-rw-r--r--eval/src/vespa/eval/eval/tensor_function.cpp231
-rw-r--r--eval/src/vespa/eval/eval/tensor_function.h28
-rw-r--r--eval/src/vespa/eval/eval/tensor_nodes.h11
-rw-r--r--eval/src/vespa/eval/eval/tensor_spec.cpp111
-rw-r--r--eval/src/vespa/eval/eval/tensor_spec.h6
-rw-r--r--eval/src/vespa/eval/eval/test/CMakeLists.txt2
-rw-r--r--eval/src/vespa/eval/eval/test/eval_fixture.cpp37
-rw-r--r--eval/src/vespa/eval/eval/test/eval_fixture.h13
-rw-r--r--eval/src/vespa/eval/eval/test/eval_spec.h9
-rw-r--r--eval/src/vespa/eval/eval/test/reference_evaluation.cpp352
-rw-r--r--eval/src/vespa/eval/eval/test/reference_evaluation.h16
-rw-r--r--eval/src/vespa/eval/eval/test/reference_operations.cpp32
-rw-r--r--eval/src/vespa/eval/eval/test/reference_operations.h15
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_conformance.cpp456
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_conformance.h14
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_model.cpp12
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_model.h260
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_model.hpp251
-rw-r--r--eval/src/vespa/eval/eval/test/value_compare.cpp2
-rw-r--r--eval/src/vespa/eval/eval/typed_cells.h2
-rw-r--r--eval/src/vespa/eval/eval/value.cpp10
-rw-r--r--eval/src/vespa/eval/eval/value.h4
-rw-r--r--eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp7
-rw-r--r--eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h9
-rw-r--r--eval/src/vespa/eval/eval/value_type.cpp2
-rw-r--r--eval/src/vespa/eval/instruction/CMakeLists.txt10
-rw-r--r--eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.cpp)15
-rw-r--r--eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h (renamed from eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.h)7
-rw-r--r--eval/src/vespa/eval/instruction/dense_cell_range_function.cpp5
-rw-r--r--eval/src/vespa/eval/instruction/dense_cell_range_function.h2
-rw-r--r--eval/src/vespa/eval/instruction/dense_dot_product_function.cpp3
-rw-r--r--eval/src/vespa/eval/instruction/dense_dot_product_function.h2
-rw-r--r--eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp)15
-rw-r--r--eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h (renamed from eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.h)7
-rw-r--r--eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp5
-rw-r--r--eval/src/vespa/eval/instruction/dense_lambda_peek_function.h2
-rw-r--r--eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp5
-rw-r--r--eval/src/vespa/eval/instruction/dense_matmul_function.cpp9
-rw-r--r--eval/src/vespa/eval/instruction/dense_matmul_function.h3
-rw-r--r--eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp7
-rw-r--r--eval/src/vespa/eval/instruction/dense_multi_matmul_function.h3
-rw-r--r--eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.cpp)11
-rw-r--r--eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.h (renamed from eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h)7
-rw-r--r--eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.cpp)16
-rw-r--r--eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h (renamed from eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h)7
-rw-r--r--eval/src/vespa/eval/instruction/dense_replace_type_function.cpp48
-rw-r--r--eval/src/vespa/eval/instruction/dense_replace_type_function.h (renamed from eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h)17
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp5
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_expand_function.h2
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_join_function.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp)31
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_join_function.h (renamed from eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h)18
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_map_function.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp)28
-rw-r--r--eval/src/vespa/eval/instruction/dense_simple_map_function.h26
-rw-r--r--eval/src/vespa/eval/instruction/dense_single_reduce_function.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp)31
-rw-r--r--eval/src/vespa/eval/instruction/dense_single_reduce_function.h (renamed from eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h)24
-rw-r--r--eval/src/vespa/eval/instruction/dense_tensor_create_function.cpp (renamed from eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp)33
-rw-r--r--eval/src/vespa/eval/instruction/dense_tensor_create_function.h34
-rw-r--r--eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp3
-rw-r--r--eval/src/vespa/eval/instruction/dense_tensor_peek_function.h2
-rw-r--r--eval/src/vespa/eval/instruction/dense_xw_product_function.cpp9
-rw-r--r--eval/src/vespa/eval/instruction/dense_xw_product_function.h3
-rw-r--r--eval/src/vespa/eval/instruction/generic_concat.cpp23
-rw-r--r--eval/src/vespa/eval/instruction/generic_concat.h5
-rw-r--r--eval/src/vespa/eval/instruction/generic_join.cpp21
-rw-r--r--eval/src/vespa/eval/instruction/generic_join.h6
-rw-r--r--eval/src/vespa/eval/instruction/generic_lambda.cpp6
-rw-r--r--eval/src/vespa/eval/instruction/generic_lambda.h2
-rw-r--r--eval/src/vespa/eval/instruction/generic_map.cpp38
-rw-r--r--eval/src/vespa/eval/instruction/generic_map.h6
-rw-r--r--eval/src/vespa/eval/instruction/generic_merge.cpp21
-rw-r--r--eval/src/vespa/eval/instruction/generic_merge.h4
-rw-r--r--eval/src/vespa/eval/instruction/generic_peek.cpp14
-rw-r--r--eval/src/vespa/eval/instruction/generic_reduce.cpp20
-rw-r--r--eval/src/vespa/eval/instruction/generic_reduce.h5
-rw-r--r--eval/src/vespa/eval/instruction/generic_rename.cpp22
-rw-r--r--eval/src/vespa/eval/instruction/generic_rename.h6
-rw-r--r--eval/src/vespa/eval/instruction/join_with_number_function.cpp2
-rw-r--r--eval/src/vespa/eval/instruction/join_with_number_function.h6
-rw-r--r--eval/src/vespa/eval/instruction/vector_from_doubles_function.cpp (renamed from eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp)32
-rw-r--r--eval/src/vespa/eval/instruction/vector_from_doubles_function.h (renamed from eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h)22
-rw-r--r--eval/src/vespa/eval/onnx/CMakeLists.txt (renamed from python/vespa/vespa/__init__.py)5
-rw-r--r--eval/src/vespa/eval/onnx/onnx_wrapper.cpp (renamed from eval/src/vespa/eval/tensor/dense/onnx_wrapper.cpp)40
-rw-r--r--eval/src/vespa/eval/onnx/onnx_wrapper.h (renamed from eval/src/vespa/eval/tensor/dense/onnx_wrapper.h)26
-rw-r--r--eval/src/vespa/eval/streamed/streamed_value_index.cpp4
-rw-r--r--eval/src/vespa/eval/streamed/streamed_value_utils.h4
-rw-r--r--eval/src/vespa/eval/tensor/CMakeLists.txt10
-rw-r--r--eval/src/vespa/eval/tensor/cell_function.h19
-rw-r--r--eval/src/vespa/eval/tensor/cell_values.h32
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.cpp489
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.h37
-rw-r--r--eval/src/vespa/eval/tensor/dense/CMakeLists.txt28
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.cpp91
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.h114
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_generic_join.h24
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_generic_join.hpp62
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp185
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_lambda_function.h30
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp124
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_number_join_function.h34
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp54
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h25
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor.cpp76
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor.h37
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp47
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h27
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp16
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h47
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h33
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp42
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h31
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp50
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.h18
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp112
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.cpp21
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.h31
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp324
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_view.h68
-rw-r--r--eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp15
-rw-r--r--eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h26
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.cpp3
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.h40
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp46
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h41
-rw-r--r--eval/src/vespa/eval/tensor/join_tensors.h46
-rw-r--r--eval/src/vespa/eval/tensor/serialization/CMakeLists.txt7
-rw-r--r--eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp127
-rw-r--r--eval/src/vespa/eval/tensor/serialization/dense_binary_format.h31
-rw-r--r--eval/src/vespa/eval/tensor/serialization/sparse_binary_format.cpp168
-rw-r--r--eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h26
-rw-r--r--eval/src/vespa/eval/tensor/serialization/typed_binary_format.cpp151
-rw-r--r--eval/src/vespa/eval/tensor/serialization/typed_binary_format.h28
-rw-r--r--eval/src/vespa/eval/tensor/sparse/CMakeLists.txt17
-rw-r--r--eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp46
-rw-r--r--eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h69
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp88
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor.h38
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp46
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h31
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp29
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h60
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.cpp65
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h31
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_decoder.h41
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.cpp28
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.h48
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.cpp14
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.h67
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.cpp294
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.h48
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.h22
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.hpp40
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.cpp44
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.h34
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp45
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.h35
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_reduce.hpp47
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.cpp50
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.h31
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.cpp259
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.h42
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.cpp36
-rw-r--r--eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.h41
-rw-r--r--eval/src/vespa/eval/tensor/tensor.cpp36
-rw-r--r--eval/src/vespa/eval/tensor/tensor.h68
-rw-r--r--eval/src/vespa/eval/tensor/tensor_address.cpp89
-rw-r--r--eval/src/vespa/eval/tensor/tensor_address.h89
-rw-r--r--eval/src/vespa/eval/tensor/tensor_address_builder.h29
-rw-r--r--eval/src/vespa/eval/tensor/tensor_address_element_iterator.h43
-rw-r--r--eval/src/vespa/eval/tensor/tensor_visitor.h22
-rw-r--r--eval/src/vespa/eval/tensor/test/test_utils.h22
-rw-r--r--eval/src/vespa/eval/tensor/types.h17
-rw-r--r--eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp186
-rw-r--r--eval/src/vespa/eval/tensor/wrapped_simple_tensor.h48
-rw-r--r--eval/src/vespa/eval/tensor/wrapped_simple_value.cpp174
-rw-r--r--eval/src/vespa/eval/tensor/wrapped_simple_value.h53
-rw-r--r--fbench/src/fbench/fbench.cpp2
-rw-r--r--flags/pom.xml5
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java40
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java235
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java172
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/ClusterCapacity.java89
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/HostCapacity.java73
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java3
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java50
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java29
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java25
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/custom/ClusterCapacityTest.java41
-rw-r--r--flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java25
-rw-r--r--fnet/src/examples/frt/rpc/echo_client.cpp4
-rw-r--r--fnet/src/examples/frt/rpc/rpc_callback_client.cpp4
-rw-r--r--fnet/src/examples/frt/rpc/rpc_callback_server.cpp6
-rw-r--r--fnet/src/examples/frt/rpc/rpc_client.cpp4
-rw-r--r--fnet/src/examples/frt/rpc/rpc_info.cpp4
-rw-r--r--fnet/src/examples/frt/rpc/rpc_invoke.cpp4
-rw-r--r--fnet/src/examples/frt/rpc/rpc_proxy.cpp25
-rw-r--r--fnet/src/examples/frt/rpc/rpc_server.cpp5
-rw-r--r--fnet/src/examples/ping/packets.cpp2
-rw-r--r--fnet/src/examples/ping/pingclient.cpp6
-rw-r--r--fnet/src/examples/ping/pingserver.cpp7
-rw-r--r--fnet/src/examples/proxy/proxy.cpp12
-rw-r--r--fnet/src/examples/timeout/timeout.cpp6
-rw-r--r--fnet/src/tests/connect/connect_test.cpp13
-rw-r--r--fnet/src/tests/connection_spread/connection_spread_test.cpp8
-rw-r--r--fnet/src/tests/frt/method_pt/method_pt.cpp5
-rw-r--r--fnet/src/tests/frt/parallel_rpc/parallel_rpc_test.cpp17
-rw-r--r--fnet/src/tests/frt/parallel_rpc/tls_rpc_bench.cpp4
-rw-r--r--fnet/src/tests/frt/rpc/detach_return_invoke.cpp5
-rw-r--r--fnet/src/tests/frt/rpc/invoke.cpp13
-rw-r--r--fnet/src/tests/frt/rpc/session.cpp4
-rw-r--r--fnet/src/tests/frt/rpc/sharedblob.cpp4
-rw-r--r--fnet/src/tests/info/info.cpp6
-rw-r--r--fnet/src/tests/locking/castspeed.cpp1
-rw-r--r--fnet/src/tests/locking/drainpackets.cpp3
-rw-r--r--fnet/src/tests/locking/lockspeed.cpp1
-rw-r--r--fnet/src/tests/scheduling/schedule.cpp25
-rw-r--r--fnet/src/tests/scheduling/sloweventloop.cpp13
-rw-r--r--fnet/src/tests/thread_selection/thread_selection_test.cpp2
-rw-r--r--fnet/src/tests/time/timespeed.cpp1
-rw-r--r--fnet/src/vespa/fnet/config.cpp3
-rw-r--r--fnet/src/vespa/fnet/config.h5
-rw-r--r--fnet/src/vespa/fnet/connection.cpp4
-rw-r--r--fnet/src/vespa/fnet/fnet.h68
-rw-r--r--fnet/src/vespa/fnet/frt/frt.h35
-rw-r--r--fnet/src/vespa/fnet/frt/supervisor.cpp2
-rw-r--r--fnet/src/vespa/fnet/iocomponent.cpp8
-rw-r--r--fnet/src/vespa/fnet/iocomponent.h6
-rw-r--r--fnet/src/vespa/fnet/scheduler.cpp8
-rw-r--r--fnet/src/vespa/fnet/scheduler.h31
-rw-r--r--fnet/src/vespa/fnet/transport.cpp74
-rw-r--r--fnet/src/vespa/fnet/transport.h115
-rw-r--r--fnet/src/vespa/fnet/transport_thread.cpp99
-rw-r--r--fnet/src/vespa/fnet/transport_thread.h84
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSet.java24
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSetSelector.java3
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/application/UriPattern.java77
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/core/DefaultBindingSelector.java1
-rw-r--r--jdisc_core/src/test/java/com/yahoo/jdisc/application/UriPatternTestCase.java52
-rw-r--r--jdisc_http_service/abi-spec.json6
-rw-r--r--jdisc_http_service/pom.xml6
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/Exceptions.java30
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java2
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java27
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java2
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java44
-rw-r--r--jrt/src/com/yahoo/jrt/Transport.java27
-rw-r--r--jrt/src/com/yahoo/jrt/TransportThread.java19
-rw-r--r--jrt/tests/com/yahoo/jrt/CryptoUtils.java4
-rw-r--r--jrt_test/src/jrt-test/simpleserver/simpleserver.cpp4
-rw-r--r--jrt_test/src/tests/echo/echo-client.cpp5
-rw-r--r--jrt_test/src/tests/mandatory-methods/extract-reflection.cpp4
-rw-r--r--jrt_test/src/tests/mockup-invoke/mockup-server.cpp10
-rw-r--r--jrt_test/src/tests/rpc-error/test-errors.cpp4
-rw-r--r--juniper/src/test/auxTest.cpp31
-rw-r--r--juniper/src/test/mcandTest.cpp2
-rw-r--r--juniper/src/vespa/juniper/Matcher.cpp4
-rw-r--r--juniper/src/vespa/juniper/Matcher.h1
-rw-r--r--juniper/src/vespa/juniper/keyocc.h1
-rw-r--r--juniper/src/vespa/juniper/matchelem.h6
-rw-r--r--juniper/src/vespa/juniper/mcand.h2
-rw-r--r--juniper/src/vespa/juniper/multiset.h81
-rw-r--r--juniper/src/vespa/juniper/sumdesc.h2
-rw-r--r--logd/src/logd/rpc_forwarder.cpp4
-rw-r--r--logd/src/logd/rpc_forwarder.h4
-rw-r--r--logd/src/tests/rpc_forwarder/rpc_forwarder_test.cpp4
-rw-r--r--messagebus/abi-spec.json2
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/DynamicThrottlePolicy.java89
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/IntermediateSession.java4
-rwxr-xr-xmessagebus/src/main/java/com/yahoo/messagebus/ProtocolRepository.java5
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/SourceSession.java4
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/network/NetworkOwner.java2
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetwork.java3
-rwxr-xr-xmessagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetworkParams.java11
-rwxr-xr-xmessagebus/src/main/java/com/yahoo/messagebus/routing/PolicyDirective.java2
-rwxr-xr-xmessagebus/src/main/java/com/yahoo/messagebus/routing/RoutingNode.java2
-rwxr-xr-xmessagebus/src/test/java/com/yahoo/messagebus/ConfigAgentTestCase.java36
-rw-r--r--messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java353
-rw-r--r--messagebus/src/test/java/com/yahoo/messagebus/ThrottlerTestCase.java8
-rw-r--r--messagebus/src/test/java/com/yahoo/messagebus/routing/RoutingTestCase.java1
-rw-r--r--messagebus/src/vespa/messagebus/network/rpcnetwork.cpp14
-rw-r--r--messagebus/src/vespa/messagebus/network/rpcnetwork.h41
-rw-r--r--messagebus/src/vespa/messagebus/network/rpctarget.cpp2
-rw-r--r--metrics/src/tests/CMakeLists.txt1
-rw-r--r--metrics/src/tests/loadmetrictest.cpp128
-rw-r--r--metrics/src/tests/metricmanagertest.cpp65
-rw-r--r--metrics/src/tests/snapshottest.cpp137
-rw-r--r--metrics/src/tests/stresstest.cpp53
-rw-r--r--metrics/src/vespa/metrics/CMakeLists.txt3
-rw-r--r--metrics/src/vespa/metrics/common/memory_usage_metrics.h3
-rw-r--r--metrics/src/vespa/metrics/loadmetric.cpp20
-rw-r--r--metrics/src/vespa/metrics/loadmetric.h66
-rw-r--r--metrics/src/vespa/metrics/loadmetric.hpp102
-rw-r--r--metrics/src/vespa/metrics/loadtype.h25
-rw-r--r--metrics/src/vespa/metrics/metricmanager.cpp4
-rw-r--r--metrics/src/vespa/metrics/metricmanager.h2
-rw-r--r--metrics/src/vespa/metrics/metrics.h2
-rw-r--r--metrics/src/vespa/metrics/metricset.cpp2
-rw-r--r--metrics/src/vespa/metrics/printutils.cpp278
-rw-r--r--metrics/src/vespa/metrics/printutils.h214
-rw-r--r--metrics/src/vespa/metrics/state_api_adapter.h2
-rw-r--r--metrics/src/vespa/metrics/updatehook.cpp18
-rw-r--r--metrics/src/vespa/metrics/updatehook.h19
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java3
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java4
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java4
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java4
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java33
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Cluster.java36
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/ScalingEvent.java32
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java33
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java117
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java68
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java22
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsDb.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java36
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java16
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java128
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java71
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java237
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java53
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainer.java18
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java110
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/History.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/JobControlFlags.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java29
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FlavorConfigBuilder.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java47
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java18
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java26
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LocksResponse.java61
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java52
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java16
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java59
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java116
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java9
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java311
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java17
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java33
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainerTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java26
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/capacity-zone.json4
-rw-r--r--parent/pom.xml11
-rw-r--r--persistence/src/vespa/persistence/conformancetest/conformancetest.cpp1
-rw-r--r--pom.xml1
-rw-r--r--python/vespa/.gitignore141
-rw-r--r--python/vespa/MANIFEST.in2
-rw-r--r--python/vespa/Pipfile11
-rw-r--r--python/vespa/README.md118
-rw-r--r--python/vespa/docs/sphinx/Makefile20
-rw-r--r--python/vespa/docs/sphinx/source/application-package.ipynb139
-rw-r--r--python/vespa/docs/sphinx/source/collect-training-data.ipynb1232
-rw-r--r--python/vespa/docs/sphinx/source/conf.py63
-rw-r--r--python/vespa/docs/sphinx/source/connect-to-vespa-instance.ipynb980
-rw-r--r--python/vespa/docs/sphinx/source/create-and-deploy-vespa-cloud.ipynb993
-rw-r--r--python/vespa/docs/sphinx/source/create-and-deploy-vespa-docker.ipynb214
-rw-r--r--python/vespa/docs/sphinx/source/deploy-application.ipynb41
-rw-r--r--python/vespa/docs/sphinx/source/evaluation.ipynb297
-rw-r--r--python/vespa/docs/sphinx/source/howto.rst12
-rw-r--r--python/vespa/docs/sphinx/source/index.rst61
-rw-r--r--python/vespa/docs/sphinx/source/install.rst8
-rw-r--r--python/vespa/docs/sphinx/source/query-model.ipynb41
-rw-r--r--python/vespa/docs/sphinx/source/query.ipynb297
-rw-r--r--python/vespa/docs/sphinx/source/quickstart.rst11
-rw-r--r--python/vespa/docs/sphinx/source/reference-api.rst35
-rw-r--r--python/vespa/docs/sphinx/source/requirements.txt5
-rw-r--r--python/vespa/setup.py39
-rw-r--r--python/vespa/vespa/_nbdev.py13
-rw-r--r--python/vespa/vespa/application.py301
-rw-r--r--python/vespa/vespa/evaluation.py132
-rw-r--r--python/vespa/vespa/json_serialization.py77
-rw-r--r--python/vespa/vespa/package.py786
-rw-r--r--python/vespa/vespa/query.py229
-rw-r--r--python/vespa/vespa/templates/hosts.xml7
-rw-r--r--python/vespa/vespa/templates/schema.txt28
-rw-r--r--python/vespa/vespa/templates/services.xml16
-rw-r--r--python/vespa/vespa/test_application.py375
-rw-r--r--python/vespa/vespa/test_evaluation.py186
-rw-r--r--python/vespa/vespa/test_package.py243
-rw-r--r--python/vespa/vespa/test_query.py190
-rw-r--r--screwdriver.yaml77
-rw-r--r--searchcommon/src/vespa/searchcommon/common/schema.cpp18
-rw-r--r--searchcommon/src/vespa/searchcommon/common/schema.h18
-rw-r--r--searchcore/src/apps/verify_ranksetup/verify_ranksetup.cpp8
-rw-r--r--searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp5
-rw-r--r--searchcore/src/apps/vespa-feed-bm/bm_cluster_controller.cpp3
-rw-r--r--searchcore/src/apps/vespa-feed-bm/bm_message_bus.cpp7
-rw-r--r--searchcore/src/apps/vespa-feed-bm/bm_message_bus.h4
-rw-r--r--searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.cpp12
-rw-r--r--searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/i_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/pending_tracker.cpp20
-rw-r--r--searchcore/src/apps/vespa-feed-bm/pending_tracker.h21
-rwxr-xr-xsearchcore/src/apps/vespa-feed-bm/runtest.sh7
-rw-r--r--searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.cpp6
-rw-r--r--searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.cpp6
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.cpp11
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.cpp16
-rw-r--r--searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.h1
-rw-r--r--searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp27
-rw-r--r--searchcore/src/apps/vespa-gen-testdocs/vespa-gen-testdocs.cpp4
-rw-r--r--searchcore/src/apps/vespa-proton-cmd/vespa-proton-cmd.cpp13
-rw-r--r--searchcore/src/tests/proton/attribute/attribute_test.cpp11
-rw-r--r--searchcore/src/tests/proton/common/attribute_updater/attribute_updater_test.cpp12
-rw-r--r--searchcore/src/tests/proton/docsummary/docsummary.cpp9
-rw-r--r--searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp10
-rw-r--r--searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp13
-rw-r--r--searchcore/src/tests/proton/documentmetastore/lidreusedelayer/lidreusedelayer_test.cpp4
-rw-r--r--searchcore/src/tests/proton/matching/matching_test.cpp9
-rw-r--r--searchcore/src/tests/proton/matching/request_context/request_context_test.cpp16
-rw-r--r--searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp1
-rw-r--r--searchcore/src/tests/proton/server/documentretriever_test.cpp13
-rw-r--r--searchcore/src/tests/proton/summaryengine/summaryengine.cpp1
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.h2
-rw-r--r--searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp4
-rw-r--r--searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.cpp9
-rw-r--r--searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.h3
-rw-r--r--searchcore/src/vespa/searchcore/proton/flushengine/flushengine.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/initializer/task_runner.cpp6
-rw-r--r--searchcore/src/vespa/searchcore/proton/matchengine/matchengine.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.cpp14
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.h6
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/docsum_matcher.cpp6
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/match_master.cpp1
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/querylimiter.h2
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/requestcontext.cpp8
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/attribute_metrics.h2
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/content_proton_metrics.h1
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.cpp37
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.h4
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/resource_usage_metrics.h3
-rw-r--r--searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp1
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/CMakeLists.txt3
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/disk_mem_usage_forwarder.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/document_db_explorer.cpp22
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdb.cpp31
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdb.h43
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.cpp11
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdbconfig.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentdbconfig.h2
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp57
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.h16
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_thread_service.cpp4
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_thread_service.h1
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.cpp84
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.h25
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton.cpp55
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton.h40
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton_configurer.cpp4
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.cpp43
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.h35
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/searchable_feed_view.cpp10
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp5
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.cpp5
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/summaryengine/summaryengine.h5
-rw-r--r--searchcore/src/vespa/searchcore/proton/test/thread_service_observer.h4
-rw-r--r--searchlib/src/apps/docstore/documentstoreinspect.cpp2
-rw-r--r--searchlib/src/apps/tests/btreestress_test.cpp14
-rw-r--r--searchlib/src/apps/tests/memoryindexstress_test.cpp4
-rw-r--r--searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp5
-rw-r--r--searchlib/src/test/java/com/yahoo/searchlib/tensor/TensorConformanceTest.java142
-rw-r--r--searchlib/src/tests/attribute/imported_attribute_vector/imported_attribute_vector_test.cpp8
-rw-r--r--searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp2
-rw-r--r--searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp9
-rw-r--r--searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp4
-rw-r--r--searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp15
-rw-r--r--searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp6
-rw-r--r--searchlib/src/tests/features/constant/constant_test.cpp10
-rw-r--r--searchlib/src/tests/features/imported_dot_product/imported_dot_product_test.cpp24
-rw-r--r--searchlib/src/tests/features/tensor/tensor_test.cpp68
-rw-r--r--searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp7
-rw-r--r--searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp6
-rw-r--r--searchlib/src/tests/memoryindex/url_field_inverter/url_field_inverter_test.cpp4
-rw-r--r--searchlib/src/tests/query/stackdumpquerycreator_test.cpp6
-rw-r--r--searchlib/src/tests/query/streaming_query_test.cpp2
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp4
-rw-r--r--searchlib/src/tests/queryeval/nearest_neighbor/nearest_neighbor_test.cpp7
-rw-r--r--searchlib/src/tests/queryeval/predicate/predicate_search_test.cpp4
-rw-r--r--searchlib/src/tests/tensor/dense_tensor_store/dense_tensor_store_test.cpp15
-rw-r--r--searchlib/src/tests/tensor/direct_tensor_store/direct_tensor_store_test.cpp7
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp1
-rw-r--r--searchlib/src/vespa/searchlib/attribute/createsinglestd.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/attribute/integerbase.cpp33
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/not_implemented_attribute.h2
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location.h3
-rw-r--r--searchlib/src/vespa/searchlib/engine/search_protocol_metrics.h4
-rw-r--r--searchlib/src/vespa/searchlib/expression/resultvector.h4
-rw-r--r--searchlib/src/vespa/searchlib/features/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/features/attributefeature.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/features/constant_tensor_executor.h8
-rw-r--r--searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.cpp3
-rw-r--r--searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.h4
-rw-r--r--searchlib/src/vespa/searchlib/features/dotproductfeature.cpp7
-rw-r--r--searchlib/src/vespa/searchlib/features/mutable_dense_value_view.cpp14
-rw-r--r--searchlib/src/vespa/searchlib/features/mutable_dense_value_view.h33
-rw-r--r--searchlib/src/vespa/searchlib/features/onnx_feature.cpp6
-rw-r--r--searchlib/src/vespa/searchlib/features/onnx_feature.h4
-rw-r--r--searchlib/src/vespa/searchlib/features/queryfeature.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp7
-rw-r--r--searchlib/src/vespa/searchlib/features/tensor_from_attribute_executor.h22
-rw-r--r--searchlib/src/vespa/searchlib/features/tensor_from_labels_feature.cpp19
-rw-r--r--searchlib/src/vespa/searchlib/features/tensor_from_weighted_set_feature.cpp24
-rw-r--r--searchlib/src/vespa/searchlib/features/termdistancefeature.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/grouping/sketch.h6
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp8
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h6
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/iterators.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/iterators.h1
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp12
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.cpp9
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.h1
-rw-r--r--searchlib/src/vespa/searchlib/tensor/CMakeLists.txt3
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp10
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.h6
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp18
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h2
-rw-r--r--searchlib/src/vespa/searchlib/tensor/direct_tensor_attribute.cpp8
-rw-r--r--searchlib/src/vespa/searchlib/tensor/direct_tensor_saver.cpp5
-rw-r--r--searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h8
-rw-r--r--searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.cpp6
-rw-r--r--searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.h4
-rw-r--r--searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.cpp234
-rw-r--r--searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.h33
-rw-r--r--searchlib/src/vespa/searchlib/tensor/serialized_tensor_store.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/tensor/streamed_value_saver.cpp48
-rw-r--r--searchlib/src/vespa/searchlib/tensor/streamed_value_saver.h35
-rw-r--r--searchlib/src/vespa/searchlib/tensor/streamed_value_store.cpp220
-rw-r--r--searchlib/src/vespa/searchlib/tensor/streamed_value_store.h96
-rw-r--r--searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp21
-rw-r--r--searchlib/src/vespa/searchlib/tensor/tensor_attribute.h4
-rw-r--r--searchlib/src/vespa/searchlib/tensor/tensor_deserialize.cpp20
-rw-r--r--searchlib/src/vespa/searchlib/tensor/tensor_deserialize.h4
-rw-r--r--searchlib/src/vespa/searchlib/transactionlog/domainpart.cpp104
-rw-r--r--searchlib/src/vespa/searchlib/transactionlog/domainpart.h24
-rw-r--r--searchlib/src/vespa/searchlib/transactionlog/session.cpp8
-rw-r--r--searchlib/src/vespa/searchlib/util/rawbuf.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/util/rawbuf.h2
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp5
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/summaryfieldconverter.cpp4
-rw-r--r--security-utils/src/main/java/com/yahoo/security/X509CertificateBuilder.java5
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java4
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java2
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java5
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java6
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java29
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/UriPattern.java46
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/DefaultTlsContextTest.java3
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/authz/PeerAuthorizerTest.java50
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java13
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/policy/AuthorizedPeersTest.java2
-rw-r--r--security-utils/src/test/resources/transport-security-options-with-authz-rules.json29
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java9
-rw-r--r--simplemetrics/src/main/java/com/yahoo/metrics/simple/MetricUpdater.java2
-rw-r--r--slobrok/src/apps/slobrok/slobrok.cpp1
-rw-r--r--staging_vespalib/src/tests/objectselection/objectselection.cpp3
-rw-r--r--staging_vespalib/src/tests/sequencedtaskexecutor/foregroundtaskexecutor_test.cpp2
-rw-r--r--staging_vespalib/src/tests/sequencedtaskexecutor/sequencedtaskexecutor_test.cpp2
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.cpp7
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.h3
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/foreground_thread_executor.h1
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.cpp9
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.h2
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/singleexecutor.h4
-rw-r--r--standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java6
-rw-r--r--storage/src/tests/bucketdb/bucketmanagertest.cpp1
-rw-r--r--storage/src/tests/common/CMakeLists.txt1
-rw-r--r--storage/src/tests/common/bucket_utils_test.cpp30
-rw-r--r--storage/src/tests/common/metricstest.cpp65
-rw-r--r--storage/src/tests/common/teststorageapp.cpp10
-rw-r--r--storage/src/tests/common/teststorageapp.h12
-rw-r--r--storage/src/tests/distributor/CMakeLists.txt2
-rw-r--r--storage/src/tests/distributor/blockingoperationstartertest.cpp5
-rw-r--r--storage/src/tests/distributor/bucketdatabasetest.cpp35
-rw-r--r--storage/src/tests/distributor/bucketdbmetricupdatertest.cpp17
-rw-r--r--storage/src/tests/distributor/bucketdbupdatertest.cpp21
-rw-r--r--storage/src/tests/distributor/bucketstateoperationtest.cpp27
-rw-r--r--storage/src/tests/distributor/distributor_bucket_space_test.cpp200
-rw-r--r--storage/src/tests/distributor/distributor_message_sender_stub.cpp4
-rw-r--r--storage/src/tests/distributor/distributor_message_sender_stub.h16
-rw-r--r--storage/src/tests/distributor/distributortest.cpp32
-rw-r--r--storage/src/tests/distributor/distributortestutil.cpp19
-rw-r--r--storage/src/tests/distributor/distributortestutil.h11
-rw-r--r--storage/src/tests/distributor/dummy_cluster_context.h13
-rw-r--r--storage/src/tests/distributor/externaloperationhandlertest.cpp122
-rw-r--r--storage/src/tests/distributor/garbagecollectiontest.cpp3
-rw-r--r--storage/src/tests/distributor/getoperationtest.cpp9
-rw-r--r--storage/src/tests/distributor/idealstatemanagertest.cpp61
-rw-r--r--storage/src/tests/distributor/joinbuckettest.cpp5
-rw-r--r--storage/src/tests/distributor/maintenancemocks.h6
-rw-r--r--storage/src/tests/distributor/mergeoperationtest.cpp27
-rw-r--r--storage/src/tests/distributor/operation_sequencer_test.cpp91
-rw-r--r--storage/src/tests/distributor/operationtargetresolvertest.cpp6
-rw-r--r--storage/src/tests/distributor/pendingmessagetrackertest.cpp131
-rw-r--r--storage/src/tests/distributor/putoperationtest.cpp30
-rw-r--r--storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp221
-rw-r--r--storage/src/tests/distributor/removebucketoperationtest.cpp7
-rw-r--r--storage/src/tests/distributor/removelocationtest.cpp6
-rw-r--r--storage/src/tests/distributor/removeoperationtest.cpp7
-rw-r--r--storage/src/tests/distributor/simplemaintenancescannertest.cpp2
-rw-r--r--storage/src/tests/distributor/splitbuckettest.cpp66
-rw-r--r--storage/src/tests/distributor/statecheckerstest.cpp24
-rw-r--r--storage/src/tests/distributor/statoperationtest.cpp3
-rw-r--r--storage/src/tests/distributor/twophaseupdateoperationtest.cpp18
-rw-r--r--storage/src/tests/distributor/updateoperationtest.cpp20
-rw-r--r--storage/src/tests/distributor/visitoroperationtest.cpp38
-rw-r--r--storage/src/tests/persistence/common/filestortestfixture.cpp4
-rw-r--r--storage/src/tests/persistence/filestorage/filestormanagertest.cpp202
-rw-r--r--storage/src/tests/persistence/filestorage/mergeblockingtest.cpp3
-rw-r--r--storage/src/tests/persistence/filestorage/operationabortingtest.cpp2
-rw-r--r--storage/src/tests/persistence/mergehandlertest.cpp4
-rw-r--r--storage/src/tests/persistence/persistencequeuetest.cpp7
-rw-r--r--storage/src/tests/persistence/persistencetestutils.cpp4
-rw-r--r--storage/src/tests/persistence/processalltest.cpp4
-rw-r--r--storage/src/tests/persistence/splitbitdetectortest.cpp1
-rw-r--r--storage/src/tests/storageserver/communicationmanagertest.cpp6
-rw-r--r--storage/src/tests/storageserver/mergethrottlertest.cpp38
-rw-r--r--storage/src/tests/storageserver/rpc/caching_rpc_target_resolver_test.cpp6
-rw-r--r--storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp2
-rw-r--r--storage/src/tests/storageserver/rpc/message_codec_provider_test.cpp11
-rw-r--r--storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp22
-rw-r--r--storage/src/tests/storageserver/statereportertest.cpp12
-rw-r--r--storage/src/tests/visiting/visitormanagertest.cpp60
-rw-r--r--storage/src/tests/visiting/visitortest.cpp89
-rw-r--r--storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp6
-rw-r--r--storage/src/vespa/storage/bucketdb/btree_bucket_database.h1
-rw-r--r--storage/src/vespa/storage/bucketdb/bucketdatabase.h17
-rw-r--r--storage/src/vespa/storage/bucketdb/bucketmanager.cpp55
-rw-r--r--storage/src/vespa/storage/bucketdb/bucketmanagermetrics.h2
-rw-r--r--storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.h2
-rw-r--r--storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.hpp34
-rw-r--r--storage/src/vespa/storage/common/CMakeLists.txt5
-rw-r--r--storage/src/vespa/storage/common/bucket_utils.h25
-rw-r--r--storage/src/vespa/storage/common/bucketmessages.cpp49
-rw-r--r--storage/src/vespa/storage/common/bucketmessages.h58
-rw-r--r--storage/src/vespa/storage/common/bucketoperationlogger.cpp330
-rw-r--r--storage/src/vespa/storage/common/bucketoperationlogger.h123
-rw-r--r--storage/src/vespa/storage/common/cluster_context.h46
-rw-r--r--storage/src/vespa/storage/common/messagebucket.cpp2
-rw-r--r--storage/src/vespa/storage/common/messagesender.h9
-rw-r--r--storage/src/vespa/storage/common/node_identity.cpp16
-rw-r--r--storage/src/vespa/storage/common/node_identity.h28
-rw-r--r--storage/src/vespa/storage/common/reindexing_constants.cpp16
-rw-r--r--storage/src/vespa/storage/common/reindexing_constants.h10
-rw-r--r--storage/src/vespa/storage/common/statusmetricconsumer.cpp915
-rw-r--r--storage/src/vespa/storage/common/statusmetricconsumer.h35
-rw-r--r--storage/src/vespa/storage/common/storagecomponent.cpp40
-rw-r--r--storage/src/vespa/storage/common/storagecomponent.h27
-rw-r--r--storage/src/vespa/storage/config/distributorconfiguration.cpp2
-rw-r--r--storage/src/vespa/storage/config/distributorconfiguration.h6
-rw-r--r--storage/src/vespa/storage/config/stor-communicationmanager.def31
-rw-r--r--storage/src/vespa/storage/config/stor-server.def2
-rw-r--r--storage/src/vespa/storage/distributor/CMakeLists.txt2
-rw-r--r--storage/src/vespa/storage/distributor/blockingoperationstarter.cpp2
-rw-r--r--storage/src/vespa/storage/distributor/blockingoperationstarter.h6
-rw-r--r--storage/src/vespa/storage/distributor/bucket_ownership_flags.h29
-rw-r--r--storage/src/vespa/storage/distributor/bucket_space_distribution_context.cpp2
-rw-r--r--storage/src/vespa/storage/distributor/bucket_space_distribution_context.h2
-rw-r--r--storage/src/vespa/storage/distributor/bucketdbupdater.cpp16
-rw-r--r--storage/src/vespa/storage/distributor/bucketdbupdater.h3
-rw-r--r--storage/src/vespa/storage/distributor/bucketownership.h2
-rw-r--r--storage/src/vespa/storage/distributor/crypto_uuid_generator.cpp20
-rw-r--r--storage/src/vespa/storage/distributor/crypto_uuid_generator.h18
-rw-r--r--storage/src/vespa/storage/distributor/distributor.cpp62
-rw-r--r--storage/src/vespa/storage/distributor/distributor.h34
-rw-r--r--storage/src/vespa/storage/distributor/distributor_bucket_space.cpp169
-rw-r--r--storage/src/vespa/storage/distributor/distributor_bucket_space.h46
-rw-r--r--storage/src/vespa/storage/distributor/distributor_bucket_space_repo.cpp24
-rw-r--r--storage/src/vespa/storage/distributor/distributor_bucket_space_repo.h6
-rw-r--r--storage/src/vespa/storage/distributor/distributor_node_context.h26
-rw-r--r--storage/src/vespa/storage/distributor/distributor_operation_context.h57
-rw-r--r--storage/src/vespa/storage/distributor/distributorcomponent.cpp240
-rw-r--r--storage/src/vespa/storage/distributor/distributorcomponent.h107
-rw-r--r--storage/src/vespa/storage/distributor/distributorinterface.h1
-rw-r--r--storage/src/vespa/storage/distributor/distributormessagesender.cpp8
-rw-r--r--storage/src/vespa/storage/distributor/distributormessagesender.h6
-rw-r--r--storage/src/vespa/storage/distributor/distributormetricsset.cpp30
-rw-r--r--storage/src/vespa/storage/distributor/distributormetricsset.h26
-rw-r--r--storage/src/vespa/storage/distributor/document_selection_parser.h21
-rw-r--r--storage/src/vespa/storage/distributor/externaloperationhandler.cpp250
-rw-r--r--storage/src/vespa/storage/distributor/externaloperationhandler.h58
-rw-r--r--storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.cpp17
-rw-r--r--storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.h28
-rw-r--r--storage/src/vespa/storage/distributor/idealstatemanager.h5
-rw-r--r--storage/src/vespa/storage/distributor/idealstatemetricsset.h4
-rw-r--r--storage/src/vespa/storage/distributor/messagetracker.cpp7
-rw-r--r--storage/src/vespa/storage/distributor/messagetracker.h9
-rw-r--r--storage/src/vespa/storage/distributor/operation_sequencer.cpp52
-rw-r--r--storage/src/vespa/storage/distributor/operation_sequencer.h102
-rw-r--r--storage/src/vespa/storage/distributor/operationowner.h12
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/CMakeLists.txt1
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/getoperation.cpp11
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/getoperation.h8
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/putoperation.cpp36
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/putoperation.h9
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp108
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h53
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/removelocationoperation.cpp21
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/removelocationoperation.h10
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/removeoperation.cpp9
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/removeoperation.h5
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/statbucketoperation.cpp1
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/statbucketoperation.h3
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp77
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.h13
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/updateoperation.cpp33
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/updateoperation.h11
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp187
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/visitoroperation.h45
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.cpp4
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h5
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.cpp18
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.h10
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.cpp19
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.h23
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.cpp18
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.h2
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/removebucketoperation.h4
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.cpp19
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h4
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp29
-rw-r--r--storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.h7
-rw-r--r--storage/src/vespa/storage/distributor/operations/operation.h3
-rw-r--r--storage/src/vespa/storage/distributor/operationtargetresolverimpl.cpp35
-rw-r--r--storage/src/vespa/storage/distributor/operationtargetresolverimpl.h21
-rw-r--r--storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp1
-rw-r--r--storage/src/vespa/storage/distributor/pendingclusterstate.cpp1
-rw-r--r--storage/src/vespa/storage/distributor/pendingmessagetracker.cpp103
-rw-r--r--storage/src/vespa/storage/distributor/pendingmessagetracker.h84
-rw-r--r--storage/src/vespa/storage/distributor/persistence_operation_metric_set.cpp1
-rw-r--r--storage/src/vespa/storage/distributor/persistence_operation_metric_set.h6
-rw-r--r--storage/src/vespa/storage/distributor/persistencemessagetracker.cpp25
-rw-r--r--storage/src/vespa/storage/distributor/persistencemessagetracker.h5
-rw-r--r--storage/src/vespa/storage/distributor/statecheckers.cpp58
-rw-r--r--storage/src/vespa/storage/distributor/update_metric_set.cpp7
-rw-r--r--storage/src/vespa/storage/distributor/update_metric_set.h2
-rw-r--r--storage/src/vespa/storage/distributor/uuid_generator.h19
-rw-r--r--storage/src/vespa/storage/distributor/visitormetricsset.cpp9
-rw-r--r--storage/src/vespa/storage/distributor/visitormetricsset.h2
-rw-r--r--storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.cpp24
-rw-r--r--storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h9
-rw-r--r--storage/src/vespa/storage/persistence/asynchandler.cpp6
-rw-r--r--storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp13
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestorhandler.h6
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp39
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.h6
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp28
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormanager.h2
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormetrics.cpp51
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormetrics.h30
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.cpp1
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.h4
-rw-r--r--storage/src/vespa/storage/persistence/mergehandler.cpp20
-rw-r--r--storage/src/vespa/storage/persistence/mergehandler.h5
-rw-r--r--storage/src/vespa/storage/persistence/persistencehandler.cpp4
-rw-r--r--storage/src/vespa/storage/persistence/processallhandler.cpp4
-rw-r--r--storage/src/vespa/storage/persistence/simplemessagehandler.cpp12
-rw-r--r--storage/src/vespa/storage/persistence/splitjoinhandler.cpp26
-rw-r--r--storage/src/vespa/storage/persistence/splitjoinhandler.h2
-rw-r--r--storage/src/vespa/storage/storageserver/bouncer_metrics.h3
-rw-r--r--storage/src/vespa/storage/storageserver/changedbucketownershiphandler.cpp6
-rw-r--r--storage/src/vespa/storage/storageserver/changedbucketownershiphandler.h4
-rw-r--r--storage/src/vespa/storage/storageserver/communicationmanager.cpp38
-rw-r--r--storage/src/vespa/storage/storageserver/communicationmanager.h4
-rw-r--r--storage/src/vespa/storage/storageserver/communicationmanagermetrics.h4
-rw-r--r--storage/src/vespa/storage/storageserver/distributornode.cpp2
-rw-r--r--storage/src/vespa/storage/storageserver/distributornodecontext.h4
-rw-r--r--storage/src/vespa/storage/storageserver/documentapiconverter.cpp2
-rw-r--r--storage/src/vespa/storage/storageserver/fnet_metrics_wrapper.h4
-rw-r--r--storage/src/vespa/storage/storageserver/framework.cpp33
-rw-r--r--storage/src/vespa/storage/storageserver/framework.h57
-rw-r--r--storage/src/vespa/storage/storageserver/mergethrottler.cpp16
-rw-r--r--storage/src/vespa/storage/storageserver/mergethrottler.h8
-rw-r--r--storage/src/vespa/storage/storageserver/priorityconverter.cpp4
-rw-r--r--storage/src/vespa/storage/storageserver/prioritymapper.h43
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/caching_rpc_target_resolver.cpp2
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/message_codec_provider.cpp16
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/message_codec_provider.h11
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp9
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h3
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.cpp10
-rw-r--r--storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.h1
-rw-r--r--storage/src/vespa/storage/storageserver/servicelayernode.cpp11
-rw-r--r--storage/src/vespa/storage/storageserver/servicelayernode.h1
-rw-r--r--storage/src/vespa/storage/storageserver/servicelayernodecontext.h4
-rw-r--r--storage/src/vespa/storage/storageserver/statemanager.cpp1
-rw-r--r--storage/src/vespa/storage/storageserver/statereporter.h1
-rw-r--r--storage/src/vespa/storage/storageserver/storagemetricsset.h1
-rw-r--r--storage/src/vespa/storage/storageserver/storagenode.cpp50
-rw-r--r--storage/src/vespa/storage/storageserver/storagenode.h20
-rw-r--r--storage/src/vespa/storage/storageserver/storagenodecontext.h4
-rw-r--r--storage/src/vespa/storage/storageserver/tls_statistics_metrics_wrapper.h3
-rw-r--r--storage/src/vespa/storage/tools/storage-cmd.cpp4
-rw-r--r--storage/src/vespa/storage/visiting/CMakeLists.txt2
-rw-r--r--storage/src/vespa/storage/visiting/dumpvisitorsingle.h3
-rw-r--r--storage/src/vespa/storage/visiting/reindexing_visitor.cpp58
-rw-r--r--storage/src/vespa/storage/visiting/reindexing_visitor.h38
-rw-r--r--storage/src/vespa/storage/visiting/stor-visitor.def1
-rw-r--r--storage/src/vespa/storage/visiting/visitor.cpp45
-rw-r--r--storage/src/vespa/storage/visiting/visitor.h16
-rw-r--r--storage/src/vespa/storage/visiting/visitormanager.cpp15
-rw-r--r--storage/src/vespa/storage/visiting/visitormessagesessionfactory.h9
-rw-r--r--storage/src/vespa/storage/visiting/visitormetrics.cpp6
-rw-r--r--storage/src/vespa/storage/visiting/visitormetrics.h16
-rw-r--r--storage/src/vespa/storage/visiting/visitorthread.cpp31
-rw-r--r--storage/src/vespa/storage/visiting/visitorthread.h9
-rw-r--r--storage/src/vespa/storage/visiting/visitorthreadmetrics.cpp27
-rw-r--r--storage/src/vespa/storage/visiting/visitorthreadmetrics.h116
-rw-r--r--storageapi/src/tests/mbusprot/storageprotocoltest.cpp39
-rw-r--r--storageapi/src/tests/messageapi/storage_message_address_test.cpp8
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp11
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.h10
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.cpp5
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.h9
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_2.h5
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.cpp9
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.h8
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.cpp15
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.h6
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/storagemessage.h2
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/storageprotocol.cpp13
-rw-r--r--storageapi/src/vespa/storageapi/mbusprot/storageprotocol.h5
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/bucketinforeply.cpp7
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/bucketinforeply.h5
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/bucketreply.cpp8
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/bucketreply.h7
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/returncode.cpp18
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/returncode.h19
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/storagemessage.cpp98
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/storagemessage.h113
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/storagereply.cpp10
-rw-r--r--storageapi/src/vespa/storageapi/messageapi/storagereply.h4
-rw-r--r--storageframework/src/vespa/storageframework/generic/metric/metricupdatehook.h4
-rw-r--r--storageframework/src/vespa/storageframework/generic/status/htmlstatusreporter.cpp10
-rw-r--r--streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp16
-rw-r--r--streamingvisitors/src/vespa/searchvisitor/hitcollector.cpp4
-rwxr-xr-xtravis/detect-what-to-build.sh33
-rwxr-xr-xtravis/travis-build-full.sh23
-rwxr-xr-xtravis/travis-build.sh52
-rwxr-xr-xtravis/travis.sh3
-rw-r--r--vbench/src/tests/handler_thread/handler_thread_test.cpp3
-rw-r--r--vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp2
-rw-r--r--vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h2
-rw-r--r--vdslib/src/vespa/vdslib/state/nodetype.cpp29
-rw-r--r--vdslib/src/vespa/vdslib/state/nodetype.h37
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java35
-rw-r--r--vespaclient/src/vespa/vespaclient/vdsstates/statesapp.cpp4
-rw-r--r--vespaclient/src/vespa/vespaclient/vesparoute/application.cpp3
-rw-r--r--vespaclient/src/vespa/vespaclient/vesparoute/application.h2
-rw-r--r--vespajlib/pom.xml5
-rw-r--r--vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java2
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/CompletableFutures.java67
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/LocalInstance.java6
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/ThreadLocalDirectory.java4
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/maintenance/JobMetrics.java2
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java16
-rw-r--r--vespajlib/src/test/java/com/yahoo/concurrent/CompletableFuturesTest.java66
-rw-r--r--vespalib/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/array/array_test.cpp13
-rw-r--r--vespalib/src/tests/net/selector/selector_test.cpp7
-rw-r--r--vespalib/src/tests/shared_string_repo/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp285
-rw-r--r--vespalib/src/tests/stllike/hash_test.cpp11
-rw-r--r--vespalib/src/tests/stllike/hashtable_test.cpp57
-rw-r--r--vespalib/src/vespa/vespalib/crypto/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/crypto/random.cpp13
-rw-r--r--vespalib/src/vespa/vespalib/crypto/random.h11
-rw-r--r--vespalib/src/vespa/vespalib/data/slime/symbol.h4
-rw-r--r--vespalib/src/vespa/vespalib/net/async_resolver.cpp12
-rw-r--r--vespalib/src/vespa/vespalib/net/async_resolver.h14
-rw-r--r--vespalib/src/vespa/vespalib/net/selector.h6
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.cpp4
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hash_map.h3
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hash_map.hpp7
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hash_set.h3
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hash_set.hpp5
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hashtable.cpp23
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hashtable.h25
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hashtable.hpp88
-rw-r--r--vespalib/src/vespa/vespalib/stllike/string.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/CMakeLists.txt3
-rw-r--r--vespalib/src/vespa/vespalib/util/shared_string_repo.cpp54
-rw-r--r--vespalib/src/vespa/vespalib/util/shared_string_repo.h238
-rw-r--r--vespalib/src/vespa/vespalib/util/threadexecutor.h5
-rw-r--r--vespalib/src/vespa/vespalib/util/threadstackexecutorbase.cpp7
-rw-r--r--vespalib/src/vespa/vespalib/util/threadstackexecutorbase.h2
-rw-r--r--vespalib/src/vespa/vespalib/websocket/websocket_server.cpp16
-rw-r--r--vespalib/src/vespa/vespalib/websocket/websocket_server.h9
-rw-r--r--vespalog/src/vespa/log/bufferedlogger.cpp10
-rw-r--r--vespamalloc/src/vespamalloc/malloc/common.h3
-rw-r--r--vespamalloc/src/vespamalloc/malloc/datasegment.h2
-rw-r--r--vespamalloc/src/vespamalloc/malloc/datasegment.hpp88
-rw-r--r--vespamalloc/src/vespamalloc/malloc/mallocdst.h2
-rw-r--r--vespamalloc/src/vespamalloc/malloc/memblock.h4
-rw-r--r--vespamalloc/src/vespamalloc/malloc/memblockboundscheck.h4
-rw-r--r--vespamalloc/src/vespamalloc/malloc/memblockboundscheck.hpp4
-rw-r--r--vespamalloc/src/vespamalloc/malloc/threadlist.h13
-rw-r--r--vespamalloc/src/vespamalloc/malloc/threadlist.hpp28
-rw-r--r--vespamalloc/src/vespamalloc/malloc/threadpool.h15
-rw-r--r--vespamalloc/src/vespamalloc/malloc/threadpool.hpp6
-rw-r--r--yolean/abi-spec.json3
-rw-r--r--yolean/src/main/java/com/yahoo/yolean/Exceptions.java21
-rw-r--r--zkfacade/src/main/java/com/yahoo/vespa/curator/stats/LatencyMetrics.java2
-rw-r--r--zookeeper-server/CMakeLists.txt4
-rw-r--r--zookeeper-server/pom.xml2
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/CMakeLists.txt3
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/pom.xml2
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java39
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java50
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java47
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java29
-rw-r--r--zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java49
-rw-r--r--zookeeper-server/zookeeper-server-3.5.8/CMakeLists.txt4
-rw-r--r--zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java57
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/CMakeLists.txt4
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/pom.xml (renamed from zookeeper-server/zookeeper-server-3.5.8/pom.xml)19
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java39
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java50
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java47
-rw-r--r--zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java46
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java28
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/DummyVespaZooKeeperServer.java13
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ExponentialBackoff.java47
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ReconfigException.java21
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Reconfigurer.java148
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Sleeper.java22
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdmin.java18
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServer.java17
-rw-r--r--zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java111
-rw-r--r--zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java131
-rw-r--r--zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ExponentialBackoffTest.java32
-rw-r--r--zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ReconfigurerTest.java203
1528 files changed, 20073 insertions, 31514 deletions
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
deleted file mode 100644
index 5839ae90dfd..00000000000
--- a/.github/workflows/python.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-name: CI
-on:
- pull_request:
- push:
- branches:
- - master
-jobs:
- build:
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: python/vespa
- steps:
- - uses: actions/checkout@v1
- - uses: actions/setup-python@v1
- with:
- python-version: '3.7'
- architecture: 'x64'
- - name: Install the library
- run: |
- pip install pytest
- pip install -e .
- - name: Test with pytest
- run: |
- pytest
- - name: Build and publish
- if: github.event_name == 'push' && github.ref == 'refs/heads/master'
- env:
- TWINE_USERNAME: __token__
- TWINE_PASSWORD: ${{ secrets.test_pypi_password }}
- run: |
- python -m pip install --upgrade pip
- pip install setuptools wheel twine
- python setup.py sdist bdist_wheel
- twine upload --repository testpypi dist/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b2d43dec0ab..aadd31ec2b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,6 +56,7 @@ add_subdirectory(config)
add_subdirectory(config-model-fat)
add_subdirectory(configd)
add_subdirectory(configdefinitions)
+add_subdirectory(configgen)
add_subdirectory(configserver)
add_subdirectory(configserver-flags)
add_subdirectory(configutil)
@@ -70,7 +71,6 @@ add_subdirectory(container-search-gui)
add_subdirectory(container-search-and-docproc)
add_subdirectory(cloud-tenant-cd)
add_subdirectory(clustercontroller-apps)
-add_subdirectory(clustercontroller-apputil)
add_subdirectory(clustercontroller-core)
add_subdirectory(clustercontroller-reindexer)
add_subdirectory(clustercontroller-utils)
diff --git a/ERRATA.md b/ERRATA.md
new file mode 100644
index 00000000000..953eed357a7
--- /dev/null
+++ b/ERRATA.md
@@ -0,0 +1,38 @@
+<!-- Copyright verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+
+## Errata
+
+### 2020-11-30: Document inconsistency
+This bug was introduced in Vespa-7.277.38, fixed in Vespa-7.292.82.
+The following needs to happen to trigger the bug:
+
+* visibility-delay is non-zero. Note that the default is zero, so for this to trigger,
+ [visibility-delay](https://docs.vespa.ai/documentation/reference/services-content.html#visibility-delay)
+ must have been set.
+* A new config change is deployed that contains changes to proton.
+ This config snapshot is stored in the transaction log on the content node.
+* vespa-proton-bin is restarted, and as part of the prepare for restart step,
+ at least one attribute vector is not flushed to the current serial number.
+* Due to the bug, replay of the transaction log will fail to replay feed operations to attributes after replaying the config change.
+ The effect is that all attributes that were not flushed as part of prepare for restart
+ will not get any of the updates since the last time they were flushed.
+* If a document was previously removed, lid space compaction will move another document to that local document id.
+ Due to later missing updates as part of restarting we might see values from the removed document for some of the attributes.
+* When the problem attributes are later flushed this inconsistency will be permanent.
+
+Solution:
+* Upgrade Vespa to minimum Vespa-7.292.82.
+* Complete re-feed of the corpus.
+
+
+
+### 2020-11-30: Regression introduced in Vespa 7.141 may cause data loss or inconsistencies when using 'create: true' updates
+There exists a regression introduced in Vespa 7.141 where updates marked as `create: true` (i.e. create if missing)
+may cause data loss or undetected inconsistencies in certain edge cases.
+This regression was introduced as part of an optimization effort to greatly reduce the common-case overhead of updates
+when replicas are out of sync.
+
+Fixed in Vespa 7.157.9 and beyond.
+If running a version affected (7.141 up to and including 7.147) you are strongly advised to upgrade.
+
+See [#11686](https://github.com/vespa-engine/vespa/issues/11686) for details.
diff --git a/application/abi-spec.json b/application/abi-spec.json
index 690facffae7..5c298471b9c 100644
--- a/application/abi-spec.json
+++ b/application/abi-spec.json
@@ -105,6 +105,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.application.MockApplicationConfig build()"
],
"fields": [
diff --git a/build_settings.cmake b/build_settings.cmake
index 3a4708bd10d..414d73b2013 100644
--- a/build_settings.cmake
+++ b/build_settings.cmake
@@ -78,10 +78,11 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -fno-omit-frame-pointer ${C_WARN_OPTS
if (VESPA_USE_SANITIZER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${VESPA_USE_SANITIZER}")
endif()
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} ${CXX_SPECIFIC_WARN_OPTS} -std=c++2a -fdiagnostics-color=auto ${EXTRA_CXX_FLAGS}")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} ${CXX_SPECIFIC_WARN_OPTS} -std=c++1z -fdiagnostics-color=auto ${EXTRA_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ")
else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} ${CXX_SPECIFIC_WARN_OPTS} -std=c++1z -fvisibility-inlines-hidden -fdiagnostics-color=auto ${EXTRA_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden ")
endif()
# Linker flags
diff --git a/clustercontroller-apps/pom.xml b/clustercontroller-apps/pom.xml
index 38f10dd74b6..10fa263a8db 100644
--- a/clustercontroller-apps/pom.xml
+++ b/clustercontroller-apps/pom.xml
@@ -31,12 +31,6 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
- <artifactId>clustercontroller-apputil</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
<artifactId>clustercontroller-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterController.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterController.java
index b04f04abfb6..ff7cbbf83da 100644
--- a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterController.java
+++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterController.java
@@ -1,4 +1,4 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.apps.clustercontroller;
import com.google.inject.Inject;
@@ -11,6 +11,7 @@ import com.yahoo.vespa.clustercontroller.core.RemoteClusterControllerTaskSchedul
import com.yahoo.vespa.clustercontroller.core.restapiv2.ClusterControllerStateRestAPI;
import com.yahoo.vespa.clustercontroller.core.status.StatusHandler;
import com.yahoo.vespa.curator.Curator;
+import com.yahoo.vespa.zookeeper.VespaZooKeeperServer;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -30,11 +31,12 @@ public class ClusterController extends AbstractComponent
private final Map<String, StatusHandler.ContainerStatusPageServer> status = new TreeMap<>();
/**
- * Dependency injection constructor for controller. {@link ZooKeeperProvider} argument given
+ * Dependency injection constructor for controller. {@link VespaZooKeeperServer} argument given
* to ensure that zookeeper has started before we start polling it.
*/
+ @SuppressWarnings("unused")
@Inject
- public ClusterController(ZooKeeperProvider zooKeeperProvider) {
+ public ClusterController(VespaZooKeeperServer ignored) {
this();
}
@@ -42,25 +44,16 @@ public class ClusterController extends AbstractComponent
metricWrapper = new JDiscMetricWrapper(null);
}
-
- public void setOptions(String clusterName, FleetControllerOptions options, Metric metricImpl) throws Exception {
+ public void setOptions(FleetControllerOptions options, Metric metricImpl) throws Exception {
metricWrapper.updateMetricImplementation(metricImpl);
- if (options.zooKeeperServerAddress != null && !"".equals(options.zooKeeperServerAddress)) {
- // Wipe this path ... it's unclear why
- String path = "/" + options.clusterName + options.fleetControllerIndex;
- Curator curator = Curator.create(options.zooKeeperServerAddress);
- if (curator.framework().checkExists().forPath(path) != null)
- curator.framework().delete().deletingChildrenIfNeeded().forPath(path);
- curator.framework().create().creatingParentsIfNeeded().forPath(path);
- }
+ verifyThatZooKeeperWorks(options);
synchronized (controllers) {
- FleetController controller = controllers.get(clusterName);
-
+ FleetController controller = controllers.get(options.clusterName);
if (controller == null) {
StatusHandler.ContainerStatusPageServer statusPageServer = new StatusHandler.ContainerStatusPageServer();
controller = FleetController.create(options, statusPageServer, metricWrapper);
- controllers.put(clusterName, controller);
- status.put(clusterName, statusPageServer);
+ controllers.put(options.clusterName, controller);
+ status.put(options.clusterName, statusPageServer);
} else {
controller.updateOptions(options, 0);
}
@@ -83,11 +76,9 @@ public class ClusterController extends AbstractComponent
@Override
public Map<String, RemoteClusterControllerTaskScheduler> getFleetControllers() {
- Map<String, RemoteClusterControllerTaskScheduler> m = new LinkedHashMap<>();
synchronized (controllers) {
- m.putAll(controllers);
+ return new LinkedHashMap<>(controllers);
}
- return m;
}
@Override
@@ -104,4 +95,14 @@ public class ClusterController extends AbstractComponent
controller.shutdown();
}
+ /**
+ * Block until we are connected to zookeeper server
+ */
+ private void verifyThatZooKeeperWorks(FleetControllerOptions options) throws Exception {
+ if (options.zooKeeperServerAddress != null && !"".equals(options.zooKeeperServerAddress)) {
+ Curator curator = Curator.create(options.zooKeeperServerAddress);
+ curator.framework().blockUntilConnected();
+ }
+ }
+
}
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurer.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurer.java
index c95d814eb99..ad65435c770 100644
--- a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurer.java
+++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurer.java
@@ -31,9 +31,8 @@ public class ClusterControllerClusterConfigurer {
configure(fleetcontrollerConfig);
configure(slobroksConfig);
configure(zookeepersConfig);
- checkIfZooKeeperNeeded();
if (controller != null) {
- controller.setOptions(options.clusterName, options, metricImpl);
+ controller.setOptions(options, metricImpl);
}
}
@@ -79,7 +78,7 @@ public class ClusterControllerClusterConfigurer {
}
private void configure(SlobroksConfig config) {
- String specs[] = new String[config.slobrok().size()];
+ String[] specs = new String[config.slobrok().size()];
for (int i = 0; i < config.slobrok().size(); i++) {
specs[i] = config.slobrok().get(i).connectionspec();
}
@@ -87,22 +86,14 @@ public class ClusterControllerClusterConfigurer {
}
private void configure(ZookeepersConfig config) {
- options.zooKeeperServerAddress = config.zookeeperserverlist();
+ options.zooKeeperServerAddress = verifyZooKeeperAddress(config.zookeeperserverlist());
}
- private void checkIfZooKeeperNeeded() {
- // For legacy (testing, presumably) reasons, support running 1 instance
- // without a ZK cluster. This is really a Horrible Thing(tm) since we
- // violate cluster state versioning invariants when the controller is
- // restarted.
- if (options.zooKeeperServerAddress == null || "".equals(options.zooKeeperServerAddress)) {
- if (options.fleetControllerCount > 1) {
- throw new IllegalArgumentException(
- "Must set zookeeper server with multiple fleetcontrollers");
- } else {
- options.zooKeeperServerAddress = null; // Force null
- }
+ private String verifyZooKeeperAddress(String zooKeeperServerAddress) {
+ if (zooKeeperServerAddress == null || "".equals(zooKeeperServerAddress)) {
+ throw new IllegalArgumentException("zookeeper server address must be set, was '" + zooKeeperServerAddress + "'");
}
+ return zooKeeperServerAddress;
}
}
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/DummyZooKeeperProvider.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/DummyZooKeeperProvider.java
deleted file mode 100644
index f961297643e..00000000000
--- a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/DummyZooKeeperProvider.java
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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.apps.clustercontroller;
-
-/**
- * A dummy zookeeper provider when we do not run our own zookeeper instance.
- *
- * @author Ulf Lilleengen
- */
-public class DummyZooKeeperProvider implements ZooKeeperProvider {
-}
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/StandaloneZooKeeperProvider.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/StandaloneZooKeeperProvider.java
deleted file mode 100644
index baad012a234..00000000000
--- a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/StandaloneZooKeeperProvider.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.apps.clustercontroller;
-
-import com.yahoo.vespa.zookeeper.VespaZooKeeperServer;
-
-/**
- * ZooKeeper provider that ensures we are running our own instance of zookeeper.
- *
- * @author Ulf Lilleengen
- */
-public class StandaloneZooKeeperProvider implements ZooKeeperProvider {
-
- public StandaloneZooKeeperProvider(VespaZooKeeperServer server) {
- }
-
-}
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ZooKeeperProvider.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ZooKeeperProvider.java
deleted file mode 100644
index bb18bcc65d6..00000000000
--- a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ZooKeeperProvider.java
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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.apps.clustercontroller;
-
-/**
- * Abstraction we can depend on providing us with a zookeeper server being up.
- *
- * @author Ulf Lilleengen
- */
-public interface ZooKeeperProvider {
-}
diff --git a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java
index f518fe23fe6..f518fe23fe6 100644
--- a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java
+++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java
diff --git a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java
index 559eaee4821..559eaee4821 100644
--- a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java
+++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java
diff --git a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java
index 5d09603bea6..5d09603bea6 100644
--- a/clustercontroller-apputil/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java
+++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java
diff --git a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurerTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurerTest.java
index 330174f0313..37131349602 100644
--- a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurerTest.java
+++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerClusterConfigurerTest.java
@@ -58,19 +58,8 @@ public class ClusterControllerClusterConfigurerTest {
assertTrue(configurer.getOptions() != null);
assertEquals(0.123, configurer.getOptions().minNodeRatioPerGroup, 0.01);
- // Oki with no zookeeper if one node
- zookeepersConfig.zookeeperserverlist("");
- new ClusterControllerClusterConfigurer(
- controller,
- new StorDistributionConfig(distributionConfig),
- new FleetcontrollerConfig(fleetcontrollerConfig),
- new SlobroksConfig(slobroksConfig),
- new ZookeepersConfig(zookeepersConfig),
- metric
- );
-
try{
- fleetcontrollerConfig.fleet_controller_count(5);
+ zookeepersConfig.zookeeperserverlist("");
new ClusterControllerClusterConfigurer(
controller,
new StorDistributionConfig(distributionConfig),
@@ -81,7 +70,7 @@ public class ClusterControllerClusterConfigurerTest {
);
fail("Should not get here");
} catch (Exception e) {
- assertEquals("Must set zookeeper server with multiple fleetcontrollers", e.getMessage());
+ assertEquals("zookeeper server address must be set, was ''", e.getMessage());
}
}
diff --git a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerTest.java
index b86d9a561d3..f4df8a4e2a3 100644
--- a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerTest.java
+++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apps/clustercontroller/ClusterControllerTest.java
@@ -1,8 +1,4 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * Doesn't really test cluster controller, but runs some lines of code.
- * System tests verifies that container can load it..
- */
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.apps.clustercontroller;
import com.yahoo.jdisc.Metric;
@@ -13,14 +9,18 @@ import org.junit.Test;
import java.util.Map;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+/**
+ * Doesn't really test cluster controller, but runs some lines of code.
+ * System tests verifies that container can load it..
+ */
public class ClusterControllerTest {
private FleetControllerOptions options = new FleetControllerOptions("storage");
- private Metric metric = new Metric() {
+ private final Metric metric = new Metric() {
@Override
public void set(String s, Number number, Context context) {}
@Override
@@ -42,13 +42,13 @@ public class ClusterControllerTest {
// Cluster controller object keeps state and should never be remade, so should
// inject nothing
ClusterController cc = new ClusterController();
- cc.setOptions("storage", options, metric);
- cc.setOptions("storage", options, metric);
+ cc.setOptions(options, metric);
+ cc.setOptions(options, metric);
cc.getFleetControllers();
cc.getAll();
- assertTrue(cc.get("storage") != null);
- assertFalse(cc.get("music") != null);
+ assertNotNull(cc.get("storage"));
+ assertNull(cc.get("music"));
cc.deconstruct();
}
@@ -59,7 +59,7 @@ public class ClusterControllerTest {
throw new Exception("Foo");
}
};
- cc.setOptions("storage", options, metric);
+ cc.setOptions(options, metric);
cc.deconstruct();
}
diff --git a/clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java
index 2326189a369..2326189a369 100644
--- a/clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java
+++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java
diff --git a/clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java
index 13abfa0ecd5..13abfa0ecd5 100644
--- a/clustercontroller-apputil/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java
+++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java
diff --git a/clustercontroller-apputil/.gitignore b/clustercontroller-apputil/.gitignore
deleted file mode 100644
index 12251442258..00000000000
--- a/clustercontroller-apputil/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/target
-/pom.xml.build
diff --git a/clustercontroller-apputil/OWNERS b/clustercontroller-apputil/OWNERS
deleted file mode 100644
index de6ac0dd8f5..00000000000
--- a/clustercontroller-apputil/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-vekterli
-hakonhall
diff --git a/clustercontroller-apputil/pom.xml b/clustercontroller-apputil/pom.xml
deleted file mode 100644
index f0da97f5b94..00000000000
--- a/clustercontroller-apputil/pom.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>parent</artifactId>
- <version>7-SNAPSHOT</version>
- <relativePath>../parent/pom.xml</relativePath>
- </parent>
- <artifactId>clustercontroller-apputil</artifactId>
- <version>7-SNAPSHOT</version>
- <packaging>container-plugin</packaging>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>annotations</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>container-dev</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>clustercontroller-utils</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>bundle-plugin</artifactId>
- <extensions>true</extensions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <compilerArgs>
- <arg>-Xlint:all</arg>
- <arg>-Xlint:-deprecation</arg>
- <arg>-Xlint:-serial</arg>
- <arg>-Werror</arg>
- </compilerArgs>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
index 4ae45701344..eb4a5cc00b0 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
@@ -21,11 +21,12 @@ import java.util.Optional;
* @author Haakon Dybdahl
*/
public class NodeStateChangeChecker {
+
public static final String BUCKETS_METRIC_NAME = "vds.datastored.bucket_space.buckets_total";
public static final Map<String, String> BUCKETS_METRIC_DIMENSIONS = Map.of("bucketSpace", "default");
private final int minStorageNodesUp;
- private double minRatioOfStorageNodesUp;
+ private final double minRatioOfStorageNodesUp;
private final int requiredRedundancy;
private final ClusterInfo clusterInfo;
@@ -296,4 +297,5 @@ public class NodeStateChangeChecker {
return Result.allowSettingOfWantedState();
}
+
}
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java
index 13ed9800db3..fd887a4196b 100644
--- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java
+++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java
@@ -12,6 +12,7 @@ import com.yahoo.documentapi.VisitorControlHandler;
import com.yahoo.documentapi.VisitorParameters;
import com.yahoo.documentapi.messagebus.protocol.DocumentProtocol;
import com.yahoo.jdisc.Metric;
+import com.yahoo.messagebus.DynamicThrottlePolicy;
import com.yahoo.vespa.curator.Lock;
import java.time.Clock;
@@ -48,10 +49,10 @@ public class Reindexer {
private final ReindexingMetrics metrics;
private final Clock clock;
private final Phaser phaser = new Phaser(2); // Reindexer and visitor.
+ private final double windowSizeIncrement;
- @Inject
public Reindexer(Cluster cluster, Map<DocumentType, Instant> ready, ReindexingCurator database,
- DocumentAccess access, Metric metric, Clock clock) {
+ DocumentAccess access, Metric metric, Clock clock, double windowSizeIncrement) {
this(cluster,
ready,
database,
@@ -64,11 +65,13 @@ public class Reindexer {
}
},
metric,
- clock);
+ clock,
+ windowSizeIncrement);
}
Reindexer(Cluster cluster, Map<DocumentType, Instant> ready, ReindexingCurator database,
- Function<VisitorParameters, Runnable> visitorSessions, Metric metric, Clock clock) {
+ Function<VisitorParameters, Runnable> visitorSessions, Metric metric, Clock clock,
+ double windowSizeIncrement) {
for (DocumentType type : ready.keySet())
cluster.bucketSpaceOf(type); // Verifies this is known.
@@ -78,6 +81,7 @@ public class Reindexer {
this.visitorSessions = visitorSessions;
this.metrics = new ReindexingMetrics(metric, cluster.name);
this.clock = clock;
+ this.windowSizeIncrement = windowSizeIncrement;
}
/** Lets the reindexer abort any ongoing visit session, wait for it to complete normally, then exit. */
@@ -90,17 +94,21 @@ public class Reindexer {
if (phaser.isTerminated())
throw new IllegalStateException("Already shut down");
- try (Lock lock = database.lockReindexing()) {
- Reindexing reindexing = updateWithReady(ready, database.readReindexing(), clock.instant());
- database.writeReindexing(reindexing);
- metrics.dump(reindexing);
+ // Keep metrics in sync across cluster controller containers.
+ metrics.dump(database.readReindexing(cluster.name));
+
+ try (Lock lock = database.lockReindexing(cluster.name())) {
+ AtomicReference<Reindexing> reindexing = new AtomicReference<>(database.readReindexing(cluster.name()));
+ reindexing.set(updateWithReady(ready, reindexing.get(), clock.instant()));
+ database.writeReindexing(reindexing.get(), cluster.name());
+ metrics.dump(reindexing.get());
for (DocumentType type : ready.keySet()) { // We consider only document types for which we have config.
if (ready.get(type).isAfter(clock.instant()))
log.log(INFO, "Received config for reindexing which is ready in the future — will process later " +
"(" + ready.get(type) + " is after " + clock.instant() + ")");
else
- progress(type, new AtomicReference<>(reindexing), new AtomicReference<>(reindexing.status().get(type)));
+ progress(type, reindexing, new AtomicReference<>(reindexing.get().status().get(type)));
if (phaser.isTerminated())
break;
@@ -125,10 +133,6 @@ public class Reindexer {
@SuppressWarnings("fallthrough") // (ノಠ ∩ಠ)ノ彡( \o°o)\
private void progress(DocumentType type, AtomicReference<Reindexing> reindexing, AtomicReference<Status> status) {
-
- database.writeReindexing(reindexing.updateAndGet(value -> value.with(type, status.get())));
- metrics.dump(reindexing.get());
-
switch (status.get().state()) {
default:
log.log(WARNING, "Unknown reindexing state '" + status.get().state() + "'");
@@ -138,12 +142,12 @@ public class Reindexer {
return;
case RUNNING:
log.log(WARNING, "Unexpected state 'RUNNING' of reindexing of " + type);
- case READY: // Intentional fallthrough — must just assume we failed updating state when exiting previously.
- log.log(FINE, () -> "Running reindexing of " + type);
+ break;
+ case READY:
+ status.updateAndGet(Status::running);
}
- // Visit buckets until they're all done, or until we are interrupted.
- status.updateAndGet(Status::running);
+ // Visit buckets until they're all done, or until we are shut down.
AtomicReference<Instant> progressLastStored = new AtomicReference<>(clock.instant());
VisitorControlHandler control = new VisitorControlHandler() {
@Override
@@ -152,7 +156,7 @@ public class Reindexer {
status.updateAndGet(value -> value.progressed(token));
if (progressLastStored.get().isBefore(clock.instant().minusSeconds(10))) {
progressLastStored.set(clock.instant());
- database.writeReindexing(reindexing.updateAndGet(value -> value.with(type, status.get())));
+ database.writeReindexing(reindexing.updateAndGet(value -> value.with(type, status.get())), cluster.name());
metrics.dump(reindexing.get());
}
}
@@ -166,10 +170,11 @@ public class Reindexer {
VisitorParameters parameters = createParameters(type, status.get().progress().orElse(null));
parameters.setControlHandler(control);
Runnable sessionShutdown = visitorSessions.apply(parameters); // Also starts the visitor session.
+ log.log(FINE, () -> "Running reindexing of " + type);
// Wait until done; or until termination is forced, in which we shut down the visitor session immediately.
phaser.arriveAndAwaitAdvance(); // Synchronize with visitor completion.
- sessionShutdown.run(); // Shutdown aborts the session, then waits for it to terminate normally.
+ sessionShutdown.run(); // Shutdown aborts the session unless already complete, then waits for it to terminate normally.
switch (control.getResult().getCode()) {
default:
@@ -186,19 +191,25 @@ public class Reindexer {
log.log(INFO, "Completed reindexing of " + type + " after " + Duration.between(status.get().startedAt(), clock.instant()));
status.updateAndGet(value -> value.successful(clock.instant()));
}
- database.writeReindexing(reindexing.updateAndGet(value -> value.with(type, status.get())));
+ database.writeReindexing(reindexing.updateAndGet(value -> value.with(type, status.get())), cluster.name());
metrics.dump(reindexing.get());
}
VisitorParameters createParameters(DocumentType type, ProgressToken progress) {
VisitorParameters parameters = new VisitorParameters(type.getName());
+ parameters.setThrottlePolicy(new DynamicThrottlePolicy().setWindowSizeIncrement(windowSizeIncrement)
+ .setWindowSizeDecrementFactor(5)
+ .setResizeRate(10)
+ .setMinWindowSize(1));
parameters.setRemoteDataHandler(cluster.name());
+ parameters.setMaxPending(32);
parameters.setResumeToken(progress);
parameters.setFieldSet(type.getName() + ":[document]");
parameters.setPriority(DocumentProtocol.Priority.NORMAL_3);
parameters.setRoute(cluster.route());
parameters.setBucketSpace(cluster.bucketSpaceOf(type));
- // parameters.setVisitorLibrary("ReindexVisitor"); // TODO jonmv: Use when ready, or perhaps an argument to the DumpVisitor is enough?
+ parameters.setMaxBucketsPerVisitor(1);
+ parameters.setVisitorLibrary("ReindexingVisitor");
return parameters;
}
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingCurator.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingCurator.java
index 202bd92d86e..22ae54fcc6b 100644
--- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingCurator.java
+++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingCurator.java
@@ -29,43 +29,41 @@ import static java.util.stream.Collectors.toUnmodifiableMap;
public class ReindexingCurator {
private final Curator curator;
- private final String clusterName;
private final ReindexingSerializer serializer;
private final Duration lockTimeout;
- public ReindexingCurator(Curator curator, String clusterName, DocumentTypeManager manager) {
- this(curator, clusterName, manager, Duration.ofSeconds(1));
+ public ReindexingCurator(Curator curator, DocumentTypeManager manager) {
+ this(curator, manager, Duration.ofSeconds(1));
}
- ReindexingCurator(Curator curator, String clusterName, DocumentTypeManager manager, Duration lockTimeout) {
+ ReindexingCurator(Curator curator, DocumentTypeManager manager, Duration lockTimeout) {
this.curator = curator;
- this.clusterName = clusterName;
this.serializer = new ReindexingSerializer(manager);
this.lockTimeout = lockTimeout;
}
- public Reindexing readReindexing() {
- return curator.getData(statusPath()).map(serializer::deserialize)
+ public Reindexing readReindexing(String cluster) {
+ return curator.getData(statusPath(cluster)).map(serializer::deserialize)
.orElse(Reindexing.empty());
}
- public void writeReindexing(Reindexing reindexing) {
- curator.set(statusPath(), serializer.serialize(reindexing));
+ public void writeReindexing(Reindexing reindexing, String cluster) {
+ curator.set(statusPath(cluster), serializer.serialize(reindexing));
}
/** This lock must be held to manipulate reindexing state, or by whoever has a running visitor. */
- public Lock lockReindexing() throws ReindexingLockException {
+ public Lock lockReindexing(String cluster) throws ReindexingLockException {
try {
- return curator.lock(lockPath(), lockTimeout);
+ return curator.lock(lockPath(cluster), lockTimeout);
}
catch (UncheckedTimeoutException e) { // TODO jonmv: Avoid use of guava classes.
throw new ReindexingLockException(e);
}
}
- private Path rootPath() { return Path.fromString("/reindexing/v1/" + clusterName); }
- private Path statusPath() { return rootPath().append("status"); }
- private Path lockPath() { return rootPath().append("lock"); }
+ private Path rootPath(String clusterName) { return Path.fromString("/reindexing/v1/" + clusterName); }
+ private Path statusPath(String clusterName) { return rootPath(clusterName).append("status"); }
+ private Path lockPath(String clusterName) { return rootPath(clusterName).append("lock"); }
private static class ReindexingSerializer {
@@ -140,7 +138,7 @@ public class ReindexingCurator {
}
- /** Indicates that taking the reindexing lock failed within the alotted time. */
+ /** Indicates that taking the reindexing lock failed within the allotted time. */
static class ReindexingLockException extends Exception {
ReindexingLockException(UncheckedTimeoutException cause) {
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java
index 7989338c406..8668ed037ef 100644
--- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java
+++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java
@@ -29,12 +29,14 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.WARNING;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toUnmodifiableList;
import static java.util.stream.Collectors.toUnmodifiableMap;
/**
@@ -48,7 +50,7 @@ public class ReindexingMaintainer extends AbstractComponent {
private static final Logger log = Logger.getLogger(Reindexing.class.getName());
- private final Reindexer reindexer;
+ private final List<Reindexer> reindexers;
private final ScheduledExecutorService executor;
@Inject
@@ -63,51 +65,58 @@ public class ReindexingMaintainer extends AbstractComponent {
ReindexingMaintainer(Clock clock, Metric metric, DocumentAccess access, ZookeepersConfig zookeepersConfig,
ClusterListConfig clusterListConfig, AllClustersBucketSpacesConfig allClustersBucketSpacesConfig,
ReindexingConfig reindexingConfig) {
- this.reindexer = new Reindexer(parseCluster(reindexingConfig.clusterName(), clusterListConfig, allClustersBucketSpacesConfig, access.getDocumentTypeManager()),
- parseReady(reindexingConfig, access.getDocumentTypeManager()),
- new ReindexingCurator(Curator.create(zookeepersConfig.zookeeperserverlist()),
- reindexingConfig.clusterName(),
- access.getDocumentTypeManager()),
- access,
- metric,
- clock);
- this.executor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("reindexer-"));
+ this.reindexers = reindexingConfig.clusters().entrySet().stream()
+ .map(cluster -> new Reindexer(parseCluster(cluster.getKey(), clusterListConfig, allClustersBucketSpacesConfig, access.getDocumentTypeManager()),
+ parseReady(cluster.getValue(), access.getDocumentTypeManager()),
+ new ReindexingCurator(Curator.create(zookeepersConfig.zookeeperserverlist()),
+ access.getDocumentTypeManager()),
+ access,
+ metric,
+ clock,
+ reindexingConfig.windowSizeIncrement()))
+ .collect(toUnmodifiableList());
+ this.executor = new ScheduledThreadPoolExecutor(reindexingConfig.clusters().size(), new DaemonThreadFactory("reindexer-"));
if (reindexingConfig.enabled())
scheduleStaggered((delayMillis, intervalMillis) -> executor.scheduleAtFixedRate(this::maintain, delayMillis, intervalMillis, TimeUnit.MILLISECONDS),
Duration.ofMinutes(1), clock.instant(), HostName.getLocalhost(), zookeepersConfig.zookeeperserverlist());
}
private void maintain() {
- try {
- reindexer.reindex();
- }
- catch (ReindexingLockException e) {
- log.log(FINE, "Failed to acquire reindexing lock");
- }
- catch (Exception e) {
- log.log(WARNING, "Exception when reindexing", e);
- }
+ for (Reindexer reindexer : reindexers)
+ executor.submit(() -> {
+ try {
+ reindexer.reindex();
+ }
+ catch (ReindexingLockException e) {
+ log.log(FINE, "Failed to acquire reindexing lock");
+ }
+ catch (Exception e) {
+ log.log(WARNING, "Exception when reindexing", e);
+ }
+ });
}
@Override
public void deconstruct() {
try {
- reindexer.shutdown();
+ for (Reindexer reindexer : reindexers)
+ reindexer.shutdown();
+
executor.shutdown();
if ( ! executor.awaitTermination(45, TimeUnit.SECONDS))
- log.log(WARNING, "Failed to shut down reindexer within timeout");
+ log.log(WARNING, "Failed to shut down reindexing within timeout");
}
catch (InterruptedException e) {
- log.log(WARNING, "Interrupted while waiting for reindexer to shut down");
+ log.log(WARNING, "Interrupted while waiting for reindexing to shut down");
Thread.currentThread().interrupt();
}
}
- static Map<DocumentType, Instant> parseReady(ReindexingConfig config, DocumentTypeManager manager) {
- return config.status().entrySet().stream()
- .collect(toUnmodifiableMap(typeStatus -> manager.getDocumentType(typeStatus.getKey()),
- typeStatus -> Instant.ofEpochMilli(typeStatus.getValue().readyAtMillis())));
+ static Map<DocumentType, Instant> parseReady(ReindexingConfig.Clusters cluster, DocumentTypeManager manager) {
+ return cluster.documentTypes().entrySet().stream()
+ .collect(toUnmodifiableMap(typeStatus -> manager.getDocumentType(typeStatus.getKey()),
+ typeStatus -> Instant.ofEpochMilli(typeStatus.getValue().readyAtMillis())));
}
/** Schedules a task with the given interval (across all containers in this ZK cluster). */
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMetrics.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMetrics.java
index 5e536d1f2ee..cd3d964b4a5 100644
--- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMetrics.java
+++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMetrics.java
@@ -5,6 +5,7 @@ import com.yahoo.documentapi.ProgressToken;
import com.yahoo.jdisc.Metric;
import java.time.Clock;
+import java.util.EnumSet;
import java.util.Map;
import static ai.vespa.reindexing.Reindexing.State.SUCCESSFUL;
@@ -26,12 +27,20 @@ class ReindexingMetrics {
void dump(Reindexing reindexing) {
reindexing.status().forEach((type, status) -> {
+ Reindexing.State state = status.state();
metric.set("reindexing.progress",
status.progress().map(ProgressToken::percentFinished).map(percentage -> percentage * 1e-2)
.orElse(status.state() == SUCCESSFUL ? 1.0 : 0.0),
metric.createContext(Map.of("clusterid", cluster,
"documenttype", type.getName(),
- "state", toString(status.state()))));
+ "state", toString(state))));
+ // Set metric value to -1 for all states not currently active, so we only have one value >= 0 at any given time.
+ for (Reindexing.State unset : EnumSet.complementOf(EnumSet.of(state)))
+ metric.set("reindexing.progress",
+ -1,
+ metric.createContext(Map.of("clusterid", cluster,
+ "documenttype", type.getName(),
+ "state", toString(unset))));
});
}
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/http/ReindexingV1ApiHandler.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/http/ReindexingV1ApiHandler.java
index fca08f7743c..56bacea5cb6 100644
--- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/http/ReindexingV1ApiHandler.java
+++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/http/ReindexingV1ApiHandler.java
@@ -22,6 +22,8 @@ import com.yahoo.vespa.config.content.reindexing.ReindexingConfig;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.zookeeper.VespaZooKeeperServer;
+import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Executor;
import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
@@ -34,6 +36,7 @@ import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
public class ReindexingV1ApiHandler extends ThreadedHttpRequestHandler {
private final ReindexingCurator database;
+ private final List<String> clusterNames;
@Inject
public ReindexingV1ApiHandler(Executor executor, Metric metric,
@@ -41,14 +44,15 @@ public class ReindexingV1ApiHandler extends ThreadedHttpRequestHandler {
ReindexingConfig reindexingConfig, DocumentmanagerConfig documentmanagerConfig) {
this(executor,
metric,
+ reindexingConfig.clusters().keySet(),
new ReindexingCurator(Curator.create(zookeepersConfig.zookeeperserverlist()),
- reindexingConfig.clusterName(),
new DocumentTypeManager(documentmanagerConfig)));
}
- ReindexingV1ApiHandler(Executor executor, Metric metric, ReindexingCurator database) {
+ ReindexingV1ApiHandler(Executor executor, Metric metric, Collection<String> clusterNames, ReindexingCurator database) {
super(executor, metric);
this.database = database;
+ this.clusterNames = List.copyOf(clusterNames);
}
@Override
@@ -71,16 +75,18 @@ public class ReindexingV1ApiHandler extends ThreadedHttpRequestHandler {
HttpResponse getStatus() {
Slime slime = new Slime();
- Cursor statusArray = slime.setObject().setArray("status");
- database.readReindexing().status().forEach((type, status) -> {
- Cursor statusObject = statusArray.addObject();
- statusObject.setString("type", type.getName());
- statusObject.setLong("startedMillis", status.startedAt().toEpochMilli());
- status.endedAt().ifPresent(endedAt -> statusObject.setLong("endedMillis", endedAt.toEpochMilli()));
- status.progress().ifPresent(progress -> statusObject.setString("progress", progress.serializeToString()));
- statusObject.setString("state", toString(status.state()));
- status.message().ifPresent(message -> statusObject.setString("message", message));
- });
+ Cursor clustersObject = slime.setObject().setObject("clusters");
+ for (String clusterName : clusterNames) {
+ Cursor documentTypesObject = clustersObject.setObject(clusterName).setObject("documentTypes");
+ database.readReindexing(clusterName).status().forEach((type, status) -> {
+ Cursor statusObject = documentTypesObject.setObject(type.getName());
+ statusObject.setLong("startedMillis", status.startedAt().toEpochMilli());
+ status.endedAt().ifPresent(endedAt -> statusObject.setLong("endedMillis", endedAt.toEpochMilli()));
+ status.progress().ifPresent(progress -> statusObject.setDouble("progress", progress.percentFinished() * 1e-2));
+ statusObject.setString("state", toString(status.state()));
+ status.message().ifPresent(message -> statusObject.setString("message", message));
+ });
+ }
return new SlimeJsonResponse(slime);
}
diff --git a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java
index b0ffdf8ae60..9a88d8aad1f 100644
--- a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java
+++ b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java
@@ -53,37 +53,32 @@ class ReindexerTest {
@BeforeEach
void setUp() {
- database = new ReindexingCurator(new MockCurator(), "cluster", manager, Duration.ofMillis(1));
+ database = new ReindexingCurator(new MockCurator(), manager, Duration.ofMillis(1));
}
@Test
void throwsWhenUnknownBuckets() {
assertThrows(NullPointerException.class,
- () -> new Reindexer(new Cluster("cluster", "id", Map.of()),
- Map.of(music, Instant.EPOCH),
- database,
- failIfCalled,
- metric,
- clock));
+ () -> new Reindexer(new Cluster("cluster", "id", Map.of()), Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2));
}
@Test
void throwsWhenLockHeldElsewhere() throws InterruptedException, ExecutionException {
- Reindexer reindexer = new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock);
- Executors.newSingleThreadExecutor().submit(database::lockReindexing).get();
+ Reindexer reindexer = new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2);
+ Executors.newSingleThreadExecutor().submit(() -> database.lockReindexing("cluster")).get();
assertThrows(ReindexingLockException.class, reindexer::reindex);
}
@Test
@Timeout(10)
void nothingToDoWithEmptyConfig() throws ReindexingLockException {
- new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock).reindex();
+ new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock, 0.2).reindex();
assertEquals(Map.of(), metric.metrics());
}
@Test
void testParameters() {
- Reindexer reindexer = new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock);
+ Reindexer reindexer = new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock, 0.2);
ProgressToken token = new ProgressToken();
VisitorParameters parameters = reindexer.createParameters(music, token);
assertEquals("music:[document]", parameters.getFieldSet());
@@ -100,32 +95,44 @@ class ReindexerTest {
void testReindexing() throws ReindexingLockException {
// Reindexer is told to update "music" documents no earlier than EPOCH, which is just now.
// Since "music" is a new document type, it is stored as just reindexed, and nothing else happens.
- new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock).reindex();
+ new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2).reindex();
Reindexing reindexing = Reindexing.empty().with(music, Status.ready(Instant.EPOCH).running().successful(Instant.EPOCH));
- assertEquals(reindexing, database.readReindexing());
+ assertEquals(reindexing, database.readReindexing("cluster"));
assertEquals(Map.of("reindexing.progress", Map.of(Map.of("documenttype", "music",
"clusterid", "cluster",
"state", "successful"),
- 1.0)),
+ 1.0,
+ Map.of("documenttype", "music",
+ "clusterid", "cluster",
+ "state", "pending"),
+ -1.0,
+ Map.of("documenttype", "music",
+ "clusterid", "cluster",
+ "state", "failed"),
+ -1.0,
+ Map.of("documenttype", "music",
+ "clusterid", "cluster",
+ "state", "running"),
+ -1.0)),
metric.metrics());
// New config tells reindexer to reindex "music" documents no earlier than at 10 millis after EPOCH, which isn't yet.
// Nothing happens, since it's not yet time. This isn't supposed to happen unless high clock skew.
clock.advance(Duration.ofMillis(5));
- new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, failIfCalled, metric, clock).reindex();
- assertEquals(reindexing, database.readReindexing());
+ new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, failIfCalled, metric, clock, 0.2).reindex();
+ assertEquals(reindexing, database.readReindexing("cluster"));
// It's time to reindex the "music" documents — let this complete successfully.
clock.advance(Duration.ofMillis(10));
AtomicBoolean shutDown = new AtomicBoolean();
Executor executor = Executors.newSingleThreadExecutor();
new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, parameters -> {
- database.writeReindexing(Reindexing.empty()); // Wipe database to verify we write data from reindexer.
- executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.SUCCESS, "OK"));
- return () -> shutDown.set(true);
- }, metric, clock).reindex();
+ database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer.
+ executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.SUCCESS, "OK"));
+ return () -> shutDown.set(true);
+ }, metric, clock, 0.2).reindex();
reindexing = reindexing.with(music, Status.ready(clock.instant()).running().successful(clock.instant()));
- assertEquals(reindexing, database.readReindexing());
+ assertEquals(reindexing, database.readReindexing("cluster"));
assertTrue(shutDown.get(), "Session was shut down");
// One more reindexing, this time shut down before visit completes, but after progress is reported.
@@ -134,39 +141,39 @@ class ReindexerTest {
shutDown.set(false);
AtomicReference<Reindexer> aborted = new AtomicReference<>();
aborted.set(new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(20)), database, parameters -> {
- database.writeReindexing(Reindexing.empty()); // Wipe database to verify we write data from reindexer.
- parameters.getControlHandler().onProgress(new ProgressToken());
- aborted.get().shutdown();
- return () -> {
- shutDown.set(true);
- parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.ABORTED, "Shut down");
- };
- }, metric, clock));
+ database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer.
+ parameters.getControlHandler().onProgress(new ProgressToken());
+ aborted.get().shutdown();
+ return () -> {
+ shutDown.set(true);
+ parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.ABORTED, "Shut down");
+ };
+ }, metric, clock, 0.2));
aborted.get().reindex();
reindexing = reindexing.with(music, Status.ready(clock.instant()).running().progressed(new ProgressToken()).halted());
- assertEquals(reindexing, database.readReindexing());
+ assertEquals(reindexing, database.readReindexing("cluster"));
assertTrue(shutDown.get(), "Session was shut down");
- assertEquals(Map.of("reindexing.progress", Map.of(Map.of("documenttype", "music",
- "clusterid", "cluster",
- "state", "pending"),
- 1.0)), // new ProgressToken() is 100% done.
- metric.metrics());
+ assertEquals(1.0, // new ProgressToken() is 100% done.
+ metric.metrics().get("reindexing.progress")
+ .get(Map.of("documenttype", "music",
+ "clusterid", "cluster",
+ "state", "pending")));
// Last reindexing fails.
clock.advance(Duration.ofMillis(10));
shutDown.set(false);
new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, parameters -> {
- database.writeReindexing(Reindexing.empty()); // Wipe database to verify we write data from reindexer.
- executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.FAILURE, "Error"));
- return () -> shutDown.set(true);
- }, metric, clock).reindex();
+ database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer.
+ executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.FAILURE, "Error"));
+ return () -> shutDown.set(true);
+ }, metric, clock, 0.2).reindex();
reindexing = reindexing.with(music, Status.ready(clock.instant()).running().failed(clock.instant(), "Error"));
- assertEquals(reindexing, database.readReindexing());
+ assertEquals(reindexing, database.readReindexing("cluster"));
assertTrue(shutDown.get(), "Session was shut down");
// Document type is ignored in next run, as it has failed fatally.
- new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, failIfCalled, metric, clock).reindex();
- assertEquals(reindexing, database.readReindexing());
+ new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, failIfCalled, metric, clock, 0.2).reindex();
+ assertEquals(reindexing, database.readReindexing("cluster"));
}
}
diff --git a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingCuratorTest.java b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingCuratorTest.java
index c5a58dcae68..7d4cb2af47e 100644
--- a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingCuratorTest.java
+++ b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingCuratorTest.java
@@ -25,24 +25,24 @@ class ReindexingCuratorTest {
DocumentTypeManager manager = new DocumentTypeManager(musicConfig);
DocumentType music = manager.getDocumentType("music");
MockCurator mockCurator = new MockCurator();
- ReindexingCurator curator = new ReindexingCurator(mockCurator, "cluster", manager);
+ ReindexingCurator curator = new ReindexingCurator(mockCurator, manager);
- assertEquals(Reindexing.empty(), curator.readReindexing());
+ assertEquals(Reindexing.empty(), curator.readReindexing("cluster"));
Reindexing.Status status = Reindexing.Status.ready(Instant.ofEpochMilli(123))
.running()
.progressed(new ProgressToken());
Reindexing reindexing = Reindexing.empty().with(music, status);
- curator.writeReindexing(reindexing);
- assertEquals(reindexing, curator.readReindexing());
+ curator.writeReindexing(reindexing, "cluster");
+ assertEquals(reindexing, curator.readReindexing("cluster"));
status = status.halted().running().failed(Instant.ofEpochMilli(321), "error");
reindexing = reindexing.with(music, status);
- curator.writeReindexing(reindexing);
- assertEquals(reindexing, curator.readReindexing());
+ curator.writeReindexing(reindexing, "cluster");
+ assertEquals(reindexing, curator.readReindexing("cluster"));
// Unknown document types are forgotten.
- assertEquals(Reindexing.empty(), new ReindexingCurator(mockCurator, "cluster", new DocumentTypeManager(emptyConfig)).readReindexing());
+ assertEquals(Reindexing.empty(), new ReindexingCurator(mockCurator, new DocumentTypeManager(emptyConfig)).readReindexing("cluster"));
}
}
diff --git a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingMaintainerTest.java b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingMaintainerTest.java
index 713fb836d62..afa68debadb 100644
--- a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingMaintainerTest.java
+++ b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexingMaintainerTest.java
@@ -31,17 +31,15 @@ class ReindexingMaintainerTest {
DocumentTypeManager manager = new DocumentTypeManager(musicConfig);
assertEquals(Map.of(manager.getDocumentType("music"), Instant.ofEpochMilli(123)),
- parseReady(new ReindexingConfig.Builder()
- .enabled(true)
- .clusterName("cluster")
- .status("music", new ReindexingConfig.Status.Builder().readyAtMillis(123))
+ parseReady(new ReindexingConfig.Clusters.Builder()
+ .documentTypes("music", new ReindexingConfig.Clusters.DocumentTypes.Builder().readyAtMillis(123))
.build(),
manager));
// Unknown document type fails
- assertThrows(IllegalArgumentException.class,
- () -> parseReady(new ReindexingConfig.Builder()
- .status("poetry", new ReindexingConfig.Status.Builder().readyAtMillis(123))
+ assertThrows(NullPointerException.class,
+ () -> parseReady(new ReindexingConfig.Clusters.Builder()
+ .documentTypes("poetry", new ReindexingConfig.Clusters.DocumentTypes.Builder().readyAtMillis(123))
.build(),
manager));
diff --git a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/http/ReindexingV1ApiTest.java b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/http/ReindexingV1ApiTest.java
index 1b6379d21e5..e00b10b80bd 100644
--- a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/http/ReindexingV1ApiTest.java
+++ b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/http/ReindexingV1ApiTest.java
@@ -15,6 +15,7 @@ import com.yahoo.vespa.curator.mock.MockCurator;
import org.junit.jupiter.api.Test;
import java.time.Instant;
+import java.util.List;
import java.util.concurrent.Executors;
import static com.yahoo.jdisc.http.HttpRequest.Method.POST;
@@ -28,8 +29,9 @@ class ReindexingV1ApiTest {
DocumentmanagerConfig musicConfig = Deriver.getDocumentManagerConfig("src/test/resources/schemas/music.sd").build();
DocumentTypeManager manager = new DocumentTypeManager(musicConfig);
DocumentType musicType = manager.getDocumentType("music");
- ReindexingCurator database = new ReindexingCurator(new MockCurator(), "cluster", manager);
- ReindexingV1ApiHandler handler = new ReindexingV1ApiHandler(Executors.newSingleThreadExecutor(), new MockMetric(), database);
+ ReindexingCurator database = new ReindexingCurator(new MockCurator(), manager);
+ ReindexingV1ApiHandler handler = new ReindexingV1ApiHandler(Executors.newSingleThreadExecutor(), new MockMetric(),
+ List.of("cluster", "oyster"), database);
@Test
void testResponses() {
@@ -43,23 +45,33 @@ class ReindexingV1ApiTest {
// GET at status with empty database
response = driver.sendRequest("http://localhost/reindexing/v1/status");
- assertEquals("{\"status\":[]}", response.readAll());
+ assertEquals("{\"clusters\":{\"cluster\":{\"documentTypes\":{}},\"oyster\":{\"documentTypes\":{}}}}", response.readAll());
assertEquals(200, response.getStatus());
// GET at status with a failed status
database.writeReindexing(Reindexing.empty().with(musicType, Status.ready(Instant.EPOCH)
.running()
.progressed(new ProgressToken())
- .failed(Instant.ofEpochMilli(123), "ヽ(。_°)ノ")));
+ .failed(Instant.ofEpochMilli(123), "ヽ(。_°)ノ")),
+ "cluster");
response = driver.sendRequest("http://localhost/reindexing/v1/status");
- assertEquals("{\"status\":[{" +
- "\"type\":\"music\"," +
- "\"startedMillis\":0," +
- "\"endedMillis\":123," +
- "\"progress\":\"" + new ProgressToken().serializeToString() + "\"," +
- "\"state\":\"failed\"," +
- "\"message\":\"ヽ(。_°)ノ\"}" +
- "]}",
+ assertEquals("{" +
+ "\"clusters\":{" +
+ "\"cluster\":{" +
+ "\"documentTypes\":{" +
+ "\"music\":{" +
+ "\"startedMillis\":0," +
+ "\"endedMillis\":123," +
+ "\"progress\":1.0," +
+ "\"state\":\"failed\"," +
+ "\"message\":\"ヽ(。_°)ノ\"}" +
+ "}" +
+ "}," +
+ "\"oyster\":{" +
+ "\"documentTypes\":{}" +
+ "}" +
+ "}" +
+ "}",
response.readAll());
assertEquals(200, response.getStatus());
diff --git a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/util/MetricReporter.java b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/util/MetricReporter.java
index a1bd0b61093..6384b21c2d8 100644
--- a/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/util/MetricReporter.java
+++ b/clustercontroller-utils/src/main/java/com/yahoo/vespa/clustercontroller/utils/util/MetricReporter.java
@@ -1,9 +1,9 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.utils.util;
/**
* Wrapper for current jdisc metrics, such that applications can report metrics without depending on
- * the whole container. The apputil project will provide an implementation of this interface that
+ * the whole container. The apps project will provide an implementation of this interface that
* reports on to injected jdisc implementation.
*/
public interface MetricReporter {
diff --git a/component/abi-spec.json b/component/abi-spec.json
index 5665075f1f2..2dfa3e0d71d 100644
--- a/component/abi-spec.json
+++ b/component/abi-spec.json
@@ -2,7 +2,8 @@
"com.yahoo.component.AbstractComponent": {
"superClass": "java.lang.Object",
"interfaces": [
- "com.yahoo.component.Component"
+ "com.yahoo.component.Component",
+ "com.yahoo.component.Deconstructable"
],
"attributes": [
"public"
@@ -105,6 +106,19 @@
],
"fields": []
},
+ "com.yahoo.component.Deconstructable": {
+ "superClass": "java.lang.Object",
+ "interfaces": [],
+ "attributes": [
+ "public",
+ "interface",
+ "abstract"
+ ],
+ "methods": [
+ "public abstract void deconstruct()"
+ ],
+ "fields": []
+ },
"com.yahoo.component.Version": {
"superClass": "java.lang.Object",
"interfaces": [
diff --git a/component/src/main/java/com/yahoo/component/AbstractComponent.java b/component/src/main/java/com/yahoo/component/AbstractComponent.java
index 163a2b0b7ef..18a19f3e238 100644
--- a/component/src/main/java/com/yahoo/component/AbstractComponent.java
+++ b/component/src/main/java/com/yahoo/component/AbstractComponent.java
@@ -11,7 +11,7 @@ import java.lang.reflect.Method;
*
* @author bratseth
*/
-public class AbstractComponent implements Component {
+public class AbstractComponent implements Component, Deconstructable {
private static final MethodCache deconstructMethods = new MethodCache("deconstruct");
@@ -20,7 +20,7 @@ public class AbstractComponent implements Component {
// We must store the class name, as this.getClass() will yield an exception when a bundled component's
// bundle has been uninstalled.
- private String className = getClass().getName();
+ private final String className = getClass().getName();
protected final boolean isDeconstructable;
/**
@@ -129,6 +129,7 @@ public class AbstractComponent implements Component {
* <p>
* This default implementation does nothing.
*/
+ @Override
public void deconstruct() { }
/**
diff --git a/component/src/main/java/com/yahoo/component/Deconstructable.java b/component/src/main/java/com/yahoo/component/Deconstructable.java
new file mode 100644
index 00000000000..4da39cd3420
--- /dev/null
+++ b/component/src/main/java/com/yahoo/component/Deconstructable.java
@@ -0,0 +1,13 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.component;
+
+/**
+ * A component in the component graph that should be deconstructed, to release resources.
+ *
+ * @author jonmv
+ */
+public interface Deconstructable {
+
+ void deconstruct();
+
+}
diff --git a/config-lib/abi-spec.json b/config-lib/abi-spec.json
index fa352d8f6bd..8a1cfa9834e 100644
--- a/config-lib/abi-spec.json
+++ b/config-lib/abi-spec.json
@@ -73,7 +73,9 @@
"public abstract boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)",
"public abstract java.lang.String getDefName()",
"public abstract java.lang.String getDefNamespace()",
- "public abstract java.lang.String getDefMd5()"
+ "public abstract java.lang.String getDefMd5()",
+ "public boolean getApplyOnRestart()",
+ "public void setApplyOnRestart(boolean)"
],
"fields": []
},
diff --git a/config-lib/pom.xml b/config-lib/pom.xml
index 1002d43bc37..90c61725466 100644
--- a/config-lib/pom.xml
+++ b/config-lib/pom.xml
@@ -26,6 +26,12 @@
<artifactId>annotations</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>configgen</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java
index e35e6916849..30bef223045 100644
--- a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java
+++ b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java
@@ -5,7 +5,6 @@ package com.yahoo.config;
* Root interface for all config builders.
*
* @author gjoranv
- * @since 5.1.6
*/
public interface ConfigBuilder {
}
diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java
index 04405839a9b..113e622a503 100644
--- a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java
+++ b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java
@@ -17,6 +17,7 @@ public abstract class ConfigInstance extends InnerNode {
/**
* Dispatches a getConfig() call if this instance's producer is of the right type
+ *
* @param producer a config producer
* @return true if this instance's producer was the correct type, and hence a getConfig call was dispatched
*/
@@ -26,6 +27,11 @@ public abstract class ConfigInstance extends InnerNode {
String getDefNamespace();
String getDefMd5();
+ /** Returns true if this instance should be applied on restart, false if it should be applied immediately */
+ default boolean getApplyOnRestart() { return false; }
+
+ default void setApplyOnRestart(boolean applyOnRestart) { throw new java.lang.UnsupportedOperationException(); }
+
}
public interface Producer {}
diff --git a/config-lib/src/main/java/com/yahoo/config/Node.java b/config-lib/src/main/java/com/yahoo/config/Node.java
index 8d16b9727c1..ed11bdc9891 100644
--- a/config-lib/src/main/java/com/yahoo/config/Node.java
+++ b/config-lib/src/main/java/com/yahoo/config/Node.java
@@ -5,7 +5,6 @@ package com.yahoo.config;
* The Node class is superclass for all nodes in a {@link
* ConfigInstance}. Important subclasses of this node are {@link
* InnerNode} and {@link LeafNode}.
- *
*/
public abstract class Node {
@@ -13,7 +12,7 @@ public abstract class Node {
* Postinitialize this node. Any node needing to process its values depending on the config
* id should override this method.
*
- * @param configId the configId of the ConfigInstance that owns (or is) this node
+ * @param configId the configId of the ConfigInstance that owns (or is) this node
*/
public void postInitialize(String configId) { return; }
@@ -26,4 +25,5 @@ public abstract class Node {
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
+
}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java
index d25de9fb334..6481c4cb2c7 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java
@@ -2,6 +2,7 @@
package com.yahoo.config.model.api;
import com.yahoo.component.Version;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.vespa.config.ConfigKey;
@@ -23,41 +24,45 @@ public interface Model {
/**
* Resolves config for a given key and config definition
*
- * @param configKey The key to resolve
- * @param configDefinition The config definition to use for the schema
+ * @param configKey the key to resolve
+ * @param configDefinition the config definition to use for the schema
*/
+ @Deprecated // TODO: Return after December 2020
ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition configDefinition);
/**
- * Produces a set of the valid config keys for this model.
+ * Resolves config for a given key and config definition
+ *
+ * @param configKey the key to resolve
+ * @param configDefinition the config definition to use for the schema
*/
+ default ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition configDefinition) {
+ return null; // TODO: Remove this default implementation after December 2020
+ }
+
+ /** Produces a set of the valid config keys for this model. */
Set<ConfigKey<?>> allConfigsProduced();
- /**
- * Returns information about all hosts used in this model.
- */
+ /** Returns information about all hosts used in this model. */
Collection<HostInfo> getHosts();
- /**
- * Returns all the config ids available for this model.
- */
+ /** Returns all the config ids available for this model. */
Set<String> allConfigIds();
/**
* Asks the {@link Model} instance to distribute files using provided filedistribution instance.
- * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance that can be called to distribute files.
+ *
+ * @param fileDistribution instance that can be called to distribute files
*/
void distributeFiles(FileDistribution fileDistribution);
- /**
- * The set of files that should be distributed to the hosts in this model.
- */
+ /** The set of files that should be distributed to the hosts in this model. */
Set<FileReference> fileReferences();
/**
* Gets the allocated hosts for this model.
*
- * @return {@link AllocatedHosts} instance, if available.
+ * @return {@link AllocatedHosts} instance, if available
*/
AllocatedHosts allocatedHosts();
@@ -80,13 +85,10 @@ public interface Model {
*/
default boolean skipOldConfigModels(Instant now) { return false; }
- /**
- * Returns the version of this model
- */
+ /** Returns the version of this model. */
default Version version() { return Version.emptyVersion; }
- /**
- * Returns the provisioned hosts of this
- */
+ /** Returns the provisioned hosts of this. */
default Provisioned provisioned() { return new Provisioned(); }
+
}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
index 6c7bd330159..1cf698af9cb 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -1,4 +1,4 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.model.api;
import com.yahoo.component.Version;
@@ -17,7 +17,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URI;
-import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -50,8 +49,39 @@ public interface ModelContext {
/** The Vespa version we want nodes to become */
Version wantedNodeVespaVersion();
+ /**
+ * How to remove a temporary feature flags:
+ * 1)
+ * - Remove flag definition from Flags
+ * - Remove method implementation from ModelContextImpl.FeatureFlags
+ * - Modify default implementation of below method to return the new default value
+ * - Remove all usage of below method from config-model
+ *
+ * 2)
+ * - (optional) Track Vespa version that introduced changes from 1) in annotation field 'removeAfter'
+ *
+ * 3)
+ * - Remove below method once all config-model versions in hosted production include changes from 1)
+ */
interface FeatureFlags {
- @ModelFeatureFlag(owner = "bjorncs") default boolean enableAutomaticReindexing() { return false; }
+ @ModelFeatureFlag(owners = {"bjorncs", "jonmv"}) default boolean enableAutomaticReindexing() { return false; }
+ @ModelFeatureFlag(owners = {"bjorncs", "jonmv"}) default double reindexerWindowSizeIncrement() { return 0.2; }
+ @ModelFeatureFlag(owners = {"baldersheim"}, comment = "Revisit in May or June 2020") default double defaultTermwiseLimit() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"vekterli"}) default boolean useThreePhaseUpdates() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"geirst"}, comment = "Remove on 7.XXX when this is default on") default boolean useDirectStorageApiRpc() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"geirst"}, comment = "Remove when 7.328 is no longer in use") default boolean useFastValueTensorImplementation() { return true; }
+ @ModelFeatureFlag(owners = {"baldersheim"}, comment = "Select sequencer type use while feeding") default String feedSequencerType() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default String responseSequencerType() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default int defaultNumResponseThreads() { return 2; }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default boolean skipCommunicationManagerThread() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default boolean skipMbusRequestThread() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default boolean skipMbusReplyThread() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"tokle"}) default boolean useAccessControlTlsHandshakeClientAuth() { return false; }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default boolean useAsyncMessageHandlingOnSchedule() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default int contentNodeBucketDBStripeBits() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default int mergeChunkSize() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"baldersheim"}) default double feedConcurrency() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"musum", "mpolden"}, comment = "Revisit in February 2021") default boolean reconfigurableZookeeperServer() { return false; }
}
/** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */
@@ -69,77 +99,44 @@ public interface ModelContext {
boolean isBootstrap();
boolean isFirstTimeDeployment();
- // TODO: Only needed for LbServicesProducerTest
- default boolean useDedicatedNodeForLogserver() { return true; }
-
default Optional<EndpointCertificateSecrets> endpointCertificateSecrets() { return Optional.empty(); }
- // TODO Revisit in May or June 2020
- double defaultTermwiseLimit();
-
- default int defaultNumResponseThreads() { return 2; }
-
- // TODO(bjorncs) Temporary feature flag
- default double threadPoolSizeFactor() { return 2.0; }
-
- // TODO(bjorncs) Temporary feature flag
- default double queueSizeFactor() { return 40.0; };
-
- /// Default setting for the gc-options attribute if not specified explicit by application
- String jvmGCOptions();
-
- // Select sequencer type use while feeding.
- String feedSequencerType();
- String responseSequencerType();
- boolean skipCommunicationManagerThread();
- boolean skipMbusRequestThread();
- boolean skipMbusReplyThread();
-
- boolean useAsyncMessageHandlingOnSchedule();
- int contentNodeBucketDBStripeBits();
- int mergeChunkSize();
- double feedConcurrency();
-
- boolean useThreePhaseUpdates();
-
- // TODO Remove on 7.XXX when this is default on.
- boolean useDirectStorageApiRpc();
-
- // TODO Remove on 7.XXX when this is default on.
- boolean useFastValueTensorImplementation();
-
- // TODO(bjorncs) Temporary feature flag
- default String proxyProtocol() { return "https+proxy-protocol"; }
-
default Optional<AthenzDomain> athenzDomain() { return Optional.empty(); }
Optional<ApplicationRoles> applicationRoles();
- // TODO(bjorncs): Temporary feature flag, revisit August 2020
- default Duration jdiscHealthCheckProxyClientTimeout() { return Duration.ofMillis(100); }
-
- // TODO(bjorncs): Temporary feature flag
- default double feedCoreThreadPoolSizeFactor() { return 4.0; }
-
default Quota quota() {
return Quota.unlimited();
}
- // TODO(bjorncs): Temporary feature flag
- default boolean useNewRestapiHandler() { return true; }
-
- // TODO(mortent): Temporary feature flag
- default boolean useAccessControlTlsHandshakeClientAuth() { return false; }
-
- // TODO(bjorncs): Temporary feature flag
- default double jettyThreadpoolSizeFactor() { return 1.0; }
+ /// Default setting for the gc-options attribute if not specified explicit by application
+ String jvmGCOptions();
+ // TODO(somebody): Only needed for LbServicesProducerTest
+ default boolean useDedicatedNodeForLogserver() { return true; }
+ // NOTE: Use FeatureFlags interface above instead of non-permament flags
+ @Deprecated double defaultTermwiseLimit();
+ @Deprecated default int defaultNumResponseThreads() { return 2; }
+ @Deprecated String feedSequencerType();
+ @Deprecated String responseSequencerType();
+ @Deprecated boolean skipCommunicationManagerThread();
+ @Deprecated boolean skipMbusRequestThread();
+ @Deprecated boolean skipMbusReplyThread();
+ @Deprecated boolean useAsyncMessageHandlingOnSchedule();
+ @Deprecated int contentNodeBucketDBStripeBits();
+ @Deprecated int mergeChunkSize();
+ @Deprecated double feedConcurrency();
+ @Deprecated boolean useThreePhaseUpdates();
+ @Deprecated boolean useDirectStorageApiRpc();
+ @Deprecated default boolean useFastValueTensorImplementation() { return true; }
+ @Deprecated default boolean useAccessControlTlsHandshakeClientAuth() { return false; }
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ModelFeatureFlag {
- String owner();
+ String[] owners();
+ String removeAfter() default ""; // On the form "7.100.10"
String comment() default "";
}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/Reindexing.java b/config-model-api/src/main/java/com/yahoo/config/model/api/Reindexing.java
index 80fdbe961dc..ae7fdf4f497 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/Reindexing.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/Reindexing.java
@@ -25,4 +25,6 @@ public interface Reindexing {
}
+ Reindexing DISABLED_INSTANCE = new Reindexing() {};
+
}
diff --git a/config-model-fat/pom.xml b/config-model-fat/pom.xml
index 0c8d45c9ea2..8a839b228a0 100644
--- a/config-model-fat/pom.xml
+++ b/config-model-fat/pom.xml
@@ -105,7 +105,7 @@
<!-- TODO: The fat bundle becomes more brittle for each package added below. Use interfaces in model-api instead. -->
com.yahoo.vespa.config,
com.yahoo.vespa.config.buildergen,
- com.yahoo.config.codegen <!-- TODO remove when InnerCNode is no longer exposed by config-bundle via ConfigDefinition.getCNode() -->
+ com.yahoo.config.codegen <!-- TODO: Remove when the model of config def, which today is InnerCNode in codegen :-(, is moved to config-lib -->
</Import-Package>
</instructions>
</configuration>
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
index 070a389b3ac..13222e323f7 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
@@ -248,6 +248,8 @@ public class DeployState implements ConfigDefinitionStore {
public ModelContext.Properties getProperties() { return properties; }
+ public ModelContext.FeatureFlags featureFlags() { return properties.featureFlags(); }
+
public Version getVespaVersion() { return vespaVersion; }
public Optional<Model> getPreviousModel() { return previousModel; }
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index 0e4d0db484e..3e7017b78e1 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -26,6 +26,7 @@ import java.util.Set;
*
* @author hakonhall
*/
+@SuppressWarnings("deprecation")
public class TestProperties implements ModelContext.Properties, ModelContext.FeatureFlags {
private boolean multitenant = false;
@@ -37,7 +38,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private boolean useDedicatedNodeForLogserver = false;
private boolean useThreePhaseUpdates = false;
private boolean useDirectStorageApiRpc = false;
- private boolean useFastValueTensorImplementation = false;
+ private boolean useFastValueTensorImplementation = true;
private double defaultTermwiseLimit = 1.0;
private String jvmGCOptions = null;
private String sequencerType = "LATENCY";
@@ -52,6 +53,8 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private int contentNodeBucketDBStripeBits = 0;
private int mergeChunkSize = 0x400000 - 0x1000; // 4M -4k
private double feedConcurrency = 0.5;
+ private boolean enableAutomaticReindexing = false;
+ private boolean reconfigurableZookeeperServer = false;
@Override public ModelContext.FeatureFlags featureFlags() { return this; }
@Override public boolean multitenant() { return multitenant; }
@@ -86,6 +89,8 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
@Override public int contentNodeBucketDBStripeBits() { return contentNodeBucketDBStripeBits; }
@Override public int mergeChunkSize() { return mergeChunkSize; }
@Override public double feedConcurrency() { return feedConcurrency; }
+ @Override public boolean enableAutomaticReindexing() { return enableAutomaticReindexing; }
+ @Override public boolean reconfigurableZookeeperServer() { return reconfigurableZookeeperServer; }
public TestProperties setFeedConcurrency(double feedConcurrency) {
this.feedConcurrency = feedConcurrency;
@@ -137,11 +142,6 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
- public TestProperties setUseFastValueTensorImplementation(boolean useFastValueTensorImplementation) {
- this.useFastValueTensorImplementation = useFastValueTensorImplementation;
- return this;
- }
-
public TestProperties setApplicationId(ApplicationId applicationId) {
this.applicationId = applicationId;
return this;
@@ -197,6 +197,14 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
+ public TestProperties enableAutomaticReindexing(boolean enabled) { this.enableAutomaticReindexing = enabled; return this; }
+
+ public TestProperties reconfigurableZookeeperServer(boolean enabled) {
+ this.reconfigurableZookeeperServer = enabled;
+ return this;
+ }
+
+
public static class Spec implements ConfigServerSpec {
private final String hostName;
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
index 56a5d539906..c656a426b61 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/derived/RawRankProfile.java
@@ -191,7 +191,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer {
numThreadsPerSearch = rankProfile.getNumThreadsPerSearch();
minHitsPerThread = rankProfile.getMinHitsPerThread();
numSearchPartitions = rankProfile.getNumSearchPartitions();
- termwiseLimit = rankProfile.getTermwiseLimit().orElse(deployProperties.defaultTermwiseLimit());
+ termwiseLimit = rankProfile.getTermwiseLimit().orElse(deployProperties.featureFlags().defaultTermwiseLimit());
keepRankCount = rankProfile.getKeepRankCount();
rankScoreDropLimit = rankProfile.getRankScoreDropLimit();
ignoreDefaultRankFeatures = rankProfile.getIgnoreDefaultRankFeatures();
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/document/SDField.java b/config-model/src/main/java/com/yahoo/searchdefinition/document/SDField.java
index ecc90e3d948..3fea5cc16e9 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/document/SDField.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/SDField.java
@@ -67,13 +67,13 @@ public class SDField extends Field implements TypedKey, FieldOperationContainer,
* to be specified in other rank profiles, while negative values
* turns the capability off.
*/
- private int literalBoost=-1;
+ private int literalBoost = -1;
/**
* The weight of this field. This is a percentage,
* so 100 is default to provide the identity transform.
*/
- private int weight=100;
+ private int weight = 100;
/**
* Indicates what kind of matching should be done on this field
@@ -87,7 +87,7 @@ public class SDField extends Field implements TypedKey, FieldOperationContainer,
* The stemming setting of this field, or null to use the default.
* Default is determined by the owning search definition.
*/
- private Stemming stemming=null;
+ private Stemming stemming = null;
/** How content of this field should be accent normalized etc. */
private NormalizeLevel normalizing = new NormalizeLevel();
@@ -179,6 +179,10 @@ public class SDField extends Field implements TypedKey, FieldOperationContainer,
if (type.dimensions().stream().anyMatch(d -> d.isIndexed() && d.size().isEmpty()))
throw new IllegalArgumentException("Illegal type in field " + name + " type " + type +
": Dense tensor dimensions must have a size");
+ addQueryCommand("type " + type);
+ }
+ else {
+ addQueryCommand("type " + dataType.getName());
}
if (populate || (dataType instanceof MapDataType)) {
populateWithStructFields(repo, name, dataType, recursion);
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/ExpressionTransforms.java b/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/ExpressionTransforms.java
index a723be8b478..b19c0c3152d 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/ExpressionTransforms.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/ExpressionTransforms.java
@@ -29,6 +29,7 @@ public class ExpressionTransforms {
new OnnxModelTransformer(),
new XgboostFeatureConverter(),
new LightGBMFeatureConverter(),
+ new TokenTransformer(),
new ConstantDereferencer(),
new ConstantTensorTransformer(),
new FunctionInliner(),
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/TokenTransformer.java b/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/TokenTransformer.java
new file mode 100644
index 00000000000..1bb38eda9ff
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/expressiontransforms/TokenTransformer.java
@@ -0,0 +1,300 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.searchdefinition.expressiontransforms;
+
+import com.yahoo.searchlib.rankingexpression.Reference;
+import com.yahoo.searchlib.rankingexpression.evaluation.DoubleValue;
+import com.yahoo.searchlib.rankingexpression.rule.ArithmeticNode;
+import com.yahoo.searchlib.rankingexpression.rule.ArithmeticOperator;
+import com.yahoo.searchlib.rankingexpression.rule.ComparisonNode;
+import com.yahoo.searchlib.rankingexpression.rule.CompositeNode;
+import com.yahoo.searchlib.rankingexpression.rule.ConstantNode;
+import com.yahoo.searchlib.rankingexpression.rule.EmbracedNode;
+import com.yahoo.searchlib.rankingexpression.rule.ExpressionNode;
+import com.yahoo.searchlib.rankingexpression.rule.IfNode;
+import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode;
+import com.yahoo.searchlib.rankingexpression.rule.TensorFunctionNode;
+import com.yahoo.searchlib.rankingexpression.rule.TruthOperator;
+import com.yahoo.searchlib.rankingexpression.transform.ExpressionTransformer;
+import com.yahoo.tensor.TensorType;
+import com.yahoo.tensor.functions.Generate;
+import com.yahoo.tensor.functions.Slice;
+import com.yahoo.tensor.functions.TensorFunction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.yahoo.searchlib.rankingexpression.rule.TensorFunctionNode.wrapScalar;
+
+/**
+ * Convenience feature transforms for inputs to Transformer type models.
+ *
+ * Replaces features of the form
+ *
+ * tokenInputIds
+ * tokenTypeIds
+ * tokenAttentionMask
+ *
+ * to tensor generation expressions that generate the required input.
+ * In general, these models expect input of the form:
+ *
+ * CLS + arg1 + SEP + arg2 + SEP + 0's
+ *
+ * @author lesters
+ */
+public class TokenTransformer extends ExpressionTransformer<RankProfileTransformContext> {
+
+ static private final ConstantNode ZERO = new ConstantNode(new DoubleValue(0.0), "0");
+ static private final ConstantNode ONE = new ConstantNode(new DoubleValue(1.0), "1");
+ static private final ConstantNode TWO = new ConstantNode(new DoubleValue(2.0), "2");
+ static private final ConstantNode CLS = new ConstantNode(new DoubleValue(101), "101");
+ static private final ConstantNode SEP = new ConstantNode(new DoubleValue(102), "102");
+
+ @Override
+ public ExpressionNode transform(ExpressionNode node, RankProfileTransformContext context) {
+ if (node instanceof ReferenceNode)
+ return transformFeature((ReferenceNode) node, context);
+ else if (node instanceof CompositeNode)
+ return super.transformChildren((CompositeNode) node, context);
+ else
+ return node;
+ }
+
+ private ExpressionNode transformFeature(ReferenceNode feature, RankProfileTransformContext context) {
+ if (feature.getName().equals("tokenInputIds") && shouldTransform(feature, context))
+ return transformTokenInputIds(feature, context);
+ if (feature.getName().equals("tokenTypeIds") && shouldTransform(feature, context))
+ return transformTokenTypeIds(feature, context);
+ if (feature.getName().equals("tokenAttentionMask") && shouldTransform(feature, context))
+ return transformTokenAttentionMask(feature, context);
+ return feature;
+ }
+
+ /**
+ * Transforms a feature of the form
+ *
+ * tokenInputIds(128, a, b, ...)
+ *
+ * to an expression that concatenates the arguments a, b, ... using the
+ * special Transformers sequences of CLS and SEP, up to length 128, so
+ * that the sequence becomes
+ *
+ * CLS + a + SEP + b + SEP + 0's
+ *
+ * Concretely, transforms to a tensor generation expression:
+ *
+ * tensor(d0[1],d1[128])(
+ * if (d1 < 1,
+ * 101,
+ * if (d1 < 1 + length_a,
+ * a{d0:(d1 - (1)},
+ * if (d1 < 1 + length_a + 1,
+ * 102,
+ * if (d1 < 1 + length_a + 1 + length_b,
+ * b{d0:(d1 - (1 + length_a + 1))},
+ * if (d1 < 1 + length_a + 1 + length_b + 1,
+ * 102,
+ * 0.0
+ * ))))))
+ *
+ * Functions calculating lengths of arguments are added to the rank profile.
+ */
+ private ExpressionNode transformTokenInputIds(ReferenceNode feature, RankProfileTransformContext context) {
+ checkArguments(feature);
+
+ TensorType type = createTensorType(feature.getName(), feature.getArguments().expressions().get(0));
+
+ // we need to add functions calculating the token lengths of the arguments
+ createTokenLengthFunctions(feature, context);
+
+ // create token sequence: CLS + arg1 + SEP + arg2 + SEP + ....
+ ExpressionNode tokenSequenceExpr = createTokenSequenceExpr(0, createTokenSequence(feature));
+ return new TensorFunctionNode(Generate.bound(type, wrapScalar(tokenSequenceExpr)));
+ }
+
+ /**
+ * Transforms a feature of the form
+ *
+ * tokenTypeIds(128, a, ...)
+ *
+ * to an expression that generates a tensor that has values 0 for "a"
+ * (including CLS and SEP tokens) and 1 for the rest of the sequence.
+ *
+ * Concretely, transforms to a tensor generation expression:
+ *
+ * tensor(d0[1],d1[128])(if(d1 < length_a + 2, 0, 1))
+ */
+ private ExpressionNode transformTokenTypeIds(ReferenceNode feature, RankProfileTransformContext context) {
+ checkArguments(feature);
+
+ TensorType type = createTensorType(feature.getName(), feature.getArguments().expressions().get(0));
+
+ // we need to add functions calculating the token lengths of the arguments
+ createTokenLengthFunctions(feature, context);
+
+ ReferenceNode arg = (ReferenceNode) feature.getArguments().expressions().get(1);
+ ExpressionNode argLength = new ReferenceNode(lengthFunctionName(arg));
+ ExpressionNode lengthExpr = new ArithmeticNode(argLength, ArithmeticOperator.PLUS, TWO);
+ ComparisonNode comparison = new ComparisonNode(new ReferenceNode("d1"), TruthOperator.SMALLER, lengthExpr);
+ ExpressionNode expr = new IfNode(comparison, ZERO, ONE);
+ return new TensorFunctionNode(Generate.bound(type, wrapScalar(expr)));
+ }
+
+ /**
+ * Transforms a feature of the form
+ *
+ * tokenAttentionMask(128, a, b, ...)
+ *
+ * to an expression that generates a tensor that has values 1 for all
+ * arguments (including CLS and SEP tokens) and 0 for the rest of the
+ * sequence.
+ *
+ * Concretely, transforms to a tensor generation expression:
+ *
+ * tensor(d0[1],d1[128])(if(d1 < 1 + length_a + 1 + length_b + 1 + ..., 1, 0))
+ *
+ */
+ private ExpressionNode transformTokenAttentionMask(ReferenceNode feature, RankProfileTransformContext context) {
+ checkArguments(feature);
+
+ TensorType type = createTensorType(feature.getName(), feature.getArguments().expressions().get(0));
+
+ // we need to add functions calculating the token lengths of the arguments
+ createTokenLengthFunctions(feature, context);
+
+ List<ExpressionNode> tokenSequence = createTokenSequence(feature);
+ ExpressionNode lengthExpr = createLengthExpr(tokenSequence.size() - 1, tokenSequence);
+ ComparisonNode comparison = new ComparisonNode(new ReferenceNode("d1"), TruthOperator.SMALLER, lengthExpr);
+ ExpressionNode expr = new IfNode(comparison, ONE, ZERO);
+ return new TensorFunctionNode(Generate.bound(type, wrapScalar(expr)));
+ }
+
+ private boolean shouldTransform(ReferenceNode feature, RankProfileTransformContext context) {
+ if (context.rankProfile().getFunctions().containsKey(feature.getName()))
+ return false;
+ if (feature.getArguments().size() < 2)
+ return false;
+ return true;
+ }
+
+ private void checkArguments(ReferenceNode feature) {
+ for (int i = 1; i < feature.getArguments().size(); ++i) {
+ ExpressionNode arg = feature.getArguments().expressions().get(i);
+ if ( ! (arg instanceof ReferenceNode)) {
+ throw new IllegalArgumentException("Invalid argument " + i + " to " + feature.getName() + ": " +
+ "the argument must be a reference. Got " + arg.toString());
+ }
+ }
+ }
+
+ private TensorType createTensorType(String featureName, ExpressionNode argument) {
+ try {
+ int length = Integer.parseInt(argument.toString());
+ return new TensorType.Builder(TensorType.Value.FLOAT).indexed("d0", 1).indexed("d1", length).build();
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException("Invalid argument to " + featureName + ": the first argument must be " +
+ "the length to the token sequence to generate. Got " + argument.toString());
+ }
+ }
+
+ private String lengthFunctionName(ReferenceNode arg) {
+ return "__token_length@" + arg.hashCode();
+ }
+
+ private List<ExpressionNode> createTokenSequence(ReferenceNode feature) {
+ List<ExpressionNode> sequence = new ArrayList<>();
+ sequence.add(CLS);
+ for (int i = 1; i < feature.getArguments().size(); ++i) {
+ sequence.add(feature.getArguments().expressions().get(i));
+ sequence.add(SEP);
+ }
+ return sequence;
+ }
+
+ /**
+ * Adds functions for calculating the token length input. Assumes that
+ * token sequences are 0-padded, so this returns the number of non-0
+ * tokens using a map and reduce-sum.
+ */
+ private void createTokenLengthFunctions(ReferenceNode feature, RankProfileTransformContext context) {
+ for (int i = 1; i < feature.getArguments().size(); ++i) {
+ ExpressionNode arg = feature.getArguments().expressions().get(i);
+ if ( ! (arg instanceof ReferenceNode)) {
+ throw new IllegalArgumentException("Invalid argument " + i + " to " + feature.getName() + ": " +
+ "the argument must be a reference. Got " + arg.toString());
+ }
+ ReferenceNode ref = (ReferenceNode) arg;
+ String functionName = lengthFunctionName(ref);
+ if ( ! context.rankProfile().getFunctions().containsKey(functionName)) {
+ context.rankProfile().addFunction(functionName, List.of(), "sum(map(" + ref + ", f(x)(x > 0)))", false);
+ }
+ }
+ }
+
+ /**
+ * Recursively creates partial expressions of the form
+ *
+ * if (d1 < 1 + length_a,
+ * a{d0:(d1 - 1},
+ * ...
+ *
+ * for each part of the token sequence. CLS and SEP are added directly,
+ * and we create a slice expression for each argument to extract the
+ * actual tokens.
+ */
+ private ExpressionNode createTokenSequenceExpr(int iter, List<ExpressionNode> sequence) {
+ ExpressionNode lengthExpr = createLengthExpr(iter, sequence);
+ ComparisonNode comparison = new ComparisonNode(new ReferenceNode("d1"), TruthOperator.SMALLER, lengthExpr);
+
+ ExpressionNode trueExpr = sequence.get(iter);
+ if (sequence.get(iter) instanceof ReferenceNode) {
+ trueExpr = createTokenExtractExpr(iter, sequence);
+ }
+
+ ExpressionNode falseExpr;
+ if (iter < sequence.size() - 1) {
+ falseExpr = createTokenSequenceExpr(iter + 1, sequence);
+ } else {
+ falseExpr = ZERO; // 0-padding for rest of sequence
+ }
+
+ return new IfNode(comparison, trueExpr, falseExpr);
+ }
+
+ /**
+ * Creates an expression for the length of the token sequence so far, where
+ * the lengths of CLS and SEP are 1, and the length of the arguments are
+ * calculated using auxiliary functions.
+ */
+ private ExpressionNode createLengthExpr(int iter, List<ExpressionNode> sequence) {
+ List<ExpressionNode> factors = new ArrayList<>();
+ List<ArithmeticOperator> operators = new ArrayList<>();
+ for (int i = 0; i < iter + 1; ++i) {
+ if (sequence.get(i) instanceof ConstantNode) {
+ factors.add(ONE);
+ } else if (sequence.get(i) instanceof ReferenceNode) {
+ factors.add(new ReferenceNode(lengthFunctionName((ReferenceNode) sequence.get(i))));
+ }
+ if (i >= 1) {
+ operators.add(ArithmeticOperator.PLUS);
+ }
+ }
+ return new ArithmeticNode(factors, operators);
+ }
+
+ /**
+ * Create the slice expression to extract the tokens from arguments
+ */
+ private ExpressionNode createTokenExtractExpr(int iter, List<ExpressionNode> sequence) {
+ ExpressionNode expr;
+ if (iter >= 1) {
+ ExpressionNode lengthExpr = new EmbracedNode(createLengthExpr(iter - 1, sequence));
+ expr = new EmbracedNode(new ArithmeticNode(new ReferenceNode("d1"), ArithmeticOperator.MINUS, lengthExpr));
+ } else {
+ expr = new ReferenceNode("d1");
+ }
+ List<Slice.DimensionValue<Reference>> slices = List.of(new Slice.DimensionValue<>("d0", wrapScalar(expr)) );
+ TensorFunction<Reference> argument = new TensorFunctionNode.ExpressionTensorFunction(sequence.get(iter));
+ return new TensorFunctionNode(new Slice<>(argument, slices));
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java b/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java
index a8404b076d4..11e97bc8a95 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java
@@ -31,7 +31,8 @@ import java.util.Map;
*
* @author Vegard Havdal
*/
-// TODO This functionality should be on VespaModel itself, but we don't have a way right now to apply a config override to a ConfigInstance.Builder
+// TODO: Most of this has been copied to ConfigInstance.Builder.buildInstance() and can be removed from here
+// when Model.getConfig is removed
class InstanceResolver {
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InstanceResolver.class.getName());
@@ -138,7 +139,6 @@ class InstanceResolver {
return packagePrefix.value + cKey.getNamespace();
}
-
enum PackagePrefix {
COM_YAHOO("com.yahoo."),
NONE("");
@@ -148,4 +148,5 @@ class InstanceResolver {
this.value = value;
}
}
+
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java
index 2ffc24239f9..9f9c5def406 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java
@@ -29,6 +29,7 @@ import com.yahoo.config.model.producer.AbstractConfigProducerRoot;
import com.yahoo.config.model.producer.UserConfigRepo;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.container.QrConfig;
import com.yahoo.searchdefinition.RankProfile;
import com.yahoo.searchdefinition.RankProfileRegistry;
import com.yahoo.searchdefinition.RankingConstants;
@@ -190,6 +191,7 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri
configModelRepo.prepareConfigModels(deployState);
validateWrapExceptions();
hostSystem.dumpPortAllocations();
+ propagateRestartOnDeploy();
// must happen after stuff above
this.allocatedHosts = AllocatedHosts.withHosts(hostSystem.getHostSpecs());
}
@@ -197,6 +199,18 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri
this.allocatedHosts = AllocatedHosts.withHosts(hostSystem.getHostSpecs());
this.fileDistributor = fileDistributor;
}
+
+ }
+
+ private void propagateRestartOnDeploy() {
+ if (applicationPackage.getMetaData().isInternalRedeploy()) return;
+
+ // Propagate application config setting of restartOnDeploy to cluster deferChangesUntilRestart
+ for (ApplicationContainerCluster containerCluster : getContainerClusters().values()) {
+ QrConfig config = getConfig(QrConfig.class, containerCluster.getConfigId());
+ if (config.restartOnDeploy())
+ containerCluster.setDeferChangesUntilRestart(true);
+ }
}
/** Returns the application package owning this */
@@ -313,6 +327,7 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri
* @param configId the config id
* @return a config instance of the given type
*/
+ @Override
public <CONFIGTYPE extends ConfigInstance> CONFIGTYPE getConfig(Class<CONFIGTYPE> clazz, String configId) {
try {
ConfigInstance.Builder builder = newBuilder(clazz);
@@ -393,6 +408,7 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri
* @param targetDef The config definition to use for the schema
* @return The payload as a list of strings
*/
+ @Deprecated // TODO: Remove after December 2020
@Override
public ConfigPayload getConfig(ConfigKey<?> configKey, com.yahoo.vespa.config.buildergen.ConfigDefinition targetDef) {
Objects.requireNonNull(targetDef, "config definition cannot be null");
@@ -405,6 +421,19 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri
}
/**
+ * Resolve config for a given key and config definition
+ *
+ * @param configKey the key to resolve.
+ * @param targetDef the config definition to use for the schema
+ * @return the resolved config instance
+ */
+ @Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, com.yahoo.vespa.config.buildergen.ConfigDefinition targetDef) {
+ Objects.requireNonNull(targetDef, "config definition cannot be null");
+ return resolveToBuilder(configKey);
+ }
+
+ /**
* Resolves the given config key into a correctly typed ConfigBuilder
* and fills in the config from this model.
*
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
index c2a4b1f3bbf..5de03f17958 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java
@@ -22,8 +22,10 @@ import com.yahoo.config.model.builder.xml.ConfigModelBuilder;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.TransientException;
import com.yahoo.config.provision.Zone;
+import com.yahoo.container.QrConfig;
import com.yahoo.vespa.config.VespaVersion;
import com.yahoo.vespa.model.application.validation.Validation;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import org.xml.sax.SAXException;
import java.io.IOException;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
index 0a61b5c91c6..916c65e5f82 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
@@ -14,7 +14,7 @@ import com.yahoo.vespa.model.container.component.SystemBindingPattern;
public class LogserverContainerCluster extends ContainerCluster<LogserverContainer> {
public LogserverContainerCluster(AbstractConfigProducer<?> parent, String name, DeployState deployState) {
- super(parent, name, name, deployState);
+ super(parent, name, name, deployState, true);
addDefaultHandlersWithVip();
addLogHandler();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerCluster.java
index a44f14e858c..c11a5017f13 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerCluster.java
@@ -2,7 +2,6 @@
package com.yahoo.vespa.model.admin.clustercontroller;
import com.google.common.base.Joiner;
-import com.yahoo.cloud.config.CuratorConfig;
import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.cloud.config.ZookeepersConfig;
import com.yahoo.config.model.producer.AbstractConfigProducer;
@@ -20,11 +19,10 @@ import java.util.Collection;
* @author Ulf Lilleengen
*/
public class ClusterControllerCluster extends AbstractConfigProducer<ClusterControllerContainerCluster> implements
- CuratorConfig.Producer,
ZookeeperServerConfig.Producer,
ZookeepersConfig.Producer {
- private static final int ZK_CLIENT_PORT = 2181;
+ private static final int ZK_CLIENT_PORT = 2181; // Must match the default in CuratorConfig
private ClusterControllerContainerCluster containerCluster = null;
public ClusterControllerCluster(AbstractConfigProducer<?> parent, String subId) {
@@ -75,15 +73,5 @@ public class ClusterControllerCluster extends AbstractConfigProducer<ClusterCont
}
}
- @Override
- public void getConfig(CuratorConfig.Builder builder) {
- for (ClusterControllerContainer container : containerCluster.getContainers()) {
- CuratorConfig.Server.Builder serverBuilder = new CuratorConfig.Server.Builder();
- serverBuilder.hostname(container.getHostName()).port(ZK_CLIENT_PORT);
- builder.server(serverBuilder);
- builder.zookeeperLocalhostAffinity(false);
- }
- }
-
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
index 9e15db348a2..d7223018b73 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
@@ -1,10 +1,10 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.admin.clustercontroller;
import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.ComponentSpecification;
-import com.yahoo.config.model.api.Reindexing;
import com.yahoo.config.model.api.container.ContainerServiceType;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.container.core.documentapi.DocumentAccessProvider;
@@ -39,17 +39,13 @@ public class ClusterControllerContainer extends Container implements
private static final ComponentSpecification REINDEXING_CONTROLLER_BUNDLE = new ComponentSpecification("clustercontroller-reindexer");
private final Set<String> bundles = new TreeSet<>();
- private final ReindexingContext reindexingContext;
public ClusterControllerContainer(
AbstractConfigProducer<?> parent,
int index,
boolean runStandaloneZooKeeper,
- boolean isHosted,
- ReindexingContext reindexingContext) {
- super(parent, "" + index, index, isHosted);
- this.reindexingContext = reindexingContext;
-
+ DeployState deployState) {
+ super(parent, "" + index, index, deployState.isHosted());
addHandler("clustercontroller-status",
"com.yahoo.vespa.clustercontroller.apps.clustercontroller.StatusHandler",
"/clustercontroller-status/*",
@@ -58,28 +54,15 @@ public class ClusterControllerContainer extends Container implements
"com.yahoo.vespa.clustercontroller.apps.clustercontroller.StateRestApiV2Handler",
"/cluster/v2/*",
CLUSTERCONTROLLER_BUNDLE);
- if (runStandaloneZooKeeper) {
- addComponent("clustercontroller-zkrunner",
- "com.yahoo.vespa.zookeeper.VespaZooKeeperServerImpl",
- ZOOKEEPER_SERVER_BUNDLE);
- addComponent("clustercontroller-zkprovider",
- "com.yahoo.vespa.clustercontroller.apps.clustercontroller.StandaloneZooKeeperProvider",
- CLUSTERCONTROLLER_BUNDLE);
- } else {
- // TODO bjorncs/jonmv: remove extraneous ZooKeeperProvider layer
- addComponent(
- "clustercontroller-zkrunner",
- "com.yahoo.vespa.zookeeper.DummyVespaZooKeeperServer",
- ZOOKEEPER_SERVER_BUNDLE);
- addComponent("clustercontroller-zkprovider",
- "com.yahoo.vespa.clustercontroller.apps.clustercontroller.DummyZooKeeperProvider",
- CLUSTERCONTROLLER_BUNDLE);
- }
- addComponent(new AccessLogComponent(AccessLogComponent.AccessLogType.jsonAccessLog, "controller", isHosted));
+ addComponent("clustercontroller-zookeeper-server",
+ zooKeeperServerImplementation(runStandaloneZooKeeper, deployState.featureFlags().reconfigurableZookeeperServer()),
+ ZOOKEEPER_SERVER_BUNDLE);
+ addComponent(new AccessLogComponent(AccessLogComponent.AccessLogType.jsonAccessLog,
+ "controller",
+ deployState.isHosted()));
// TODO: Why are bundles added here instead of in the cluster?
addFileBundle("clustercontroller-apps");
- addFileBundle("clustercontroller-apputil");
addFileBundle("clustercontroller-core");
addFileBundle("clustercontroller-utils");
addFileBundle("zookeeper-server");
@@ -101,7 +84,16 @@ public class ClusterControllerContainer extends Container implements
return ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
}
- private void addHandler(Handler h, String path) {
+ private String zooKeeperServerImplementation(boolean runStandaloneZooKeeper, boolean reconfigurable) {
+ if (reconfigurable)
+ return "com.yahoo.vespa.zookeeper.ReconfigurableVespaZooKeeperServer";
+ else
+ return runStandaloneZooKeeper
+ ? "com.yahoo.vespa.zookeeper.VespaZooKeeperServerImpl"
+ : "com.yahoo.vespa.zookeeper.DummyVespaZooKeeperServer";
+ }
+
+ private void addHandler(Handler<?> h, String path) {
h.addServerBindings(SystemBindingPattern.fromHttpPath(path));
super.addHandler(h);
}
@@ -121,21 +113,23 @@ public class ClusterControllerContainer extends Container implements
}
private void addHandler(String id, String className, String path, ComponentSpecification bundle) {
- addHandler(new Handler(createComponentModel(id, className, bundle)), path);
+ addHandler(new Handler<>(createComponentModel(id, className, bundle)), path);
+ }
+
+ private ReindexingContext reindexingContext() {
+ return ((ClusterControllerContainerCluster) parent).reindexingContext();
}
private void configureReindexing() {
- if (reindexingContext != null) {
- addFileBundle(REINDEXING_CONTROLLER_BUNDLE.getName());
- addComponent(new SimpleComponent(DocumentAccessProvider.class.getName()));
- addComponent("reindexing-maintainer",
- "ai.vespa.reindexing.ReindexingMaintainer",
- REINDEXING_CONTROLLER_BUNDLE);
- addHandler("reindexing-status",
- "ai.vespa.reindexing.http.ReindexingV1ApiHandler",
- "/reindexing/v1/*",
- REINDEXING_CONTROLLER_BUNDLE);
- }
+ addFileBundle(REINDEXING_CONTROLLER_BUNDLE.getName());
+ addComponent(new SimpleComponent(DocumentAccessProvider.class.getName()));
+ addComponent("reindexing-maintainer",
+ "ai.vespa.reindexing.ReindexingMaintainer",
+ REINDEXING_CONTROLLER_BUNDLE);
+ addHandler("reindexing-status",
+ "ai.vespa.reindexing.http.ReindexingV1ApiHandler",
+ "/reindexing/v1/*",
+ REINDEXING_CONTROLLER_BUNDLE);
}
@@ -151,17 +145,25 @@ public class ClusterControllerContainer extends Container implements
@Override
public void getConfig(ReindexingConfig.Builder builder) {
- if (reindexingContext == null)
+ ReindexingContext ctx = reindexingContext();
+ if (!ctx.reindexing().enabled()) {
+ builder.enabled(false);
return;
+ }
- builder.clusterName(reindexingContext.contentClusterName());
- builder.enabled(reindexingContext.reindexing().enabled());
- for (NewDocumentType type : reindexingContext.documentTypes()) {
- String typeName = type.getFullName().getName();
- reindexingContext.reindexing().status(reindexingContext.contentClusterName(), typeName)
- .ifPresent(status -> builder.status(typeName,
- new ReindexingConfig.Status.Builder()
- .readyAtMillis(status.ready().toEpochMilli())));
+ builder.enabled(ctx.reindexing().enabled());
+ builder.windowSizeIncrement(ctx.windowSizeIncrement());
+ for (String clusterId : ctx.clusterIds()) {
+ ReindexingConfig.Clusters.Builder clusterBuilder = new ReindexingConfig.Clusters.Builder();
+ for (NewDocumentType type : ctx.documentTypesForCluster(clusterId)) {
+ String typeName = type.getFullName().getName();
+ ctx.reindexing().status(clusterId, typeName).ifPresent(
+ status -> clusterBuilder.documentTypes(
+ typeName,
+ new ReindexingConfig.Clusters.DocumentTypes.Builder()
+ .readyAtMillis(status.ready().toEpochMilli())));
+ }
+ builder.clusters(clusterId, clusterBuilder);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java
index 3ee2a840f20..3fe6ce3ff27 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java
@@ -1,6 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.admin.clustercontroller;
+import com.yahoo.config.model.api.Reindexing;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.model.container.ContainerCluster;
@@ -9,12 +10,18 @@ import com.yahoo.vespa.model.container.ContainerCluster;
* Container cluster for cluster-controller containers.
*
* @author gjoranv
+ * @author bjorncs
*/
public class ClusterControllerContainerCluster extends ContainerCluster<ClusterControllerContainer>
{
- public ClusterControllerContainerCluster(AbstractConfigProducer<?> parent, String subId, String name, DeployState deployState) {
- super(parent, subId, name, deployState);
+
+ private final ReindexingContext reindexingContext;
+
+ public ClusterControllerContainerCluster(
+ AbstractConfigProducer<?> parent, String subId, String name, DeployState deployState) {
+ super(parent, subId, name, deployState, false);
addDefaultHandlersWithVip();
+ this.reindexingContext = createReindexingContext(deployState);
}
@Override
@@ -22,4 +29,13 @@ public class ClusterControllerContainerCluster extends ContainerCluster<ClusterC
@Override protected boolean messageBusEnabled() { return false; }
+ public ReindexingContext reindexingContext() { return reindexingContext; }
+
+ private static ReindexingContext createReindexingContext(DeployState deployState) {
+ Reindexing reindexing = deployState.featureFlags().enableAutomaticReindexing()
+ ? deployState.reindexing().orElse(Reindexing.DISABLED_INSTANCE)
+ : Reindexing.DISABLED_INSTANCE;
+ return new ReindexingContext(reindexing, deployState.featureFlags().reindexerWindowSizeIncrement());
+ }
+
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java
index fdd12088d04..7380b950fb2 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java
@@ -5,7 +5,11 @@ import com.yahoo.config.model.api.Reindexing;
import com.yahoo.documentmodel.NewDocumentType;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* Context required to configure automatic reindexing for a given cluster controller cluster (for a given content cluster).
@@ -14,20 +18,37 @@ import java.util.Objects;
*/
public class ReindexingContext {
+ private final Object monitor = new Object();
+ private final Map<String, Set<NewDocumentType>> documentTypesPerCluster = new HashMap<>();
private final Reindexing reindexing;
- private final String contentClusterName;
- private final Collection<NewDocumentType> documentTypes;
+ private final double windowSizeIncrement;
- public ReindexingContext(
- Reindexing reindexing,
- String contentClusterName,
- Collection<NewDocumentType> documentTypes) {
+ public ReindexingContext(Reindexing reindexing, double windowSizeIncrement) {
this.reindexing = Objects.requireNonNull(reindexing);
- this.contentClusterName = Objects.requireNonNull(contentClusterName);
- this.documentTypes = Objects.requireNonNull(documentTypes);
+ this.windowSizeIncrement = windowSizeIncrement;
+ }
+
+ public void addDocumentType(String clusterId, NewDocumentType type) {
+ synchronized (monitor) {
+ documentTypesPerCluster.computeIfAbsent(clusterId, ignored -> new HashSet<>())
+ .add(type);
+ }
+ }
+
+ public Collection<String> clusterIds() {
+ synchronized (monitor) {
+ return new HashSet<>(documentTypesPerCluster.keySet());
+ }
+ }
+
+ public Collection<NewDocumentType> documentTypesForCluster(String clusterId) {
+ synchronized (monitor) {
+ return new HashSet<>(documentTypesPerCluster.getOrDefault(clusterId, Set.of()));
+ }
}
public Reindexing reindexing() { return reindexing; }
- public String contentClusterName() { return contentClusterName; }
- public Collection<NewDocumentType> documentTypes() { return documentTypes; }
+
+ public double windowSizeIncrement() { return windowSizeIncrement; }
+
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
index 4b9e1c302b7..3e2adeaacc9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
@@ -88,7 +88,7 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC
public MetricsProxyContainerCluster(AbstractConfigProducer<?> parent, String name, DeployState deployState) {
- super(parent, name, name, deployState);
+ super(parent, name, name, deployState, true);
this.parent = parent;
applicationId = deployState.getProperties().applicationId();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
index 4317f947e12..1998be3c262 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
@@ -220,6 +220,8 @@ public class VespaMetricSet {
addMetric(metrics, "jdisc.http.filtering.response.handled", List.of("rate"));
addMetric(metrics, "jdisc.http.filtering.response.unhandled", List.of("rate"));
+ addMetric(metrics, "jdisc.application.failed_component_graphs", List.of("rate"));
+
return metrics;
}
@@ -239,7 +241,7 @@ public class VespaMetricSet {
// DO NOT RELY ON THIS METRIC YET.
metrics.add(new Metric("cluster-controller.node-event.count"));
- metrics.add(new Metric("cluster-controller.reindexing.progress.last"));
+ metrics.add(new Metric("reindexing.progress.last"));
return metrics;
}
@@ -542,6 +544,7 @@ public class VespaMetricSet {
// TODO: For the purpose of this file and likely elsewhere, all but the last aggregate specifier,
// TODO: such as 'average' and 'sum' in the metric names below are just confusing and can be mentally
// TODO: disregarded when considering metric names. Consider cleaning up for Vespa 8.
+ // TODO Vespa 8 all metrics with .sum in the name should have that removed.
metrics.add(new Metric("vds.datastored.alldisks.docs.average"));
metrics.add(new Metric("vds.datastored.alldisks.bytes.average"));
metrics.add(new Metric("vds.visitor.allthreads.averagevisitorlifetime.sum.max"));
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
index e028eaea3c1..d1c93bcd611 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
@@ -9,6 +9,7 @@ import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ValidationParameters;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.container.QrConfig;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.application.validation.change.ChangeValidator;
import com.yahoo.vespa.model.application.validation.change.ClusterSizeReductionValidator;
@@ -24,6 +25,8 @@ import com.yahoo.vespa.model.application.validation.change.ResourcesReductionVal
import com.yahoo.vespa.model.application.validation.change.StartupCommandChangeValidator;
import com.yahoo.vespa.model.application.validation.change.StreamingSearchClusterChangeValidator;
import com.yahoo.vespa.model.application.validation.first.AccessControlOnFirstDeploymentValidator;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.Container;
import java.time.Instant;
import java.util.Arrays;
@@ -127,7 +130,6 @@ public class Validation {
private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) {
Set<ClusterSpec.Id> clustersToBeRestarted = actions.stream()
.filter(action -> action.getType() == ConfigChangeAction.Type.RESTART)
- .filter(action -> action.clusterId() != null) // TODO: Remove this line after October 2020
.map(action -> action.clusterId())
.collect(Collectors.toSet());
for (var clusterToRestart : clustersToBeRestarted) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV2Builder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV2Builder.java
index 3719c8a43a2..3879df52390 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV2Builder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV2Builder.java
@@ -1,4 +1,4 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.builder.xml.dom;
import com.yahoo.config.application.api.FileRegistry;
@@ -207,7 +207,7 @@ public class DomAdminV2Builder extends DomAdminBuilderBase {
@Override
protected ClusterControllerContainer doBuild(DeployState deployState, AbstractConfigProducer parent, Element spec) {
- return new ClusterControllerContainer(parent, i, runStandaloneZooKeeper, deployState.isHosted(), /*reindexingContext*/null);
+ return new ClusterControllerContainer(parent, i, runStandaloneZooKeeper, deployState);
}
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
index 12d5e8d32ed..a28475c94f3 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java
@@ -118,7 +118,9 @@ public class DomAdminV4Builder extends DomAdminBuilderBase {
return nodesSpecification.provision(hostSystem,
ClusterSpec.Type.admin,
ClusterSpec.Id.from(clusterId),
- context.getDeployLogger()).keySet();
+ context.getDeployLogger(),
+ false)
+ .keySet();
}
/**
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
index 526e88749fc..aace6818ba6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java
@@ -202,15 +202,17 @@ public class NodesSpecification {
public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem,
ClusterSpec.Type clusterType,
ClusterSpec.Id clusterId,
- DeployLogger logger) {
+ DeployLogger logger,
+ boolean stateful) {
if (combinedId.isPresent())
clusterType = ClusterSpec.Type.combined;
ClusterSpec cluster = ClusterSpec.request(clusterType, clusterId)
- .vespaVersion(version)
- .exclusive(exclusive)
- .combinedId(combinedId.map(ClusterSpec.Id::from))
- .dockerImageRepository(dockerImageRepo)
- .build();
+ .vespaVersion(version)
+ .exclusive(exclusive)
+ .combinedId(combinedId.map(ClusterSpec.Id::from))
+ .dockerImageRepository(dockerImageRepo)
+ .stateful(stateful)
+ .build();
return hostSystem.allocateHosts(cluster, Capacity.from(min, max, required, canFail), logger);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
index cb8abb919ac..fddfcabeb0e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
@@ -1,6 +1,7 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.config.model.api.container.ContainerServiceType;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.config.provision.NodeResources;
@@ -15,17 +16,19 @@ import com.yahoo.vespa.model.container.component.Component;
*
* @author gjoranv
*/
-public final class ApplicationContainer extends Container implements QrStartConfig.Producer {
+public final class ApplicationContainer extends Container implements
+ QrStartConfig.Producer,
+ ZookeeperServerConfig.Producer {
private static final String defaultHostedJVMArgs = "-XX:+UseOSErrorReporting -XX:+SuppressFatalErrorMessage";
private final boolean isHostedVespa;
- public ApplicationContainer(AbstractConfigProducer parent, String name, int index, boolean isHostedVespa) {
+ public ApplicationContainer(AbstractConfigProducer<?> parent, String name, int index, boolean isHostedVespa) {
this(parent, name, false, index, isHostedVespa);
}
- public ApplicationContainer(AbstractConfigProducer parent, String name, boolean retired, int index, boolean isHostedVespa) {
+ public ApplicationContainer(AbstractConfigProducer<?> parent, String name, boolean retired, int index, boolean isHostedVespa) {
super(parent, name, retired, index, isHostedVespa);
this.isHostedVespa = isHostedVespa;
@@ -51,7 +54,7 @@ public final class ApplicationContainer extends Container implements QrStartConf
@Override
protected ContainerServiceType myServiceType() {
if (parent instanceof ContainerCluster) {
- ContainerCluster cluster = (ContainerCluster)parent;
+ ContainerCluster<?> cluster = (ContainerCluster<?>)parent;
// TODO: The 'qrserver' name is retained for legacy reasons (e.g. system tests and log parsing).
if (cluster.getSearch() != null && cluster.getDocproc() == null && cluster.getDocumentApi() == null) {
return ContainerServiceType.QRSERVER;
@@ -70,6 +73,12 @@ public final class ApplicationContainer extends Container implements QrStartConf
}
private boolean hasDocproc() {
- return (parent instanceof ContainerCluster) && (((ContainerCluster)parent).getDocproc() != null);
+ return (parent instanceof ContainerCluster) && (((ContainerCluster<?>)parent).getDocproc() != null);
}
+
+ @Override
+ public void getConfig(ZookeeperServerConfig.Builder builder) {
+ builder.myid(index());
+ }
+
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
index 93717f0f532..f8ff7bcdc18 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
@@ -2,13 +2,16 @@
package com.yahoo.vespa.model.container;
import ai.vespa.metricsproxy.http.application.ApplicationMetricsHandler;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.config.FileReference;
import com.yahoo.config.application.api.ComponentInfo;
+import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
-import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.AllocatedHosts;
+import com.yahoo.config.provision.HostSpec;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.container.di.config.ApplicationBundlesConfig;
import com.yahoo.container.handler.metrics.MetricsProxyApiConfig;
@@ -28,6 +31,7 @@ import com.yahoo.vespa.model.container.component.ConfigProducerGroup;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.Servlet;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
+import com.yahoo.vespa.model.container.configserver.ConfigserverCluster;
import com.yahoo.vespa.model.container.jersey.Jersey2Servlet;
import com.yahoo.vespa.model.container.jersey.RestApi;
import com.yahoo.vespa.model.container.xml.PlatformBundles;
@@ -54,7 +58,8 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
RankingConstantsConfig.Producer,
ServletPathsConfig.Producer,
ContainerMbusConfig.Producer,
- MetricsProxyApiConfig.Producer {
+ MetricsProxyApiConfig.Producer,
+ ZookeeperServerConfig.Producer {
public static final String METRICS_V2_HANDLER_CLASS = MetricsV2Handler.class.getName();
public static final BindingPattern METRICS_V2_HANDLER_BINDING_1 = SystemBindingPattern.fromHttpPath(MetricsV2Handler.V2_PATH);
@@ -72,6 +77,7 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
private final ConfigProducerGroup<Servlet> servletGroup;
private final ConfigProducerGroup<RestApi> restApiGroup;
+ private final Set<String> previousHosts;
private ContainerModelEvaluation modelEvaluation;
@@ -83,10 +89,16 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
private Integer memoryPercentage = null;
public ApplicationContainerCluster(AbstractConfigProducer<?> parent, String configSubId, String clusterId, DeployState deployState) {
- super(parent, configSubId, clusterId, deployState);
+ super(parent, configSubId, clusterId, deployState, true);
this.tlsClientAuthority = deployState.tlsClientAuthority();
restApiGroup = new ConfigProducerGroup<>(this, "rest-api");
servletGroup = new ConfigProducerGroup<>(this, "servlet");
+ previousHosts = deployState.getPreviousModel().stream()
+ .map(Model::allocatedHosts)
+ .map(AllocatedHosts::getHosts)
+ .flatMap(Collection::stream)
+ .map(HostSpec::hostname)
+ .collect(Collectors.toUnmodifiableSet());
addSimpleComponent(DEFAULT_LINGUISTICS_PROVIDER);
addSimpleComponent("com.yahoo.container.jdisc.SecretStoreProvider");
@@ -252,6 +264,22 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
}
}
+ @Override
+ public void getConfig(ZookeeperServerConfig.Builder builder) {
+ if (getParent() instanceof ConfigserverCluster) return; // Produces its own config
+
+ // Note: Default client and server ports are used, so not set here
+ for (Container container : getContainers()) {
+ ZookeeperServerConfig.Server.Builder serverBuilder = new ZookeeperServerConfig.Server.Builder();
+ serverBuilder.hostname(container.getHostName())
+ .id(container.index())
+ .joining(!previousHosts.isEmpty() &&
+ !previousHosts.contains(container.getHostName()));
+ builder.server(serverBuilder)
+ .dynamicReconfiguration(true);
+ }
+ }
+
public Optional<String> getTlsClientAuthority() {
return tlsClientAuthority;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java
index e8b56a6190a..5e95403313c 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java
@@ -1,4 +1,4 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container;
import com.yahoo.component.ComponentId;
@@ -58,10 +58,10 @@ public abstract class Container extends AbstractService implements
public static final int BASEPORT = Defaults.getDefaults().vespaWebServicePort();
public static final String SINGLENODE_CONTAINER_SERVICESPEC = "default_singlenode_container";
- /** The cluster this contasiner belongs to, or null if it is not added to any cluster */
- private ContainerCluster owner = null;
+ /** The cluster this container belongs to, or null if it is not added to any cluster */
+ private ContainerCluster<?> owner = null;
- protected final AbstractConfigProducer parent;
+ protected final AbstractConfigProducer<?> parent;
private final String name;
private boolean requireSpecificPorts = true;
@@ -78,11 +78,11 @@ public abstract class Container extends AbstractService implements
private final JettyHttpServer defaultHttpServer;
- protected Container(AbstractConfigProducer parent, String name, int index, boolean isHostedVespa) {
+ protected Container(AbstractConfigProducer<?> parent, String name, int index, boolean isHostedVespa) {
this(parent, name, false, index, isHostedVespa);
}
- protected Container(AbstractConfigProducer parent, String name, boolean retired, int index, boolean isHostedVespa) {
+ protected Container(AbstractConfigProducer<?> parent, String name, boolean retired, int index, boolean isHostedVespa) {
super(parent, name);
this.name = name;
this.parent = parent;
@@ -106,7 +106,7 @@ public abstract class Container extends AbstractService implements
return handlers;
}
- public ComponentGroup getComponents() {
+ public ComponentGroup<?> getComponents() {
return components;
}
@@ -118,7 +118,7 @@ public abstract class Container extends AbstractService implements
addComponent(new SimpleComponent(new ComponentModel(idSpec, classSpec, bundleSpec)));
}
- public final void addHandler(Handler h) {
+ public final void addHandler(Handler<?> h) {
handlers.addComponent(h);
}
@@ -133,7 +133,7 @@ public abstract class Container extends AbstractService implements
}
public Http getHttp() {
- return (parent instanceof ContainerCluster) ? ((ContainerCluster) parent).getHttp() : null;
+ return (parent instanceof ContainerCluster) ? ((ContainerCluster<?>) parent).getHttp() : null;
}
public JettyHttpServer getDefaultHttpServer() {
@@ -306,9 +306,7 @@ public abstract class Container extends AbstractService implements
.port(getRpcPort())
.slobrokId(serviceSlobrokId()))
.filedistributor(filedistributorConfig())
- .discriminator((clusterName != null ? clusterName + "." : "" ) + name)
- .restartOnDeploy(owner != null && owner.getDeferChangesUntilRestart());
-
+ .discriminator((clusterName != null ? clusterName + "." : "" ) + name);
}
/** Returns the jvm args set explicitly for this node */
@@ -330,6 +328,7 @@ public abstract class Container extends AbstractService implements
@Override
public void getConfig(ComponentsConfig.Builder builder) {
+ builder.setApplyOnRestart(owner.getDeferChangesUntilRestart()); // Sufficient to set on one config
builder.components.addAll(ComponentsConfigGenerator.generate(allEnabledComponents()));
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
index 0909376cb18..c0fd4eb7b05 100755
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.model.container;
import com.yahoo.cloud.config.ClusterInfoConfig;
import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.cloud.config.CuratorConfig;
import com.yahoo.cloud.config.RoutingProviderConfig;
import com.yahoo.component.ComponentId;
import com.yahoo.config.application.api.ApplicationMetaData;
@@ -50,6 +51,7 @@ import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.component.StatisticsComponent;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
+import com.yahoo.vespa.model.container.configserver.ConfigserverCluster;
import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
import com.yahoo.vespa.model.container.docproc.DocprocChains;
import com.yahoo.vespa.model.container.http.Http;
@@ -100,7 +102,8 @@ public abstract class ContainerCluster<CONTAINER extends Container>
DocprocConfig.Producer,
ClusterInfoConfig.Producer,
RoutingProviderConfig.Producer,
- ConfigserverConfig.Producer
+ ConfigserverConfig.Producer,
+ CuratorConfig.Producer
{
/**
@@ -147,6 +150,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
private final List<String> endpointAliases = new ArrayList<>();
private final ComponentGroup<Component<?, ?>> componentGroup;
private final boolean isHostedVespa;
+ private final boolean zooKeeperLocalhostAffinity;
private final Map<String, String> concreteDocumentTypes = new LinkedHashMap<>();
@@ -161,11 +165,12 @@ public abstract class ContainerCluster<CONTAINER extends Container>
private boolean deferChangesUntilRestart = false;
- public ContainerCluster(AbstractConfigProducer<?> parent, String configSubId, String clusterId, DeployState deployState) {
+ public ContainerCluster(AbstractConfigProducer<?> parent, String configSubId, String clusterId, DeployState deployState, boolean zooKeeperLocalhostAffinity) {
super(parent, configSubId);
this.name = clusterId;
this.isHostedVespa = stateIsHosted(deployState);
this.zone = (deployState != null) ? deployState.zone() : Zone.defaultZone();
+ this.zooKeeperLocalhostAffinity = zooKeeperLocalhostAffinity;
componentGroup = new ComponentGroup<>(this, "component");
@@ -408,6 +413,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
@Override
public void getConfig(ComponentsConfig.Builder builder) {
+ builder.setApplyOnRestart(getDeferChangesUntilRestart()); // Sufficient to set on one config
builder.components.addAll(ComponentsConfigGenerator.generate(getAllComponents()));
builder.components(new ComponentsConfig.Components.Builder().id("com.yahoo.container.core.config.HandlersConfigurerDi$RegistriesHack"));
}
@@ -552,7 +558,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
/**
* Returns a config server config containing the right zone settings (and defaults for the rest).
- * This is useful to allow applications to find out in which zone they are runnung by having the Zone
+ * This is useful to allow applications to find out in which zone they are running by having the Zone
* object (which is constructed from this config) injected.
*/
@Override
@@ -562,6 +568,15 @@ public abstract class ContainerCluster<CONTAINER extends Container>
builder.region(zone.region().value());
}
+ @Override
+ public void getConfig(CuratorConfig.Builder builder) {
+ if (getParent() instanceof ConfigserverCluster) return; // Produces its own config
+ for (var container : containers) {
+ builder.server(new CuratorConfig.Server.Builder().hostname(container.getHostResource().getHostname()));
+ }
+ builder.zookeeperLocalhostAffinity(zooKeeperLocalhostAffinity);
+ }
+
private List<ClusterInfoConfig.Services.Ports.Builder> getPorts(Service service) {
List<ClusterInfoConfig.Services.Ports.Builder> builders = new ArrayList<>();
PortsMeta portsMeta = service.getPortsMeta();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/MbusClient.java b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/MbusClient.java
index 533fc36aad3..f837695d65e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/MbusClient.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/MbusClient.java
@@ -10,7 +10,7 @@ import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.model.container.component.Handler;
/**
- * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ * @author Einar M R Rosenvinge
*/
public class MbusClient extends Handler<AbstractConfigProducer<?>> implements SessionConfig.Producer {
private static final ComponentSpecification CLASSNAME =
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 7eea5d8496f..7dca3b9f23b 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -30,6 +30,7 @@ import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Zone;
+import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.search.rendering.RendererRegistry;
import com.yahoo.searchdefinition.derived.RankProfileList;
import com.yahoo.text.XML;
@@ -60,6 +61,7 @@ import com.yahoo.vespa.model.container.SecretStore;
import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.FileStatusHandlerComponent;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.UserBindingPattern;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
@@ -85,7 +87,6 @@ import org.w3c.dom.Node;
import java.net.URI;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -113,6 +114,10 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private static final String DEPRECATED_CONTAINER_TAG = "jdisc";
private static final String ENVIRONMENT_VARIABLES_ELEMENT = "environment-variables";
+ // The node count to enforce in a cluster running ZooKeeper
+ private static final int MIN_ZOOKEEPER_NODE_COUNT = 1;
+ private static final int MAX_ZOOKEEPER_NODE_COUNT = 7;
+
public enum Networking { disable, enable }
private ApplicationPackage app;
@@ -196,7 +201,38 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
addClientProviders(deployState, spec, cluster);
addServerProviders(deployState, spec, cluster);
- addAthensCopperArgos(cluster, context); // Must be added after nodes.
+ // Must be added after nodes:
+ addAthensCopperArgos(cluster, context);
+ addZooKeeper(cluster, spec);
+ }
+
+ private void addZooKeeper(ApplicationContainerCluster cluster, Element spec) {
+ if (!hasZooKeeper(spec)) return;
+ Element nodesElement = XML.getChild(spec, "nodes");
+ boolean isCombined = nodesElement != null && nodesElement.hasAttribute("of");
+ if (isCombined) {
+ throw new IllegalArgumentException("A combined cluster cannot run ZooKeeper");
+ }
+ long nonRetiredNodes = cluster.getContainers().stream().filter(c -> !c.isRetired()).count();
+ if (nonRetiredNodes < MIN_ZOOKEEPER_NODE_COUNT || nonRetiredNodes > MAX_ZOOKEEPER_NODE_COUNT || nonRetiredNodes % 2 == 0) {
+ throw new IllegalArgumentException("Cluster with ZooKeeper needs an odd number of nodes, between " +
+ MIN_ZOOKEEPER_NODE_COUNT + " and " + MAX_ZOOKEEPER_NODE_COUNT +
+ ", have " + nonRetiredNodes + " non-retired");
+ }
+ cluster.addSimpleComponent("com.yahoo.vespa.curator.Curator", null, "zkfacade");
+
+ // These need to be setup so that they will use the container's config id, since each container
+ // have different config (id of zookeeper server)
+ cluster.getContainers().forEach(container -> {
+ container.addComponent(zookeeperComponent("com.yahoo.vespa.zookeeper.ReconfigurableVespaZooKeeperServer", container));
+ container.addComponent(zookeeperComponent("com.yahoo.vespa.zookeeper.Reconfigurer", container));
+ container.addComponent(zookeeperComponent("com.yahoo.vespa.zookeeper.VespaZooKeeperAdminImpl", container));
+ });
+ }
+
+ private SimpleComponent zookeeperComponent(String idSpec, Container container) {
+ String configId = container.getConfigId();
+ return new SimpleComponent(new ComponentModel(idSpec, null, "zookeeper-server", configId));
}
private void addSecretStore(ApplicationContainerCluster cluster, Element spec) {
@@ -342,7 +378,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
EndpointCertificateSecrets endpointCertificateSecrets = deployState.endpointCertificateSecrets().get();
- boolean enforceHandshakeClientAuth = context.properties().useAccessControlTlsHandshakeClientAuth() &&
+ boolean enforceHandshakeClientAuth = context.properties().featureFlags().useAccessControlTlsHandshakeClientAuth() &&
cluster.getHttp().getAccessControl()
.map(accessControl -> accessControl.clientAuthentication)
.map(clientAuth -> clientAuth.equals(AccessControl.ClientAuthentication.need))
@@ -554,7 +590,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
Element nodesElement, ConfigModelContext context) {
applyNodesTagJvmArgs(nodes, getJvmOptions(cluster, nodesElement, context.getDeployLogger()));
- if (!cluster.getJvmGCOptions().isPresent()) {
+ if (cluster.getJvmGCOptions().isEmpty()) {
String jvmGCOptions = extractAttribute(nodesElement, VespaDomBuilder.JVM_GC_OPTIONS);
cluster.setJvmGCOptions(buildJvmGCOptions(context.getDeployState(), jvmGCOptions));
}
@@ -582,7 +618,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
if (nodesElement == null) {
cluster.addContainers(allocateWithoutNodesTag(cluster, context));
} else {
- List<ApplicationContainer> nodes = createNodes(cluster, nodesElement, context);
+ List<ApplicationContainer> nodes = createNodes(cluster, containerElement, nodesElement, context);
Element jvmElement = XML.getChild(nodesElement, "jvm");
if (jvmElement == null) {
@@ -593,7 +629,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
applyRoutingAliasProperties(nodes, cluster);
applyDefaultPreload(nodes, nodesElement);
String environmentVars = getEnvironmentVariables(XML.getChild(nodesElement, ENVIRONMENT_VARIABLES_ELEMENT));
- if (environmentVars != null && !environmentVars.isEmpty()) {
+ if (!environmentVars.isEmpty()) {
cluster.setEnvironmentVars(environmentVars);
}
if (useCpuSocketAffinity(nodesElement))
@@ -613,15 +649,15 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
return sb.toString();
}
- private List<ApplicationContainer> createNodes(ApplicationContainerCluster cluster, Element nodesElement, ConfigModelContext context) {
+ private List<ApplicationContainer> createNodes(ApplicationContainerCluster cluster, Element containerElement, Element nodesElement, ConfigModelContext context) {
if (nodesElement.hasAttribute("type")) // internal use for hosted system infrastructure nodes
return createNodesFromNodeType(cluster, nodesElement, context);
else if (nodesElement.hasAttribute("of")) // hosted node spec referencing a content cluster
return createNodesFromContentServiceReference(cluster, nodesElement, context);
else if (nodesElement.hasAttribute("count")) // regular, hosted node spec
- return createNodesFromNodeCount(cluster, nodesElement, context);
+ return createNodesFromNodeCount(cluster, containerElement, nodesElement, context);
else if (cluster.isHostedVespa() && cluster.getZone().environment().isManuallyDeployed()) // default to 1 in manual zones
- return createNodesFromNodeCount(cluster, nodesElement, context);
+ return createNodesFromNodeCount(cluster, containerElement, nodesElement, context);
else // the non-hosted option
return createNodesFromNodeList(context.getDeployState(), cluster, nodesElement);
}
@@ -685,12 +721,13 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
return List.of(node);
}
- private List<ApplicationContainer> createNodesFromNodeCount(ApplicationContainerCluster cluster, Element nodesElement, ConfigModelContext context) {
+ private List<ApplicationContainer> createNodesFromNodeCount(ApplicationContainerCluster cluster, Element containerElement, Element nodesElement, ConfigModelContext context) {
NodesSpecification nodesSpecification = NodesSpecification.from(new ModelElement(nodesElement), context);
Map<HostResource, ClusterMembership> hosts = nodesSpecification.provision(cluster.getRoot().hostSystem(),
ClusterSpec.Type.container,
ClusterSpec.Id.from(cluster.getName()),
- log);
+ log,
+ hasZooKeeper(containerElement));
return createNodesFromHosts(context.getDeployLogger(), hosts, cluster);
}
@@ -724,43 +761,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
return createNodesFromHosts(context.getDeployLogger(), hosts, cluster);
}
- /**
- * This is used in case we are on hosted Vespa and no nodes tag is supplied:
- * If there are content clusters this will pick the first host in the first cluster as the container node.
- * If there are no content clusters this will return empty (such that the node can be created by the container here).
- */
- private Optional<HostResource> getHostResourceFromContentClusters(ApplicationContainerCluster cluster, Element containersElement, ConfigModelContext context) {
- Optional<Element> services = servicesRootOf(containersElement);
- if ( ! services.isPresent())
- return Optional.empty();
- List<Element> contentServices = XML.getChildren(services.get(), "content");
- if ( contentServices.isEmpty() ) return Optional.empty();
- Element contentNodesElementOrNull = XML.getChild(contentServices.get(0), "nodes");
-
- NodesSpecification nodesSpec;
- if (contentNodesElementOrNull == null)
- nodesSpec = NodesSpecification.nonDedicated(1, context);
- else
- nodesSpec = NodesSpecification.from(new ModelElement(contentNodesElementOrNull), context);
-
- Map<HostResource, ClusterMembership> hosts =
- StorageGroup.provisionHosts(nodesSpec,
- contentServices.get(0).getAttribute("id"),
- cluster.getRoot().hostSystem(),
- context.getDeployLogger());
- return Optional.of(hosts.keySet().iterator().next());
- }
-
- /** Returns the services element above the given Element, or empty if there is no services element */
- private Optional<Element> servicesRootOf(Element element) {
- Node parent = element.getParentNode();
- if (parent == null) return Optional.empty();
- if ( ! (parent instanceof Element)) return Optional.empty();
- Element parentElement = (Element)parent;
- if (parentElement.getTagName().equals("services")) return Optional.of(parentElement);
- return servicesRootOf(parentElement);
- }
-
private List<ApplicationContainer> createNodesFromHosts(DeployLogger deployLogger, Map<HostResource, ClusterMembership> hosts, ApplicationContainerCluster cluster) {
List<ApplicationContainer> nodes = new ArrayList<>();
for (Map.Entry<HostResource, ClusterMembership> entry : hosts.entrySet()) {
@@ -864,7 +864,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addIncludes(Element parentElement) {
List<Element> includes = XML.getChildren(parentElement, IncludeDirs.INCLUDE);
- if (includes == null || includes.isEmpty()) {
+ if (includes.isEmpty()) {
return;
}
if (app == null) {
@@ -942,6 +942,10 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
));
}
+ private static boolean hasZooKeeper(Element spec) {
+ return XML.getChild(spec, "zookeeper") != null;
+ }
+
/** Disallow renderers named "XmlRenderer" or "JsonRenderer" */
private static void validateRendererElement(Element element) {
String idAttr = element.getAttribute("id");
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java
index 34b6dd017cf..736424e263d 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java
@@ -29,14 +29,14 @@ public abstract class ContentNode extends AbstractService
private final boolean skipMbusReplyThread;
private final boolean useDirectStorageApiRpc;
- public ContentNode(ModelContext.Properties properties, AbstractConfigProducer parent, String clusterName, String rootDirectory, int distributionKey) {
+ public ContentNode(ModelContext.FeatureFlags featureFlags, AbstractConfigProducer<?> parent, String clusterName, String rootDirectory, int distributionKey) {
super(parent, "" + distributionKey);
this.distributionKey = distributionKey;
- this.skipCommunicationManagerThread = properties.skipCommunicationManagerThread();
- this.skipMbusRequestThread = properties.skipMbusRequestThread();
- this.skipMbusReplyThread = properties.skipMbusReplyThread();
+ this.skipCommunicationManagerThread = featureFlags.skipCommunicationManagerThread();
+ this.skipMbusRequestThread = featureFlags.skipMbusRequestThread();
+ this.skipMbusReplyThread = featureFlags.skipMbusReplyThread();
this.rootDirectory = rootDirectory;
- this.useDirectStorageApiRpc = properties.useDirectStorageApiRpc();
+ this.useDirectStorageApiRpc = featureFlags.useDirectStorageApiRpc();
initialize();
setProp("clustertype", "content");
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java
index 948093f6c77..dd7c89b91ed 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java
@@ -64,7 +64,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot
private final Map<StorageGroup, NodeSpec> groupToSpecMap = new LinkedHashMap<>();
private Optional<ResourceLimits> resourceLimits = Optional.empty();
private final ProtonConfig.Indexing.Optimize.Enum feedSequencerType;
- private double defaultFeedConcurrency;
+ private final double defaultFeedConcurrency;
/** Whether the nodes of this cluster also hosts a container cluster in a hosted system */
private final boolean combined;
@@ -95,7 +95,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot
ContentSearchCluster search = new ContentSearchCluster(ancestor,
clusterName,
- deployState.getProperties(),
+ deployState.getProperties().featureFlags(),
documentDefinitions,
globallyDistributedDocuments,
getFlushOnShutdown(flushOnShutdownElem, deployState),
@@ -191,7 +191,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot
private ContentSearchCluster(AbstractConfigProducer parent,
String clusterName,
- ModelContext.Properties featureFlags,
+ ModelContext.FeatureFlags featureFlags,
Map<String, NewDocumentType> documentDefinitions,
Set<NewDocumentType> globallyDistributedDocuments,
boolean flushOnShutdown,
@@ -267,7 +267,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot
TransactionLogServer tls;
Optional<Tuning> tuning = Optional.ofNullable(this.tuning);
if (element == null) {
- searchNode = SearchNode.create(deployState.getProperties(), parent, "" + node.getDistributionKey(), node.getDistributionKey(), spec,
+ searchNode = SearchNode.create(parent, "" + node.getDistributionKey(), node.getDistributionKey(), spec,
clusterName, node, flushOnShutdown, tuning, resourceLimits, parentGroup.isHosted(), combined);
searchNode.setHostResource(node.getHostResource());
searchNode.initService(deployState.getDeployLogger());
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/Distributor.java b/config-model/src/main/java/com/yahoo/vespa/model/content/Distributor.java
index f03b7144e38..ec677911da6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/Distributor.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/Distributor.java
@@ -35,7 +35,7 @@ public class Distributor extends ContentNode {
}
Distributor(ModelContext.Properties properties, DistributorCluster parent, int distributionKey, Integer distributorBasePort, PersistenceEngine provider) {
- super(properties, parent, parent.getClusterName(),
+ super(properties.featureFlags(), parent, parent.getClusterName(),
StorageNode.rootFolder + parent.getClusterName() + "/distributor/" + distributionKey, distributionKey);
this.provider = provider;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
index 25e3efcb78f..d7140ee0a71 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
@@ -102,7 +102,7 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
final ModelElement documentsNode = clusterElement.child("documents");
final GcOptions gc = parseGcOptions(documentsNode);
final boolean hasIndexedDocumentType = clusterContainsIndexedDocumentType(documentsNode);
- boolean useThreePhaseUpdates = deployState.getProperties().useThreePhaseUpdates();
+ boolean useThreePhaseUpdates = deployState.getProperties().featureFlags().useThreePhaseUpdates();
return new DistributorCluster(parent,
new BucketSplitting.Builder().build(new ModelElement(producerSpec)), gc,
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java
index aa9b04d084d..655ee1d1d57 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java
@@ -48,6 +48,7 @@ public class Redundancy implements StorDistributionConfig.Producer, ProtonConfig
builder.redundancy(effectiveFinalRedundancy());
builder.ready_copies(effectiveReadyCopies());
}
+
@Override
public void getConfig(ProtonConfig.Builder builder) {
ProtonConfig.Distribution.Builder distBuilder = new ProtonConfig.Distribution.Builder();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
index 894022d936d..3c0f8996c22 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java
@@ -1,12 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.content;
+import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.application.api.DeployLogger;
-import java.util.logging.Level;
import com.yahoo.vespa.config.content.StorDistributionConfig;
import com.yahoo.vespa.model.HostResource;
import com.yahoo.vespa.model.HostSystem;
@@ -25,6 +24,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.logging.Level;
/**
* A group of storage nodes/distributors.
@@ -189,7 +189,7 @@ public class StorageGroup {
HostSystem hostSystem,
DeployLogger logger) {
ClusterSpec.Id clusterId = ClusterSpec.Id.from(clusterIdString);
- return nodesSpecification.provision(hostSystem, ClusterSpec.Type.content, clusterId, logger);
+ return nodesSpecification.provision(hostSystem, ClusterSpec.Type.content, clusterId, logger, true);
}
public static class Builder {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java
index d47d77897e8..afe285faf19 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java
@@ -3,12 +3,11 @@ package com.yahoo.vespa.model.content;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.provision.Flavor;
+import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.config.content.StorFilestorConfig;
import com.yahoo.vespa.config.content.core.StorBucketmoverConfig;
import com.yahoo.vespa.config.content.core.StorCommunicationmanagerConfig;
import com.yahoo.vespa.config.content.core.StorServerConfig;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.defaults.Defaults;
import com.yahoo.vespa.model.application.validation.RestartConfigs;
import com.yahoo.vespa.model.builder.xml.dom.ModelElement;
@@ -39,7 +38,7 @@ public class StorageNode extends ContentNode implements StorServerConfig.Produce
}
StorageNode(ModelContext.Properties properties, StorageCluster cluster, Double capacity, int distributionKey, boolean retired) {
- super(properties, cluster, cluster.getClusterName(),
+ super(properties.featureFlags(), cluster, cluster.getClusterName(),
rootFolder + cluster.getClusterName() + "/storage/" + distributionKey,
distributionKey);
this.retired = retired;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
index 16ccbad00c0..7ec2dc67cf2 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java
@@ -1,11 +1,10 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.content.cluster;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.ConfigModelContext;
-import com.yahoo.config.model.api.Reindexing;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.config.model.producer.AbstractConfigProducerRoot;
@@ -165,7 +164,7 @@ public class ContentCluster extends AbstractConfigProducer implements
if (context.getParentProducer().getRoot() == null) return c;
- addClusterControllers(containers, context, c.rootGroup, contentElement, c.clusterId, c, documentDefinitions);
+ addClusterControllers(containers, context, c.rootGroup, contentElement, c.clusterId, c);
return c;
}
@@ -278,10 +277,9 @@ public class ContentCluster extends AbstractConfigProducer implements
}
}
- private void addClusterControllers(Collection<ContainerModel> containers, ConfigModelContext context,
- StorageGroup rootGroup, ModelElement contentElement,
- String contentClusterName, ContentCluster contentCluster,
- Map<String, NewDocumentType> documentDefinitions) {
+ private void addClusterControllers(Collection<ContainerModel> containers, ConfigModelContext context,
+ StorageGroup rootGroup, ModelElement contentElement,
+ String contentClusterName, ContentCluster contentCluster) {
if (admin == null) return; // only in tests
if (contentCluster.getPersistence() == null) return;
@@ -303,13 +301,11 @@ public class ContentCluster extends AbstractConfigProducer implements
Collection<HostResource> hosts = nodesSpecification.isDedicated() ?
getControllerHosts(nodesSpecification, admin, clusterName, context) :
drawControllerHosts(nodesSpecification.minResources().nodes(), rootGroup, containers);
- ReindexingContext reindexingContext = createReindexingContent(context, contentClusterName, documentDefinitions);
clusterControllers = createClusterControllers(new ClusterControllerCluster(contentCluster, "standalone"),
hosts,
clusterName,
true,
- context.getDeployState(),
- reindexingContext);
+ context.getDeployState());
contentCluster.clusterControllers = clusterControllers;
}
else {
@@ -320,22 +316,15 @@ public class ContentCluster extends AbstractConfigProducer implements
context.getDeployState().getDeployLogger().log(Level.INFO,
"When having content cluster(s) and more than 1 config server it is recommended to configure cluster controllers explicitly.");
}
- ReindexingContext reindexingContext = createReindexingContent(context, contentClusterName, documentDefinitions);
- clusterControllers = createClusterControllers(admin, hosts, "cluster-controllers", false, context.getDeployState(), reindexingContext);
+ clusterControllers = createClusterControllers(admin, hosts, "cluster-controllers", false, context.getDeployState());
admin.setClusterControllers(clusterControllers);
}
}
addClusterControllerComponentsForThisCluster(clusterControllers, contentCluster);
- }
-
- private static ReindexingContext createReindexingContent(
- ConfigModelContext ctx, String contentClusterName, Map<String, NewDocumentType> documentDefinitions) {
- class DisabledReindexing implements Reindexing {}
- Reindexing reindexing = ctx.properties().featureFlags().enableAutomaticReindexing()
- ? ctx.getDeployState().reindexing().orElse(new DisabledReindexing())
- : new DisabledReindexing();
- return new ReindexingContext(reindexing, contentClusterName, documentDefinitions.values());
+ ReindexingContext reindexingContext = clusterControllers.reindexingContext();
+ contentCluster.documentDefinitions.values()
+ .forEach(type -> reindexingContext.addDocumentType(contentCluster.clusterId, type));
}
/** Returns any other content cluster which shares nodes with this, or null if none are built */
@@ -354,7 +343,7 @@ public class ContentCluster extends AbstractConfigProducer implements
}
private Collection<HostResource> getControllerHosts(NodesSpecification nodesSpecification, Admin admin, String clusterName, ConfigModelContext context) {
- return nodesSpecification.provision(admin.hostSystem(), ClusterSpec.Type.admin, ClusterSpec.Id.from(clusterName), context.getDeployLogger()).keySet();
+ return nodesSpecification.provision(admin.hostSystem(), ClusterSpec.Type.admin, ClusterSpec.Id.from(clusterName), context.getDeployLogger(), false).keySet();
}
private List<HostResource> drawControllerHosts(int count, StorageGroup rootGroup, Collection<ContainerModel> containers) {
@@ -468,8 +457,7 @@ public class ContentCluster extends AbstractConfigProducer implements
Collection<HostResource> hosts,
String name,
boolean multitenant,
- DeployState deployState,
- ReindexingContext reindexingContext) {
+ DeployState deployState) {
var clusterControllers = new ClusterControllerContainerCluster(parent, name, name, deployState);
List<ClusterControllerContainer> containers = new ArrayList<>();
// Add a cluster controller on each config server (there is always at least one).
@@ -477,12 +465,7 @@ public class ContentCluster extends AbstractConfigProducer implements
int index = 0;
for (HostResource host : hosts) {
var clusterControllerContainer =
- new ClusterControllerContainer(
- clusterControllers,
- index,
- multitenant,
- deployState.isHosted(),
- reindexingContext);
+ new ClusterControllerContainer(clusterControllers, index, multitenant, deployState);
clusterControllerContainer.setHostResource(host);
clusterControllerContainer.initService(deployState.getDeployLogger());
clusterControllerContainer.setProp("clustertype", "admin")
@@ -582,20 +565,19 @@ public class ContentCluster extends AbstractConfigProducer implements
@Override
public void getConfig(MessagetyperouteselectorpolicyConfig.Builder builder) {
- if (!getSearch().hasIndexedCluster()) return;
- builder.
- defaultroute(com.yahoo.vespa.model.routing.DocumentProtocol.getDirectRouteName(getConfigId())).
- route(new MessagetyperouteselectorpolicyConfig.Route.Builder().
- messagetype(DocumentProtocol.MESSAGE_PUTDOCUMENT).
- name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId()))).
- route(new MessagetyperouteselectorpolicyConfig.Route.Builder().
- messagetype(DocumentProtocol.MESSAGE_REMOVEDOCUMENT).
- name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId()))).
- route(new MessagetyperouteselectorpolicyConfig.Route.Builder().
- messagetype(DocumentProtocol.MESSAGE_UPDATEDOCUMENT).
- name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId())));
+ if ( ! getSearch().hasIndexedCluster()) return;
+ builder.defaultroute(com.yahoo.vespa.model.routing.DocumentProtocol.getDirectRouteName(getConfigId()))
+ .route(new MessagetyperouteselectorpolicyConfig.Route.Builder()
+ .messagetype(DocumentProtocol.MESSAGE_PUTDOCUMENT)
+ .name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId())))
+ .route(new MessagetyperouteselectorpolicyConfig.Route.Builder()
+ .messagetype(DocumentProtocol.MESSAGE_REMOVEDOCUMENT)
+ .name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId())))
+ .route(new MessagetyperouteselectorpolicyConfig.Route.Builder()
+ .messagetype(DocumentProtocol.MESSAGE_UPDATEDOCUMENT)
+ .name(com.yahoo.vespa.model.routing.DocumentProtocol.getIndexedRouteName(getConfigId())));
}
-
+
public com.yahoo.vespa.model.content.StorageGroup getRootGroup() {
return rootGroup;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java
index 61bf42af379..8e91f14238e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/DomResourceLimitsBuilder.java
@@ -25,4 +25,5 @@ public class DomResourceLimitsBuilder {
}
return builder.build();
}
+
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java
index fd4de13be39..ab5dab4fbb9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java
@@ -13,7 +13,7 @@ public class FileStorProducer implements StorFilestorConfig.Producer {
public static class Builder {
protected FileStorProducer build(ModelContext.Properties properties, ContentCluster parent, ModelElement clusterElem) {
- return new FileStorProducer(properties, parent, getThreads(clusterElem));
+ return new FileStorProducer(properties.featureFlags(), parent, getThreads(clusterElem));
}
private Integer getThreads(ModelElement clusterElem) {
@@ -60,13 +60,13 @@ public class FileStorProducer implements StorFilestorConfig.Producer {
final int twoMB = 0x200000;
return ((value + twoMB - 1)/twoMB) * twoMB;
}
- public FileStorProducer(ModelContext.Properties properties, ContentCluster parent, Integer numThreads) {
+ public FileStorProducer(ModelContext.FeatureFlags featureFlags, ContentCluster parent, Integer numThreads) {
this.numThreads = numThreads;
this.cluster = parent;
- this.reponseNumThreads = properties.defaultNumResponseThreads();
- this.responseSequencerType = convertResponseSequencerType(properties.responseSequencerType());
- useAsyncMessageHandlingOnSchedule = properties.useAsyncMessageHandlingOnSchedule();
- mergeChunkSize = alignUp2MiB(properties.mergeChunkSize()); // Align up to default huge page size.
+ this.reponseNumThreads = featureFlags.defaultNumResponseThreads();
+ this.responseSequencerType = convertResponseSequencerType(featureFlags.responseSequencerType());
+ useAsyncMessageHandlingOnSchedule = featureFlags.useAsyncMessageHandlingOnSchedule();
+ mergeChunkSize = alignUp2MiB(featureFlags.mergeChunkSize()); // Align up to default huge page size.
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java
index dc9a7cda32c..e34ccb9696c 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java
@@ -15,7 +15,7 @@ public class StorServerProducer implements StorServerConfig.Producer {
ModelElement tuning = element.child("tuning");
StorServerProducer producer = new StorServerProducer(ContentCluster.getClusterId(element));
- producer.setBucketDBStripeBits(properties.contentNodeBucketDBStripeBits());
+ producer.setBucketDBStripeBits(properties.featureFlags().contentNodeBucketDBStripeBits());
if (tuning == null) return producer;
ModelElement merges = tuning.child("merges");
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorVisitorProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorVisitorProducer.java
index ec93881aae7..748fd7ab04e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorVisitorProducer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorVisitorProducer.java
@@ -1,13 +1,14 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.content.storagecluster;
+import com.yahoo.vespa.config.content.StorFilestorConfig;
import com.yahoo.vespa.config.content.core.StorVisitorConfig;
import com.yahoo.vespa.model.builder.xml.dom.ModelElement;
/**
* Serves stor-visitor config for storage clusters.
*/
-public class StorVisitorProducer implements StorVisitorConfig.Producer {
+public class StorVisitorProducer implements StorVisitorConfig.Producer, StorFilestorConfig.Producer {
public static class Builder {
public StorVisitorProducer build(ModelElement element) {
ModelElement tuning = element.child("tuning");
@@ -42,6 +43,13 @@ public class StorVisitorProducer implements StorVisitorConfig.Producer {
}
@Override
+ public void getConfig(StorFilestorConfig.Builder builder) {
+ if (threadCount != null) {
+ builder.num_visitor_threads(threadCount);
+ }
+ }
+
+ @Override
public void getConfig(StorVisitorConfig.Builder builder) {
if (threadCount != null) {
builder.visitorthreads(threadCount);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
index 88b6833221d..035c69a5bd4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java
@@ -121,6 +121,7 @@ public class StorageCluster extends AbstractConfigProducer<StorageNode>
@Override
public void getConfig(StorFilestorConfig.Builder builder) {
fileStorProducer.getConfig(builder);
+ storVisitorProducer.getConfig(builder);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java
index c8cf9407a31..16302ddff49 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java
@@ -2,7 +2,6 @@
package com.yahoo.vespa.model.search;
import com.yahoo.cloud.config.filedistribution.FiledistributorrpcConfig;
-import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
@@ -15,7 +14,6 @@ import com.yahoo.vespa.config.content.core.StorCommunicationmanagerConfig;
import com.yahoo.vespa.config.content.core.StorServerConfig;
import com.yahoo.vespa.config.content.core.StorStatusConfig;
import com.yahoo.vespa.config.search.core.ProtonConfig;
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
import com.yahoo.vespa.model.AbstractService;
import com.yahoo.vespa.model.PortAllocBridge;
import com.yahoo.vespa.model.admin.monitoring.Monitoring;
@@ -30,6 +28,8 @@ import org.w3c.dom.Element;
import java.util.HashMap;
import java.util.Optional;
+import static com.yahoo.vespa.defaults.Defaults.getDefaults;
+
/**
* Represents a search node (proton).
* <p>
@@ -69,7 +69,6 @@ public class SearchNode extends AbstractService implements
private AbstractService serviceLayerService;
private final Optional<Tuning> tuning;
private final Optional<ResourceLimits> resourceLimits;
- private final boolean useFastValueTensorImplementation;
/** Whether this search node is co-located with a container node on a hosted system */
private final boolean combined;
@@ -100,31 +99,31 @@ public class SearchNode extends AbstractService implements
@Override
protected SearchNode doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element producerSpec) {
- return new SearchNode(deployState.getProperties(), ancestor, name, contentNode.getDistributionKey(), nodeSpec, clusterName, contentNode,
+ return new SearchNode(ancestor, name, contentNode.getDistributionKey(), nodeSpec, clusterName, contentNode,
flushOnShutdown, tuning, resourceLimits, deployState.isHosted(), combined);
}
}
- public static SearchNode create(ModelContext.Properties props, AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec,
+ public static SearchNode create(AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec,
String clusterName, AbstractService serviceLayerService, boolean flushOnShutdown,
Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa,
boolean combined) {
- return new SearchNode(props, parent, name, distributionKey, nodeSpec, clusterName, serviceLayerService,
+ return new SearchNode(parent, name, distributionKey, nodeSpec, clusterName, serviceLayerService,
flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined);
}
- private SearchNode(ModelContext.Properties props, AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec,
+ private SearchNode(AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec,
String clusterName, AbstractService serviceLayerService, boolean flushOnShutdown,
Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa,
boolean combined) {
- this(props, parent, name, nodeSpec, clusterName, flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined);
+ this(parent, name, nodeSpec, clusterName, flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined);
this.distributionKey = distributionKey;
this.serviceLayerService = serviceLayerService;
setPropertiesElastic(clusterName, distributionKey);
}
- private SearchNode(ModelContext.Properties props, AbstractConfigProducer parent, String name, NodeSpec nodeSpec, String clusterName,
+ private SearchNode(AbstractConfigProducer parent, String name, NodeSpec nodeSpec, String clusterName,
boolean flushOnShutdown, Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa,
boolean combined) {
super(parent, name);
@@ -142,7 +141,6 @@ public class SearchNode extends AbstractService implements
// Properties are set in DomSearchBuilder
this.tuning = tuning;
this.resourceLimits = resourceLimits;
- this.useFastValueTensorImplementation = props.useFastValueTensorImplementation();
}
private void setPropertiesElastic(String clusterName, int distributionKey) {
@@ -297,9 +295,6 @@ public class SearchNode extends AbstractService implements
tuning.ifPresent(t -> t.getConfig(builder));
resourceLimits.ifPresent(l -> l.getConfig(builder));
}
- if (useFastValueTensorImplementation) {
- builder.tensor_implementation(ProtonConfig.Tensor_implementation.FAST_VALUE);
- }
}
@Override
diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc
index 25d10e0d9b3..ca7efd5a938 100644
--- a/config-model/src/main/resources/schema/containercluster.rnc
+++ b/config-model/src/main/resources/schema/containercluster.rnc
@@ -27,6 +27,7 @@ ContainerServices =
Http? &
AccessLog* &
SecretStore? &
+ ZooKeeper? &
GenericConfig*
# TODO(ogronnesby): Change this configuration syntax
@@ -91,6 +92,10 @@ SecretStore = element secret-store {
} +
}
+ZooKeeper = element zookeeper {
+ empty
+}
+
ModelEvaluation = element model-evaluation {
empty
}
diff --git a/config-model/src/test/derived/advanced/index-info.cfg b/config-model/src/test/derived/advanced/index-info.cfg
index 162a677be67..c693597a75e 100644
--- a/config-model/src/test/derived/advanced/index-info.cfg
+++ b/config-model/src/test/derived/advanced/index-info.cfg
@@ -5,18 +5,32 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "debug_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "debug_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "attributes_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "attributes_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "location_str"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "location_str"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "title_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "title_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "product_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product2_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "product2_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product3_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "product3_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "attributes"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "attributes"
@@ -25,6 +39,8 @@ indexinfo[].command[].indexname "attributes"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "attributes"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "attributes"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "debug"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "debug"
@@ -33,10 +49,14 @@ indexinfo[].command[].indexname "debug"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "debug"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "debug"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "location"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "location"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "location"
+indexinfo[].command[].command "type position"
indexinfo[].command[].indexname "location_zcurve"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "location_zcurve"
@@ -45,8 +65,12 @@ indexinfo[].command[].indexname "location_zcurve"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "location_zcurve"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "location_zcurve"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "mysummary"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mysummary"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "product"
@@ -55,6 +79,8 @@ indexinfo[].command[].indexname "product"
indexinfo[].command[].command "stem:BEST"
indexinfo[].command[].indexname "product"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "product"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "product2"
@@ -63,6 +89,8 @@ indexinfo[].command[].indexname "product2"
indexinfo[].command[].command "stem:BEST"
indexinfo[].command[].indexname "product2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "product2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "product3"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "product3"
@@ -71,6 +99,8 @@ indexinfo[].command[].indexname "product3"
indexinfo[].command[].command "stem:BEST"
indexinfo[].command[].indexname "product3"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "product3"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "title"
@@ -79,8 +109,12 @@ indexinfo[].command[].indexname "title"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "title_s"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "title_s"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "titleabstract"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "titleabstract"
diff --git a/config-model/src/test/derived/array_of_struct_attribute/index-info.cfg b/config-model/src/test/derived/array_of_struct_attribute/index-info.cfg
index ebe87df9852..de7b744a95b 100644
--- a/config-model/src/test/derived/array_of_struct_attribute/index-info.cfg
+++ b/config-model/src/test/derived/array_of_struct_attribute/index-info.cfg
@@ -10,6 +10,8 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "elem_array.name"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "elem_array.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "elem_array.name"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "elem_array.weight"
indexinfo[].command[].command "index"
@@ -17,7 +19,11 @@ indexinfo[].command[].indexname "elem_array.weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "elem_array.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "elem_array.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "elem_array"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_array"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "elem_array"
+indexinfo[].command[].command "type Array<elem>"
diff --git a/config-model/src/test/derived/arrays/index-info.cfg b/config-model/src/test/derived/arrays/index-info.cfg
index e2a0ea9dedc..c51c927071d 100644
--- a/config-model/src/test/derived/arrays/index-info.cfg
+++ b/config-model/src/test/derived/arrays/index-info.cfg
@@ -15,12 +15,16 @@ indexinfo[].command[].indexname "tags"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "tags"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "tags"
+indexinfo[].command[].command "type Array<string>"
indexinfo[].command[].indexname "ratings"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ratings"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "ratings"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "ratings"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "a"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a"
@@ -31,6 +35,8 @@ indexinfo[].command[].indexname "a"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "a"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "a"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "b"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b"
@@ -43,6 +49,8 @@ indexinfo[].command[].indexname "b"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "b"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "b"
+indexinfo[].command[].command "type Array<string>"
indexinfo[].command[].indexname "c"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "c"
@@ -55,6 +63,8 @@ indexinfo[].command[].indexname "c"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "c"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "c"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "default"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "default"
diff --git a/config-model/src/test/derived/attributeprefetch/index-info.cfg b/config-model/src/test/derived/attributeprefetch/index-info.cfg
index a113e1f1b20..dcf49f787ab 100644
--- a/config-model/src/test/derived/attributeprefetch/index-info.cfg
+++ b/config-model/src/test/derived/attributeprefetch/index-info.cfg
@@ -9,103 +9,139 @@ indexinfo[].command[].indexname "singlebyte"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "singlebyte"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "singlebyte"
+indexinfo[].command[].command "type byte"
indexinfo[].command[].indexname "multibyte"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multibyte"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multibyte"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multibyte"
+indexinfo[].command[].command "type Array<byte>"
indexinfo[].command[].indexname "wsbyte"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wsbyte"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wsbyte"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wsbyte"
+indexinfo[].command[].command "type WeightedSet<byte>"
indexinfo[].command[].indexname "singleint"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "singleint"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "singleint"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "singleint"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "multiint"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multiint"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multiint"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multiint"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "wsint"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wsint"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wsint"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wsint"
+indexinfo[].command[].command "type WeightedSet<int>"
indexinfo[].command[].indexname "singlelong"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "singlelong"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "singlelong"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "singlelong"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "multilong"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multilong"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multilong"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multilong"
+indexinfo[].command[].command "type Array<long>"
indexinfo[].command[].indexname "wslong"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wslong"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wslong"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wslong"
+indexinfo[].command[].command "type WeightedSet<long>"
indexinfo[].command[].indexname "singlefloat"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "singlefloat"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "singlefloat"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "singlefloat"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "multifloat"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multifloat"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multifloat"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multifloat"
+indexinfo[].command[].command "type Array<float>"
indexinfo[].command[].indexname "wsfloat"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wsfloat"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wsfloat"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wsfloat"
+indexinfo[].command[].command "type WeightedSet<float>"
indexinfo[].command[].indexname "singledouble"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "singledouble"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "singledouble"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "singledouble"
+indexinfo[].command[].command "type double"
indexinfo[].command[].indexname "multidouble"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multidouble"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multidouble"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multidouble"
+indexinfo[].command[].command "type Array<double>"
indexinfo[].command[].indexname "wsdouble"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wsdouble"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wsdouble"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wsdouble"
+indexinfo[].command[].command "type WeightedSet<double>"
indexinfo[].command[].indexname "singlestring"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "singlestring"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "singlestring"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "multistring"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "multistring"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "multistring"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "multistring"
+indexinfo[].command[].command "type Array<string>"
indexinfo[].command[].indexname "wsstring"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "wsstring"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "wsstring"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "wsstring"
+indexinfo[].command[].command "type WeightedSet<string>"
diff --git a/config-model/src/test/derived/attributes/index-info.cfg b/config-model/src/test/derived/attributes/index-info.cfg
index 4b06e8dec36..aacd1baa060 100644
--- a/config-model/src/test/derived/attributes/index-info.cfg
+++ b/config-model/src/test/derived/attributes/index-info.cfg
@@ -7,16 +7,24 @@ indexinfo[].command[].indexname "a1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a1"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "a1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a2"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "a2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a3"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a3"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "a3"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "a4"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a5"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a5"
@@ -27,6 +35,8 @@ indexinfo[].command[].indexname "a5"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "a5"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "a5"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a6"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a6"
@@ -37,15 +47,23 @@ indexinfo[].command[].indexname "a6"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "a6"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "a6"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a7"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "a7"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "a8"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "a8"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "b1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b1"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "b1"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "b1"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "b2"
indexinfo[].command[].command "index"
@@ -57,6 +75,8 @@ indexinfo[].command[].indexname "b2"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "b2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "b2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "b3"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b3"
@@ -67,36 +87,48 @@ indexinfo[].command[].indexname "b3"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "b3"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "b3"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "b4"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b4"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "b4"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "b4"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "b5"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b5"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "b5"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "b5"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "b6"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b6"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "b6"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "b6"
+indexinfo[].command[].command "type Array<long>"
indexinfo[].command[].indexname "b7"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b7"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "b7"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "b7"
+indexinfo[].command[].command "type WeightedSet<double>"
indexinfo[].command[].indexname "a9"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a9"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a9"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "a9"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "a10"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a10"
@@ -105,18 +137,24 @@ indexinfo[].command[].indexname "a10"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a10"
indexinfo[].command[].command "fast-search"
+indexinfo[].command[].indexname "a10"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "a11"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a11"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a11"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "a11"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "a12"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a12"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a12"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "a12"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "a7_arr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a7_arr"
@@ -124,6 +162,8 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "a7_arr"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a7_arr"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "a7_arr"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "a8_arr"
indexinfo[].command[].command "index"
@@ -132,6 +172,8 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "a8_arr"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a8_arr"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "a8_arr"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "default"
indexinfo[].command[].command "lowercase"
diff --git a/config-model/src/test/derived/combinedattributeandindexsearch/index-info.cfg b/config-model/src/test/derived/combinedattributeandindexsearch/index-info.cfg
index f88524ae220..e7bf410250f 100644
--- a/config-model/src/test/derived/combinedattributeandindexsearch/index-info.cfg
+++ b/config-model/src/test/derived/combinedattributeandindexsearch/index-info.cfg
@@ -13,6 +13,8 @@ indexinfo[].command[].indexname "index1"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "index1"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "index1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "index2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "index2"
@@ -23,14 +25,20 @@ indexinfo[].command[].indexname "index2"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "index2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "index2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "attribute1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "attribute1"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "attribute1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "attribute2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "attribute2"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "attribute2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "default"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "default"
diff --git a/config-model/src/test/derived/emptydefault/index-info.cfg b/config-model/src/test/derived/emptydefault/index-info.cfg
index a506ef52b52..aa30192e826 100644
--- a/config-model/src/test/derived/emptydefault/index-info.cfg
+++ b/config-model/src/test/derived/emptydefault/index-info.cfg
@@ -13,6 +13,8 @@ indexinfo[].command[].indexname "one"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "one"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "one"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "two"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "two"
@@ -23,3 +25,5 @@ indexinfo[].command[].indexname "two"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "two"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "two"
+indexinfo[].command[].command "type string"
diff --git a/config-model/src/test/derived/exactmatch/index-info.cfg b/config-model/src/test/derived/exactmatch/index-info.cfg
index a4a193b1fcd..cdf38849a24 100644
--- a/config-model/src/test/derived/exactmatch/index-info.cfg
+++ b/config-model/src/test/derived/exactmatch/index-info.cfg
@@ -8,54 +8,80 @@ indexinfo[].command[].command "index"
indexinfo[].command[].indexname "tag"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "tag"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "tag"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "screweduserids"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "screweduserids"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "screweduserids"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "screweduserids"
indexinfo[].command[].command "exact *!!!*"
indexinfo[].command[].indexname "string_map.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "string_map.key"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "string_map.key"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "string_map.key"
indexinfo[].command[].command "exact *!!!*"
indexinfo[].command[].indexname "string_map.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "string_map.value"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "string_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "string_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "string_map"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "elem_map.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "elem_map.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "elem_map.value.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_map.value.name"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "elem_map.value.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "elem_map.value.name"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "elem_map.value.weight"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_map.value.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "elem_map.value.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "elem_map.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "elem_map.value"
+indexinfo[].command[].command "type elem"
indexinfo[].command[].indexname "elem_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "elem_map"
+indexinfo[].command[].command "type Map<string,elem>"
indexinfo[].command[].indexname "elem_array.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_array.name"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "elem_array.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "elem_array.name"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "elem_array.weight"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_array.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "elem_array.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "elem_array"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "elem_array"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "elem_array"
+indexinfo[].command[].command "type Array<elem>"
diff --git a/config-model/src/test/derived/fieldset/index-info.cfg b/config-model/src/test/derived/fieldset/index-info.cfg
index 25f37750cc9..b75bc006961 100644
--- a/config-model/src/test/derived/fieldset/index-info.cfg
+++ b/config-model/src/test/derived/fieldset/index-info.cfg
@@ -10,6 +10,8 @@ indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "word1"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "word1"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "word1"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "word2"
indexinfo[].command[].command "index"
@@ -18,6 +20,8 @@ indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "word2"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "word2"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "word2"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "words"
indexinfo[].command[].command "lowercase"
diff --git a/config-model/src/test/derived/id/index-info.cfg b/config-model/src/test/derived/id/index-info.cfg
index ca8daef9848..00d0c92d68e 100644
--- a/config-model/src/test/derived/id/index-info.cfg
+++ b/config-model/src/test/derived/id/index-info.cfg
@@ -27,17 +27,33 @@ indexinfo[].command[].indexname "uri.hostname"
indexinfo[].command[].command "urlhost"
indexinfo[].command[].indexname "uri.hostname"
indexinfo[].command[].command "lowercase"
+indexinfo[].command[].indexname "uri"
+indexinfo[].command[].command "type uri"
indexinfo[].command[].indexname "uri.fragment"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.fragment"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.host"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.host"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.hostname"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.hostname"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.path"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.path"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.port"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.port"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.query"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.query"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "uri.scheme"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "uri.scheme"
+indexinfo[].command[].command "type string"
diff --git a/config-model/src/test/derived/imported_position_field/index-info.cfg b/config-model/src/test/derived/imported_position_field/index-info.cfg
index 4d1f76c9b4c..a36bcb20979 100644
--- a/config-model/src/test/derived/imported_position_field/index-info.cfg
+++ b/config-model/src/test/derived/imported_position_field/index-info.cfg
@@ -1,23 +1,29 @@
-indexinfo[0].name "child"
-indexinfo[0].command[0].indexname "sddocname"
-indexinfo[0].command[0].command "index"
-indexinfo[0].command[1].indexname "sddocname"
-indexinfo[0].command[1].command "word"
-indexinfo[0].command[2].indexname "parent_ref"
-indexinfo[0].command[2].command "index"
-indexinfo[0].command[3].indexname "parent_ref"
-indexinfo[0].command[3].command "attribute"
-indexinfo[0].command[4].indexname "parent_ref"
-indexinfo[0].command[4].command "word"
-indexinfo[0].command[7].indexname "my_pos_zcurve"
-indexinfo[0].command[7].command "index"
-indexinfo[0].command[8].indexname "my_pos_zcurve"
-indexinfo[0].command[8].command "attribute"
-indexinfo[0].command[9].indexname "my_pos_zcurve"
-indexinfo[0].command[9].command "fast-search"
-indexinfo[0].command[10].indexname "my_pos_zcurve"
-indexinfo[0].command[10].command "numerical"
-indexinfo[0].command[11].indexname "my_pos"
-indexinfo[0].command[11].command "default-position"
-indexinfo[0].command[12].indexname "my_pos"
-indexinfo[0].command[12].command "index"
+indexinfo[].name "child"
+indexinfo[].command[].indexname "sddocname"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sddocname"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "type Reference<parent>"
+indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "fast-search"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "type long"
+indexinfo[].command[].indexname "my_pos"
+indexinfo[].command[].command "default-position"
+indexinfo[].command[].indexname "my_pos"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "my_pos"
+indexinfo[].command[].command "type position"
diff --git a/config-model/src/test/derived/imported_position_field_summary/index-info.cfg b/config-model/src/test/derived/imported_position_field_summary/index-info.cfg
index bf7297851dd..a36bcb20979 100644
--- a/config-model/src/test/derived/imported_position_field_summary/index-info.cfg
+++ b/config-model/src/test/derived/imported_position_field_summary/index-info.cfg
@@ -8,6 +8,8 @@ indexinfo[].command[].command "index"
indexinfo[].command[].indexname "parent_ref"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "type Reference<parent>"
+indexinfo[].command[].indexname "parent_ref"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_pos_zcurve"
indexinfo[].command[].command "index"
@@ -17,7 +19,11 @@ indexinfo[].command[].indexname "my_pos_zcurve"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "my_pos_zcurve"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_pos_zcurve"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "my_pos"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "my_pos"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "my_pos"
+indexinfo[].command[].command "type position"
diff --git a/config-model/src/test/derived/imported_struct_fields/index-info.cfg b/config-model/src/test/derived/imported_struct_fields/index-info.cfg
index 4aa54dac933..a4cef79f861 100644
--- a/config-model/src/test/derived/imported_struct_fields/index-info.cfg
+++ b/config-model/src/test/derived/imported_struct_fields/index-info.cfg
@@ -8,9 +8,13 @@ indexinfo[].command[].command "index"
indexinfo[].command[].indexname "parent_ref"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "parent_ref"
+indexinfo[].command[].command "type Reference<parent>"
+indexinfo[].command[].indexname "parent_ref"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "documentid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "documentid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "my_elem_array.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_elem_array.name"
@@ -18,6 +22,8 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_elem_array.name"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "my_elem_array.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "my_elem_array.name"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_elem_array.weight"
indexinfo[].command[].command "index"
@@ -25,10 +31,14 @@ indexinfo[].command[].indexname "my_elem_array.weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_elem_array.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_elem_array.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "my_elem_array"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_elem_array"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "my_elem_array"
+indexinfo[].command[].command "type Array<elem>"
indexinfo[].command[].indexname "my_elem_map.value.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_elem_map.value.name"
@@ -36,6 +46,8 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_elem_map.value.name"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "my_elem_map.value.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "my_elem_map.value.name"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_elem_map.value.weight"
indexinfo[].command[].command "index"
@@ -43,8 +55,12 @@ indexinfo[].command[].indexname "my_elem_map.value.weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_elem_map.value.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_elem_map.value.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "my_elem_map.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "my_elem_map.value"
+indexinfo[].command[].command "type elem"
indexinfo[].command[].indexname "my_elem_map.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_elem_map.key"
@@ -52,11 +68,15 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_elem_map.key"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "my_elem_map.key"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "my_elem_map.key"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_elem_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_elem_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "my_elem_map"
+indexinfo[].command[].command "type Map<string,elem>"
indexinfo[].command[].indexname "my_str_int_map.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_str_int_map.key"
@@ -64,6 +84,8 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_str_int_map.key"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "my_str_int_map.key"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "my_str_int_map.key"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_str_int_map.value"
indexinfo[].command[].command "index"
@@ -71,7 +93,11 @@ indexinfo[].command[].indexname "my_str_int_map.value"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_str_int_map.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_str_int_map.value"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "my_str_int_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_str_int_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "my_str_int_map"
+indexinfo[].command[].command "type Map<string,int>"
diff --git a/config-model/src/test/derived/importedfields/index-info.cfg b/config-model/src/test/derived/importedfields/index-info.cfg
index bc688f48fc4..76382e4fd80 100644
--- a/config-model/src/test/derived/importedfields/index-info.cfg
+++ b/config-model/src/test/derived/importedfields/index-info.cfg
@@ -8,18 +8,24 @@ indexinfo[].command[].command "index"
indexinfo[].command[].indexname "a_ref"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "a_ref"
+indexinfo[].command[].command "type Reference<parent_a>"
+indexinfo[].command[].indexname "a_ref"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "b_ref"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b_ref"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "b_ref"
+indexinfo[].command[].command "type Reference<parent_b>"
+indexinfo[].command[].indexname "b_ref"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "b_ref_with_summary"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "b_ref_with_summary"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "b_ref_with_summary"
+indexinfo[].command[].command "type Reference<parent_b>"
+indexinfo[].command[].indexname "b_ref_with_summary"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_int_field"
indexinfo[].command[].command "index"
@@ -27,11 +33,15 @@ indexinfo[].command[].indexname "my_int_field"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_int_field"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_int_field"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "my_string_field"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_string_field"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_string_field"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "my_string_field"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "my_int_array_field"
indexinfo[].command[].command "index"
@@ -39,18 +49,24 @@ indexinfo[].command[].indexname "my_int_array_field"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "my_int_array_field"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "my_int_array_field"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "my_int_wset_field"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_int_wset_field"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "my_int_wset_field"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "my_int_wset_field"
+indexinfo[].command[].command "type WeightedSet<int>"
indexinfo[].command[].indexname "my_ancient_int_field"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "my_ancient_int_field"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "my_ancient_int_field"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "my_ancient_int_field"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "myfieldset"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "myfieldset"
diff --git a/config-model/src/test/derived/indexinfo_fieldsets/index-info.cfg b/config-model/src/test/derived/indexinfo_fieldsets/index-info.cfg
index 15d50762134..d08b080df7b 100644
--- a/config-model/src/test/derived/indexinfo_fieldsets/index-info.cfg
+++ b/config-model/src/test/derived/indexinfo_fieldsets/index-info.cfg
@@ -11,6 +11,8 @@ indexinfo[].command[].indexname "nostemming1"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemming1"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemming1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nostemming2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nostemming2"
@@ -19,6 +21,8 @@ indexinfo[].command[].indexname "nostemming2"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemming2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemming2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nonormalizing1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nonormalizing1"
@@ -27,6 +31,8 @@ indexinfo[].command[].indexname "nonormalizing1"
indexinfo[].command[].command "stem:BEST"
indexinfo[].command[].indexname "nonormalizing1"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nonormalizing1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nonormalizing2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nonormalizing2"
@@ -35,17 +41,23 @@ indexinfo[].command[].indexname "nonormalizing2"
indexinfo[].command[].command "stem:BEST"
indexinfo[].command[].indexname "nonormalizing2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nonormalizing2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "exact1"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "exact2"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "nostemming"
indexinfo[].command[].command "lowercase"
diff --git a/config-model/src/test/derived/indexinfo_lowercase/index-info.cfg b/config-model/src/test/derived/indexinfo_lowercase/index-info.cfg
index f5815627d2b..ac640c09e8c 100644
--- a/config-model/src/test/derived/indexinfo_lowercase/index-info.cfg
+++ b/config-model/src/test/derived/indexinfo_lowercase/index-info.cfg
@@ -5,15 +5,23 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "lc_attribute_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "lc_attribute_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "lc_index_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "lc_index_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "lc_summary_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "lc_summary_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nc_attribute"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nc_attribute"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "nc_attribute"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "nc_attribute"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "nc_index"
indexinfo[].command[].command "index"
@@ -25,8 +33,12 @@ indexinfo[].command[].indexname "nc_index"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nc_index"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nc_index"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nc_summary"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "nc_summary"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "lc_attribute"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "lc_attribute"
@@ -34,6 +46,8 @@ indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "lc_attribute"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "lc_attribute"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "lc_attribute"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "lc_index"
indexinfo[].command[].command "index"
@@ -45,10 +59,14 @@ indexinfo[].command[].indexname "lc_index"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "lc_index"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "lc_index"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "lc_summary"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "lc_summary"
indexinfo[].command[].command "lowercase"
+indexinfo[].command[].indexname "lc_summary"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "lc_set1"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "lc_set1"
diff --git a/config-model/src/test/derived/indexschema/index-info.cfg b/config-model/src/test/derived/indexschema/index-info.cfg
index 388b212689a..8a28038a18d 100644
--- a/config-model/src/test/derived/indexschema/index-info.cfg
+++ b/config-model/src/test/derived/indexschema/index-info.cfg
@@ -13,6 +13,8 @@ indexinfo[].command[].indexname "sa"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sa"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sa"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sb"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sb"
@@ -23,6 +25,8 @@ indexinfo[].command[].indexname "sb"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sb"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sb"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sc"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sc"
@@ -33,6 +37,8 @@ indexinfo[].command[].indexname "sc"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sc"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sc"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sd"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sd"
@@ -44,6 +50,8 @@ indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sd"
indexinfo[].command[].command "plain-tokens"
indexinfo[].command[].indexname "sd"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "sd"
indexinfo[].command[].command "phrase-segmenting false"
indexinfo[].command[].indexname "sd"
indexinfo[].command[].command "literal-boost"
@@ -51,19 +59,27 @@ indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.x"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.y"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pos"
+indexinfo[].command[].command "type position"
indexinfo[].command[].indexname "se"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "se"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "se"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "se"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "sf"
indexinfo[].command[].command "index"
@@ -77,6 +93,8 @@ indexinfo[].command[].indexname "sf"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sf"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sf"
+indexinfo[].command[].command "type Array<string>"
indexinfo[].command[].indexname "sg"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sg"
@@ -89,6 +107,8 @@ indexinfo[].command[].indexname "sg"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "sg"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sg"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "sh"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sh"
@@ -113,6 +133,8 @@ indexinfo[].command[].indexname "sh.hostname"
indexinfo[].command[].command "urlhost"
indexinfo[].command[].indexname "sh.hostname"
indexinfo[].command[].command "lowercase"
+indexinfo[].command[].indexname "sh"
+indexinfo[].command[].command "type uri"
indexinfo[].command[].indexname "si"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "si"
@@ -123,17 +145,23 @@ indexinfo[].command[].indexname "si"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "si"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "si"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "exact1"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "exact1"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "exact2"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "exact2"
indexinfo[].command[].command "exact @@"
indexinfo[].command[].indexname "bm25_field"
indexinfo[].command[].command "index"
@@ -145,24 +173,32 @@ indexinfo[].command[].indexname "bm25_field"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "bm25_field"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "bm25_field"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "ia"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ia"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "ia"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "ia"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "ib"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ib"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "ib"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "ib"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "ic"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ic"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "ic"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "ic"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "nostemstring1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nostemstring1"
@@ -171,6 +207,8 @@ indexinfo[].command[].indexname "nostemstring1"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemstring1"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemstring1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nostemstring2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nostemstring2"
@@ -179,6 +217,8 @@ indexinfo[].command[].indexname "nostemstring2"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemstring2"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemstring2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nostemstring3"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nostemstring3"
@@ -187,6 +227,8 @@ indexinfo[].command[].indexname "nostemstring3"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemstring3"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemstring3"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "nostemstring4"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "nostemstring4"
@@ -195,6 +237,8 @@ indexinfo[].command[].indexname "nostemstring4"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "nostemstring4"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "nostemstring4"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "fs9"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "fs9"
@@ -205,6 +249,8 @@ indexinfo[].command[].indexname "fs9"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "fs9"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "fs9"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "f10.text"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "f10.text"
@@ -215,12 +261,18 @@ indexinfo[].command[].indexname "f10.text"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "f10.text"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "f10.text"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "f10.name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f10.name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "f10"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "f10"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "f10"
+indexinfo[].command[].command "type Array<part>"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos_zcurve"
@@ -229,32 +281,54 @@ indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos_zcurve"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "sd_literal"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sd_literal"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "sd_literal"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "sd_literal"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "searchfield1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "searchfield1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "searchfield2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "searchfield2"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "searchfield2"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "sh.fragment"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.fragment"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.host"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.host"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.hostname"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.hostname"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.path"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.path"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.port"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.port"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.query"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.query"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sh.scheme"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sh.scheme"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sa"
indexinfo[].command[].command "dynteaser"
indexinfo[].command[].indexname "fs1"
diff --git a/config-model/src/test/derived/indexswitches/index-info.cfg b/config-model/src/test/derived/indexswitches/index-info.cfg
index 1ba38ad554b..ae1eb48952f 100644
--- a/config-model/src/test/derived/indexswitches/index-info.cfg
+++ b/config-model/src/test/derived/indexswitches/index-info.cfg
@@ -13,6 +13,8 @@ indexinfo[].command[].indexname "title"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "descr"
@@ -23,8 +25,12 @@ indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "descr"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "source_src"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "source_src"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "source"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "source"
@@ -33,6 +39,8 @@ indexinfo[].command[].indexname "source"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "source"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "source"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "default"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "default"
diff --git a/config-model/src/test/derived/inheritance/index-info.cfg b/config-model/src/test/derived/inheritance/index-info.cfg
index ff3aad45906..d8849778c23 100644
--- a/config-model/src/test/derived/inheritance/index-info.cfg
+++ b/config-model/src/test/derived/inheritance/index-info.cfg
@@ -9,14 +9,20 @@ indexinfo[].command[].indexname "onlygrandparent"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "onlygrandparent"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "onlygrandparent"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "overridden"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "overridden"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "overridden"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "overridden"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "onlyfather"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "onlyfather"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "onlymother"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "onlymother"
@@ -27,6 +33,8 @@ indexinfo[].command[].indexname "onlymother"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "onlymother"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "onlymother"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "onlychild"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "onlychild"
@@ -37,3 +45,5 @@ indexinfo[].command[].indexname "onlychild"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "onlychild"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "onlychild"
+indexinfo[].command[].command "type string"
diff --git a/config-model/src/test/derived/inheritstruct/index-info.cfg b/config-model/src/test/derived/inheritstruct/index-info.cfg
index 2d5b832a07f..21e68f0c127 100644
--- a/config-model/src/test/derived/inheritstruct/index-info.cfg
+++ b/config-model/src/test/derived/inheritstruct/index-info.cfg
@@ -13,9 +13,13 @@ indexinfo[].command[].indexname "child_struct_field.my_str"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "child_struct_field.my_str"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "child_struct_field.my_str"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "child_struct_field"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "child_struct_field"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "child_struct_field"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "child_struct_field"
+indexinfo[].command[].command "type my_struct"
diff --git a/config-model/src/test/derived/map_attribute/index-info.cfg b/config-model/src/test/derived/map_attribute/index-info.cfg
index 67c6bbf4d1b..51ab1f07a43 100644
--- a/config-model/src/test/derived/map_attribute/index-info.cfg
+++ b/config-model/src/test/derived/map_attribute/index-info.cfg
@@ -10,28 +10,40 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "str_map.key"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "str_map.key"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "str_map.key"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "str_map.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "str_map.value"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "str_map.value"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "str_map.value"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "str_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "str_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "str_map"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "int_map.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_map.key"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "int_map.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "int_map.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "int_map.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_map.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "int_map.value"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "int_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "int_map"
+indexinfo[].command[].command "type Map<int,int>"
diff --git a/config-model/src/test/derived/map_of_struct_attribute/index-info.cfg b/config-model/src/test/derived/map_of_struct_attribute/index-info.cfg
index 84296b00a5d..606012c17e2 100644
--- a/config-model/src/test/derived/map_of_struct_attribute/index-info.cfg
+++ b/config-model/src/test/derived/map_of_struct_attribute/index-info.cfg
@@ -10,12 +10,16 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "str_elem_map.key"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "str_elem_map.key"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "str_elem_map.key"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "str_elem_map.value.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "str_elem_map.value.name"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "str_elem_map.value.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "str_elem_map.value.name"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "str_elem_map.value.weight"
indexinfo[].command[].command "index"
@@ -23,18 +27,26 @@ indexinfo[].command[].indexname "str_elem_map.value.weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "str_elem_map.value.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "str_elem_map.value.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "str_elem_map.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "str_elem_map.value"
+indexinfo[].command[].command "type elem"
indexinfo[].command[].indexname "str_elem_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "str_elem_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "str_elem_map"
+indexinfo[].command[].command "type Map<string,elem>"
indexinfo[].command[].indexname "int_elem_map.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_elem_map.key"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "int_elem_map.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "int_elem_map.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "int_elem_map.value.name"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_elem_map.value.name"
@@ -42,14 +54,22 @@ indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "int_elem_map.value.name"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "int_elem_map.value.name"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "int_elem_map.value.name"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "int_elem_map.value.weight"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_elem_map.value.weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "int_elem_map.value.weight"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "int_elem_map.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "int_elem_map.value"
+indexinfo[].command[].command "type elem"
indexinfo[].command[].indexname "int_elem_map"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "int_elem_map"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "int_elem_map"
+indexinfo[].command[].command "type Map<int,elem>"
diff --git a/config-model/src/test/derived/music/index-info.cfg b/config-model/src/test/derived/music/index-info.cfg
index 9e26df5fbea..4d44bc7acbe 100644
--- a/config-model/src/test/derived/music/index-info.cfg
+++ b/config-model/src/test/derived/music/index-info.cfg
@@ -5,18 +5,24 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "bgndata"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "bgndata"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "sales"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pto"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "keys"
@@ -27,12 +33,16 @@ indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "keys"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "mid"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ew"
@@ -43,24 +53,38 @@ indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "ew"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "surl"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "surl"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "userrate"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "userrate"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "userrate"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "weight"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "url"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "url"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "isbn"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "isbn"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "fmt"
@@ -71,10 +95,16 @@ indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "fmt"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "albumid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "albumid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "disp_song"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "disp_song"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "song"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "song"
@@ -85,16 +115,22 @@ indexinfo[].command[].indexname "song"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "song"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "song"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "pfrom"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pfrom"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pfrom"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "bgnpfrom"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "categories"
@@ -105,18 +141,28 @@ indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "categories"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "data"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "data"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "numreview"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "numreview"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "numreview"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnsellers"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "bgnsellers"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "bgnsellers"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "image"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "image"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "artist"
@@ -127,8 +173,12 @@ indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "artist"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "artistspid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "artistspid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "title"
@@ -139,40 +189,58 @@ indexinfo[].command[].indexname "title"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "newestedition"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnpto"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "bgnpto"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "year"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "did"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "scorekey"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "scorekey"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "scorekey"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "cbid"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "metalvalue"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "metalvalue"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "hiphopvalue"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "hiphopvalue"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "powermetalvalue"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "powermetalvalue"
@@ -183,6 +251,8 @@ indexinfo[].command[].indexname "powermetalvalue"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "powermetalvalue"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "powermetalvalue"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "progvalue"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "progvalue"
@@ -193,6 +263,8 @@ indexinfo[].command[].indexname "progvalue"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "progvalue"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "progvalue"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "hiphopvalue_arr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "hiphopvalue_arr"
@@ -200,6 +272,8 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "hiphopvalue_arr"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "hiphopvalue_arr"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "hiphopvalue_arr"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "metalvalue_arr"
indexinfo[].command[].command "index"
@@ -208,6 +282,8 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "metalvalue_arr"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "metalvalue_arr"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "metalvalue_arr"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "bgndata"
indexinfo[].command[].command "dynteaser"
diff --git a/config-model/src/test/derived/newrank/index-info.cfg b/config-model/src/test/derived/newrank/index-info.cfg
index 6967bf43538..20f8784fcf0 100644
--- a/config-model/src/test/derived/newrank/index-info.cfg
+++ b/config-model/src/test/derived/newrank/index-info.cfg
@@ -5,18 +5,24 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "bgndata"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "bgndata"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "sales"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "sales"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "pto"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pto"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "keys"
@@ -27,12 +33,16 @@ indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "keys"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "keys"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "mid"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "mid"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "ew"
@@ -43,24 +53,38 @@ indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "ew"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "ew"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "surl"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "surl"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "userrate"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "userrate"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "userrate"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "weight"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "weight"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "url"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "url"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "isbn"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "isbn"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "fmt"
@@ -71,10 +95,16 @@ indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "fmt"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "fmt"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "albumid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "albumid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "disp_song"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "disp_song"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "song"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "song"
@@ -85,16 +115,22 @@ indexinfo[].command[].indexname "song"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "song"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "song"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "pfrom"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pfrom"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pfrom"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "bgnpfrom"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "bgnpfrom"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "categories"
@@ -105,18 +141,28 @@ indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "categories"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "categories"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "data"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "data"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "numreview"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "numreview"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "numreview"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnsellers"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "bgnsellers"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "bgnsellers"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "image"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "image"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "artist"
@@ -127,8 +173,12 @@ indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "artist"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "artist"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "artistspid"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "artistspid"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "title"
@@ -139,38 +189,52 @@ indexinfo[].command[].indexname "title"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "newestedition"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "newestedition"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgnpto"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "bgnpto"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "year"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "year"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "did"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "did"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "scorekey"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "scorekey"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "scorekey"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "scorekey"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "cbid"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "cbid"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "bgndata"
indexinfo[].command[].command "dynteaser"
indexinfo[].command[].indexname "ew"
diff --git a/config-model/src/test/derived/position_array/index-info.cfg b/config-model/src/test/derived/position_array/index-info.cfg
index e4b9ebb5008..c8008e9d440 100644
--- a/config-model/src/test/derived/position_array/index-info.cfg
+++ b/config-model/src/test/derived/position_array/index-info.cfg
@@ -7,16 +7,22 @@ indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.x"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.y"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "pos"
+indexinfo[].command[].command "type Array<position>"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos_zcurve"
@@ -25,3 +31,5 @@ indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "fast-search"
+indexinfo[].command[].indexname "pos_zcurve"
+indexinfo[].command[].command "type Array<long>"
diff --git a/config-model/src/test/derived/position_attribute/index-info.cfg b/config-model/src/test/derived/position_attribute/index-info.cfg
index 75a8ada6193..92d8876cfed 100644
--- a/config-model/src/test/derived/position_attribute/index-info.cfg
+++ b/config-model/src/test/derived/position_attribute/index-info.cfg
@@ -7,14 +7,20 @@ indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.x"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.x"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos.y"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos.y"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "pos"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pos"
+indexinfo[].command[].command "type position"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos_zcurve"
@@ -23,3 +29,5 @@ indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "pos_zcurve"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos_zcurve"
+indexinfo[].command[].command "type long"
diff --git a/config-model/src/test/derived/position_extra/index-info.cfg b/config-model/src/test/derived/position_extra/index-info.cfg
index 945508f9518..45813140b1d 100644
--- a/config-model/src/test/derived/position_extra/index-info.cfg
+++ b/config-model/src/test/derived/position_extra/index-info.cfg
@@ -5,10 +5,14 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "pos_str"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pos_str"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "pos_ext"
indexinfo[].command[].command "default-position"
indexinfo[].command[].indexname "pos_ext"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "pos_ext"
+indexinfo[].command[].command "type position"
indexinfo[].command[].indexname "pos_ext_zcurve"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pos_ext_zcurve"
@@ -17,3 +21,5 @@ indexinfo[].command[].indexname "pos_ext_zcurve"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "pos_ext_zcurve"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "pos_ext_zcurve"
+indexinfo[].command[].command "type long"
diff --git a/config-model/src/test/derived/predicate_attribute/index-info.cfg b/config-model/src/test/derived/predicate_attribute/index-info.cfg
index 4ebac65e1f5..615f86b8c02 100644
--- a/config-model/src/test/derived/predicate_attribute/index-info.cfg
+++ b/config-model/src/test/derived/predicate_attribute/index-info.cfg
@@ -11,3 +11,5 @@ indexinfo[].command[].indexname "some_predicate_field"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "some_predicate_field"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "some_predicate_field"
+indexinfo[].command[].command "type predicate"
diff --git a/config-model/src/test/derived/prefixexactattribute/index-info.cfg b/config-model/src/test/derived/prefixexactattribute/index-info.cfg
index e0d5786ef13..941c5b598cf 100644
--- a/config-model/src/test/derived/prefixexactattribute/index-info.cfg
+++ b/config-model/src/test/derived/prefixexactattribute/index-info.cfg
@@ -13,27 +13,37 @@ indexinfo[].command[].indexname "indexfield0"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "indexfield0"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "indexfield0"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "attributefield1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "attributefield1"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "attributefield1"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "attributefield1"
indexinfo[].command[].command "exact @"
indexinfo[].command[].indexname "attributefield2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "attributefield2"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "attributefield2"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "attributefield2"
indexinfo[].command[].command "exact @"
indexinfo[].command[].indexname "indexfield1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "indexfield1"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "indexfield1"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "indexfield1"
indexinfo[].command[].command "exact @"
indexinfo[].command[].indexname "indexfield2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "indexfield2"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "indexfield2"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "indexfield2"
indexinfo[].command[].command "exact @"
diff --git a/config-model/src/test/derived/ranktypes/index-info.cfg b/config-model/src/test/derived/ranktypes/index-info.cfg
index 112183ceac5..9ff5ee0635d 100644
--- a/config-model/src/test/derived/ranktypes/index-info.cfg
+++ b/config-model/src/test/derived/ranktypes/index-info.cfg
@@ -13,6 +13,8 @@ indexinfo[].command[].indexname "title"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "title"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "descr"
@@ -23,6 +25,8 @@ indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "descr"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "descr"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "keywords"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "keywords"
@@ -33,6 +37,8 @@ indexinfo[].command[].indexname "keywords"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "keywords"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "keywords"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "identity"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "identity"
@@ -44,6 +50,8 @@ indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "identity"
indexinfo[].command[].command "plain-tokens"
indexinfo[].command[].indexname "identity"
+indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "identity"
indexinfo[].command[].command "literal-boost"
indexinfo[].command[].indexname "identity_literal"
indexinfo[].command[].command "index"
@@ -51,3 +59,5 @@ indexinfo[].command[].indexname "identity_literal"
indexinfo[].command[].command "lowercase"
indexinfo[].command[].indexname "identity_literal"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "identity_literal"
+indexinfo[].command[].command "type string"
diff --git a/config-model/src/test/derived/structanyorder/index-info.cfg b/config-model/src/test/derived/structanyorder/index-info.cfg
index 7a8b06bceec..10afd9b6f10 100644
--- a/config-model/src/test/derived/structanyorder/index-info.cfg
+++ b/config-model/src/test/derived/structanyorder/index-info.cfg
@@ -5,239 +5,439 @@ indexinfo[].command[].indexname "sddocname"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "structfield.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structfield.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structfield.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structfield.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structfield.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s3.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s3.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s3.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s3.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield.s3"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s3"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s4.s1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield.s4.s1"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "structarrayfield.s4.s1"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "structarrayfield.s4"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s4"
+indexinfo[].command[].command "type foo"
indexinfo[].command[].indexname "structarrayfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "structarrayfield"
+indexinfo[].command[].command "type Array<sct>"
diff --git a/config-model/src/test/derived/tensor/index-info.cfg b/config-model/src/test/derived/tensor/index-info.cfg
new file mode 100644
index 00000000000..ba8d2d7e086
--- /dev/null
+++ b/config-model/src/test/derived/tensor/index-info.cfg
@@ -0,0 +1,49 @@
+indexinfo[].name "tensor"
+indexinfo[].command[].indexname "sddocname"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "sddocname"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "f1"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f1"
+indexinfo[].command[].command "type tensor(x[3])"
+indexinfo[].command[].indexname "f2"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f2"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "f2"
+indexinfo[].command[].command "type tensor<float>(x[2],y[1])"
+indexinfo[].command[].indexname "f2"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "f3"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f3"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "f3"
+indexinfo[].command[].command "type tensor(x{})"
+indexinfo[].command[].indexname "f3"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "f4"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f4"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "f4"
+indexinfo[].command[].command "type tensor(x[10],y[10])"
+indexinfo[].command[].indexname "f4"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "f5"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f5"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "f5"
+indexinfo[].command[].command "type tensor<float>(x[10])"
+indexinfo[].command[].indexname "f5"
+indexinfo[].command[].command "word"
+indexinfo[].command[].indexname "f6"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "f6"
+indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "f6"
+indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "f6"
+indexinfo[].command[].command "type float"
diff --git a/config-model/src/test/derived/types/index-info.cfg b/config-model/src/test/derived/types/index-info.cfg
index 6332316e7d0..cb10bb561d5 100644
--- a/config-model/src/test/derived/types/index-info.cfg
+++ b/config-model/src/test/derived/types/index-info.cfg
@@ -9,17 +9,23 @@ indexinfo[].command[].indexname "abyte"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "abyte"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "abyte"
+indexinfo[].command[].command "type byte"
indexinfo[].command[].indexname "along"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "along"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "along"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "along"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "abool"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "abool"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "abool"
+indexinfo[].command[].command "type bool"
+indexinfo[].command[].indexname "abool"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "ashortfloat"
indexinfo[].command[].command "index"
@@ -27,18 +33,24 @@ indexinfo[].command[].indexname "ashortfloat"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "ashortfloat"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "ashortfloat"
+indexinfo[].command[].command "type float16"
indexinfo[].command[].indexname "arrayfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "arrayfield"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "arrayfield"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "arrayfield"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "setfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "setfield"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "setfield"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "setfield"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "setfield2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "setfield2"
@@ -46,6 +58,8 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "setfield2"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "setfield2"
+indexinfo[].command[].command "type WeightedSet<string>"
+indexinfo[].command[].indexname "setfield2"
indexinfo[].command[].command "word"
indexinfo[].command[].indexname "setfield3"
indexinfo[].command[].command "index"
@@ -53,32 +67,50 @@ indexinfo[].command[].indexname "setfield3"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "setfield3"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "setfield3"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "setfield4"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "setfield4"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "setfield4"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "setfield4"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "tagfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "tagfield"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "tagfield"
indexinfo[].command[].command "attribute"
+indexinfo[].command[].indexname "tagfield"
+indexinfo[].command[].command "type tag"
indexinfo[].command[].indexname "structfield.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structfield"
+indexinfo[].command[].command "type sct"
indexinfo[].command[].indexname "structarrayfield.s1"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s1"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield.s2"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "structarrayfield.s2"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "structarrayfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "structarrayfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "structarrayfield"
+indexinfo[].command[].command "type Array<sct>"
indexinfo[].command[].indexname "stringmapfield.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "stringmapfield.key"
@@ -89,6 +121,8 @@ indexinfo[].command[].indexname "stringmapfield.key"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "stringmapfield.key"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "stringmapfield.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "stringmapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "stringmapfield.value"
@@ -99,6 +133,8 @@ indexinfo[].command[].indexname "stringmapfield.value"
indexinfo[].command[].command "normalize"
indexinfo[].command[].indexname "stringmapfield.value"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "stringmapfield.value"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "stringmapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "stringmapfield"
@@ -107,304 +143,506 @@ indexinfo[].command[].indexname "stringmapfield"
indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "stringmapfield"
indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "stringmapfield"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "intmapfield.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "intmapfield.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "intmapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "intmapfield.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "intmapfield.value"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "intmapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "intmapfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "intmapfield"
+indexinfo[].command[].command "type Map<string,int>"
indexinfo[].command[].indexname "floatmapfield.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "floatmapfield.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "floatmapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "floatmapfield.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "floatmapfield.value"
+indexinfo[].command[].command "type float"
indexinfo[].command[].indexname "floatmapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "floatmapfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "floatmapfield"
+indexinfo[].command[].command "type Map<string,float>"
indexinfo[].command[].indexname "longmapfield.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "longmapfield.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "longmapfield.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "longmapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "longmapfield.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "longmapfield.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "longmapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "longmapfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "longmapfield"
+indexinfo[].command[].command "type Map<int,long>"
indexinfo[].command[].indexname "doublemapfield.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "doublemapfield.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "doublemapfield.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "doublemapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "doublemapfield.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "doublemapfield.value"
+indexinfo[].command[].command "type double"
indexinfo[].command[].indexname "doublemapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "doublemapfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "doublemapfield"
+indexinfo[].command[].command "type Map<int,double>"
indexinfo[].command[].indexname "arraymapfield.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "arraymapfield.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "arraymapfield.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "arraymapfield.value"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "arraymapfield.value"
+indexinfo[].command[].command "type Array<int>"
indexinfo[].command[].indexname "arraymapfield"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "arraymapfield"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "arraymapfield"
+indexinfo[].command[].command "type Map<string,Array<int>>"
indexinfo[].command[].indexname "arrarr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "arrarr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "arrarr"
+indexinfo[].command[].command "type Array<Array<Array<string>>>"
indexinfo[].command[].indexname "maparr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "maparr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "maparr"
+indexinfo[].command[].command "type Array<Map<string,string>>"
+indexinfo[].command[].indexname "complexarray"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "complexarray"
+indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "complexarray"
+indexinfo[].command[].command "type Array<Map<int,Array<Array<string>>>>"
indexinfo[].command[].indexname "mystructfield.bytearr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructfield.bytearr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructfield.bytearr"
+indexinfo[].command[].command "type Array<byte>"
indexinfo[].command[].indexname "mystructfield.mymap.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructfield.mymap.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructfield.mymap.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructfield.mymap.value"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructfield.mymap"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructfield.mymap"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructfield.mymap"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "mystructfield.title"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructfield.title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructfield.structfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructfield.structfield"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructfield"
+indexinfo[].command[].command "type mystruct"
indexinfo[].command[].indexname "mystructmap.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructmap.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "mystructmap.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "mystructmap.value.bytearr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructmap.value.bytearr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructmap.value.bytearr"
+indexinfo[].command[].command "type Array<byte>"
indexinfo[].command[].indexname "mystructmap.value.mymap.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructmap.value.mymap.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructmap.value.mymap.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructmap.value.mymap.value"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructmap.value.mymap"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructmap.value.mymap"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructmap.value.mymap"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "mystructmap.value.title"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructmap.value.title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructmap.value.structfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructmap.value.structfield"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructmap.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructmap.value"
+indexinfo[].command[].command "type mystruct"
indexinfo[].command[].indexname "mystructmap"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructmap"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructmap"
+indexinfo[].command[].command "type Map<int,mystruct>"
indexinfo[].command[].indexname "mystructarr.bytearr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructarr.bytearr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructarr.bytearr"
+indexinfo[].command[].command "type Array<byte>"
indexinfo[].command[].indexname "mystructarr.mymap.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructarr.mymap.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructarr.mymap.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructarr.mymap.value"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructarr.mymap"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructarr.mymap"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructarr.mymap"
+indexinfo[].command[].command "type Map<string,string>"
indexinfo[].command[].indexname "mystructarr.title"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructarr.title"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructarr.structfield"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mystructarr.structfield"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "mystructarr"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "mystructarr"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mystructarr"
+indexinfo[].command[].command "type Array<mystruct>"
indexinfo[].command[].indexname "Folders.key"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.key"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.key"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Version"
+indexinfo[].command[].command "type int"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.Name"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.key"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter.value"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.FlagsCounter"
+indexinfo[].command[].command "type Map<string,long>"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value.anotherfolder"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value.anotherfolder"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders.value"
indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "Folders.value"
+indexinfo[].command[].command "type folder"
indexinfo[].command[].indexname "Folders"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "Folders"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "Folders"
+indexinfo[].command[].command "type Map<int,folder>"
indexinfo[].command[].indexname "juletre"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "juletre"
@@ -413,10 +651,14 @@ indexinfo[].command[].indexname "juletre"
indexinfo[].command[].command "fast-search"
indexinfo[].command[].indexname "juletre"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "juletre"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "album0"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "album0"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "album0"
+indexinfo[].command[].command "type WeightedSet<string>"
indexinfo[].command[].indexname "album1"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "album1"
@@ -424,18 +666,20 @@ indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "album1"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "album1"
+indexinfo[].command[].command "type WeightedSet<string>"
+indexinfo[].command[].indexname "album1"
indexinfo[].command[].command "word"
-indexinfo[].command[].indexname "complexarray"
-indexinfo[].command[].command "index"
-indexinfo[].command[].indexname "complexarray"
-indexinfo[].command[].command "multivalue"
indexinfo[].command[].indexname "other"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "other"
indexinfo[].command[].command "attribute"
indexinfo[].command[].indexname "other"
indexinfo[].command[].command "numerical"
+indexinfo[].command[].indexname "other"
+indexinfo[].command[].command "type long"
indexinfo[].command[].indexname "pst_sta_boldingoff_nomatch_tag_01"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "pst_sta_boldingoff_nomatch_tag_01"
indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "pst_sta_boldingoff_nomatch_tag_01"
+indexinfo[].command[].command "type tag"
diff --git a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
index 4ee05b56bca..d35682fa354 100644
--- a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java
+++ b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.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.config.model.provision;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.cloud.config.log.LogdConfig;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.api.container.ContainerServiceType;
@@ -20,6 +21,7 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.admin.Admin;
import com.yahoo.vespa.model.admin.Logserver;
import com.yahoo.vespa.model.admin.Slobrok;
+import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainer;
import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainerCluster;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.Container;
@@ -40,6 +42,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static com.yahoo.config.model.test.TestUtil.joinLines;
@@ -951,6 +954,48 @@ public class ModelProvisioningTest {
}
@Test
+ @Ignore // WIP, fails now
+ public void testClusterControllersWithNodeChange() {
+ String services =
+ "<?xml version='1.0' encoding='utf-8' ?>\n" +
+ "<services>" +
+ " <content version='1.0' id='bar'>" +
+ " <redundancy>2</redundancy>" +
+ " <documents>" +
+ " <document type='type1' mode='index'/>" +
+ " </documents>" +
+ " <nodes count='3'/>" +
+ " </content>" +
+ "</services>";
+
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(3);
+ VespaModel model = tester.createModel(services);
+
+ List<ClusterControllerContainer> containers = model.getContentClusters().get("bar").getClusterControllers().getContainers();
+ assertEquals(3, containers.size());
+ assertEquals("node-1-3-9-03", containers.get(0).getHostName());
+ assertEquals("node-1-3-9-02", containers.get(1).getHostName());
+ assertEquals("node-1-3-9-01", containers.get(2).getHostName());
+
+ int indexForHost03 = containers.get(1).index();
+ String hostnameForHost03 = containers.get(1).getHostName();
+
+ // Add 1 node to see if this changes index of already existing cluster controllers
+ tester.addHosts(4);
+ model = tester.createModel(services);
+ containers = model.getContentClusters().get("bar").getClusterControllers().getContainers();
+ assertEquals(3, containers.size());
+ assertEquals("node-1-3-9-04", containers.get(0).getHostName());
+ assertEquals("node-1-3-9-03", containers.get(1).getHostName());
+ assertEquals("node-1-3-9-02", containers.get(2).getHostName());
+
+ assertEquals(hostnameForHost03, containers.get(2).getHostName());
+ // TODO: Fails here because index has changed
+ assertEquals(indexForHost03, containers.get(2).index());
+ }
+
+ @Test
public void testLogserverContainerWhenDedicatedLogserver() {
String services =
"<?xml version='1.0' encoding='utf-8' ?>\n" +
@@ -1815,6 +1860,101 @@ public class ModelProvisioningTest {
assertEquals(1, controller.getContainers().size());
}
+ @Test
+ public void testStatefulProperty() {
+ String servicesXml =
+ "<?xml version='1.0' encoding='utf-8' ?>" +
+ "<services>" +
+ " <container version='1.0' id='qrs'>" +
+ " <nodes count='1'/>" +
+ " </container>" +
+ " <container version='1.0' id='zk'>" +
+ " <zookeeper/>" +
+ " <nodes count='3'/>" +
+ " </container>" +
+ " <content version='1.0' id='content'>" +
+ " <redundancy>2</redundancy>" +
+ " <documents>" +
+ " <document type='type1' mode='index'/>" +
+ " </documents>" +
+ " <nodes count='2'/>" +
+ " </content>" +
+ "</services>";
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(6);
+ VespaModel model = tester.createModel(servicesXml, true);
+
+ Map<String, Boolean> tests = Map.of("qrs", false,
+ "zk", true,
+ "content", true);
+ Map<String, List<HostResource>> hostsByCluster = model.hostSystem().getHosts().stream()
+ .collect(Collectors.groupingBy(h -> h.spec().membership().get().cluster().id().value()));
+ tests.forEach((clusterId, stateful) -> {
+ List<HostResource> hosts = hostsByCluster.getOrDefault(clusterId, List.of());
+ assertFalse("Hosts are provisioned for '" + clusterId + "'", hosts.isEmpty());
+ assertEquals("Hosts in cluster '" + clusterId + "' are " + (stateful ? "" : "not ") + "stateful",
+ stateful,
+ hosts.stream().allMatch(h -> h.spec().membership().get().cluster().isStateful()));
+ });
+ }
+
+ @Test
+ public void containerWithZooKeeperSuboptimalNodeCountDuringRetirement() {
+ String servicesXml =
+ "<?xml version='1.0' encoding='utf-8' ?>" +
+ "<services>" +
+ " <container version='1.0' id='zk'>" +
+ " <zookeeper/>" +
+ " <nodes count='4'/>" + // (3 + 1 retired)
+ " </container>" +
+ "</services>";
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(4);
+ VespaModel model = tester.createModel(servicesXml, true, "node-1-3-9-01");
+ ApplicationContainerCluster cluster = model.getContainerClusters().get("zk");
+ assertEquals(1, cluster.getContainers().stream().filter(Container::isRetired).count());
+ assertEquals(3, cluster.getContainers().stream().filter(c -> !c.isRetired()).count());
+ }
+
+ @Test
+ public void containerWithZooKeeperJoiningServers() {
+ Function<Integer, String> servicesXml = (nodeCount) -> {
+ return "<?xml version='1.0' encoding='utf-8' ?>" +
+ "<services>" +
+ " <container version='1.0' id='zk'>" +
+ " <zookeeper/>" +
+ " <nodes count='" + nodeCount + "'/>" +
+ " </container>" +
+ "</services>";
+ };
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(5);
+ VespaModel model = tester.createModel(servicesXml.apply(3), true);
+
+ {
+ ApplicationContainerCluster cluster = model.getContainerClusters().get("zk");
+ ZookeeperServerConfig.Builder config = new ZookeeperServerConfig.Builder();
+ cluster.getContainers().forEach(c -> c.getConfig(config));
+ cluster.getConfig(config);
+ assertTrue("Initial servers are not joining", config.build().server().stream().noneMatch(ZookeeperServerConfig.Server::joining));
+ }
+ {
+ VespaModel nextModel = tester.createModel(Zone.defaultZone(), servicesXml.apply(5), true, false, 0, Optional.of(model));
+ ApplicationContainerCluster cluster = nextModel.getContainerClusters().get("zk");
+ ZookeeperServerConfig.Builder config = new ZookeeperServerConfig.Builder();
+ cluster.getContainers().forEach(c -> c.getConfig(config));
+ cluster.getConfig(config);
+ assertEquals("New nodes are joining",
+ Map.of(0, false,
+ 1, false,
+ 2, false,
+ 3, true,
+ 4, true),
+ config.build().server().stream().collect(Collectors.toMap(ZookeeperServerConfig.Server::id,
+ ZookeeperServerConfig.Server::joining)));
+ }
+ }
+
private VespaModel createNonProvisionedMultitenantModel(String services) {
return createNonProvisionedModel(true, null, services);
}
diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/NGramTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/NGramTestCase.java
index c792d3bf40b..16883a835d8 100644
--- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/NGramTestCase.java
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/NGramTestCase.java
@@ -48,8 +48,8 @@ public class NGramTestCase extends SchemaTestCase {
assertEquals(Stemming.NONE, gram1.getStemming());
List<String> queryCommands = gram1.getQueryCommands();
- assertEquals(1, queryCommands.size());
- assertEquals("ngram 1", queryCommands.get(0));
+ assertEquals(2, queryCommands.size());
+ assertEquals("ngram 1", queryCommands.get(1));
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/RankingExpressionWithTransformerTokensTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/RankingExpressionWithTransformerTokensTestCase.java
new file mode 100644
index 00000000000..174e685b112
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/RankingExpressionWithTransformerTokensTestCase.java
@@ -0,0 +1,95 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.searchdefinition.processing;
+
+import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.search.query.profile.QueryProfileRegistry;
+import com.yahoo.searchdefinition.RankProfile;
+import com.yahoo.searchdefinition.RankProfileRegistry;
+import com.yahoo.searchdefinition.Search;
+import com.yahoo.searchdefinition.SearchBuilder;
+import com.yahoo.searchdefinition.expressiontransforms.RankProfileTransformContext;
+import com.yahoo.searchdefinition.expressiontransforms.TokenTransformer;
+import com.yahoo.searchdefinition.parser.ParseException;
+import com.yahoo.searchlib.rankingexpression.RankingExpression;
+import com.yahoo.searchlib.rankingexpression.evaluation.MapContext;
+import com.yahoo.searchlib.rankingexpression.evaluation.TensorValue;
+import com.yahoo.tensor.Tensor;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+public class RankingExpressionWithTransformerTokensTestCase {
+
+ @Test
+ public void testTokenInputIds() throws Exception {
+ String expected = "tensor(d0[1],d1[12]):[101,1,2,102,3,4,5,102,6,7,102,0]";
+ String a = "tensor(d0[2]):[1,2]";
+ String b = "tensor(d0[3]):[3,4,5]";
+ String c = "tensor(d0[2]):[6,7]";
+ String expression = "tokenInputIds(12, a, b, c)";
+ Tensor result = evaluateExpression(expression, a, b, c);
+ assertEquals(Tensor.from(expected), result);
+ }
+
+ @Test
+ public void testTokenTypeIds() throws Exception {
+ String expected = "tensor(d0[1],d1[10]):[0,0,0,0,1,1,1,1,1,1]";
+ String a = "tensor(d0[2]):[1,2]";
+ String b = "tensor(d0[3]):[3,4,5]";
+ String expression = "tokenTypeIds(10, a, b)";
+ Tensor result = evaluateExpression(expression, a, b);
+ assertEquals(Tensor.from(expected), result);
+ }
+
+ @Test
+ public void testAttentionMask() throws Exception {
+ String expected = "tensor(d0[1],d1[10]):[1,1,1,1,1,1,1,1,0,0]";
+ String a = "tensor(d0[2]):[1,2]";
+ String b = "tensor(d0[3]):[3,4,5]";
+ String expression = "tokenAttentionMask(10, a, b)";
+ Tensor result = evaluateExpression(expression, a, b);
+ assertEquals(Tensor.from(expected), result);
+ }
+
+ private Tensor evaluateExpression(String expression, String a, String b) throws Exception {
+ return evaluateExpression(expression, a, b, null, null);
+ }
+
+ private Tensor evaluateExpression(String expression, String a, String b, String c) throws Exception {
+ return evaluateExpression(expression, a, b, c, null);
+ }
+
+ private Tensor evaluateExpression(String expression, String a, String b, String c, String d) throws Exception {
+ MapContext context = new MapContext();
+ if (a != null) context.put("a", new TensorValue(Tensor.from(a)));
+ if (b != null) context.put("b", new TensorValue(Tensor.from(b)));
+ if (c != null) context.put("c", new TensorValue(Tensor.from(c)));
+ if (d != null) context.put("d", new TensorValue(Tensor.from(d)));
+ var transformContext = createTransformContext();
+ var rankingExpression = new RankingExpression(expression);
+ var transformed = new TokenTransformer().transform(rankingExpression, transformContext);
+ for (var entry : transformContext.rankProfile().getFunctions().entrySet()) {
+ context.put(entry.getKey(), entry.getValue().function().getBody().evaluate(context).asDouble());
+ }
+ return transformed.evaluate(context).asTensor();
+ }
+
+ private RankProfileTransformContext createTransformContext() throws ParseException {
+ MockApplicationPackage application = (MockApplicationPackage) MockApplicationPackage.createEmpty();
+ RankProfileRegistry rankProfileRegistry = new RankProfileRegistry();
+ QueryProfileRegistry queryProfileRegistry = application.getQueryProfiles();
+ String sdContent = "search test {\n" +
+ " document test {}\n" +
+ " rank-profile my_profile inherits default {}\n" +
+ "}";
+ SearchBuilder searchBuilder = new SearchBuilder(application, rankProfileRegistry, queryProfileRegistry);
+ searchBuilder.importString(sdContent);
+ searchBuilder.build();
+ Search search = searchBuilder.getSearch();
+ RankProfile rp = rankProfileRegistry.get(search, "my_profile");
+ return new RankProfileTransformContext(rp, queryProfileRegistry, Collections.EMPTY_MAP, null, Collections.EMPTY_MAP, Collections.EMPTY_MAP);
+ }
+
+}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/ClusterControllerTestCase.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/ClusterControllerTestCase.java
index ca7e4b43bdf..194ebb0f3b2 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/admin/ClusterControllerTestCase.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/ClusterControllerTestCase.java
@@ -9,9 +9,12 @@ import com.yahoo.component.Version;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.NullConfigModelRegistry;
+import com.yahoo.config.model.api.Reindexing;
import com.yahoo.config.model.application.provider.SimpleApplicationValidator;
+import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
+import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.model.test.TestDriver;
import com.yahoo.config.model.test.TestRoot;
import com.yahoo.config.provision.Environment;
@@ -21,11 +24,13 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.search.config.QrStartConfig;
import com.yahoo.vespa.config.content.FleetcontrollerConfig;
import com.yahoo.vespa.config.content.StorDistributionConfig;
-import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
-import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.vespa.config.content.reindexing.ReindexingConfig;
import com.yahoo.vespa.model.HostResource;
import com.yahoo.vespa.model.Service;
import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainer;
+import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainerCluster;
+import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils;
import com.yahoo.vespa.model.test.utils.DeployLoggerStub;
import org.junit.Before;
@@ -34,8 +39,10 @@ import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.StringReader;
+import java.time.Instant;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
@@ -390,6 +397,9 @@ public class ClusterControllerTestCase extends DomBuilderTest {
assertEquals(512, qrStartConfig.jvm().stacksize());
assertEquals(0, qrStartConfig.jvm().directMemorySizeCache());
assertEquals(75, qrStartConfig.jvm().baseMaxDirectMemorySize());
+
+ assertReindexingConfigPresent(model);
+ assertReindexingConfiguredOnAdminCluster(model);
}
@Test
@@ -477,11 +487,40 @@ public class ClusterControllerTestCase extends DomBuilderTest {
DeployLogger logger = new DeployLoggerStub();
VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
.applicationPackage(applicationPackage)
+ .reindexing(new DummyReindexing())
.deployLogger(logger)
.zone(new Zone(SystemName.cd, Environment.dev, RegionName.from("here")))
- .properties(new TestProperties().setHostedVespa(isHosted))
+ .properties(new TestProperties().setHostedVespa(isHosted).enableAutomaticReindexing(true))
.build());
SimpleApplicationValidator.checkServices(new StringReader(servicesXml), new Version(7));
return model;
}
+
+ private static void assertReindexingConfigPresent(VespaModel model) {
+ ReindexingConfig reindexingConfig = model.getConfig(ReindexingConfig.class, "admin/cluster-controllers/0");
+ assertTrue(reindexingConfig.enabled());
+ assertEquals(1, reindexingConfig.clusters().size());
+ String contentClusterId = "bar";
+ assertEquals(Instant.EPOCH.toEpochMilli(), reindexingConfig.clusters(contentClusterId).documentTypes("type1").readyAtMillis());
+ }
+
+ private static void assertReindexingConfiguredOnAdminCluster(VespaModel model) {
+ ClusterControllerContainerCluster clusterControllerCluster = model.getAdmin().getClusterControllers();
+ assertReindexingMaintainerConfiguredOnClusterController(clusterControllerCluster);
+ }
+
+ private static void assertReindexingMaintainerConfiguredOnClusterController(ClusterControllerContainerCluster clusterControllerCluster) {
+ ClusterControllerContainer container = clusterControllerCluster.getContainers().get(0);
+ Component<?, ?> reindexingMaintainer = container.getComponents().getComponents().stream()
+ .filter(component -> component.getComponentId().getName().equals("reindexing-maintainer"))
+ .findAny()
+ .get();
+ assertEquals("ai.vespa.reindexing.ReindexingMaintainer", reindexingMaintainer.getClassId().getName());
+ }
+
+ private static class DummyReindexing implements Reindexing, Reindexing.Status {
+ @Override public Optional<Status> status(String cluster, String documentType) { return Optional.of(this); }
+ @Override public boolean enabled() { return true; }
+ @Override public Instant ready() { return Instant.EPOCH; }
+ }
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
index c1730528a39..ad05180cf60 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.container.QrConfig;
import com.yahoo.vespa.defaults.Defaults;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationOverrides;
@@ -13,6 +14,7 @@ import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
@@ -44,6 +46,19 @@ public class ContainerRestartValidatorTest {
assertTrue(result.isEmpty());
}
+ @Test
+ public void restart_on_deploy_is_propagated_to_cluster() {
+ VespaModel model1 = createModel(false);
+ assertFalse(model1.getContainerClusters().get("cluster1").getDeferChangesUntilRestart());
+ assertFalse(model1.getContainerClusters().get("cluster2").getDeferChangesUntilRestart());
+ assertFalse(model1.getContainerClusters().get("cluster3").getDeferChangesUntilRestart());
+
+ VespaModel model2 = createModel(true);
+ assertTrue(model2.getContainerClusters().get("cluster1").getDeferChangesUntilRestart());
+ assertTrue(model2.getContainerClusters().get("cluster2").getDeferChangesUntilRestart());
+ assertFalse(model2.getContainerClusters().get("cluster3").getDeferChangesUntilRestart());
+ }
+
private static List<ConfigChangeAction> validateModel(VespaModel current, VespaModel next) {
return new ContainerRestartValidator()
.validate(current, next, new ValidationOverrides(Collections.emptyList()), Instant.now());
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java
index 35aa9a3c988..fda4c54c154 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java
@@ -1,9 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
+import com.yahoo.cloud.config.log.LogdConfig;
import com.yahoo.config.model.provision.InMemoryProvisioner;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeResources;
+import com.yahoo.container.ComponentsConfig;
import com.yahoo.container.QrConfig;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.application.validation.ValidationTester;
@@ -26,15 +28,15 @@ public class RestartChangesDefersConfigChangesTest {
// Change node count - no restart
VespaModel gen2 = tester.deploy(gen1, getServices(4, 3), Environment.prod, null).getFirst();
- var config2 = new QrConfig.Builder();
+ var config2 = new ComponentsConfig.Builder();
gen2.getContainerClusters().get("default").getContainers().get(0).getConfig(config2);
- assertFalse(config2.build().restartOnDeploy());
+ assertFalse(config2.getApplyOnRestart());
// Change memory amount - requires restart
VespaModel gen3 = tester.deploy(gen2, getServices(4, 2), Environment.prod, null).getFirst();
- var config3 = new QrConfig.Builder();
+ var config3 = new ComponentsConfig.Builder();
gen3.getContainerClusters().get("default").getContainers().get(0).getConfig(config3);
- assertTrue(config3.build().restartOnDeploy());
+ assertTrue(config3.getApplyOnRestart());
}
private static String getServices(int nodes, int memory) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
index b1cd9c5c604..21db5bd2d4a 100755
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
@@ -1,9 +1,11 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container;
import com.yahoo.cloud.config.ClusterInfoConfig;
import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.cloud.config.CuratorConfig;
import com.yahoo.cloud.config.RoutingProviderConfig;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.ComponentId;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.deploy.DeployState;
@@ -42,6 +44,7 @@ import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInA
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
* @author Simon Thoresen Hult
@@ -69,7 +72,7 @@ public class ContainerClusterTest {
}
@Test
- public void requreThatWeCanGetTheZoneConfig() {
+ public void requireThatWeCanGetTheZoneConfig() {
DeployState state = new DeployState.Builder().properties(new TestProperties().setHostedVespa(true))
.zone(new Zone(SystemName.cd, Environment.test, RegionName.from("some-region")))
.build();
@@ -163,7 +166,7 @@ public class ContainerClusterTest {
public void testClusterControllerResourceUsage() {
MockRoot root = createRoot(false);
ClusterControllerContainerCluster cluster = createClusterControllerCluster(root);
- addClusterController(root.deployLogger(), cluster, "host-c1");
+ addClusterController(root.deployLogger(), cluster, "host-c1", root.getDeployState());
assertEquals(1, cluster.getContainers().size());
QrStartConfig.Builder qrBuilder = new QrStartConfig.Builder();
cluster.getConfig(qrBuilder);
@@ -183,7 +186,7 @@ public class ContainerClusterTest {
public void testThatLinguisticsIsExcludedForClusterControllerCluster() {
MockRoot root = createRoot(false);
ClusterControllerContainerCluster cluster = createClusterControllerCluster(root);
- addClusterController(root.deployLogger(), cluster, "host-c1");
+ addClusterController(root.deployLogger(), cluster, "host-c1", root.getDeployState());
assertFalse(contains("com.yahoo.language.provider.DefaultLinguisticsProvider", cluster.getAllComponents()));
}
@@ -320,6 +323,43 @@ public class ContainerClusterTest {
}
+ @Test
+ public void requireCuratorConfig() {
+ DeployState state = new DeployState.Builder().build();
+ MockRoot root = new MockRoot("foo", state);
+ var cluster = new ApplicationContainerCluster(root, "container", "search-cluster", state);
+ addContainer(root.deployLogger(), cluster, "c1", "host-c1");
+ addContainer(root.deployLogger(), cluster, "c2", "host-c2");
+ CuratorConfig.Builder configBuilder = new CuratorConfig.Builder();
+ cluster.getConfig(configBuilder);
+ CuratorConfig config = configBuilder.build();
+ assertEquals(List.of("host-c1", "host-c2"),
+ config.server().stream().map(CuratorConfig.Server::hostname).collect(Collectors.toList()));
+ assertTrue(config.zookeeperLocalhostAffinity());
+ }
+
+ @Test
+ public void requireZooKeeperServerConfig() {
+ DeployState state = new DeployState.Builder().build();
+ MockRoot root = new MockRoot("foo", state);
+ var cluster = new ApplicationContainerCluster(root, "container", "search-cluster", state);
+ addContainer(root.deployLogger(), cluster, "c1", "host-c1");
+ addContainer(root.deployLogger(), cluster, "c2", "host-c2");
+ addContainer(root.deployLogger(), cluster, "c3", "host-c3");
+
+ // Only myid is set for container
+ ZookeeperServerConfig.Builder configBuilder = new ZookeeperServerConfig.Builder();
+ cluster.getContainers().get(0).getConfig(configBuilder);
+ assertEquals(0, configBuilder.build().myid());
+
+ // the rest (e.g. servers) is set for cluster
+ cluster.getConfig(configBuilder);
+ assertEquals(0, configBuilder.build().myid());
+ assertEquals(List.of("host-c1", "host-c2", "host-c3"),
+ configBuilder.build().server().stream().map(ZookeeperServerConfig.Server::hostname).collect(Collectors.toList()));
+
+ }
+
private void verifyTesterApplicationInstalledBundles(Zone zone, List<String> expectedBundleNames) {
ApplicationId appId = ApplicationId.from("tenant", "application", "instance-t");
DeployState state = new DeployState.Builder().properties(
@@ -351,8 +391,11 @@ public class ContainerClusterTest {
cluster.addContainer(container);
}
- private static void addClusterController(DeployLogger deployLogger, ClusterControllerContainerCluster cluster, String hostName) {
- ClusterControllerContainer container = new ClusterControllerContainer(cluster, 1, false, cluster.isHostedVespa(), /*reindexingContext*/null);
+ private static void addClusterController(DeployLogger deployLogger,
+ ClusterControllerContainerCluster cluster,
+ String hostName,
+ DeployState deployState) {
+ ClusterControllerContainer container = new ClusterControllerContainer(cluster, 1, false, deployState);
container.setHostResource(new HostResource(new Host(null, hostName)));
container.initService(deployLogger);
cluster.addContainer(container);
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/configserver/ConfigserverClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/configserver/ConfigserverClusterTest.java
index d56acb3cff0..2b55d7a3948 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/configserver/ConfigserverClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/configserver/ConfigserverClusterTest.java
@@ -13,6 +13,9 @@ import com.yahoo.container.jdisc.config.HealthMonitorConfig;
import com.yahoo.net.HostName;
import com.yahoo.text.XML;
import com.yahoo.vespa.defaults.Defaults;
+import com.yahoo.vespa.model.HostResource;
+import com.yahoo.vespa.model.container.Container;
+import com.yahoo.vespa.model.container.ContainerModel;
import com.yahoo.vespa.model.container.configserver.option.CloudConfigOptions;
import com.yahoo.vespa.model.container.xml.ConfigServerContainerModelBuilder;
import org.junit.Test;
@@ -167,10 +170,17 @@ public class ConfigserverClusterTest {
+ " <server port='1337' id='configserver' />"
+ " </http>"
+ "</container>";
- new ConfigServerContainerModelBuilder(testOptions)
+ ContainerModel containerModel = new ConfigServerContainerModelBuilder(testOptions)
.build(new DeployState.Builder().build(), null, null, root, XML.getDocument(services).getDocumentElement());
- root.freezeModelTopology();
+ // Simulate the behaviour of StandaloneContainer
+ List<? extends Container> containers = containerModel.getCluster().getContainers();
+ assertEquals("Standalone container", 1, containers.size());
+ HostResource hostResource = root.hostSystem().getHost(Container.SINGLENODE_CONTAINER_SERVICESPEC);
+ containers.get(0).setHostResource(hostResource);
+
+ root.freezeModelTopology();
return root.getConfig(clazz, "configserver/standalone");
}
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
index 13c1631e0ce..35257686a5a 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.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.model.container.xml;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.ComponentId;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.NullConfigModelRegistry;
@@ -40,11 +41,13 @@ import com.yahoo.vespa.defaults.Defaults;
import com.yahoo.vespa.model.AbstractService;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.container.ApplicationContainer;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.SecretStore;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.http.ConnectorFactory;
import com.yahoo.vespa.model.content.utils.ContentClusterUtils;
+import com.yahoo.vespa.model.test.VespaModelTester;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithFilePkg;
import org.hamcrest.Matchers;
import org.junit.Rule;
@@ -59,6 +62,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -871,6 +875,62 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
assertThat(connectorConfig.ssl().caCertificate(), isEmptyString());
}
+ @Test
+ public void cluster_with_zookeeper() {
+ Function<Integer, String> servicesXml = (nodeCount) -> "<container version='1.0' id='default'>" +
+ "<nodes count='" + nodeCount + "'/>" +
+ "<zookeeper/>" +
+ "</container>";
+ VespaModelTester tester = new VespaModelTester();
+ tester.addHosts(3);
+ {
+ VespaModel model = tester.createModel(servicesXml.apply(3), true);
+ ApplicationContainerCluster cluster = model.getContainerClusters().get("default");
+ assertNotNull(cluster);
+ assertComponentConfigured(cluster,"com.yahoo.vespa.curator.Curator");
+ cluster.getContainers().forEach(container -> {
+ assertComponentConfigured(container, "com.yahoo.vespa.zookeeper.ReconfigurableVespaZooKeeperServer");
+ assertComponentConfigured(container, "com.yahoo.vespa.zookeeper.Reconfigurer");
+ assertComponentConfigured(container, "com.yahoo.vespa.zookeeper.VespaZooKeeperAdminImpl");
+
+ ZookeeperServerConfig config = model.getConfig(ZookeeperServerConfig.class, container.getConfigId());
+ assertEquals(container.index(), config.myid());
+ assertEquals(3, config.server().size());
+ });
+ }
+ {
+ try {
+ tester.createModel(servicesXml.apply(2), true);
+ fail("Expected exception");
+ } catch (IllegalArgumentException ignored) {}
+ }
+ {
+ String xmlWithNodes =
+ "<?xml version='1.0' encoding='utf-8' ?>" +
+ "<services>" +
+ " <container version='1.0' id='container1'>" +
+ " <zookeeper/>" +
+ " <nodes of='content1'/>" +
+ " </container>" +
+ " <content version='1.0' id='content1'>" +
+ " <nodes count='3'/>" +
+ " </content>" +
+ "</services>";
+ try {
+ tester.createModel(xmlWithNodes, true);
+ fail("Expected exception");
+ } catch (IllegalArgumentException ignored) {}
+ }
+ }
+
+ private void assertComponentConfigured(ApplicationContainerCluster cluster, String componentId) {
+ Component<?, ?> component = cluster.getComponentsMap().get(ComponentId.fromString(componentId));
+ assertNotNull(component);
+ }
+
+ private void assertComponentConfigured(ApplicationContainer container, String id) {
+ assertTrue(container.getComponents().getComponents().stream().anyMatch(component -> id.equals(component.getComponentId().getName())));
+ }
private Element generateContainerElementWithRenderer(String rendererId) {
return DomBuilderTest.parse(
@@ -880,4 +940,5 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
" </search>",
"</container>");
}
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
index fe0b9841d1c..a55d221f8c4 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
@@ -10,6 +10,7 @@ import com.yahoo.config.model.test.TestRoot;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Zone;
+import com.yahoo.container.ComponentsConfig;
import com.yahoo.messagebus.routing.RoutingTableSpec;
import com.yahoo.metrics.MetricsmanagerConfig;
import com.yahoo.vespa.config.content.AllClustersBucketSpacesConfig;
@@ -22,6 +23,7 @@ import com.yahoo.vespa.config.content.core.StorServerConfig;
import com.yahoo.vespa.config.search.DispatchConfig;
import com.yahoo.vespa.config.search.core.ProtonConfig;
import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.admin.clustercontroller.ClusterControllerContainer;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import com.yahoo.vespa.model.content.engines.ProtonEngine;
@@ -30,7 +32,6 @@ import com.yahoo.vespa.model.content.utils.ContentClusterUtils;
import com.yahoo.vespa.model.content.utils.SchemaBuilder;
import com.yahoo.vespa.model.routing.DocumentProtocol;
import com.yahoo.vespa.model.routing.Routing;
-import com.yahoo.vespa.model.search.SearchNode;
import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
import org.junit.Rule;
@@ -993,4 +994,27 @@ public class ContentClusterTest extends ContentBaseTest {
assertDirectStorageApiRpcFlagIsPropagatedToConfig(true);
}
+ void assertZookeeperServerImplementation(boolean reconfigurable, String expectedClassName) {
+ VespaModel model = createEnd2EndOneNode(
+ new TestProperties()
+ .reconfigurableZookeeperServer(reconfigurable)
+ .setMultitenant(true));
+
+ ContentCluster cc = model.getContentClusters().get("storage");
+ for (ClusterControllerContainer c : cc.getClusterControllers().getContainers()) {
+ var builder = new ComponentsConfig.Builder();
+ c.getConfig(builder);
+ assertEquals(1, new ComponentsConfig(builder).components().stream()
+ .filter(component -> component.id().equals("clustercontroller-zookeeper-server"))
+ .map(component -> component.classId().equals(expectedClassName))
+ .count());
+ }
+ }
+
+ @Test
+ public void reconfigurableZookeeperServerForClusterController() {
+ assertZookeeperServerImplementation(false, "com.yahoo.vespa.zookeeper.VespaZooKeeperServerImpl");
+ assertZookeeperServerImplementation(true, "com.yahoo.vespa.zookeeper.ReconfigurableVespaZooKeeperServer");
+ }
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java
index e4dabfaddae..e270c81fe78 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java
@@ -53,7 +53,7 @@ public class SearchNodeTest {
private static SearchNode createSearchNode(MockRoot root, String name, int distributionKey,
NodeSpec nodeSpec, boolean flushOnShutDown, boolean isHosted, boolean combined) {
- return SearchNode.create(root.getDeployState().getProperties(), root, name, distributionKey, nodeSpec, "mycluster", null, flushOnShutDown, Optional.empty(), Optional.empty(), isHosted, combined);
+ return SearchNode.create(root, name, distributionKey, nodeSpec, "mycluster", null, flushOnShutDown, Optional.empty(), Optional.empty(), isHosted, combined);
}
private static SearchNode createSearchNode(MockRoot root) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
index 813ca4ac0cb..7484095c5bc 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/test/VespaModelTester.java
@@ -104,22 +104,22 @@ public class VespaModelTester {
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, 0, retiredHostNames);
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, 0, Optional.empty(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, boolean useMaxResources, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, 0, retiredHostNames);
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, useMaxResources, 0, Optional.empty(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(String services, boolean failOnOutOfCapacity, int startIndexForClusters, String ... retiredHostNames) {
- return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, startIndexForClusters, retiredHostNames);
+ return createModel(Zone.defaultZone(), services, failOnOutOfCapacity, false, startIndexForClusters, Optional.empty(), retiredHostNames);
}
/** Creates a model which uses 0 as start index */
public VespaModel createModel(Zone zone, String services, boolean failOnOutOfCapacity, String ... retiredHostNames) {
- return createModel(zone, services, failOnOutOfCapacity, false, 0, retiredHostNames);
+ return createModel(zone, services, failOnOutOfCapacity, false, 0, Optional.empty(), retiredHostNames);
}
/**
@@ -132,7 +132,7 @@ public class VespaModelTester {
* @return the resulting model
*/
public VespaModel createModel(Zone zone, String services, boolean failOnOutOfCapacity, boolean useMaxResources,
- int startIndexForClusters, String ... retiredHostNames) {
+ int startIndexForClusters, Optional<VespaModel> previousModel, String ... retiredHostNames) {
VespaModelCreatorWithMockPkg modelCreatorWithMockPkg = new VespaModelCreatorWithMockPkg(null, services, ApplicationPackageUtils.generateSearchDefinition("type1"));
ApplicationPackage appPkg = modelCreatorWithMockPkg.appPkg;
@@ -148,12 +148,13 @@ public class VespaModelTester {
.setApplicationId(applicationId)
.setUseDedicatedNodeForLogserver(useDedicatedNodeForLogserver);
- DeployState deployState = new DeployState.Builder()
+ DeployState.Builder deployState = new DeployState.Builder()
.applicationPackage(appPkg)
.modelHostProvisioner(provisioner)
.properties(properties)
- .zone(zone)
- .build();
- return modelCreatorWithMockPkg.create(false, deployState, configModelRegistry);
+ .zone(zone);
+ previousModel.ifPresent(deployState::previousModel);
+ return modelCreatorWithMockPkg.create(false, deployState.build(), configModelRegistry);
}
+
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
index 45465fa91c4..113a4512331 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterMembership.java
@@ -3,11 +3,12 @@ package com.yahoo.config.provision;
import com.yahoo.component.Version;
+import java.util.Objects;
import java.util.Optional;
/**
* A node's membership in a cluster. This is a value object.
- * The format is "clusterType/clusterId/groupId/index[/exclusive][/retired][/combinedId]"
+ * The format is "clusterType/clusterId/groupId/index[/exclusive][/retired][/stateful][/combinedId]"
*
* @author bratseth
*/
@@ -24,9 +25,10 @@ public class ClusterMembership {
String[] components = stringValue.split("/");
if (components.length < 4)
throw new RuntimeException("Could not parse '" + stringValue + "' to a cluster membership. " +
- "Expected 'clusterType/clusterId/groupId/index[/retired][/exclusive][/combinedId]'");
+ "Expected 'clusterType/clusterId/groupId/index[/retired][/exclusive][/stateful][/combinedId]'");
boolean exclusive = false;
+ boolean stateful = false;
var combinedId = Optional.<String>empty();
if (components.length > 4) {
for (int i = 4; i < components.length; i++) {
@@ -34,18 +36,21 @@ public class ClusterMembership {
switch (component) {
case "exclusive": exclusive = true; break;
case "retired": retired = true; break;
+ case "stateful": stateful = true; break;
default: combinedId = Optional.of(component); break;
}
}
}
- this.cluster = ClusterSpec.specification(ClusterSpec.Type.valueOf(components[0]), ClusterSpec.Id.from(components[1]))
- .group(ClusterSpec.Group.from(Integer.parseInt(components[2])))
- .vespaVersion(vespaVersion)
- .exclusive(exclusive)
- .combinedId(combinedId.map(ClusterSpec.Id::from))
- .dockerImageRepository(dockerImageRepo)
- .build();
+ this.cluster = ClusterSpec.specification(ClusterSpec.Type.valueOf(components[0]),
+ ClusterSpec.Id.from(components[1]))
+ .group(ClusterSpec.Group.from(Integer.parseInt(components[2])))
+ .vespaVersion(vespaVersion)
+ .exclusive(exclusive)
+ .combinedId(combinedId.map(ClusterSpec.Id::from))
+ .dockerImageRepository(dockerImageRepo)
+ .stateful(stateful)
+ .build();
this.index = Integer.parseInt(components[3]);
this.stringValue = toStringValue();
}
@@ -64,6 +69,7 @@ public class ClusterMembership {
"/" + index +
( cluster.isExclusive() ? "/exclusive" : "") +
( retired ? "/retired" : "") +
+ ( cluster.isStateful() ? "/stateful" : "") +
( cluster.combinedId().isPresent() ? "/" + cluster.combinedId().get().value() : "");
}
@@ -98,13 +104,19 @@ public class ClusterMembership {
public String stringValue() { return stringValue; }
@Override
- public int hashCode() { return stringValue().hashCode(); }
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ClusterMembership that = (ClusterMembership) o;
+ return index == that.index &&
+ retired == that.retired &&
+ cluster.equals(that.cluster) &&
+ stringValue.equals(that.stringValue);
+ }
@Override
- public boolean equals(Object other) {
- if (other == this) return true;
- if ( ! (other instanceof ClusterMembership)) return false;
- return ((ClusterMembership)other).stringValue().equals(stringValue());
+ public int hashCode() {
+ return Objects.hash(cluster, index, retired, stringValue);
}
@Override
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterResources.java
index 8f4c9f81d7f..7f7357ea77f 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterResources.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterResources.java
@@ -1,9 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
-import com.yahoo.config.Node;
-
-import java.util.List;
import java.util.Objects;
/**
@@ -63,6 +60,10 @@ public class ClusterResources {
.withBandwidthGbps(nodeResources.bandwidthGbps() * nodes);
}
+ public ClusterResources justNumbers() {
+ return new ClusterResources(nodes, groups, nodeResources.justNumbers());
+ }
+
@Override
public boolean equals(Object o) {
if (o == this) return true;
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 71776a7641d..14658e57c1b 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -19,13 +19,15 @@ public final class ClusterSpec {
/** The group id of these hosts, or empty if this is represents a request for hosts */
private final Optional<Group> groupId;
+
private final Version vespaVersion;
private final boolean exclusive;
private final Optional<Id> combinedId;
private final Optional<DockerImage> dockerImageRepo;
+ private final boolean stateful;
private ClusterSpec(Type type, Id id, Optional<Group> groupId, Version vespaVersion, boolean exclusive,
- Optional<Id> combinedId, Optional<DockerImage> dockerImageRepo) {
+ Optional<Id> combinedId, Optional<DockerImage> dockerImageRepo, boolean stateful) {
this.type = type;
this.id = id;
this.groupId = groupId;
@@ -40,6 +42,10 @@ public final class ClusterSpec {
if (dockerImageRepo.isPresent() && dockerImageRepo.get().tag().isPresent())
throw new IllegalArgumentException("dockerImageRepo is not allowed to have a tag");
this.dockerImageRepo = dockerImageRepo;
+ if (type.isContent() && !stateful) {
+ throw new IllegalArgumentException("Cluster of type " + type + " must be stateful");
+ }
+ this.stateful = stateful;
}
/** Returns the cluster type */
@@ -71,12 +77,17 @@ public final class ClusterSpec {
*/
public boolean isExclusive() { return exclusive; }
+ /** Whether this cluster has state */
+ public boolean isStateful() {
+ return stateful;
+ }
+
public ClusterSpec with(Optional<Group> newGroup) {
- return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo);
+ return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
public ClusterSpec exclusive(boolean exclusive) {
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
/** Creates a ClusterSpec when requesting a cluster */
@@ -94,6 +105,7 @@ public final class ClusterSpec {
private final Type type;
private final Id id;
private final boolean specification;
+ private boolean stateful;
private Optional<Group> groupId = Optional.empty();
private Optional<DockerImage> dockerImageRepo = Optional.empty();
@@ -101,10 +113,11 @@ public final class ClusterSpec {
private boolean exclusive = false;
private Optional<Id> combinedId = Optional.empty();
- Builder(Type type, Id id, boolean specification) {
+ private Builder(Type type, Id id, boolean specification) {
this.type = type;
this.id = id;
this.specification = specification;
+ this.stateful = type.isContent(); // Default to true for content clusters
}
public ClusterSpec build() {
@@ -113,7 +126,7 @@ public final class ClusterSpec {
if (vespaVersion == null) throw new IllegalArgumentException("vespaVersion is required to be set when creating a ClusterSpec with specification()");
} else
if (groupId.isPresent()) throw new IllegalArgumentException("groupId is not allowed to be set when creating a ClusterSpec with request()");
- return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo);
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
public Builder group(Group groupId) {
@@ -146,6 +159,11 @@ public final class ClusterSpec {
return this;
}
+ public Builder stateful(boolean stateful) {
+ this.stateful = stateful;
+ return this;
+ }
+
}
@Override
@@ -154,19 +172,23 @@ public final class ClusterSpec {
}
@Override
- public int hashCode() { return type.hashCode() + 17 * id.hashCode() + 31 * groupId.hashCode(); }
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ClusterSpec that = (ClusterSpec) o;
+ return exclusive == that.exclusive &&
+ stateful == that.stateful &&
+ type == that.type &&
+ id.equals(that.id) &&
+ groupId.equals(that.groupId) &&
+ vespaVersion.equals(that.vespaVersion) &&
+ combinedId.equals(that.combinedId) &&
+ dockerImageRepo.equals(that.dockerImageRepo);
+ }
@Override
- public boolean equals(Object o) {
- if (o == this) return true;
- if ( ! (o instanceof ClusterSpec)) return false;
- ClusterSpec other = (ClusterSpec)o;
- if ( ! other.type.equals(this.type)) return false;
- if ( ! other.id.equals(this.id)) return false;
- if ( ! other.groupId.equals(this.groupId)) return false;
- if ( ! other.vespaVersion.equals(this.vespaVersion)) return false;
- if ( ! other.dockerImageRepo.equals(this.dockerImageRepo)) return false;
- return true;
+ public int hashCode() {
+ return Objects.hash(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
/**
@@ -216,8 +238,7 @@ public final class ClusterSpec {
private final String id;
public Id(String id) {
- Objects.requireNonNull(id, "Id cannot be null");
- this.id = id;
+ this.id = Objects.requireNonNull(id, "Id cannot be null");
}
public static Id from(String id) {
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
index f695f0b75eb..6b4a4f2a073 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
@@ -213,14 +213,14 @@ public class NodeResources {
return Objects.hash(vcpu, memoryGb, diskGb, bandwidthGbps, diskSpeed, storageType);
}
- private static StringBuffer appendDouble(StringBuffer sb, double d) {
+ private static StringBuilder appendDouble(StringBuilder sb, double d) {
long x10 = Math.round(d*10);
sb.append(x10/10).append('.').append(x10%10);
return sb;
}
@Override
public String toString() {
- StringBuffer sb = new StringBuffer("[vcpu: ");
+ StringBuilder sb = new StringBuilder("[vcpu: ");
appendDouble(sb, vcpu);
sb.append(", memory: ");
appendDouble(sb, memoryGb);
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
index 137773ce8fe..2cbbb3c92b4 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
@@ -44,11 +44,6 @@ public class AllocatedHostsSerializer {
private static final String realResourcesKey = "realResources";
private static final String advertisedResourcesKey = "advertisedResources";
-
- // Flavor can be removed when all allocated nodes are docker nodes
- private static final String flavorKey = "flavor";
-
- private static final String resourcesKey = "resources";
private static final String requestedResourcesKey = "requestedResources";
private static final String vcpuKey = "vcpu";
private static final String memoryKey = "memory";
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
index 71e039f6e8e..3bbdf7cff28 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/ClusterMembershipTest.java
@@ -26,31 +26,33 @@ public class ClusterMembershipTest {
{
ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive/retired", Vtag.currentVersion, Optional.empty());
ClusterMembership serialized = ClusterMembership.from(instance.stringValue(), Vtag.currentVersion, Optional.empty());
+ assertFalse(serialized.cluster().isStateful());
assertEquals(instance, serialized);
assertTrue(instance.retired());
assertTrue(instance.cluster().isExclusive());
- assertFalse(instance.cluster().combinedId().isPresent());
- assertTrue(instance.cluster().dockerImageRepo().isEmpty());
}
{
ClusterMembership instance = ClusterMembership.from("container/id1/4/37/exclusive", Vtag.currentVersion, Optional.empty());
ClusterMembership serialized = ClusterMembership.from(instance.stringValue(), Vtag.currentVersion, Optional.empty());
+ assertFalse(serialized.cluster().isStateful());
assertEquals(instance, serialized);
- assertFalse(instance.retired());
assertTrue(instance.cluster().isExclusive());
- assertFalse(instance.cluster().combinedId().isPresent());
- assertTrue(instance.cluster().dockerImageRepo().isEmpty());
}
{
Optional<DockerImage> dockerImageRepo = Optional.of(DockerImage.fromString("docker.foo.com:4443/vespa/bar"));
- ClusterMembership instance = ClusterMembership.from("combined/id1/4/37/exclusive/containerId1", Vtag.currentVersion, dockerImageRepo);
+ ClusterMembership instance = ClusterMembership.from("combined/id1/4/37/exclusive/stateful/containerId1", Vtag.currentVersion, dockerImageRepo);
ClusterMembership serialized = ClusterMembership.from(instance.stringValue(), Vtag.currentVersion, dockerImageRepo);
+ assertTrue(serialized.cluster().isStateful());
assertEquals(instance, serialized);
- assertFalse(instance.retired());
- assertTrue(instance.cluster().isExclusive());
assertEquals(ClusterSpec.Id.from("containerId1"), instance.cluster().combinedId().get());
assertEquals(dockerImageRepo.get(), instance.cluster().dockerImageRepo().get());
}
+ {
+ ClusterMembership instance = ClusterMembership.from("container/id1/4/37/stateful", Vtag.currentVersion, Optional.empty());
+ ClusterMembership serialized = ClusterMembership.from(instance.stringValue(), Vtag.currentVersion, Optional.empty());
+ assertEquals(instance, serialized);
+ assertTrue(instance.cluster().isStateful());
+ }
}
@Test
@@ -70,7 +72,7 @@ public class ClusterMembershipTest {
@Test
public void testServiceInstanceWithGroupFromString() {
- assertContentServiceWithGroup(ClusterMembership.from("content/id1/4/37", Vtag.currentVersion, Optional.empty()));
+ assertContentServiceWithGroup(ClusterMembership.from("content/id1/4/37/stateful", Vtag.currentVersion, Optional.empty()));
}
@Test
@@ -90,7 +92,7 @@ public class ClusterMembershipTest {
@Test
public void testServiceInstanceWithGroupAndRetireFromString() {
- assertContentServiceWithGroupAndRetire(ClusterMembership.from("content/id1/4/37/retired", Vtag.currentVersion, Optional.empty()));
+ assertContentServiceWithGroupAndRetire(ClusterMembership.from("content/id1/4/37/retired/stateful", Vtag.currentVersion, Optional.empty()));
}
private void assertContainerService(ClusterMembership instance) {
@@ -107,7 +109,7 @@ public class ClusterMembershipTest {
assertFalse(instance.cluster().group().isPresent());
assertEquals(37, instance.index());
assertFalse(instance.retired());
- assertEquals("content/id1/37", instance.stringValue());
+ assertEquals("content/id1/37/stateful", instance.stringValue());
}
private void assertContentServiceWithGroup(ClusterMembership instance) {
@@ -116,7 +118,7 @@ public class ClusterMembershipTest {
assertEquals(4, instance.cluster().group().get().index());
assertEquals(37, instance.index());
assertFalse(instance.retired());
- assertEquals("content/id1/4/37", instance.stringValue());
+ assertEquals("content/id1/4/37/stateful", instance.stringValue());
}
/** Serializing a spec without a group assigned works, but not deserialization */
@@ -125,7 +127,7 @@ public class ClusterMembershipTest {
assertEquals("id1", instance.cluster().id().value());
assertEquals(37, instance.index());
assertTrue(instance.retired());
- assertEquals("content/id1/37/retired", instance.stringValue());
+ assertEquals("content/id1/37/retired/stateful", instance.stringValue());
}
private void assertContentServiceWithGroupAndRetire(ClusterMembership instance) {
@@ -134,7 +136,7 @@ public class ClusterMembershipTest {
assertEquals(4, instance.cluster().group().get().index());
assertEquals(37, instance.index());
assertTrue(instance.retired());
- assertEquals("content/id1/4/37/retired", instance.stringValue());
+ assertEquals("content/id1/4/37/retired/stateful", instance.stringValue());
}
}
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/HostFilterTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/HostFilterTest.java
index 66ca1170487..91d4ae17042 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/HostFilterTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/HostFilterTest.java
@@ -4,13 +4,11 @@ package com.yahoo.config.provision;
import com.yahoo.component.Vtag;
import org.junit.Test;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
/**
* @author bratseth
@@ -29,20 +27,20 @@ public class HostFilterTest {
assertFalse(type.matches("anyhost", "flavor", membership("container/anytype/0/0")));
assertFalse(id.matches("anyhost", "flavor", membership("container/anytype/0/0")));
- assertTrue( all.matches("anyhost", "flavor", membership("content/anytype/0/0")));
- assertFalse(hostname.matches("anyhost", "flavor", membership("content/anytype/0/0")));
- assertTrue( type.matches("anyhost", "flavor", membership("content/anytype/0/0")));
- assertFalse( id.matches("anyhost", "flavor", membership("content/anytype/0/0")));
+ assertTrue( all.matches("anyhost", "flavor", membership("content/anytype/0/0/stateful")));
+ assertFalse(hostname.matches("anyhost", "flavor", membership("content/anytype/0/0/stateful")));
+ assertTrue( type.matches("anyhost", "flavor", membership("content/anytype/0/0/stateful")));
+ assertFalse( id.matches("anyhost", "flavor", membership("content/anytype/0/0/stateful")));
- assertTrue( all.matches("host1", "flavor", membership("content/anytype/0/0")));
- assertTrue( hostname.matches("host1", "flavor", membership("content/anytype/0/0")));
- assertTrue( type.matches("host1", "flavor", membership("content/anytype/0/0")));
- assertFalse( id.matches("host1", "flavor", membership("content/anytype/0/0")));
+ assertTrue( all.matches("host1", "flavor", membership("content/anytype/0/0/stateful")));
+ assertTrue( hostname.matches("host1", "flavor", membership("content/anytype/0/0/stateful")));
+ assertTrue( type.matches("host1", "flavor", membership("content/anytype/0/0/stateful")));
+ assertFalse( id.matches("host1", "flavor", membership("content/anytype/0/0/stateful")));
- assertTrue( all.matches("host1", "flavor", membership("content/type1/0/0")));
- assertTrue( hostname.matches("host1", "flavor", membership("content/type1/0/0")));
- assertTrue( type.matches("host1", "flavor", membership("content/type1/0/0")));
- assertTrue( id.matches("host1", "flavor", membership("content/type1/0/0")));
+ assertTrue( all.matches("host1", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue( hostname.matches("host1", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue( type.matches("host1", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue( id.matches("host1", "flavor", membership("content/type1/0/0/stateful")));
}
@Test
@@ -52,22 +50,22 @@ public class HostFilterTest {
Collections.singletonList(ClusterSpec.Type.content),
Collections.singletonList(ClusterSpec.Id.from("type1")));
- assertFalse(typeAndId.matches("anyhost", "flavor", membership("content/anyType/0/0")));
+ assertFalse(typeAndId.matches("anyhost", "flavor", membership("content/anyType/0/0/stateful")));
assertFalse(typeAndId.matches("anyhost", "flavor", membership("container/type1/0/0")));
- assertTrue(typeAndId.matches("anyhost", "flavor", membership("content/type1/0/0")));
+ assertTrue(typeAndId.matches("anyhost", "flavor", membership("content/type1/0/0/stateful")));
}
@Test
public void testMultiConditionFilterFromStrings() {
HostFilter typeAndId = HostFilter.from("host1 host2, host3,host4", " , ,flavor", null, "type1 ");
- assertFalse(typeAndId.matches("anotherhost", "flavor", membership("content/type1/0/0")));
- assertTrue(typeAndId.matches("host1", "flavor", membership("content/type1/0/0")));
- assertTrue(typeAndId.matches("host2", "flavor", membership("content/type1/0/0")));
- assertTrue(typeAndId.matches("host3", "flavor", membership("content/type1/0/0")));
- assertTrue(typeAndId.matches("host4", "flavor", membership("content/type1/0/0")));
- assertFalse(typeAndId.matches("host1", "flavor", membership("content/type2/0/0")));
- assertFalse(typeAndId.matches("host4", "differentflavor", membership("content/type1/0/0")));
+ assertFalse(typeAndId.matches("anotherhost", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue(typeAndId.matches("host1", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue(typeAndId.matches("host2", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue(typeAndId.matches("host3", "flavor", membership("content/type1/0/0/stateful")));
+ assertTrue(typeAndId.matches("host4", "flavor", membership("content/type1/0/0/stateful")));
+ assertFalse(typeAndId.matches("host1", "flavor", membership("content/type2/0/0/stateful")));
+ assertFalse(typeAndId.matches("host4", "differentflavor", membership("content/type1/0/0/stateful")));
}
private Optional<ClusterMembership> membership(String membershipString) {
diff --git a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java
index 30f4884c737..fbc10c772d7 100644
--- a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java
+++ b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java
@@ -350,7 +350,10 @@ public class ConfigProxyRpcServer implements Runnable, TargetWatcher, RpcServer
public void returnOkResponse(JRTServerConfigRequest request, RawConfig config) {
request.getRequestTrace().trace(TRACELEVEL, "Config proxy returnOkResponse()");
- request.addOkResponse(config.getPayload(), config.getGeneration(), config.isInternalRedeploy(), config.getConfigMd5());
+ request.addOkResponse(config.getPayload(),
+ config.getGeneration(),
+ config.applyOnRestart(),
+ config.getConfigMd5());
log.log(Level.FINE, () -> "Return response: " + request.getShortDescription() + ",configMd5=" + config.getConfigMd5() +
",generation=" + config.getGeneration());
log.log(Level.FINEST, () -> "Config payload in response for " + request.getShortDescription() + ":" + config.getPayload());
diff --git a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/Subscriber.java b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/Subscriber.java
index f96d6470679..e79497e0dd3 100644
--- a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/Subscriber.java
+++ b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/Subscriber.java
@@ -43,7 +43,7 @@ public class Subscriber {
}
public Optional<RawConfig> nextGeneration() {
- if (subscriber.nextGeneration(0)) {
+ if (subscriber.nextGeneration(0, true)) { // Proxy should never skip config due to not initializing
try {
return Optional.of(handle.getRawConfig());
} catch (Exception e) { // To avoid thread throwing exception and loop never running this again
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java
index f52598b3ee5..87c1fa151f8 100644
--- a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java
@@ -34,9 +34,9 @@ public class ProxyServerTest {
// errorConfig based on fooConfig
private static final ConfigKey<?> errorConfigKey = new ConfigKey<>("error", fooConfig.getConfigId(), fooConfig.getNamespace());
- static final RawConfig errorConfig = new RawConfig(errorConfigKey, fooConfig.getDefMd5(),
- fooConfig.getPayload(), fooConfig.getConfigMd5(),
- fooConfig.getGeneration(), false, ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty());
+ static final RawConfig errorConfig = new RawConfig(errorConfigKey, fooConfig.getDefMd5(), fooConfig.getPayload(),
+ fooConfig.getConfigMd5(), fooConfig.getGeneration(), false,
+ ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty());
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -178,9 +178,9 @@ public class ProxyServerTest {
assertEquals(1, cache.size());
// Simulate an empty response
- RawConfig emptyConfig = new RawConfig(fooConfig.getKey(), fooConfig.getDefMd5(),
- Payload.from("{}"), fooConfig.getConfigMd5(),
- 0, false, 0, fooConfig.getDefContent(), Optional.empty());
+ RawConfig emptyConfig = new RawConfig(fooConfig.getKey(), fooConfig.getDefMd5(), Payload.from("{}"),
+ fooConfig.getConfigMd5(), 0, false,
+ 0, fooConfig.getDefContent(), Optional.empty());
source.put(fooConfig.getKey(), emptyConfig);
res = proxy.resolveConfig(tester.createRequest(fooConfig));
diff --git a/config/abi-spec.json b/config/abi-spec.json
index b60f9053642..fa016fd91da 100644
--- a/config/abi-spec.json
+++ b/config/abi-spec.json
@@ -202,9 +202,13 @@
"public com.yahoo.config.subscription.ConfigHandle subscribe(java.lang.Class, java.lang.String, long)",
"protected void checkStateBeforeSubscribe()",
"protected void subscribeAndHandleErrors(com.yahoo.config.subscription.impl.ConfigSubscription, com.yahoo.vespa.config.ConfigKey, com.yahoo.config.subscription.ConfigHandle, com.yahoo.vespa.config.TimingValues)",
+ "public boolean nextConfig(boolean)",
"public boolean nextConfig()",
+ "public boolean nextConfig(long, boolean)",
"public boolean nextConfig(long)",
+ "public boolean nextGeneration(boolean)",
"public boolean nextGeneration()",
+ "public boolean nextGeneration(long, boolean)",
"public boolean nextGeneration(long)",
"protected void throwIfExceptionSet(com.yahoo.config.subscription.impl.ConfigSubscription)",
"public void close()",
@@ -218,7 +222,6 @@
"public boolean isClosed()",
"public com.yahoo.config.subscription.ConfigHandle subscribe(com.yahoo.config.subscription.ConfigSubscriber$SingleSubscriber, java.lang.Class, java.lang.String)",
"public long getGeneration()",
- "public boolean isInternalRedeploy()",
"protected void finalize()"
],
"fields": [
diff --git a/config/src/apps/vespa-get-config/getconfig.cpp b/config/src/apps/vespa-get-config/getconfig.cpp
index dc12d2bbf0e..e8ef1765473 100644
--- a/config/src/apps/vespa-get-config/getconfig.cpp
+++ b/config/src/apps/vespa-get-config/getconfig.cpp
@@ -1,13 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
#include <vespa/config/config.h>
#include <vespa/config/frt/frtconfigrequestfactory.h>
#include <vespa/config/frt/frtconnection.h>
#include <vespa/config/common/payload_converter.h>
#include <vespa/fastos/app.h>
-
#include <string>
#include <sstream>
#include <fstream>
@@ -28,7 +28,7 @@ private:
public:
GetConfig() : _server(), _target(nullptr) {}
- virtual ~GetConfig();
+ ~GetConfig() override;
int usage();
void initRPC(const char *spec);
void finiRPC();
@@ -216,8 +216,7 @@ GetConfig::Main()
vespaVersion = VespaVersion::fromString(vespaVersionString);
}
- int protocolVersion = config::protocol::readProtocolVersion();
- FRTConfigRequestFactory requestFactory(protocolVersion, traceLevel, vespaVersion, config::protocol::readProtocolCompressionType());
+ FRTConfigRequestFactory requestFactory(traceLevel, vespaVersion, config::protocol::readProtocolCompressionType());
FRTConnection connection(spec, _server->supervisor(), TimingValues());
ConfigKey key(configId, defName, defNamespace, defMD5, defSchema);
ConfigState state(configMD5, generation, false);
@@ -244,7 +243,6 @@ GetConfig::Main()
printf("configMD5 %s\n", rState.md5.c_str());
printf("generation %" PRId64 "\n", rState.generation);
- printf("internalRedeploy %s\n", rState.internalRedeploy == 0 ? "false" : "true");
printf("trace %s\n", response->getTrace().toString().c_str());
} else if (traceLevel > 0) {
printf("trace %s\n", response->getTrace().toString().c_str());
diff --git a/config/src/apps/vespa-ping-configproxy/pingproxy.cpp b/config/src/apps/vespa-ping-configproxy/pingproxy.cpp
index 208f9312ada..a47fd25f9af 100644
--- a/config/src/apps/vespa-ping-configproxy/pingproxy.cpp
+++ b/config/src/apps/vespa-ping-configproxy/pingproxy.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <sstream>
@@ -15,12 +17,11 @@ private:
std::unique_ptr<fnet::frt::StandaloneFRT> _server;
FRT_Target *_target;
- PingProxy(const PingProxy &);
- PingProxy &operator=(const PingProxy &);
-
public:
+ PingProxy(const PingProxy &) = delete;
+ PingProxy &operator=(const PingProxy &) = delete;
PingProxy() : _server(), _target(nullptr) {}
- virtual ~PingProxy();
+ ~PingProxy() override ;
int usage();
void initRPC(const char *spec);
void finiRPC();
diff --git a/config/src/main/java/com/yahoo/config/subscription/ConfigGetter.java b/config/src/main/java/com/yahoo/config/subscription/ConfigGetter.java
index b2aa0147259..e3d1f2eac55 100755
--- a/config/src/main/java/com/yahoo/config/subscription/ConfigGetter.java
+++ b/config/src/main/java/com/yahoo/config/subscription/ConfigGetter.java
@@ -50,7 +50,7 @@ public class ConfigGetter<T extends ConfigInstance> {
try (ConfigSubscriber subscriber =
source == null ? new ConfigSubscriber() : new ConfigSubscriber(source)) {
ConfigHandle<T> handle = subscriber.subscribe(clazz, configId);
- subscriber.nextConfig();
+ subscriber.nextConfig(true);
return handle.getConfig();
}
}
diff --git a/config/src/main/java/com/yahoo/config/subscription/ConfigHandle.java b/config/src/main/java/com/yahoo/config/subscription/ConfigHandle.java
index c0eb3e98157..6a271f6a401 100644
--- a/config/src/main/java/com/yahoo/config/subscription/ConfigHandle.java
+++ b/config/src/main/java/com/yahoo/config/subscription/ConfigHandle.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.config.subscription;
-
import com.yahoo.config.ConfigInstance;
import com.yahoo.config.subscription.impl.ConfigSubscription;
@@ -23,7 +22,6 @@ public class ConfigHandle<T extends ConfigInstance> {
/**
* Returns true if:
- *
* The config generation for the {@link ConfigSubscriber} that produced this is the first one in its life cycle. (Typically first time config.)
* or
* All configs for the subscriber have a new generation since the last time nextConfig() was called
diff --git a/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java b/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java
index 6bfaa992eb1..558213c43b9 100644
--- a/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java
+++ b/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java
@@ -33,6 +33,7 @@ import static java.util.stream.Collectors.toList;
public class ConfigSubscriber implements AutoCloseable {
private static final Logger log = Logger.getLogger(ConfigSubscriber.class.getName());
+
private State state = State.OPEN;
protected final List<ConfigHandle<? extends ConfigInstance>> subscriptionHandles = new CopyOnWriteArrayList<>();
private final ConfigSource source;
@@ -42,8 +43,12 @@ public class ConfigSubscriber implements AutoCloseable {
/** The last complete config generation received by this */
private long generation = -1;
- /** Whether the last generation received was due to a system-internal redeploy, not an application package change */
- private boolean internalRedeploy = false;
+ /**
+ * Whether the last generation should only be applied on restart, not immediately.
+ * Once this is set it will not be unset, as no future generation should be applied
+ * once there is a generation which require restart.
+ */
+ private boolean applyOnRestart = false;
/**
* Reuse requesters for equal source sets, limit number if many subscriptions.
@@ -150,11 +155,18 @@ public class ConfigSubscriber implements AutoCloseable {
*
* If the call times out (timeout 1000 ms), no handle will have the changed flag set. You should not configure anything then.
*
+ * @param isInitializing true if this the config is needed to create the initial configuration for the caller,
+ * false if this is for reconfiguration
* @return true if a config/reconfig of your system should happen
* @throws ConfigInterruptedException if thread performing this call interrupted.
*/
+ public boolean nextConfig(boolean isInitializing) {
+ return nextConfig(TimingValues.defaultNextConfigTimeout, isInitializing);
+ }
+
+ @Deprecated // TODO: Remove on Vespa 8
public boolean nextConfig() {
- return nextConfig(TimingValues.defaultNextConfigTimeout);
+ return nextConfig(false);
}
/**
@@ -174,11 +186,18 @@ public class ConfigSubscriber implements AutoCloseable {
* If the call times out, no handle will have the changed flag set. You should not configure anything then.
*
* @param timeoutMillis timeout in milliseconds
+ * @param isInitializing true if this the config is needed to create the initial configuration for the caller,
+ * false if this is for reconfiguration
* @return true if a config/reconfig of your system should happen
* @throws ConfigInterruptedException if thread performing this call interrupted.
*/
+ public boolean nextConfig(long timeoutMillis, boolean isInitializing) {
+ return acquireSnapshot(timeoutMillis, true, isInitializing);
+ }
+
+ @Deprecated // TODO: Remove on Vespa 8
public boolean nextConfig(long timeoutMillis) {
- return acquireSnapshot(timeoutMillis, true);
+ return nextConfig(timeoutMillis, false);
}
/**
@@ -198,11 +217,18 @@ public class ConfigSubscriber implements AutoCloseable {
*
* If the call times out (timeout 1000 ms), no handle will have the changed flag set. You should not configure anything then.
*
+ * @param isInitializing true if this the next generation is needed to create the initial configuration for the caller,
+ * false if this is for reconfiguration
* @return true if generations for all configs have been updated.
* @throws ConfigInterruptedException if thread performing this call interrupted.
*/
+ public boolean nextGeneration(boolean isInitializing) {
+ return nextGeneration(TimingValues.defaultNextConfigTimeout, isInitializing);
+ }
+
+ @Deprecated // TODO: Remove on Vespa 8
public boolean nextGeneration() {
- return nextGeneration(TimingValues.defaultNextConfigTimeout);
+ return nextGeneration(false);
}
/**
@@ -222,11 +248,18 @@ public class ConfigSubscriber implements AutoCloseable {
* If the call times out (timeout 1000 ms), no handle will have the changed flag set. You should not configure anything then.
*
* @param timeoutMillis timeout in milliseconds
+ * @param isInitializing true if this the next generation is needed to create the initial configuration for the caller,
+ * false if this is for reconfiguration
* @return true if generations for all configs have been updated.
* @throws ConfigInterruptedException if thread performing this call interrupted.
*/
+ public boolean nextGeneration(long timeoutMillis, boolean isInitializing) {
+ return acquireSnapshot(timeoutMillis, false, isInitializing);
+ }
+
+ @Deprecated // TODO: Remov4e on Vespa 8
public boolean nextGeneration(long timeoutMillis) {
- return acquireSnapshot(timeoutMillis, false);
+ return nextGeneration(timeoutMillis, false);
}
/**
@@ -235,12 +268,15 @@ public class ConfigSubscriber implements AutoCloseable {
* @param timeoutInMillis timeout to wait in milliseconds
* @param requireChange if set, at least one config have to change
* @return true, if a new config generation has been found for all configs (additionally requires
- * that at lest one of them has changed if <code>requireChange</code> is true), false otherwise
+ * that at lest one of them has changed if <code>requireChange</code> is true), and
+ * the config should be applied at this time, false otherwise
*/
- private boolean acquireSnapshot(long timeoutInMillis, boolean requireChange) {
+ private boolean acquireSnapshot(long timeoutInMillis, boolean requireChange, boolean isInitializing) {
+ boolean applyOnRestartOnly;
synchronized (monitor) {
if (state == State.CLOSED) return false;
state = State.FROZEN;
+ applyOnRestartOnly = applyOnRestart;
}
long started = System.currentTimeMillis();
long timeLeftMillis = timeoutInMillis;
@@ -251,7 +287,6 @@ public class ConfigSubscriber implements AutoCloseable {
h.setChanged(false); // Reset this flag, if it was set, the user should have acted on it the last time this method returned true.
}
boolean reconfigDue;
- boolean internalRedeployOnly = true;
do {
boolean allGenerationsChanged = true;
boolean allGenerationsTheSame = true;
@@ -268,10 +303,18 @@ public class ConfigSubscriber implements AutoCloseable {
allGenerationsTheSame &= currentGen.equals(config.getGeneration());
allGenerationsChanged &= config.isGenerationChanged();
anyConfigChanged |= config.isConfigChanged();
- internalRedeployOnly &= config.isInternalRedeploy();
+ applyOnRestartOnly |= config.applyOnRestart();
timeLeftMillis = timeoutInMillis + started - System.currentTimeMillis();
}
- reconfigDue = (anyConfigChanged || !requireChange) && allGenerationsChanged && allGenerationsTheSame;
+ reconfigDue = (isInitializing || !applyOnRestartOnly) && (anyConfigChanged || !requireChange)
+ && allGenerationsChanged && allGenerationsTheSame;
+
+ if (applyOnRestartOnly && ! isInitializing) { // disable any reconfig until restart
+ synchronized (monitor) {
+ applyOnRestart = applyOnRestartOnly;
+ }
+ }
+
if (!reconfigDue && timeLeftMillis > 0) {
sleep(timeLeftMillis);
}
@@ -281,7 +324,6 @@ public class ConfigSubscriber implements AutoCloseable {
// Also if appropriate update the changed flag on the handler, which clients use.
markSubsChangedSeen(currentGen);
synchronized (monitor) {
- internalRedeploy = internalRedeployOnly;
generation = currentGen;
}
}
@@ -471,12 +513,6 @@ public class ConfigSubscriber implements AutoCloseable {
}
/**
- * Whether the current config generation received by this was due to a system-internal redeploy,
- * not an application package change
- */
- public boolean isInternalRedeploy() { synchronized (monitor) { return internalRedeploy; } }
-
- /**
* Convenience interface for clients who only subscribe to one config. Implement this, and pass it to {@link ConfigSubscriber#subscribe(SingleSubscriber, Class, String)}.
*
* @author vegardh
diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java
index 3bf6093e872..b58817305e9 100644
--- a/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java
+++ b/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java
@@ -25,7 +25,7 @@ import com.yahoo.vespa.config.protocol.DefContent;
*/
public abstract class ConfigSubscription<T extends ConfigInstance> {
- protected static Logger log = Logger.getLogger(ConfigSubscription.class.getName());
+ protected static final Logger log = Logger.getLogger(ConfigSubscription.class.getName());
protected final ConfigSubscriber subscriber;
private final AtomicReference<ConfigState<T>> config = new AtomicReference<>();
protected final ConfigKey<T> key;
@@ -39,12 +39,16 @@ public abstract class ConfigSubscription<T extends ConfigInstance> {
private final boolean generationChanged;
private final T config;
private final Long generation;
- private final boolean internalRedeploy;
+ private final boolean applyOnRestart;
- private ConfigState(boolean generationChanged, Long generation, boolean internalRedeploy, boolean configChanged, T config) {
+ private ConfigState(boolean generationChanged,
+ Long generation,
+ boolean applyOnRestart,
+ boolean configChanged,
+ T config) {
this.generationChanged = generationChanged;
this.generation = generation;
- this.internalRedeploy = internalRedeploy;
+ this.applyOnRestart = applyOnRestart;
this.configChanged = configChanged;
this.config = config;
}
@@ -62,11 +66,7 @@ public abstract class ConfigSubscription<T extends ConfigInstance> {
public boolean isGenerationChanged() { return generationChanged; }
public Long getGeneration() { return generation; }
- /**
- * Returns whether this config generation was caused by a system-internal redeploy,
- * not an application package change
- */
- public boolean isInternalRedeploy() { return internalRedeploy; }
+ public boolean applyOnRestart() { return applyOnRestart; }
public T getConfig() { return config; }
@@ -181,29 +181,29 @@ public abstract class ConfigSubscription<T extends ConfigInstance> {
return !prev.getGeneration().equals(requiredGen) || prev.isConfigChanged();
}
- void setConfig(Long generation, boolean internalRedeploy, T config) {
- this.config.set(new ConfigState<>(true, generation, internalRedeploy, true, config));
+ void setConfig(Long generation, boolean applyOnRestart, T config) {
+ this.config.set(new ConfigState<>(true, generation, applyOnRestart, true, config));
}
/** Used by {@link FileConfigSubscription} and {@link ConfigSetSubscription} */
protected void setConfigIncGen(T config) {
ConfigState<T> prev = this.config.get();
- this.config.set(new ConfigState<>(true, prev.getGeneration() + 1, prev.isInternalRedeploy(), true, config));
+ this.config.set(new ConfigState<>(true, prev.getGeneration() + 1, prev.applyOnRestart(), true, config));
}
protected void setConfigIfChanged(T config) {
ConfigState<T> prev = this.config.get();
- this.config.set(new ConfigState<>(true, prev.getGeneration(), prev.isInternalRedeploy(), !config.equals(prev.getConfig()), config));
+ this.config.set(new ConfigState<>(true, prev.getGeneration(), prev.applyOnRestart(), !config.equals(prev.getConfig()), config));
}
void setGeneration(Long generation) {
ConfigState<T> prev = config.get();
- this.config.set(new ConfigState<>(true, generation, prev.isInternalRedeploy(), prev.isConfigChanged(), prev.getConfig()));
+ this.config.set(new ConfigState<>(true, generation, prev.applyOnRestart(), prev.isConfigChanged(), prev.getConfig()));
}
- void setInternalRedeploy(boolean internalRedeploy) {
+ void setApplyOnRestart(boolean applyOnRestart) {
ConfigState<T> prev = config.get();
- this.config.set(new ConfigState<>(prev.isGenerationChanged(), prev.getGeneration(), internalRedeploy, prev.isConfigChanged(), prev.getConfig()));
+ this.config.set(new ConfigState<>(prev.isGenerationChanged(), prev.getGeneration(), applyOnRestart, prev.isConfigChanged(), prev.getConfig()));
}
/**
diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java
index eec18b93e71..b052c79f429 100644
--- a/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java
+++ b/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java
@@ -18,7 +18,6 @@ import static java.util.logging.Level.FINE;
* Used by config proxy.
*
* @author Vegard Havdal
- *
*/
public class GenericJRTConfigSubscription extends JRTConfigSubscription<RawConfig> {
@@ -33,7 +32,7 @@ public class GenericJRTConfigSubscription extends JRTConfigSubscription<RawConfi
@Override
protected void setNewConfig(JRTClientConfigRequest jrtReq) {
- setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsInternalRedeploy(), RawConfig.createFromResponseParameters(jrtReq) );
+ setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsApplyOnRestart(), RawConfig.createFromResponseParameters(jrtReq) );
log.log(FINE, () -> "in setNewConfig, config=" + this.getConfigState().getConfig());
}
@@ -51,12 +50,12 @@ public class GenericJRTConfigSubscription extends JRTConfigSubscription<RawConfi
// Override to propagate internal redeploy into the config value in addition to the config state
@Override
- void setInternalRedeploy(boolean internalRedeploy) {
- super.setInternalRedeploy(internalRedeploy);
+ void setApplyOnRestart(boolean applyOnRestart) {
+ super.setApplyOnRestart(applyOnRestart);
ConfigState<RawConfig> configState = getConfigState();
if (configState.getConfig() != null) {
- configState.getConfig().setInternalRedeploy(internalRedeploy);
+ configState.getConfig().setApplyOnRestart(applyOnRestart);
}
}
diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
index 44f6d65ee65..b48e5905239 100644
--- a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
+++ b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
@@ -93,7 +93,7 @@ public class JRTConfigSubscription<T extends ConfigInstance> extends ConfigSubsc
}
log.log(FINE, () -> "Polled queue and found config " + jrtReq);
if (jrtReq.hasUpdatedGeneration()) {
- setInternalRedeploy(jrtReq.responseIsInternalRedeploy());
+ setApplyOnRestart(jrtReq.responseIsApplyOnRestart());
if (jrtReq.hasUpdatedConfig()) {
setNewConfig(jrtReq);
} else {
@@ -111,7 +111,7 @@ public class JRTConfigSubscription<T extends ConfigInstance> extends ConfigSubsc
} catch (IllegalArgumentException e) {
badConfigE = e;
}
- setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsInternalRedeploy(), configInstance);
+ setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsApplyOnRestart(), configInstance);
if (badConfigE != null) {
throw new IllegalArgumentException("Bad config from jrt", badConfigE);
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java
index 2f3a4bd2172..8153179e49c 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java
@@ -17,7 +17,7 @@ import java.io.IOException;
import java.io.OutputStream;
/**
- * A class that holds a representation of a config payload.
+ * A config payload.
*
* @author Ulf Lilleengen
*/
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
index b4df42c802e..d24f09bda12 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
@@ -38,6 +38,7 @@ import static java.util.logging.Level.INFO;
* @author Ulf Lilleengen, hmusum, Tony Vaagenes
*/
public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
+
private final static Logger log = Logger.getLogger(ConfigPayloadApplier.class.getPackage().getName());
private final ConfigInstance.Builder rootBuilder;
diff --git a/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java b/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java
index 2f351cc2bd4..123d7c22093 100644
--- a/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java
+++ b/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java
@@ -12,6 +12,7 @@ import com.yahoo.config.ConfigInstance;
* @author Ulf Lilleengen
*/
public class GenericConfig {
+
public static class GenericConfigBuilder implements ConfigInstance.Builder {
private final ConfigPayloadBuilder payloadBuilder;
@@ -49,6 +50,7 @@ public class GenericConfig {
public String getDefMd5() {
return "";
}
+
}
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/RawConfig.java b/config/src/main/java/com/yahoo/vespa/config/RawConfig.java
index 96908f055f1..1c28d4c5e05 100755
--- a/config/src/main/java/com/yahoo/vespa/config/RawConfig.java
+++ b/config/src/main/java/com/yahoo/vespa/config/RawConfig.java
@@ -31,7 +31,7 @@ public class RawConfig extends ConfigInstance {
private final String configMd5;
private final Optional<VespaVersion> vespaVersion;
private long generation;
- private boolean internalRedeploy;
+ private boolean applyOnRestart;
/**
* Constructor for an empty config (not yet resolved).
@@ -44,25 +44,27 @@ public class RawConfig extends ConfigInstance {
}
public RawConfig(ConfigKey<?> key, String defMd5, Payload payload, String configMd5, long generation,
- boolean internalRedeploy, List<String> defContent, Optional<VespaVersion> vespaVersion) {
- this(key, defMd5, payload, configMd5, generation, internalRedeploy, 0, defContent, vespaVersion);
+ boolean applyOnRestart, List<String> defContent,
+ Optional<VespaVersion> vespaVersion) {
+ this(key, defMd5, payload, configMd5, generation, applyOnRestart, 0, defContent, vespaVersion);
}
/** Copy constructor */
public RawConfig(RawConfig rawConfig) {
this(rawConfig.key, rawConfig.defMd5, rawConfig.payload, rawConfig.configMd5,
- rawConfig.generation, rawConfig.internalRedeploy, rawConfig.errorCode,
- rawConfig.defContent, rawConfig.getVespaVersion());
+ rawConfig.generation, rawConfig.applyOnRestart,
+ rawConfig.errorCode, rawConfig.defContent, rawConfig.getVespaVersion());
}
public RawConfig(ConfigKey<?> key, String defMd5, Payload payload, String configMd5, long generation,
- boolean internalRedeploy, int errorCode, List<String> defContent, Optional<VespaVersion> vespaVersion) {
+ boolean applyOnRestart, int errorCode, List<String> defContent,
+ Optional<VespaVersion> vespaVersion) {
this.key = key;
this.defMd5 = ConfigUtils.getDefMd5FromRequest(defMd5, defContent);
this.payload = payload;
this.configMd5 = configMd5;
this.generation = generation;
- this.internalRedeploy = internalRedeploy;
+ this.applyOnRestart = applyOnRestart;
this.errorCode = errorCode;
this.defContent = defContent;
this.vespaVersion = vespaVersion;
@@ -79,7 +81,7 @@ public class RawConfig extends ConfigInstance {
req.getNewPayload(),
req.getNewConfigMd5(),
req.getNewGeneration(),
- req.responseIsInternalRedeploy(),
+ req.responseIsApplyOnRestart(),
0,
req.getDefContent().asList(),
req.getVespaVersion());
@@ -96,7 +98,7 @@ public class RawConfig extends ConfigInstance {
Payload.from(new Utf8String(""), CompressionInfo.uncompressed()),
req.getRequestConfigMd5(),
req.getRequestGeneration(),
- req.isInternalRedeploy(),
+ req.applyOnRestart(),
0,
req.getDefContent().asList(),
req.getVespaVersion());
@@ -119,13 +121,9 @@ public class RawConfig extends ConfigInstance {
public void setGeneration(long generation) { this.generation = generation; }
- public void setInternalRedeploy(boolean internalRedeploy) { this.internalRedeploy = internalRedeploy; }
+ public void setApplyOnRestart(boolean applyOnRestart) { this.applyOnRestart = applyOnRestart; }
- /**
- * Returns whether this config generation was created by a system internal redeploy, not an
- * application package change.
- */
- public boolean isInternalRedeploy() { return internalRedeploy; }
+ public boolean applyOnRestart() { return applyOnRestart; }
public Payload getPayload() { return payload; }
@@ -165,24 +163,17 @@ public class RawConfig extends ConfigInstance {
@Override
public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (! (o instanceof RawConfig)) {
- return false;
- }
+ if (o == this) return true;
+ if (! (o instanceof RawConfig)) return false;
+
RawConfig other = (RawConfig) o;
- if (! (key.equals(other.key) &&
- defMd5.equals(other.defMd5) &&
- (errorCode == other.errorCode)) ) {
+ if (! (key.equals(other.key) && defMd5.equals(other.defMd5) && (errorCode == other.errorCode)) )
return false;
- }
+
// Need to check error codes before isError, since unequal error codes always means unequal requests,
// while non-zero and equal error codes means configs are equal.
- if (isError())
- return true;
- if (generation != other.generation)
- return false;
+ if (isError()) return true;
+ if (generation != other.generation) return false;
if (configMd5 != null) {
return configMd5.equals(other.configMd5);
} else {
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/CompilationTask.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/CompilationTask.java
deleted file mode 100644
index 05125f8b08b..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/CompilationTask.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-import javax.tools.Diagnostic;
-import javax.tools.DiagnosticCollector;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-
-/**
- * Represents a compilation task that can be run and also collects diagnostic messages from the compilation.
- * TODO: Assumes that diagnostics is the same as given to the task, not ideal.
- *
- * @author Ulf Lilleengen
- */
-class CompilationTask {
- private final JavaCompiler.CompilationTask task;
- private final DiagnosticCollector<JavaFileObject> diagnostics;
-
- CompilationTask(JavaCompiler.CompilationTask task, DiagnosticCollector<JavaFileObject> diagnostics) {
- this.task = task;
- this.diagnostics = diagnostics;
- }
-
- void call() {
- boolean success = task.call();
- if (!success) {
- throw new IllegalArgumentException("Compilation diagnostics: " + getDiagnosticMessage());
- }
- }
-
- private String getDiagnosticMessage() {
- StringBuilder diagnosticMessages = new StringBuilder();
- for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
- diagnosticMessages.append(diagnostic.getCode()).append("\n");
- diagnosticMessages.append(diagnostic.getKind()).append("\n");
- diagnosticMessages.append(diagnostic.getPosition()).append("\n");
- diagnosticMessages.append(diagnostic.getStartPosition()).append("\n");
- diagnosticMessages.append(diagnostic.getEndPosition()).append("\n");
- diagnosticMessages.append(diagnostic.getSource()).append("\n");
- diagnosticMessages.append(diagnostic.getMessage(null)).append("\n");
- }
- return diagnosticMessages.toString();
- }
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/CompiledBuilder.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/CompiledBuilder.java
deleted file mode 100644
index fa5cf427aad..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/CompiledBuilder.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-import com.yahoo.config.ConfigInstance;
-
-/**
- * Represents a builder that can be instantiated.
- *
- * @author Ulf Lilleengen
- */
-public interface CompiledBuilder {
- <BUILDER extends ConfigInstance.Builder> BUILDER newInstance();
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigCompiler.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigCompiler.java
deleted file mode 100644
index 9473a05332f..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigCompiler.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-/**
- * Interface towards compilers for compiling builders from a config class definition.
- *
- * @author Ulf Lilleengen
- */
-public interface ConfigCompiler {
-
- CompiledBuilder compile(ConfigDefinitionClass defClass);
-
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java
index 7ded55e046a..3fe42ce90ad 100644
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java
+++ b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java
@@ -1,13 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.buildergen;
-import com.google.common.io.Files;
import com.yahoo.config.codegen.DefParser;
import com.yahoo.config.codegen.InnerCNode;
-import com.yahoo.config.codegen.JavaClassBuilder;
import com.yahoo.text.StringUtilities;
-import java.io.File;
import java.io.StringReader;
/**
@@ -15,6 +12,7 @@ import java.io.StringReader;
* @author Ulf Lilleengen
*/
public class ConfigDefinition {
+
private final String name;
private final String[] defSchema;
private final InnerCNode cnode;
@@ -30,12 +28,4 @@ public class ConfigDefinition {
return cnode;
}
- public ConfigDefinitionClass generateClass() {
- File tempDir = Files.createTempDir();
- DefParser parser = new DefParser(name, new StringReader(StringUtilities.implode(defSchema, "\n")));
- JavaClassBuilder builder = new JavaClassBuilder(parser.getTree(), parser.getNormalizedDefinition(), tempDir, null);
- String className = builder.className();
- return new ConfigDefinitionClass(className, builder.javaPackage(), builder.getConfigClass(className));
- }
-
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinitionClass.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinitionClass.java
deleted file mode 100644
index 8f222de3b55..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinitionClass.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-/**
- * @author Ulf Lilleengen
- */
-class ConfigDefinitionClass {
-
- private final String name;
- private final String pkg;
- private final String definition;
-
- ConfigDefinitionClass(String name, String pkg, String definition) {
- this.name = name;
- this.pkg = pkg;
- this.definition = definition;
- }
-
- String getDefinition() {
- return definition;
- }
-
- String getName() {
- return pkg + "." + name;
- }
-
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/LazyConfigCompiler.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/LazyConfigCompiler.java
deleted file mode 100644
index 2af19d1c6f2..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/LazyConfigCompiler.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-import com.yahoo.config.ConfigInstance;
-
-import javax.tools.*;
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-import java.util.Locale;
-
-/**
- * Represents a compiler that waits performing the compilation until the requested builder is requested from the
- * {@link CompiledBuilder}.
- *
- * @author Ulf Lilleengen
- */
-public class LazyConfigCompiler implements ConfigCompiler {
-
- private final File outputDirectory;
- private final ClassLoader classLoader;
- private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-
- public LazyConfigCompiler(File outputDirectory) {
- this.outputDirectory = outputDirectory;
- try {
- this.classLoader = new URLClassLoader(new URL[]{outputDirectory.toURI().toURL()});
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException("Unable to create class loader for directory '" + outputDirectory.getAbsolutePath() + "'", e);
- }
- }
-
- @Override
- public CompiledBuilder compile(ConfigDefinitionClass defClass) {
- Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(new StringSourceObject(defClass.getName(), defClass.getDefinition()));
- DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
-
- StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, Locale.ENGLISH, null);
- Iterable<String> options = Arrays.asList("-d", outputDirectory.getAbsolutePath());
- JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
- return new LazyCompiledBuilder(classLoader, defClass.getName(), new CompilationTask(task, diagnostics));
- }
-
- /**
- * Lazy implementation of compiled builder that defers compilation until class is requested.
- */
- private static class LazyCompiledBuilder implements CompiledBuilder {
- private final ClassLoader classLoader;
- private final String classUrl;
- private final CompilationTask compilationTask;
- private LazyCompiledBuilder(ClassLoader classLoader, String classUrl, CompilationTask compilationTask) {
- this.classLoader = classLoader;
- this.classUrl = classUrl;
- this.compilationTask = compilationTask;
- }
-
- @Override
- public <BUILDER extends ConfigInstance.Builder> BUILDER newInstance() {
- compileBuilder();
- String builderClassUrl = classUrl + "$Builder";
- return loadBuilder(builderClassUrl);
-
- }
-
- private void compileBuilder() {
- try {
- compilationTask.call();
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Error compiling '" + classUrl + "'", e);
- }
- }
-
- @SuppressWarnings("unchecked")
- private <BUILDER extends ConfigInstance.Builder> BUILDER loadBuilder(String builderClassUrl) {
- try {
- Class<BUILDER> clazz = (Class<BUILDER>) classLoader.loadClass(builderClassUrl);
- return clazz.getDeclaredConstructor().newInstance();
- } catch (ReflectiveOperationException e) {
- throw new RuntimeException("Error creating new instance of '" + builderClassUrl + "'", e);
- }
- }
- }
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/StringSourceObject.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/StringSourceObject.java
deleted file mode 100644
index c67d2121844..00000000000
--- a/config/src/main/java/com/yahoo/vespa/config/buildergen/StringSourceObject.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-import javax.tools.SimpleJavaFileObject;
-import java.net.URI;
-
-/**
- * Represents an in memory source object that can be compiled.
- *
- * @author Ulf Lilleengen
- */
-class StringSourceObject extends SimpleJavaFileObject {
- private final String code;
- StringSourceObject(String name, String code) {
- super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),Kind.SOURCE);
- this.code = code;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return code;
- }
-}
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java b/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java
index bb0ee2bb935..31e280e708c 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java
@@ -20,7 +20,7 @@ public interface ConfigResponse {
long getGeneration();
- boolean isInternalRedeploy();
+ boolean applyOnRestart();
String getConfigMd5();
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java
index ab47fec0641..8535cc23225 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java
@@ -53,8 +53,8 @@ public interface JRTClientConfigRequest extends JRTConfigRequest {
*/
long getNewGeneration();
- /** Returns whether this config change is due to an internal change not an application package change */
- boolean responseIsInternalRedeploy();
+ /** Returns true if this config should only be applied at the last restart, false if it should be applied immediately */
+ boolean responseIsApplyOnRestart();
/**
* Get the config md5 of the config returned by the server. Return an empty string if no response has been returned.
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java
index 12e5968ab83..87e63399fc3 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java
@@ -180,7 +180,7 @@ public class JRTClientConfigRequestV3 implements JRTClientConfigRequest {
.append("'\n");
sb.append("response='").append(getNewConfigMd5())
.append(",").append(getNewGeneration())
- .append(",").append(responseIsInternalRedeploy())
+ .append(",").append(responseIsApplyOnRestart())
.append("'\n");
return sb.toString();
}
@@ -290,8 +290,8 @@ public class JRTClientConfigRequestV3 implements JRTClientConfigRequest {
}
@Override
- public boolean responseIsInternalRedeploy() {
- return responseData.getResponseInternalRedeployment();
+ public boolean responseIsApplyOnRestart() {
+ return responseData.getResponseApplyOnRestart();
}
@Override
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java
index 763f672a513..c085be5924c 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java
@@ -32,11 +32,11 @@ public interface JRTServerConfigRequest extends JRTConfigRequest, GetConfigReque
*
* @param payload The config payload that the client should receive.
* @param generation The config generation of the given payload.
- * @param internalRedeployment whether this payload was generated from an internal redeployment not an
- * application package change
+ * @param applyOnRestart true if this config should only be applied on the next restart,
+ * false if it should be applied right away
* @param configMd5 The md5sum of the given payload.
*/
- void addOkResponse(Payload payload, long generation, boolean internalRedeployment, String configMd5);
+ void addOkResponse(Payload payload, long generation, boolean applyOnRestart, String configMd5);
/**
* Get the current config md5 of the client config.
@@ -59,11 +59,7 @@ public interface JRTServerConfigRequest extends JRTConfigRequest, GetConfigReque
*/
boolean isDelayedResponse();
- /**
- * Returns whether the response config was created by a system internal redeploy, not an application
- * package change
- */
- boolean isInternalRedeploy();
+ boolean applyOnRestart();
/**
* Get the request trace for this request. The trace can be used to trace config execution to provide useful
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java
index 3609ba04424..53a2f4019f9 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java
@@ -36,7 +36,7 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest {
protected final Request request;
private final SlimeRequestData requestData;
/** Response field */
- private boolean internalRedeploy = false;
+ private boolean applyOnRestart = false;
// Response values
private boolean isDelayed = false;
private Trace requestTrace = null;
@@ -67,8 +67,8 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest {
}
@Override
- public void addOkResponse(Payload payload, long generation, boolean internalRedeploy, String configMd5) {
- this.internalRedeploy = internalRedeploy;
+ public void addOkResponse(Payload payload, long generation, boolean applyOnRestart, String configMd5) {
+ this.applyOnRestart = applyOnRestart;
boolean changedConfig = !configMd5.equals(getRequestConfigMd5());
boolean changedConfigAndNewGeneration = changedConfig && ConfigUtils.isGenerationNewer(generation, getRequestGeneration());
Payload responsePayload = payload.withCompression(getCompressionType());
@@ -79,7 +79,7 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest {
addCommonReturnValues(jsonGenerator);
setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_CONFIG_MD5, configMd5);
setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_CONFIG_GENERATION, generation);
- setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_INTERNAL_REDEPLOY, internalRedeploy);
+ setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_APPLY_ON_RESTART, applyOnRestart);
jsonGenerator.writeObjectFieldStart(SlimeResponseData.RESPONSE_COMPRESSION_INFO);
if (responsePayload == null) {
throw new RuntimeException("Payload is null for ' " + this + ", not able to create response");
@@ -111,7 +111,7 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest {
}
@Override
- public boolean isInternalRedeploy() { return internalRedeploy; }
+ public boolean applyOnRestart() { return applyOnRestart; }
public static JRTServerConfigRequestV3 createFromRequest(Request req) {
return new JRTServerConfigRequestV3(req);
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java
index ff0b7f964bf..1fec7e17d06 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java
@@ -17,25 +17,25 @@ public class SlimeConfigResponse implements ConfigResponse {
private final Utf8Array payload;
private final CompressionInfo compressionInfo;
private final long generation;
- private final boolean internalRedeploy;
+ private final boolean applyOnRestart;
private final String configMd5;
public static SlimeConfigResponse fromConfigPayload(ConfigPayload payload, long generation,
- boolean internalRedeploy, String configMd5) {
+ boolean applyOnRestart, String configMd5) {
Utf8Array data = payload.toUtf8Array(true);
- return new SlimeConfigResponse(data, generation, internalRedeploy,
+ return new SlimeConfigResponse(data, generation, applyOnRestart,
configMd5,
CompressionInfo.create(CompressionType.UNCOMPRESSED, data.getByteLength()));
}
public SlimeConfigResponse(Utf8Array payload,
long generation,
- boolean internalRedeploy,
+ boolean applyOnRestart,
String configMd5,
CompressionInfo compressionInfo) {
this.payload = payload;
this.generation = generation;
- this.internalRedeploy = internalRedeploy;
+ this.applyOnRestart = applyOnRestart;
this.configMd5 = configMd5;
this.compressionInfo = compressionInfo;
}
@@ -50,12 +50,8 @@ public class SlimeConfigResponse implements ConfigResponse {
return generation;
}
- /**
- * Returns whether this application instance was produced by an internal redeployment,
- * not an application package change
- */
@Override
- public boolean isInternalRedeploy() { return internalRedeploy; }
+ public boolean applyOnRestart() { return applyOnRestart; }
@Override
public String getConfigMd5() {
diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java
index ba1e7a8c72e..cc98587456c 100644
--- a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java
+++ b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java
@@ -23,7 +23,7 @@ class SlimeResponseData {
static final String RESPONSE_TRACE = "trace";
static final String RESPONSE_CONFIG_MD5 = "configMD5";
static final String RESPONSE_CONFIG_GENERATION = "generation";
- static final String RESPONSE_INTERNAL_REDEPLOY = "internalRedeploy";
+ static final String RESPONSE_APPLY_ON_RESTART = "applyOnRestart";
static final String RESPONSE_COMPRESSION_INFO = "compressionInfo";
private final Request request;
@@ -67,8 +67,8 @@ class SlimeResponseData {
return CompressionInfo.fromSlime(getResponseField(RESPONSE_COMPRESSION_INFO));
}
- boolean getResponseInternalRedeployment() {
- Inspector inspector = getResponseField(RESPONSE_INTERNAL_REDEPLOY);
+ boolean getResponseApplyOnRestart() {
+ Inspector inspector = getResponseField(RESPONSE_APPLY_ON_RESTART);
return inspector.valid() && inspector.asBool();
}
diff --git a/config/src/test/java/com/yahoo/config/subscription/AppService.java b/config/src/test/java/com/yahoo/config/subscription/AppService.java
index 0f8d93e6fe0..3cf301a9b03 100644
--- a/config/src/test/java/com/yahoo/config/subscription/AppService.java
+++ b/config/src/test/java/com/yahoo/config/subscription/AppService.java
@@ -11,6 +11,7 @@ import com.yahoo.vespa.config.TimingValues;
* generated code in AppConfig.java.
*/
class AppService {
+
private int timesConfigured = 0;
private AppConfig config = null;
@@ -33,17 +34,17 @@ class AppService {
} else {
temp = subscriber.subscribe(AppConfig.class, configId, csource, timingValues);
}
- final ConfigHandle<AppConfig> handle = temp;
+ ConfigHandle<AppConfig> handle = temp;
Thread configThread = new Thread(() -> {
while (!stopThread) {
- boolean changed = subscriber.nextConfig(500);
+ boolean changed = subscriber.nextConfig(500, false);
if (changed) {
configure(handle.getConfig());
timesConfigured++;
}
}
});
- subscriber.nextConfig(5000);
+ subscriber.nextConfig(5000, false);
timesConfigured++;
configure(handle.getConfig());
configThread.setDaemon(true);
diff --git a/config/src/test/java/com/yahoo/config/subscription/BasicTest.java b/config/src/test/java/com/yahoo/config/subscription/BasicTest.java
index 5b145d40b7f..5af45e3a999 100644
--- a/config/src/test/java/com/yahoo/config/subscription/BasicTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/BasicTest.java
@@ -15,7 +15,7 @@ public class BasicTest {
public void testSubBasic() {
ConfigSubscriber s = new ConfigSubscriber();
ConfigHandle<AppConfig> h = s.subscribe(AppConfig.class, "raw:times 0");
- s.nextConfig(0);
+ s.nextConfig(0, false);
AppConfig c = h.getConfig();
assertEquals(0, c.times());
s.close();
@@ -25,7 +25,7 @@ public class BasicTest {
public void testSubBasicGeneration() {
ConfigSubscriber s = new ConfigSubscriber();
ConfigHandle<AppConfig> h = s.subscribe(AppConfig.class, "raw:times 2");
- s.nextGeneration(0);
+ s.nextGeneration(0, false);
AppConfig c = h.getConfig();
assertEquals(2, c.times());
s.close();
diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigApiTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigApiTest.java
index c0080091db6..be09e57b27e 100755
--- a/config/src/test/java/com/yahoo/config/subscription/ConfigApiTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/ConfigApiTest.java
@@ -23,13 +23,13 @@ public class ConfigApiTest {
ConfigSubscriber subscriber = new ConfigSubscriber();
ConfigHandle<AppConfig> h = subscriber.subscribe(AppConfig.class, CONFIG_ID);
assertNotNull(h);
- subscriber.nextConfig();
+ subscriber.nextConfig(false);
assertNotNull(h.getConfig());
assertEquals(AppConfig.CONFIG_DEF_NAME, ConfigInstance.getDefName(h.getConfig().getClass()));
- assertThat(h.isChanged(), is(true));
+ assertTrue(h.isChanged());
assertTrue(h.toString().startsWith("Handle changed: true\nSub:\n"));
subscriber.close();
- assertThat(subscriber.state(), is(ConfigSubscriber.State.CLOSED));
+ assertEquals(ConfigSubscriber.State.CLOSED, subscriber.state());
}
/**
@@ -40,7 +40,7 @@ public class ConfigApiTest {
public void testSubscribeAfterClose() {
ConfigSubscriber subscriber = new ConfigSubscriber();
subscriber.subscribe(AppConfig.class, CONFIG_ID);
- subscriber.nextConfig();
+ subscriber.nextConfig(false);
subscriber.close();
subscriber.subscribe(AppConfig.class, CONFIG_ID);
}
@@ -52,7 +52,7 @@ public class ConfigApiTest {
public void testSubscribeAfterNextConfig() {
ConfigSubscriber subscriber = new ConfigSubscriber();
subscriber.subscribe(AppConfig.class, CONFIG_ID);
- subscriber.nextConfig();
+ subscriber.nextConfig(false);
subscriber.subscribe(AppConfig.class, CONFIG_ID);
subscriber.close();
}
diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
index 4da0c3f51e0..f706f021ba0 100644
--- a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java
@@ -114,8 +114,9 @@ public class ConfigInstanceTest {
public TestNonstring(String configId) {
ConfigSubscriber subscriber = new ConfigSubscriber();
ConfigHandle<TestNonstringConfig> handle = subscriber.subscribe(TestNonstringConfig.class, configId);
- subscriber.nextConfig();
+ subscriber.nextConfig(false);
handle.getConfig();
}
}
+
}
diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigSetSubscriptionTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigSetSubscriptionTest.java
index db30e7b7389..b31924e94e7 100644
--- a/config/src/test/java/com/yahoo/config/subscription/ConfigSetSubscriptionTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/ConfigSetSubscriptionTest.java
@@ -65,7 +65,7 @@ public class ConfigSetSubscriptionTest {
ConfigHandle<AppConfig> hA1 = subscriber.subscribe(AppConfig.class, "app/1");
ConfigHandle<StringConfig> hS = subscriber.subscribe(StringConfig.class, "bar");
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertTrue(hA0.isChanged());
assertTrue(hA1.isChanged());
assertTrue(hS.isChanged());
@@ -75,7 +75,7 @@ public class ConfigSetSubscriptionTest {
assertEquals(hA0.getConfig().times(), 88);
assertEquals(hA1.getConfig().times(), 89);
- assertFalse(subscriber.nextConfig(10));
+ assertFalse(subscriber.nextConfig(10, false));
assertFalse(hA0.isChanged());
assertFalse(hA1.isChanged());
assertFalse(hS.isChanged());
@@ -90,7 +90,7 @@ public class ConfigSetSubscriptionTest {
a1builder.message("A new message, 1").times(890);
barBuilder.stringVal("new StringVal");
subscriber.reload(1);
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertTrue(hA0.isChanged());
assertTrue(hA1.isChanged());
assertTrue(hS.isChanged());
@@ -104,7 +104,7 @@ public class ConfigSetSubscriptionTest {
// Reconfigure only one
a0builder.message("Another new message, 0").times(8800);
subscriber.reload(2);
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertTrue(hA0.isChanged());
assertFalse(hA1.isChanged());
assertFalse(hS.isChanged());
@@ -118,7 +118,7 @@ public class ConfigSetSubscriptionTest {
//Reconfigure only one, and only one field on the builder
a1builder.message("Yet another message, 1");
subscriber.reload(3);
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertFalse(hA0.isChanged());
assertTrue(hA1.isChanged());
assertFalse(hS.isChanged());
@@ -139,11 +139,11 @@ public class ConfigSetSubscriptionTest {
ConfigSubscriber subscriber = new ConfigSubscriber(myConfigs);
ConfigHandle<AppConfig> hA0 = subscriber.subscribe(AppConfig.class, "app/0");
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertTrue(hA0.isChanged());
assertEquals(hA0.getConfig().message(), "A message, 1");
- assertFalse(subscriber.nextConfig(10));
+ assertFalse(subscriber.nextConfig(10, false));
assertFalse(hA0.isChanged());
assertEquals(hA0.getConfig().message(), "A message, 1");
@@ -154,7 +154,7 @@ public class ConfigSetSubscriptionTest {
subscriber.reload(2);
// Should pick up the last one
- assertTrue(subscriber.nextConfig(0));
+ assertTrue(subscriber.nextConfig(0, false));
assertTrue(hA0.isChanged());
assertEquals(hA0.getConfig().message(), "An even newer message, 3");
}
diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigSubscriptionTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigSubscriptionTest.java
index c8d4c081fc9..f70602c64e7 100644
--- a/config/src/test/java/com/yahoo/config/subscription/ConfigSubscriptionTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/ConfigSubscriptionTest.java
@@ -68,7 +68,7 @@ public class ConfigSubscriptionTest {
ConfigSubscriber sub = new ConfigSubscriber();
ConfigHandle<SimpletypesConfig> handle = sub.subscribe(SimpletypesConfig.class, "raw:boolval true", 10000);
assertNotNull(handle);
- sub.nextConfig();
+ sub.nextConfig(false);
assertTrue(handle.getConfig().boolval());
//assertTrue(sub.getSource() instanceof RawSource);
sub.close();
diff --git a/config/src/test/java/com/yahoo/config/subscription/DefaultConfigTest.java b/config/src/test/java/com/yahoo/config/subscription/DefaultConfigTest.java
index 1bcf09a4028..21bf7469591 100644
--- a/config/src/test/java/com/yahoo/config/subscription/DefaultConfigTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/DefaultConfigTest.java
@@ -34,9 +34,8 @@ public class DefaultConfigTest {
@Test(expected = IllegalArgumentException.class)
public void testFailUponUnitializedValue() {
ConfigSubscriber subscriber = new ConfigSubscriber();
- subscriber.subscribe(DefaulttestConfig.class, "raw:" +
- "defaultstring \"new value\"");
- subscriber.nextConfig();
+ subscriber.subscribe(DefaulttestConfig.class, "raw:defaultstring \"new value\"");
+ subscriber.nextConfig(false);
subscriber.close();
}
@@ -51,7 +50,7 @@ public class DefaultConfigTest {
public void testDefaultConfig() {
ConfigSubscriber subscriber = new ConfigSubscriber();
ConfigHandle<DefaulttestConfig> h = subscriber.subscribe(DefaulttestConfig.class, CONFIG_ID);
- assertTrue(subscriber.nextConfig());
+ assertTrue(subscriber.nextConfig(false));
DefaulttestConfig config = h.getConfig();
verifyConfigValues(config);
subscriber.close();
diff --git a/config/src/test/java/com/yahoo/config/subscription/GenericConfigSubscriberTest.java b/config/src/test/java/com/yahoo/config/subscription/GenericConfigSubscriberTest.java
index 9c83f2f3c9a..d5eccdfe94b 100644
--- a/config/src/test/java/com/yahoo/config/subscription/GenericConfigSubscriberTest.java
+++ b/config/src/test/java/com/yahoo/config/subscription/GenericConfigSubscriberTest.java
@@ -38,10 +38,10 @@ public class GenericConfigSubscriberTest {
GenericConfigSubscriber sub = new GenericConfigSubscriber(requesters);
final List<String> defContent = List.of("myVal int");
GenericConfigHandle handle = sub.subscribe(new ConfigKey<>("simpletypes", "id", "config"), defContent, sourceSet, JRTConfigRequesterTest.getTestTimingValues());
- assertTrue(sub.nextConfig());
+ assertTrue(sub.nextConfig(false));
assertTrue(handle.isChanged());
assertThat(handle.getRawConfig().getPayload().withCompression(CompressionType.UNCOMPRESSED).toString(), is("{}")); // MockConnection returns empty string
- assertFalse(sub.nextConfig());
+ assertFalse(sub.nextConfig(false));
assertFalse(handle.isChanged());
}
diff --git a/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java b/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java
index 3f6c54ea46e..e1d11f82eea 100644
--- a/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java
+++ b/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java
@@ -113,7 +113,7 @@ public class RawConfigTest {
assertThat(config.getDefMd5(), is(defMd5));
config = new RawConfig(key, null, payload, configMd5, generation, false, null, Optional.empty());
assertNull(config.getDefMd5());
- config = new RawConfig(key, null, payload, configMd5, generation, false,List.of(""), Optional.empty());
+ config = new RawConfig(key, null, payload, configMd5, generation, false, List.of(""), Optional.empty());
assertThat(config.getDefMd5(), is(defMd5ForEmptyDefContent));
config = new RawConfig(key, "", payload, configMd5, generation, false, null, Optional.empty());
assertThat(config.getDefMd5(), is(""));
diff --git a/config/src/test/java/com/yahoo/vespa/config/buildergen/ConfigBuilderGeneratorTest.java b/config/src/test/java/com/yahoo/vespa/config/buildergen/ConfigBuilderGeneratorTest.java
deleted file mode 100644
index 4501768822c..00000000000
--- a/config/src/test/java/com/yahoo/vespa/config/buildergen/ConfigBuilderGeneratorTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.buildergen;
-
-import com.google.common.io.Files;
-import com.yahoo.config.ConfigInstance;
-import com.yahoo.slime.Cursor;
-import com.yahoo.slime.Slime;
-import com.yahoo.vespa.config.ConfigDefinitionKey;
-import com.yahoo.vespa.config.ConfigPayload;
-import com.yahoo.vespa.config.ConfigPayloadApplier;
-import org.junit.Test;
-
-import java.io.File;
-import java.lang.reflect.InvocationTargetException;
-
-import static com.yahoo.config.codegen.ConfiggenUtil.createClassName;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * @author Ulf Lilleengen
- */
-public class ConfigBuilderGeneratorTest {
-
- @Test
- public void require_that_custom_classes_can_be_generated() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
- String[] schema = new String[] {
- "namespace=foo.bar",
- "intval int",
- "stringval string"
- };
- File tempDir = Files.createTempDir();
- ConfigDefinitionKey key = new ConfigDefinitionKey("quux", "foo.bar");
- ConfigCompiler compiler = new LazyConfigCompiler(tempDir);
- ConfigInstance.Builder builder = compiler.compile(new ConfigDefinition(key.getName(), schema).generateClass()).newInstance();
- assertNotNull(builder);
- ConfigPayloadApplier<?> payloadApplier = new ConfigPayloadApplier<>(builder);
- Slime slime = new Slime();
- Cursor root = slime.setObject();
- root.setString("intval", "3");
- root.setString("stringval", "Hello, world");
- payloadApplier.applyPayload(new ConfigPayload(slime));
- String className = createClassName(key.getName());
- ConfigInstance instance = (ConfigInstance) builder.getClass().getClassLoader().loadClass("com.yahoo." + key.getNamespace() + "." + className).getConstructor(new Class<?>[]{builder.getClass()}).newInstance(builder);
- assertNotNull(instance);
- assertEquals("intval 3\nstringval \"Hello, world\"", instance.toString());
- }
-
-}
diff --git a/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java b/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java
index d4f8b771880..006a6fc6a0a 100644
--- a/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java
+++ b/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java
@@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
@@ -74,11 +75,10 @@ public class JRTConfigRequestV3Test {
public void emptypayload() {
ConfigPayload payload = ConfigPayload.empty();
SlimeConfigResponse response = SlimeConfigResponse.fromConfigPayload(payload, 0, false, ConfigUtils.getMd5(payload));
- serverReq.addOkResponse(serverReq.payloadFromResponse(response), response.getGeneration(), false, response.getConfigMd5());
+ serverReq.addOkResponse(serverReq.payloadFromResponse(response), response.getGeneration(), false, response.getConfigMd5());
assertTrue(clientReq.validateResponse());
assertTrue(clientReq.hasUpdatedGeneration());
- assertThat(clientReq.getNewPayload().withCompression(CompressionType.UNCOMPRESSED).getData().toString(), is("{}"));
- assertFalse(clientReq.responseIsInternalRedeploy());
+ assertEquals("{}", clientReq.getNewPayload().withCompression(CompressionType.UNCOMPRESSED).getData().toString());
}
@Test
@@ -94,9 +94,7 @@ public class JRTConfigRequestV3Test {
public void next_request_when_error_is_correct() {
serverReq.addOkResponse(createPayload(), 999999, false, "newmd5");
serverReq.addErrorResponse(ErrorCode.OUTDATED_CONFIG, "error message");
- System.out.println(serverReq);
JRTClientConfigRequest next = clientReq.nextRequest(6);
- System.out.println(next);
// Should use config md5 and generation from the request, not the response
// when there are errors
assertThat(next.getRequestConfigMd5(), is(clientReq.getRequestConfigMd5()));
diff --git a/config/src/tests/configagent/configagent.cpp b/config/src/tests/configagent/configagent.cpp
index a7cc95ab883..d6766cce822 100644
--- a/config/src/tests/configagent/configagent.cpp
+++ b/config/src/tests/configagent/configagent.cpp
@@ -141,7 +141,7 @@ TEST("require that agent returns correct values") {
ConfigState cs;
ASSERT_EQUAL(cs.md5, handler.getConfigState().md5);
ASSERT_EQUAL(cs.generation, handler.getConfigState().generation);
- ASSERT_EQUAL(cs.internalRedeploy, handler.getConfigState().internalRedeploy);
+ ASSERT_EQUAL(cs.applyOnRestart, handler.getConfigState().applyOnRestart);
}
TEST("require that successful request is delivered to holder") {
diff --git a/config/src/tests/failover/failover.cpp b/config/src/tests/failover/failover.cpp
index 99b6967c929..2e039081716 100644
--- a/config/src/tests/failover/failover.cpp
+++ b/config/src/tests/failover/failover.cpp
@@ -5,7 +5,9 @@
#include <vespa/config/frt/protocol.h>
#include <vespa/config/config.h>
#include <vespa/config/common/configcontext.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+
#include "config-my.h"
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/data/simple_buffer.h>
diff --git a/config/src/tests/file_acquirer/file_acquirer_test.cpp b/config/src/tests/file_acquirer/file_acquirer_test.cpp
index 33bb8f47e09..da4bd71b82b 100644
--- a/config/src/tests/file_acquirer/file_acquirer_test.cpp
+++ b/config/src/tests/file_acquirer/file_acquirer_test.cpp
@@ -1,7 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/config/file_acquirer/file_acquirer.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/vespalib/util/stringfmt.h>
using namespace config;
diff --git a/config/src/tests/frt/frt.cpp b/config/src/tests/frt/frt.cpp
index 85b9789821d..6cffe079dae 100644
--- a/config/src/tests/frt/frt.cpp
+++ b/config/src/tests/frt/frt.cpp
@@ -11,9 +11,8 @@
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/data/slime/json_format.h>
#include <vespa/vespalib/data/simple_buffer.h>
-#include <vespa/fnet/fnet.h>
-#include <vespa/fnet/frt/frt.h>
#include <vespa/fnet/frt/error.h>
+#include <vespa/fnet/frt/supervisor.h>
#include <vespa/config/frt/protocol.h>
#include <lz4.h>
#include "config-my.h"
@@ -219,7 +218,7 @@ namespace {
FRTFixture(SourceFixture & f1)
: result(2000, 10000),
- requestFactory(1, 3, VespaVersion::fromString("1.2.3"), CompressionType::UNCOMPRESSED),
+ requestFactory(3, VespaVersion::fromString("1.2.3"), CompressionType::UNCOMPRESSED),
src(ConnectionFactory::SP(new FactoryMock(&f1.conn)),
requestFactory,
ConfigAgent::UP(new AgentFixture(&result)),
diff --git a/config/src/vespa/config/common/configstate.h b/config/src/vespa/config/common/configstate.h
index fe415f038e3..2dbea3cc30f 100644
--- a/config/src/vespa/config/common/configstate.h
+++ b/config/src/vespa/config/common/configstate.h
@@ -15,17 +15,17 @@ public:
ConfigState()
: md5(""),
generation(0),
- internalRedeploy(false)
+ applyOnRestart(false)
{ }
- ConfigState(const vespalib::string & md5sum, int64_t gen, bool value)
+ ConfigState(const vespalib::string & md5sum, int64_t gen, bool _applyOnRestart)
: md5(md5sum),
generation(gen),
- internalRedeploy(value)
+ applyOnRestart(_applyOnRestart)
{ }
vespalib::string md5;
int64_t generation;
- bool internalRedeploy;
+ bool applyOnRestart;
bool isNewerGenerationThan(const ConfigState & other) const {
return isGenerationNewer(generation, other.generation);
diff --git a/config/src/vespa/config/frt/frtconfigrequestfactory.cpp b/config/src/vespa/config/frt/frtconfigrequestfactory.cpp
index d32ae411125..fbc13556d14 100644
--- a/config/src/vespa/config/frt/frtconfigrequestfactory.cpp
+++ b/config/src/vespa/config/frt/frtconfigrequestfactory.cpp
@@ -10,7 +10,7 @@ namespace config {
/**
* Factory for creating config requests depending on protocol version;
*/
-FRTConfigRequestFactory::FRTConfigRequestFactory([[maybe_unused]] int protocolVersion, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType)
+FRTConfigRequestFactory::FRTConfigRequestFactory(int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType)
: _traceLevel(traceLevel),
_vespaVersion(vespaVersion),
_hostName(vespalib::HostName::get()),
@@ -18,8 +18,7 @@ FRTConfigRequestFactory::FRTConfigRequestFactory([[maybe_unused]] int protocolVe
{
}
-FRTConfigRequestFactory::~FRTConfigRequestFactory() {
-}
+FRTConfigRequestFactory::~FRTConfigRequestFactory() = default;
FRTConfigRequest::UP
FRTConfigRequestFactory::createConfigRequest(const ConfigKey & key, Connection * connection,
diff --git a/config/src/vespa/config/frt/frtconfigrequestfactory.h b/config/src/vespa/config/frt/frtconfigrequestfactory.h
index c70b8920fdd..7c37ecd76b2 100644
--- a/config/src/vespa/config/frt/frtconfigrequestfactory.h
+++ b/config/src/vespa/config/frt/frtconfigrequestfactory.h
@@ -18,7 +18,7 @@ namespace config {
class FRTConfigRequestFactory
{
public:
- FRTConfigRequestFactory(int protocolVersion, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType);
+ FRTConfigRequestFactory(int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType);
~FRTConfigRequestFactory();
FRTConfigRequest::UP createConfigRequest(const ConfigKey & key, Connection * connection, const ConfigState & state, int64_t serverTimeout) const;
diff --git a/config/src/vespa/config/frt/frtconfigresponsev3.cpp b/config/src/vespa/config/frt/frtconfigresponsev3.cpp
index 9635b4c811c..80cdf88a79a 100644
--- a/config/src/vespa/config/frt/frtconfigresponsev3.cpp
+++ b/config/src/vespa/config/frt/frtconfigresponsev3.cpp
@@ -1,7 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "frtconfigresponsev3.h"
#include "compressioninfo.h"
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/values.h>
#include <vespa/vespalib/data/simple_buffer.h>
#include <vespa/log/log.h>
diff --git a/config/src/vespa/config/frt/frtsourcefactory.cpp b/config/src/vespa/config/frt/frtsourcefactory.cpp
index c58571e3ac4..67e973562db 100644
--- a/config/src/vespa/config/frt/frtsourcefactory.cpp
+++ b/config/src/vespa/config/frt/frtsourcefactory.cpp
@@ -4,9 +4,9 @@
namespace config {
-FRTSourceFactory::FRTSourceFactory(ConnectionFactory::UP connectionFactory, const TimingValues & timingValues, int protocolVersion, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType)
+FRTSourceFactory::FRTSourceFactory(ConnectionFactory::UP connectionFactory, const TimingValues & timingValues, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType)
: _connectionFactory(std::move(connectionFactory)),
- _requestFactory(protocolVersion, traceLevel, vespaVersion, compressionType),
+ _requestFactory(traceLevel, vespaVersion, compressionType),
_timingValues(timingValues)
{
}
diff --git a/config/src/vespa/config/frt/frtsourcefactory.h b/config/src/vespa/config/frt/frtsourcefactory.h
index 23596c1c6cd..4bbcbcb366d 100644
--- a/config/src/vespa/config/frt/frtsourcefactory.h
+++ b/config/src/vespa/config/frt/frtsourcefactory.h
@@ -14,7 +14,7 @@ namespace config {
class FRTSourceFactory : public SourceFactory
{
public:
- FRTSourceFactory(ConnectionFactory::UP connectionFactory, const TimingValues & timingValues, int protocolVersion, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType);
+ FRTSourceFactory(ConnectionFactory::UP connectionFactory, const TimingValues & timingValues, int traceLevel, const VespaVersion & vespaVersion, const CompressionType & compressionType);
/**
* Create source handling config described by key.
diff --git a/config/src/vespa/config/frt/protocol.cpp b/config/src/vespa/config/frt/protocol.cpp
index cfd248e5d86..269c3477ba8 100644
--- a/config/src/vespa/config/frt/protocol.cpp
+++ b/config/src/vespa/config/frt/protocol.cpp
@@ -40,7 +40,7 @@ const Memory RESPONSE_CONFIG_MD5 = "configMD5";
const Memory RESPONSE_CONFIG_GENERATION = "generation";
const Memory RESPONSE_PAYLOAD = "payload";
const Memory RESPONSE_TRACE = "trace";
-const Memory RESPONSE_INTERNAL_REDEPLOY = "internalRedeploy";
+const Memory RESPONSE_APPLY_ON_RESTART = "applyOnRestart";
const Inspector &
extractPayload(const Slime & data)
diff --git a/config/src/vespa/config/frt/protocol.h b/config/src/vespa/config/frt/protocol.h
index a14fa492ac7..0ec16952701 100644
--- a/config/src/vespa/config/frt/protocol.h
+++ b/config/src/vespa/config/frt/protocol.h
@@ -52,7 +52,7 @@ extern const vespalib::Memory RESPONSE_CONFIG_MD5;
extern const vespalib::Memory RESPONSE_CONFIG_GENERATION;
extern const vespalib::Memory RESPONSE_PAYLOAD;
extern const vespalib::Memory RESPONSE_TRACE;
-extern const vespalib::Memory RESPONSE_INTERNAL_REDEPLOY;
+extern const vespalib::Memory RESPONSE_APPLY_ON_RESTART;
const vespalib::slime::Inspector & extractPayload(const vespalib::Slime & data);
diff --git a/config/src/vespa/config/frt/slimeconfigrequest.cpp b/config/src/vespa/config/frt/slimeconfigrequest.cpp
index 696789f74c1..8a6706974f6 100644
--- a/config/src/vespa/config/frt/slimeconfigrequest.cpp
+++ b/config/src/vespa/config/frt/slimeconfigrequest.cpp
@@ -1,12 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "slimeconfigrequest.h"
#include "connection.h"
-#include <vespa/fnet/frt/frt.h>
#include <vespa/config/common/configkey.h>
#include <vespa/config/common/configstate.h>
#include <vespa/config/common/configdefinition.h>
#include <vespa/config/common/trace.h>
#include <vespa/config/common/vespa_version.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/vespalib/data/simple_buffer.h>
diff --git a/config/src/vespa/config/frt/slimeconfigresponse.cpp b/config/src/vespa/config/frt/slimeconfigresponse.cpp
index 181ab58b184..af224008d01 100644
--- a/config/src/vespa/config/frt/slimeconfigresponse.cpp
+++ b/config/src/vespa/config/frt/slimeconfigresponse.cpp
@@ -1,7 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "slimeconfigresponse.h"
#include <vespa/config/common/misc.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/values.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/log/log.h>
LOG_SETUP(".config.frt.slimeconfigresponse");
@@ -66,7 +66,9 @@ ConfigState
SlimeConfigResponse::readState() const
{
const Slime & data(*_data);
- return ConfigState(data.get()[RESPONSE_CONFIG_MD5].asString().make_string(), data.get()[RESPONSE_CONFIG_GENERATION].asLong(), data.get()[RESPONSE_INTERNAL_REDEPLOY].asBool());
+ return ConfigState(data.get()[RESPONSE_CONFIG_MD5].asString().make_string(),
+ data.get()[RESPONSE_CONFIG_GENERATION].asLong(),
+ data.get()[RESPONSE_APPLY_ON_RESTART].asBool());
}
vespalib::string
diff --git a/config/src/vespa/config/subscription/sourcespec.cpp b/config/src/vespa/config/subscription/sourcespec.cpp
index 326b3191fd0..e355e0c1bd6 100644
--- a/config/src/vespa/config/subscription/sourcespec.cpp
+++ b/config/src/vespa/config/subscription/sourcespec.cpp
@@ -121,7 +121,7 @@ ServerSpec::createSourceFactory(const TimingValues & timingValues) const
{
const auto vespaVersion = VespaVersion::getCurrentVersion();
return std::make_unique<FRTSourceFactory>(std::make_unique<FRTConnectionPool>(*this, timingValues), timingValues,
- _protocolVersion, _traceLevel, vespaVersion, _compressionType);
+ _traceLevel, vespaVersion, _compressionType);
}
diff --git a/configd/src/apps/sentinel/cmdq.cpp b/configd/src/apps/sentinel/cmdq.cpp
index 8fa3726c7f6..489ae97228f 100644
--- a/configd/src/apps/sentinel/cmdq.cpp
+++ b/configd/src/apps/sentinel/cmdq.cpp
@@ -1,7 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "cmdq.h"
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/rpcrequest.h>
namespace config::sentinel {
diff --git a/configd/src/apps/sentinel/rpchooks.cpp b/configd/src/apps/sentinel/rpchooks.cpp
index 99bcd404402..aef58b8a1dc 100644
--- a/configd/src/apps/sentinel/rpchooks.cpp
+++ b/configd/src/apps/sentinel/rpchooks.cpp
@@ -2,7 +2,8 @@
#include "rpchooks.h"
#include "cmdq.h"
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/log/log.h>
LOG_SETUP(".rpchooks");
diff --git a/configdefinitions/src/vespa/CMakeLists.txt b/configdefinitions/src/vespa/CMakeLists.txt
index 6bcd196d023..c6e4d612a0a 100644
--- a/configdefinitions/src/vespa/CMakeLists.txt
+++ b/configdefinitions/src/vespa/CMakeLists.txt
@@ -16,6 +16,8 @@ vespa_generate_config(configdefinitions cluster-list.def)
install_config_definition(cluster-list.def cloud.config.cluster-list.def)
vespa_generate_config(configdefinitions configserver.def)
install_config_definition(configserver.def cloud.config.configserver.def)
+vespa_generate_config(configdefinitions curator.def)
+install_config_definition(curator.def cloud.config.curator.def)
vespa_generate_config(configdefinitions dispatch.def)
install_config_definition(dispatch.def vespa.config.search.dispatch.def)
vespa_generate_config(configdefinitions filereferences.def)
diff --git a/configdefinitions/src/vespa/reindexing.def b/configdefinitions/src/vespa/reindexing.def
index d577f62b10b..93dc767fed0 100644
--- a/configdefinitions/src/vespa/reindexing.def
+++ b/configdefinitions/src/vespa/reindexing.def
@@ -6,8 +6,16 @@ namespace=vespa.config.content.reindexing
# Whether reindexing should run at all
enabled bool default=false
+# TODO jonmv: remove after 7.324 is gone
# The name of the content cluster to reindex documents from
-clusterName string
+clusterName string default=""
+# TODO jonmv: remove after 7.324 is gone
# Epoch millis after which latest reprocessing may begin, per document type
status{}.readyAtMillis long
+
+# Epoch millis after which latest reprocessing may begin, per document type, per cluster
+clusters{}.documentTypes{}.readyAtMillis long
+
+# Window size increment used for the dynamic throttling policy of the reindexing visitor session
+windowSizeIncrement double default=0.2
diff --git a/configdefinitions/src/vespa/stor-filestor.def b/configdefinitions/src/vespa/stor-filestor.def
index bab19c923d9..e9165f5adc9 100644
--- a/configdefinitions/src/vespa/stor-filestor.def
+++ b/configdefinitions/src/vespa/stor-filestor.def
@@ -31,7 +31,12 @@ num_threads int default=8 restart
## Negative number will choose a good number based on # cores.
num_response_threads int default=2 restart
-## Number of handler objects that might be created by networkthreads
+## Number of handler objects that might be created by visitor threads
+## This is a temporary setting that only skilled vespa developers should modify
+## This must be kept in line with stor-visitor:visitorthreads
+num_visitor_threads int default=16 restart
+
+## Number of handler objects that might be created by network threads
## This is a temporary setting that only skilled vespa developers should modify
## This must be kept in line with stor-communicationmanager:rpc.num_network_threads
num_network_threads int default=1 restart
diff --git a/configdefinitions/src/vespa/zookeeper-server.def b/configdefinitions/src/vespa/zookeeper-server.def
index 5aa0bb2ae9b..2e80f9b35e0 100644
--- a/configdefinitions/src/vespa/zookeeper-server.def
+++ b/configdefinitions/src/vespa/zookeeper-server.def
@@ -33,6 +33,8 @@ server[].id int
server[].hostname string
server[].quorumPort int default=2182
server[].electionPort int default=2183
+# Whether this server is joining an existing cluster
+server[].joining bool default=false
# Needed when upgrading from ZooKeeper 3.4 to 3.5, see https://issues.apache.org/jira/browse/ZOOKEEPER-3056,
# and in general where there is a zookeeper ensemble running that has had few transactions.
diff --git a/clustercontroller-apputil/CMakeLists.txt b/configgen/CMakeLists.txt
index bdfb3ab3ed7..107037f8008 100644
--- a/clustercontroller-apputil/CMakeLists.txt
+++ b/configgen/CMakeLists.txt
@@ -1,2 +1,2 @@
# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-install_fat_java_artifact(clustercontroller-apputil)
+install_java_artifact(configgen)
diff --git a/configgen/pom.xml b/configgen/pom.xml
index 7d316061a99..a335e345234 100644
--- a/configgen/pom.xml
+++ b/configgen/pom.xml
@@ -52,6 +52,38 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
</plugin>
+ <plugin>
+ <!-- Add headers making this an OSGi bundle (cannot use bundle plugin as this is needed at bootstrap).
+ This is needed because the model of config definitions is part of codegen but needed by modules
+ doing generic access over config.
+ -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <configuration>
+ <finalName>${project.artifactId}</finalName>
+ <transformers>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <manifestEntries>
+ <Export-Package>com.yahoo.config.codegen</Export-Package>
+ <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Version>7.0.0</Bundle-Version>
+ <Bundle-Name>${project.artifactId}</Bundle-Name>
+ <Bundle-Vendor>Yahoo!</Bundle-Vendor>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ </manifestEntries>
+ </transformer>
+ </transformers>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
index b3c4d0c5ff8..2ebe7ad03bf 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java
@@ -44,7 +44,7 @@ public class BuilderGenerator {
}
private static String getSpecialRootBuilderCode(InnerCNode node) {
- return (node.getParent() == null) ? "\n" + getDispatchCode() + "\n" : "";
+ return (node.getParent() == null) ? "\n" + getRootDeclarations() + "\n" : "";
}
private static String getBuildMethod(InnerCNode node) {
@@ -53,26 +53,36 @@ public class BuilderGenerator {
"}\n";
}
- private static String getDispatchCode() {
+ private static String getRootDeclarations() {
// Use full path to @Override, as users are free to define an inner node called
// 'override'. (summarymap.def does)
// The generated inner 'Override' class would otherwise be mistaken for the
// annotation.
- return "@java.lang.Override\n" + //
- "public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {\n" + //
- " if (producer instanceof Producer) {\n" + //
- " ((Producer)producer).getConfig(this);\n" + //
- " return true;\n" + //
+ return "private boolean _applyOnRestart = false;\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {\n" +
+ " if (producer instanceof Producer) {\n" +
+ " ((Producer)producer).getConfig(this);\n" +
+ " return true;\n" +
" }\n" + //
- " return false;\n" + //
- "}\n" + //
- "\n" + //
- "@java.lang.Override\n" + //
- "public final String getDefMd5() { return CONFIG_DEF_MD5; }\n" + //
- "@java.lang.Override\n" + //
- "public final String getDefName() { return CONFIG_DEF_NAME; }\n" + //
- "@java.lang.Override\n" + //
- "public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }";
+ " return false;\n" +
+ "}\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final String getDefMd5() { return CONFIG_DEF_MD5; }\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final String getDefName() { return CONFIG_DEF_NAME; }\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final boolean getApplyOnRestart() { return _applyOnRestart; }\n" +
+ "\n" +
+ "@java.lang.Override\n" +
+ "public final void setApplyOnRestart(boolean applyOnRestart) { _applyOnRestart = applyOnRestart; }";
}
private static String getUninitializedScalars(InnerCNode node) {
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/CppClassBuilder.java b/configgen/src/main/java/com/yahoo/config/codegen/CppClassBuilder.java
index c8c30277953..c2539b53b28 100644
--- a/configgen/src/main/java/com/yahoo/config/codegen/CppClassBuilder.java
+++ b/configgen/src/main/java/com/yahoo/config/codegen/CppClassBuilder.java
@@ -141,6 +141,39 @@ public class CppClassBuilder implements ClassBuilder {
return removeDashesAndUpperCaseAllFirstChars(name, false);
}
+ /**
+ * Class to generate noexcept specifier if default constructor, copy constructor or copy assignment is non-throwing
+ */
+ private static class NoExceptSpecifier {
+ private boolean enabled;
+
+ public NoExceptSpecifier(CNode node) {
+ enabled = checkNode(node);
+ }
+
+ private static boolean checkNode(CNode node) {
+ if (node instanceof InnerCNode) {
+ for (CNode child: node.getChildren()) {
+ if (child.isArray || child.isMap) {
+ return false;
+ }
+ if (!checkNode(child)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public String toString() {
+ if (enabled) {
+ return " noexcept";
+ } else {
+ return "";
+ }
+ }
+ }
+
void writeHeaderFile(Writer w, CNode root) throws IOException {
writeHeaderHeader(w, root);
writeHeaderPublic(w, root);
@@ -327,29 +360,31 @@ public class CppClassBuilder implements ClassBuilder {
w.write(indent + "void serialize(vespalib::slime::Cursor & __cursor) const;\n");
}
- void writeClassCopyConstructorDeclaration(Writer w, String className, String indent) throws IOException {
- w.write(indent + className + "(const " + className + " & __rhs);\n");
+ void writeClassCopyConstructorDeclaration(Writer w, String className, NoExceptSpecifier noexcept, String indent) throws IOException {
+ w.write(indent + className + "(const " + className + " & __rhs)" + noexcept + ";\n");
}
- void writeClassAssignmentOperatorDeclaration(Writer w, String className, String indent) throws IOException {
- w.write(indent + className + " & operator = (const " + className + " & __rhs);\n");
+ void writeClassAssignmentOperatorDeclaration(Writer w, String className, NoExceptSpecifier noexcept, String indent) throws IOException {
+ w.write(indent + className + " & operator = (const " + className + " & __rhs)" + noexcept + ";\n");
}
- void writeConfigClassCopyConstructorDefinition(Writer w, String parent, String className) throws IOException {
- w.write(parent + "::" + className + "(const " + className + " & __rhs) = default;\n");
+ void writeConfigClassCopyConstructorDefinition(Writer w, String parent, String className, NoExceptSpecifier noexcept) throws IOException {
+ w.write(parent + "::" + className + "(const " + className + " & __rhs)" + noexcept + " = default;\n");
}
- void writeConfigClassAssignmentOperatorDefinition(Writer w, String parent, String className) throws IOException {
- w.write(parent + " & " + parent + "::" + "operator =(const " + className + " & __rhs) = default;\n");
+ void writeConfigClassAssignmentOperatorDefinition(Writer w, String parent, String className, NoExceptSpecifier noexcept) throws IOException {
+ w.write(parent + " & " + parent + "::" + "operator =(const " + className + " & __rhs)" + noexcept + " = default;\n");
}
void writeClassCopyConstructorDefinition(Writer w, String parent, CNode node) throws IOException {
String typeName = getTypeName(node, false);
- w.write(parent + "::" + typeName + "(const " + typeName + " & __rhs) = default;\n");
+ NoExceptSpecifier noexcept = new NoExceptSpecifier(node);
+ w.write(parent + "::" + typeName + "(const " + typeName + " & __rhs)" + noexcept + " = default;\n");
}
void writeClassAssignmentOperatorDefinition(Writer w, String parent, CNode node) throws IOException {
String typeName = getTypeName(node, false);
+ NoExceptSpecifier noexcept = new NoExceptSpecifier(node);
// Write empty constructor
- w.write(parent + " & " + parent + "::" + "operator = (const " + typeName + " & __rhs) = default;\n");
+ w.write(parent + " & " + parent + "::" + "operator = (const " + typeName + " & __rhs)" + noexcept + " = default;\n");
}
void writeDestructor(Writer w, String parent, String className) throws IOException {
@@ -357,13 +392,14 @@ public class CppClassBuilder implements ClassBuilder {
}
void writeCommonFunctionDeclarations(Writer w, String className, CNode node, String indent) throws IOException {
- w.write("" + indent + className + "();\n");
- writeClassCopyConstructorDeclaration(w, className, indent);
- writeClassAssignmentOperatorDeclaration(w, className, indent);
+ NoExceptSpecifier noexcept = new NoExceptSpecifier(node);
+ w.write("" + indent + className + "() " + noexcept + ";\n");
+ writeClassCopyConstructorDeclaration(w, className, noexcept, indent);
+ writeClassAssignmentOperatorDeclaration(w, className, noexcept, indent);
w.write("" + indent + "~" + className + "();\n");
w.write("\n"
- + indent + "bool operator==(const " + className + "& __rhs) const;\n"
- + indent + "bool operator!=(const " + className + "& __rhs) const;\n"
+ + indent + "bool operator==(const " + className + "& __rhs) const noexcept;\n"
+ + indent + "bool operator!=(const " + className + "& __rhs) const noexcept;\n"
+ "\n"
);
}
@@ -665,8 +701,9 @@ public class CppClassBuilder implements ClassBuilder {
}
String tmpName = getTypeName(node, false);
String typeName = root ? getInternalClassName(node) : tmpName;
+ NoExceptSpecifier noexcept = new NoExceptSpecifier(node);
// Write empty constructor
- w.write(parent + typeName + "()\n");
+ w.write(parent + typeName + "()" + noexcept + "\n");
for (int i=0; i<node.getChildren().length; ++i) {
CNode child = node.getChildren()[i];
String childName = getIdentifier(child.getName());
@@ -712,8 +749,8 @@ public class CppClassBuilder implements ClassBuilder {
);
// Write copy constructor
if (root) {
- writeConfigClassCopyConstructorDefinition(w, fullClassName, typeName);
- writeConfigClassAssignmentOperatorDefinition(w, fullClassName, typeName);
+ writeConfigClassCopyConstructorDefinition(w, fullClassName, typeName, noexcept);
+ writeConfigClassAssignmentOperatorDefinition(w, fullClassName, typeName, noexcept);
} else {
writeClassCopyConstructorDefinition(w, fullClassName, node);
writeClassAssignmentOperatorDefinition(w, fullClassName, node);
@@ -825,7 +862,7 @@ public class CppClassBuilder implements ClassBuilder {
// Write operator==
String lineBreak = (parent.length() + typeName.length() < 50 ? "" : "\n");
w.write("bool\n"
- + parent + lineBreak + "operator==(const " + typeName + "& __rhs) const\n"
+ + parent + lineBreak + "operator==(const " + typeName + "& __rhs) const noexcept\n"
+ "{\n"
+ " return ("
);
@@ -844,7 +881,7 @@ public class CppClassBuilder implements ClassBuilder {
// Write operator!=
lineBreak = (parent.length() + typeName.length() < 50 ? "" : "\n");
w.write("bool\n"
- + parent + lineBreak + "operator!=(const " + typeName + "& __rhs) const\n"
+ + parent + lineBreak + "operator!=(const " + typeName + "& __rhs) const noexcept\n"
+ "{\n"
+ " return !(operator==(__rhs));\n"
+ "}\n"
diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference
index b84f01f380b..2008bbf6b52 100644
--- a/configgen/src/test/resources/allfeatures.reference
+++ b/configgen/src/test/resources/allfeatures.reference
@@ -601,6 +601,8 @@ public final class AllfeaturesConfig extends ConfigInstance {
return this;
}
+ private boolean _applyOnRestart = false;
+
@java.lang.Override
public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {
if (producer instanceof Producer) {
@@ -611,12 +613,20 @@ public final class AllfeaturesConfig extends ConfigInstance {
}
@java.lang.Override
- public final String getDefMd5() { return CONFIG_DEF_MD5; }
+ public final String getDefMd5() { return CONFIG_DEF_MD5; }
+
@java.lang.Override
- public final String getDefName() { return CONFIG_DEF_NAME; }
+ public final String getDefName() { return CONFIG_DEF_NAME; }
+
@java.lang.Override
public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }
+ @java.lang.Override
+ public final boolean getApplyOnRestart() { return _applyOnRestart; }
+
+ @java.lang.Override
+ public final void setApplyOnRestart(boolean applyOnRestart) { _applyOnRestart = applyOnRestart; }
+
public AllfeaturesConfig build() {
return new AllfeaturesConfig(this);
}
diff --git a/configserver-flags/src/main/java/com/yahoo/vespa/configserver/flags/http/DefinedFlag.java b/configserver-flags/src/main/java/com/yahoo/vespa/configserver/flags/http/DefinedFlag.java
index c706a2b1e51..c4e784e5717 100644
--- a/configserver-flags/src/main/java/com/yahoo/vespa/configserver/flags/http/DefinedFlag.java
+++ b/configserver-flags/src/main/java/com/yahoo/vespa/configserver/flags/http/DefinedFlag.java
@@ -16,7 +16,7 @@ import java.io.OutputStream;
* @author hakonhall
*/
public class DefinedFlag extends HttpResponse {
- private static ObjectMapper mapper = new ObjectMapper();
+ private static final ObjectMapper mapper = new ObjectMapper();
private final FlagDefinition flagDefinition;
@@ -35,6 +35,11 @@ public class DefinedFlag extends HttpResponse {
static void renderFlagDefinition(FlagDefinition flagDefinition, ObjectNode definitionNode) {
definitionNode.put("description", flagDefinition.getDescription());
definitionNode.put("modification-effect", flagDefinition.getModificationEffect());
+ ArrayNode ownersNode = mapper.createArrayNode();
+ flagDefinition.getOwners().forEach(ownersNode::add);
+ definitionNode.set("owners", ownersNode);
+ definitionNode.put("createdAt", flagDefinition.getCreatedAt().toString());
+ definitionNode.put("expiresAt", flagDefinition.getExpiresAt().toString());
ArrayNode dimensionsNode = definitionNode.putArray("dimensions");
flagDefinition.getDimensions().forEach(dimension -> dimensionsNode.add(DimensionHelper.toWire(dimension)));
}
diff --git a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/ConfigServerFlagSourceTest.java b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/ConfigServerFlagSourceTest.java
index 56762e7bae5..531ab98cafb 100644
--- a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/ConfigServerFlagSourceTest.java
+++ b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/ConfigServerFlagSourceTest.java
@@ -17,6 +17,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertFalse;
@@ -52,7 +53,7 @@ public class ConfigServerFlagSourceTest {
private void initialize() {
flagSource = new ConfigServerFlagSource(fileSystem, flagsDb);
- flag = Flags.defineFeatureFlag(flagId.toString(), false, "", "").bindTo(flagSource);
+ flag = Flags.defineFeatureFlag(flagId.toString(), false, List.of("joe"), "2010-01-01", "2030-01-01", "", "").bindTo(flagSource);
}
@Test
diff --git a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java
index cbd37c8a5cf..a833d4d1608 100644
--- a/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java
+++ b/configserver-flags/src/test/java/com/yahoo/vespa/configserver/flags/http/FlagsHandlerTest.java
@@ -12,6 +12,7 @@ import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagId;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.UnboundBooleanFlag;
+import com.yahoo.vespa.jdk8compat.List;
import com.yahoo.yolean.Exceptions;
import org.junit.Test;
@@ -32,9 +33,9 @@ import static org.junit.Assert.assertEquals;
*/
public class FlagsHandlerTest {
private static final UnboundBooleanFlag FLAG1 = Flags.defineFeatureFlag(
- "id1", false, "desc1", "mod1");
+ "id1", false, List.of("joe"), "2010-01-01", "2030-01-01", "desc1", "mod1");
private static final UnboundBooleanFlag FLAG2 = Flags.defineFeatureFlag(
- "id2", true, "desc2", "mod2",
+ "id2", true, List.of("joe"), "2010-01-01", "2030-01-01", "desc2", "mod2",
FetchVector.Dimension.HOSTNAME, FetchVector.Dimension.APPLICATION_ID);
private static final String FLAGS_V1_URL = "https://foo.com:4443/flags/v1";
@@ -57,12 +58,12 @@ public class FlagsHandlerTest {
public void testDefined() {
try (Flags.Replacer replacer = Flags.clearFlagsForTesting()) {
fixUnusedWarning(replacer);
- Flags.defineFeatureFlag("id", false, "desc", "mod", FetchVector.Dimension.HOSTNAME);
+ Flags.defineFeatureFlag("id", false, List.of("joe"), "2010-01-01", "2030-01-01", "desc", "mod", FetchVector.Dimension.HOSTNAME);
verifySuccessfulRequest(Method.GET, "/defined", "",
- "{\"id\":{\"description\":\"desc\",\"modification-effect\":\"mod\",\"dimensions\":[\"hostname\"]}}");
+ "{\"id\":{\"description\":\"desc\",\"modification-effect\":\"mod\",\"owners\":[\"joe\"],\"createdAt\":\"2010-01-01T00:00:00Z\",\"expiresAt\":\"2030-01-01T00:00:00Z\",\"dimensions\":[\"hostname\"]}}");
verifySuccessfulRequest(Method.GET, "/defined/id", "",
- "{\"description\":\"desc\",\"modification-effect\":\"mod\",\"dimensions\":[\"hostname\"]}");
+ "{\"description\":\"desc\",\"modification-effect\":\"mod\",\"owners\":[\"joe\"],\"createdAt\":\"2010-01-01T00:00:00Z\",\"expiresAt\":\"2030-01-01T00:00:00Z\",\"dimensions\":[\"hostname\"]}");
}
}
diff --git a/configserver/pom.xml b/configserver/pom.xml
index 35c38eb7d7d..3b7fef085b1 100644
--- a/configserver/pom.xml
+++ b/configserver/pom.xml
@@ -64,9 +64,27 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
<artifactId>config-bundle</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-lib</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>configgen</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 6cc05a0f69e..1ffefd1a6b7 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -32,8 +32,11 @@ import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.application.ApplicationReindexing;
import com.yahoo.vespa.config.server.application.ApplicationSet;
+import com.yahoo.vespa.config.server.application.ClusterReindexing;
+import com.yahoo.vespa.config.server.application.ClusterReindexingStatusClient;
import com.yahoo.vespa.config.server.application.CompressedApplicationInputStream;
import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker;
+import com.yahoo.vespa.config.server.application.DefaultClusterReindexingStatusClient;
import com.yahoo.vespa.config.server.application.FileDistributionStatus;
import com.yahoo.vespa.config.server.application.HttpProxy;
import com.yahoo.vespa.config.server.application.TenantApplications;
@@ -134,6 +137,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
private final LogRetriever logRetriever;
private final TesterClient testerClient;
private final Metric metric;
+ private final ClusterReindexingStatusClient clusterReindexingStatusClient;
@Inject
public ApplicationRepository(TenantRepository tenantRepository,
@@ -157,7 +161,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
Clock.systemUTC(),
testerClient,
metric,
- flagSource);
+ flagSource,
+ new DefaultClusterReindexingStatusClient());
}
private ApplicationRepository(TenantRepository tenantRepository,
@@ -171,7 +176,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
Clock clock,
TesterClient testerClient,
Metric metric,
- FlagSource flagSource) {
+ FlagSource flagSource,
+ ClusterReindexingStatusClient clusterReindexingStatusClient) {
this.tenantRepository = Objects.requireNonNull(tenantRepository);
this.hostProvisioner = Objects.requireNonNull(hostProvisioner);
this.infraDeployer = Objects.requireNonNull(infraDeployer);
@@ -183,6 +189,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
this.clock = Objects.requireNonNull(clock);
this.testerClient = Objects.requireNonNull(testerClient);
this.metric = Objects.requireNonNull(metric);
+ this.clusterReindexingStatusClient = clusterReindexingStatusClient;
}
public static class Builder {
@@ -266,7 +273,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
clock,
testerClient,
metric,
- flagSource);
+ flagSource,
+ ClusterReindexingStatusClient.DUMMY_INSTANCE);
}
}
@@ -528,6 +536,10 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
CLUSTERCONTROLLER_CONTAINER.serviceName, relativePath);
}
+ public Map<String, ClusterReindexing> getClusterReindexingStatus(ApplicationId applicationId) {
+ return uncheck(() -> clusterReindexingStatusClient.getReindexingStatus(getApplication(applicationId)));
+ }
+
public Long getApplicationGeneration(ApplicationId applicationId) {
return getApplication(applicationId).getApplicationGeneration();
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
index 8d001d5d5df..e77592dc011 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.config.server.application;
import com.yahoo.component.Version;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.ConfigurationRuntimeException;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.Model;
@@ -11,6 +12,8 @@ import com.yahoo.vespa.config.ConfigCacheKey;
import com.yahoo.vespa.config.ConfigDefinitionKey;
import com.yahoo.vespa.config.ConfigKey;
import com.yahoo.vespa.config.ConfigPayload;
+import com.yahoo.vespa.config.ConfigPayloadBuilder;
+import com.yahoo.vespa.config.GenericConfig;
import com.yahoo.vespa.config.GetConfigRequest;
import com.yahoo.vespa.config.buildergen.ConfigDefinition;
import com.yahoo.vespa.config.protocol.ConfigResponse;
@@ -23,6 +26,7 @@ import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory;
import com.yahoo.vespa.config.server.rpc.UncompressedConfigResponseFactory;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
import com.yahoo.vespa.config.util.ConfigUtils;
+import com.yahoo.yolean.Exceptions;
import java.util.Objects;
import java.util.Set;
@@ -40,30 +44,24 @@ public class Application implements ModelResult {
/** The config generation for this application. */
private final long applicationGeneration;
- private final boolean internalRedeploy;
private final Version vespaVersion;
private final Model model;
private final ServerCache cache;
private final MetricUpdater metricUpdater;
private final ApplicationId app;
- public Application(Model model, ServerCache cache, long applicationGeneration, boolean internalRedeploy,
+ public Application(Model model, ServerCache cache, long applicationGeneration,
Version vespaVersion, MetricUpdater metricUpdater, ApplicationId app) {
Objects.requireNonNull(model, "The model cannot be null");
this.model = model;
this.cache = cache;
this.applicationGeneration = applicationGeneration;
- this.internalRedeploy = internalRedeploy;
this.vespaVersion = vespaVersion;
this.metricUpdater = metricUpdater;
this.app = app;
}
- /**
- * Returns the generation for the config we are currently serving
- *
- * @return the config generation
- */
+ /** Returns the generation for the config we are currently serving. */
public Long getApplicationGeneration() { return applicationGeneration; }
/** Returns the application model, never null */
@@ -98,6 +96,7 @@ public class Application implements ModelResult {
/**
* Gets a config from ZK. Returns null if not found.
*/
+ @SuppressWarnings("deprecation")
public ConfigResponse resolveConfig(GetConfigRequest req, ConfigResponseFactory responseFactory) {
long start = System.currentTimeMillis();
metricUpdater.incrementRequests();
@@ -131,18 +130,42 @@ public class Application implements ModelResult {
debug("Resolving " + configKey + " with config definition " + def);
}
- ConfigPayload payload = null;
+ ConfigInstance.Builder builder;
+ ConfigPayload payload;
+ boolean applyOnRestart = false;
try {
- payload = model.getConfig(configKey, def);
+ builder = model.getConfigInstance(configKey, def);
+ if (builder == null) { // TODO: Remove this condition after December 2020
+ payload = model.getConfig(configKey, def);
+ if (def.getCNode() != null)
+ payload.applyDefaultsFromDef(def.getCNode());
+ }
+ else if (builder instanceof GenericConfig.GenericConfigBuilder) {
+ payload = ((GenericConfig.GenericConfigBuilder) builder).getPayload();
+ applyOnRestart = builder.getApplyOnRestart();
+ }
+ else {
+ try {
+ ConfigInstance instance = ConfigInstanceBuilder.buildInstance(builder, def.getCNode());
+ payload = ConfigPayload.fromInstance(instance);
+ applyOnRestart = builder.getApplyOnRestart();
+ } catch (ConfigurationRuntimeException e) {
+ // This can happen in cases where services ask for config that no longer exist before they have been able
+ // to reconfigure themselves
+ log.log(Level.INFO, "Error resolving instance for builder '" + builder.getClass().getName() +
+ "', returning empty config: " + Exceptions.toMessageString(e));
+ payload = ConfigPayload.fromBuilder(new ConfigPayloadBuilder());
+ }
+ if (def.getCNode() != null)
+ payload.applyDefaultsFromDef(def.getCNode());
+ }
} catch (Exception e) {
throw new ConfigurationRuntimeException("Unable to get config for " + app, e);
}
- if (payload == null) {
- metricUpdater.incrementFailedRequests();
- throw new ConfigurationRuntimeException("Unable to resolve config " + configKey);
- }
- ConfigResponse configResponse = responseFactory.createResponse(payload, applicationGeneration, internalRedeploy);
+ ConfigResponse configResponse = responseFactory.createResponse(payload,
+ applicationGeneration,
+ applyOnRestart);
metricUpdater.incrementProcTime(System.currentTimeMillis() - start);
if (useCache(req)) {
cache.put(cacheKey, configResponse, configResponse.getConfigMd5());
@@ -197,4 +220,5 @@ public class Application implements ModelResult {
public Set<String> allConfigIds() {
return model.allConfigIds();
}
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexing.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexing.java
index ca9aa01ea56..f162007b0e4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexing.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexing.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.config.server.application;
import java.time.Instant;
+import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -10,6 +11,7 @@ import java.util.Optional;
* Reindexing status for each document type in a content cluster.
*
* @author jonmv
+ * @author bjorncs
*/
public class ClusterReindexing {
@@ -25,6 +27,26 @@ public class ClusterReindexing {
public Map<String, Status> documentTypeStatus() { return documentTypeStatus; }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ClusterReindexing that = (ClusterReindexing) o;
+ return documentTypeStatus.equals(that.documentTypeStatus);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(documentTypeStatus);
+ }
+
+ @Override
+ public String toString() {
+ return "ClusterReindexing{" +
+ "documentTypeStatus=" + documentTypeStatus +
+ '}';
+ }
+
public static class Status {
@@ -32,9 +54,9 @@ public class ClusterReindexing {
private final Instant endedAt;
private final State state;
private final String message;
- private final String progress;
+ private final Double progress;
- public Status(Instant startedAt, Instant endedAt, State state, String message, String progress) {
+ public Status(Instant startedAt, Instant endedAt, State state, String message, Double progress) {
this.startedAt = Objects.requireNonNull(startedAt);
this.endedAt = endedAt;
this.state = state;
@@ -46,13 +68,55 @@ public class ClusterReindexing {
public Optional<Instant> endedAt() { return Optional.ofNullable(endedAt); }
public Optional<State> state() { return Optional.ofNullable(state); }
public Optional<String> message() { return Optional.ofNullable(message); }
- public Optional<String> progress() { return Optional.ofNullable(progress); }
+ public Optional<Double> progress() { return Optional.ofNullable(progress); }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Status status = (Status) o;
+ return startedAt.equals(status.startedAt) &&
+ Objects.equals(endedAt, status.endedAt) &&
+ state == status.state &&
+ Objects.equals(message, status.message) &&
+ Objects.equals(progress, status.progress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(startedAt, endedAt, state, message, progress);
+ }
+
+ @Override
+ public String toString() {
+ return "Status{" +
+ "startedAt=" + startedAt +
+ ", endedAt=" + endedAt +
+ ", state=" + state +
+ ", message='" + message + '\'' +
+ ", progress='" + progress + '\'' +
+ '}';
+ }
+
}
public enum State {
+ PENDING("pending"), RUNNING("running"), FAILED("failed"), SUCCESSFUL("successful");
+
+ private final String stringValue;
- PENDING, RUNNING, FAILED, SUCCESSFUL;
+ State(String stringValue) { this.stringValue = stringValue; }
+
+ public static State fromString(String value) {
+ return Arrays.stream(values())
+ .filter(v -> v.stringValue.equals(value))
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("Unknown value: " + value));
+ }
+
+ public String asString() { return stringValue; }
}
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexingStatusClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexingStatusClient.java
new file mode 100644
index 00000000000..1201bbd4814
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ClusterReindexingStatusClient.java
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.application;
+
+import com.yahoo.vespa.config.server.modelfactory.ModelResult;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Retrieves reindexing status from content clusters
+ *
+ * @author bjorncs
+ */
+public interface ClusterReindexingStatusClient extends AutoCloseable {
+
+ Map<String, ClusterReindexing> getReindexingStatus(ModelResult application) throws IOException;
+
+ void close();
+
+ ClusterReindexingStatusClient DUMMY_INSTANCE = new ClusterReindexingStatusClient() {
+ @Override public Map<String, ClusterReindexing> getReindexingStatus(ModelResult application) { return Map.of(); }
+ @Override public void close() {}
+ };
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java
index 434b254336c..7fcda86aa98 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigConvergenceChecker.java
@@ -21,6 +21,7 @@ import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBu
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.net.URIBuilder;
+import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.util.Timeout;
import java.io.IOException;
@@ -240,6 +241,9 @@ public class ConfigConvergenceChecker extends AbstractComponent {
.setMaxConnPerRoute(10)
.setTlsStrategy(tlsStrategy)
.build())
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(2))
+ .build())
.setUserAgent("config-convergence-checker")
.setConnectionReuseStrategy((request, response, context) -> false) // Disable connection reuse
.build();
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java
new file mode 100644
index 00000000000..389e8394c9e
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java
@@ -0,0 +1,117 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.application;
+
+import com.yahoo.config.ConfigBuilder;
+import com.yahoo.config.ConfigInstance;
+import com.yahoo.config.ConfigurationRuntimeException;
+import com.yahoo.config.codegen.CNode;
+import com.yahoo.config.codegen.InnerCNode;
+import com.yahoo.config.codegen.LeafCNode;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+/**
+ * Builds a ConfigInstance from a ConfigInstance.Builder.
+ * (Put here not in ConfigInstance.Builder temporarily to work around dependency problems.)
+ */
+class ConfigInstanceBuilder {
+
+ private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ConfigInstanceBuilder.class.getName());
+
+ static ConfigInstance buildInstance(ConfigInstance.Builder builder, InnerCNode targetDef) {
+ try {
+ if (targetDef != null) applyDef(builder, targetDef);
+ Class<? extends ConfigInstance> clazz = getConfigClass(builder.getClass());
+ return clazz.getConstructor(builder.getClass()).newInstance(builder);
+ } catch (Exception e) {
+ throw new ConfigurationRuntimeException(e);
+ }
+ }
+
+ /**
+ * If some fields on the builder are null now, set them from the def. Do recursively.
+ * <p>
+ * If the targetDef has some schema incompatibilities, they are not handled here
+ * (except logging in some cases), but in ConfigInstance.serialize().
+ *
+ * @param builder a {@link com.yahoo.config.ConfigBuilder}
+ * @param targetDef a config definition
+ * @throws Exception if applying values form config definitions fails
+ */
+ static void applyDef(ConfigBuilder builder, InnerCNode targetDef) throws Exception {
+ for (Map.Entry<String, CNode> e: targetDef.children().entrySet()) {
+ CNode node = e.getValue();
+ if (node instanceof LeafCNode) {
+ setLeafValueIfUnset(targetDef, builder, (LeafCNode)node);
+ } else if (node instanceof InnerCNode) {
+ // Is there a private field on the builder that matches this inner node in the def?
+ if (hasField(builder.getClass(), node.getName())) {
+ Field innerField = builder.getClass().getDeclaredField(node.getName());
+ innerField.setAccessible(true);
+ Object innerFieldVal = innerField.get(builder);
+ if (innerFieldVal instanceof List) {
+ // inner array? Check that list elems are ConfigBuilder
+ List<?> innerList = (List<?>) innerFieldVal;
+ for (Object b : innerList) {
+ if (b instanceof ConfigBuilder) {
+ applyDef((ConfigBuilder) b, (InnerCNode) node);
+ }
+ }
+ } else if (innerFieldVal instanceof ConfigBuilder) {
+ // Struct perhaps
+ applyDef((ConfigBuilder) innerFieldVal, (InnerCNode) node);
+ } else {
+ // Likely a config value mismatch. That is handled in ConfigInstance.serialize() (error message, omit from response.)
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean hasField(Class<?> aClass, String name) {
+ for (Field field : aClass.getDeclaredFields()) {
+ if (name.equals(field.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void setLeafValueIfUnset(InnerCNode targetDef, Object builder, LeafCNode node) throws Exception {
+ if (hasField(builder.getClass(), node.getName())) {
+ Field field = builder.getClass().getDeclaredField(node.getName());
+ field.setAccessible(true);
+ Object val = field.get(builder);
+ if (val==null) {
+ // Not set on builder, if the leaf node has a default value, try the private setter that takes String
+ try {
+ if (node.getDefaultValue()!=null) {
+ Method setter = builder.getClass().getDeclaredMethod(node.getName(), String.class);
+ setter.setAccessible(true);
+ setter.invoke(builder, node.getDefaultValue().getValue());
+ }
+ } catch (Exception e) {
+ log.log(Level.SEVERE,
+ "For config '" + targetDef.getFullName() + "': " +
+ "Unable to apply the default value for field '" + node.getName() +
+ "' to config Builder (where it wasn't set)",
+ e);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<? extends ConfigInstance> getConfigClass(Class<? extends ConfigInstance.Builder> builderClass) {
+ Class<?> configClass = builderClass.getEnclosingClass();
+ if (configClass == null || ! ConfigInstance.class.isAssignableFrom(configClass)) {
+ throw new ConfigurationRuntimeException("Builder class " + builderClass + " has enclosing class " + configClass + ", which is not a ConfigInstance");
+ }
+ return (Class<? extends ConfigInstance>) configClass;
+ }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClient.java
new file mode 100644
index 00000000000..1ced0c4ce4f
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClient.java
@@ -0,0 +1,166 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.application;
+
+import ai.vespa.util.http.VespaAsyncHttpClientBuilder;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yahoo.concurrent.CompletableFutures;
+import com.yahoo.concurrent.DaemonThreadFactory;
+import com.yahoo.config.model.api.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.config.server.modelfactory.ModelResult;
+import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
+import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.util.Timeout;
+
+import java.io.IOException;
+import java.net.URI;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
+import static com.yahoo.yolean.Exceptions.throwUnchecked;
+import static com.yahoo.yolean.Exceptions.uncheck;
+
+/**
+ * Retrieves reindexing status from cluster controllers over HTTP
+ *
+ * @author bjorncs
+ */
+public class DefaultClusterReindexingStatusClient implements ClusterReindexingStatusClient {
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ private final Executor executor =
+ Executors.newSingleThreadExecutor(new DaemonThreadFactory("cluster-controller-reindexing-client-"));
+ private final CloseableHttpAsyncClient httpClient = createHttpClient();
+
+ public DefaultClusterReindexingStatusClient() {
+ httpClient.start();
+ }
+
+ @Override
+ public Map<String, ClusterReindexing> getReindexingStatus(ModelResult application) throws IOException {
+ Map<ClusterId, List<ServiceInfo>> clusters = clusterControllerClusters(application);
+ Map<ClusterId, CompletableFuture<Map<String, ClusterReindexing>>> futureStatusPerCluster = new HashMap<>();
+ clusters.forEach((clusterId, clusterNodes) -> {
+ var parallelRequests = clusterNodes.stream()
+ .map(this::getReindexingStatus)
+ .collect(Collectors.toList());
+ CompletableFuture<Map<String, ClusterReindexing>> combinedRequest = CompletableFutures.firstOf(parallelRequests);
+ futureStatusPerCluster.put(clusterId, combinedRequest);
+ });
+
+ try {
+ Map<String, ClusterReindexing> statusPerCluster = new HashMap<>();
+ futureStatusPerCluster.forEach((clusterId, futureStatus) -> {
+ statusPerCluster.putAll(futureStatus.join());
+ });
+ return Map.copyOf(statusPerCluster);
+ } catch (Exception e) {
+ throw new IOException("Failed to get reindexing status from cluster controllers: " + e.getMessage(), e);
+ }
+ }
+
+ @Override public void close() { uncheck(() -> httpClient.close()); }
+
+ private CompletableFuture<Map<String, ClusterReindexing>> getReindexingStatus(ServiceInfo service) {
+ URI uri = URI.create(String.format("http://%s:%d/reindexing/v1/status", service.getHostName(), getStatePort(service)));
+ CompletableFuture<SimpleHttpResponse> responsePromise = new CompletableFuture<>();
+ httpClient.execute(SimpleHttpRequests.get(uri), new FutureCallback<>() {
+ @Override public void completed(SimpleHttpResponse result) { responsePromise.complete(result); }
+ @Override public void failed(Exception ex) { responsePromise.completeExceptionally(ex); }
+ @Override public void cancelled() { responsePromise.cancel(false); }
+ });
+ return responsePromise.handleAsync((response, error) -> {
+ if (response != null) {
+ return uncheck(() -> toClusterReindexing(response));
+ } else {
+ throw throwUnchecked(new IOException(String.format("For '%s': %s", uri, error.getMessage()), error));
+ }
+ }, executor);
+ }
+
+ private static Map<String, ClusterReindexing> toClusterReindexing(SimpleHttpResponse response) throws IOException {
+ if (response.getCode() != HttpStatus.SC_OK) throw new IOException("Expected status code 200, got " + response.getCode());
+ if (response.getBody() == null) throw new IOException("Response has no content");
+ return toClusterReindexing(response.getBodyBytes());
+ }
+
+ private static Map<String, ClusterReindexing> toClusterReindexing(byte[] requestBody) throws IOException {
+ JsonNode jsonNode = mapper.readTree(requestBody);
+ Map<String, ClusterReindexing> clusters = new HashMap<>();
+ for (var clusterNames = jsonNode.get("clusters").fieldNames(); clusterNames.hasNext(); ) {
+ String clusterName = clusterNames.next();
+ JsonNode clusterJson = jsonNode.get("clusters").get(clusterName);
+ Map<String, ClusterReindexing.Status> documentStatuses = new HashMap<>();
+ for (var documentTypes = clusterJson.get("documentTypes").fieldNames(); documentTypes.hasNext(); ) {
+ String type = documentTypes.next();
+ JsonNode statusJson = clusterJson.get("documentTypes").get(type);
+ Instant startedMillis = Instant.ofEpochMilli(statusJson.get("startedMillis").longValue());
+ Instant endedMillis = Optional.ofNullable(statusJson.get("endedMillis"))
+ .map(json -> Instant.ofEpochMilli(json.longValue()))
+ .orElse(null);
+ Double progress = Optional.ofNullable(statusJson.get("progress"))
+ .map(JsonNode::doubleValue)
+ .orElse(null);
+ ClusterReindexing.State state = Optional.ofNullable(statusJson.get("state"))
+ .map(json -> ClusterReindexing.State.fromString(json.textValue()))
+ .orElse(null);
+ String message = Optional.ofNullable(statusJson.get("message"))
+ .map(JsonNode::textValue)
+ .orElse(null);
+ documentStatuses.put(type, new ClusterReindexing.Status(startedMillis, endedMillis, state, message, progress));
+ }
+ clusters.put(clusterName, new ClusterReindexing(documentStatuses));
+ }
+ return Map.copyOf(clusters);
+ }
+
+ private static int getStatePort(ServiceInfo service) {
+ return service.getPorts().stream()
+ .filter(port -> port.getTags().contains("state"))
+ .map(PortInfo::getPort)
+ .findAny()
+ .orElseThrow(() -> new IllegalStateException("Cluster controller container has no container port"));
+ }
+
+ private static Map<ClusterId, List<ServiceInfo>> clusterControllerClusters(ModelResult application) {
+ return application.getModel().getHosts().stream()
+ .flatMap(host -> host.getServices().stream())
+ .filter(service -> service.getServiceType().equals(CLUSTERCONTROLLER_CONTAINER.serviceName))
+ .collect(Collectors.groupingBy(service -> new ClusterId(service.getProperty("clustername").get())));
+
+ }
+
+ private static CloseableHttpAsyncClient createHttpClient() {
+ return VespaAsyncHttpClientBuilder
+ .create()
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(2))
+ .build())
+ .setDefaultRequestConfig(
+ RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(2))
+ .setConnectionRequestTimeout(Timeout.ofSeconds(2))
+ .setResponseTimeout(Timeout.ofSeconds(4))
+ .build())
+ .setUserAgent("cluster-controller-reindexing-client")
+ .build();
+
+ }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
index 0eeb9759a39..5a34217dbdd 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
@@ -27,6 +27,7 @@ import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import java.nio.file.Files;
@@ -185,16 +186,17 @@ public class TenantApplications implements RequestHandler, HostValidator<Applica
private void childEvent(CuratorFramework ignored, PathChildrenCacheEvent event) {
zkWatcherExecutor.execute(() -> {
- ApplicationId applicationId = ApplicationId.fromSerializedForm(Path.fromString(event.getData().getPath()).getName());
+ // Note: event.getData() might return null on types not handled here (CONNECTION_*, INITIALIZED, see javadoc)
switch (event.getType()) {
case CHILD_ADDED:
/* A new application is added when a session is added, @see
{@link com.yahoo.vespa.config.server.session.SessionRepository#childEvent(CuratorFramework, PathChildrenCacheEvent)} */
+ ApplicationId applicationId = ApplicationId.fromSerializedForm(Path.fromString(event.getData().getPath()).getName());
log.log(Level.FINE, TenantRepository.logPre(applicationId) + "Application added: " + applicationId);
break;
// Event CHILD_REMOVED will be triggered on all config servers if deleteApplication() above is called on one of them
case CHILD_REMOVED:
- removeApplication(applicationId);
+ removeApplication(ApplicationId.fromSerializedForm(Path.fromString(event.getData().getPath()).getName()));
break;
case CHILD_UPDATED:
// do nothing, application just got redeployed
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
index 5c24922c92f..fae06291f8f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
@@ -15,7 +15,6 @@ import com.yahoo.vespa.config.server.TimeoutBudget;
import com.yahoo.vespa.config.server.configchange.ConfigChangeActions;
import com.yahoo.vespa.config.server.configchange.ReindexActions;
import com.yahoo.vespa.config.server.configchange.RestartActions;
-import com.yahoo.vespa.config.server.http.InternalServerException;
import com.yahoo.vespa.config.server.session.PrepareParams;
import com.yahoo.vespa.config.server.session.Session;
import com.yahoo.vespa.config.server.tenant.Tenant;
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 720da3d40d3..14d156d39fb 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -25,6 +25,7 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.flags.UnboundFlag;
import java.io.File;
@@ -148,12 +149,63 @@ public class ModelContextImpl implements ModelContext {
public static class FeatureFlags implements ModelContext.FeatureFlags {
private final boolean enableAutomaticReindexing;
+ private final double reindexerWindowSizeIncrement;
+ private final double defaultTermwiseLimit;
+ private final boolean useThreePhaseUpdates;
+ private final boolean useDirectStorageApiRpc;
+ private final boolean useFastValueTensorImplementation;
+ private final String feedSequencer;
+ private final String responseSequencer;
+ private final int numResponseThreads;
+ private final boolean skipCommunicationManagerThread;
+ private final boolean skipMbusRequestThread;
+ private final boolean skipMbusReplyThread;
+ private final boolean useAccessControlTlsHandshakeClientAuth;
+ private final boolean useAsyncMessageHandlingOnSchedule;
+ private final int contentNodeBucketDBStripeBits;
+ private final int mergeChunkSize;
+ private final double feedConcurrency;
+ private final boolean reconfigurableZookeeperServer;
public FeatureFlags(FlagSource source, ApplicationId appId) {
this.enableAutomaticReindexing = flagValue(source, appId, Flags.ENABLE_AUTOMATIC_REINDEXING);
+ this.reindexerWindowSizeIncrement = flagValue(source, appId, Flags.REINDEXER_WINDOW_SIZE_INCREMENT);
+ this.defaultTermwiseLimit = flagValue(source, appId, Flags.DEFAULT_TERM_WISE_LIMIT);
+ this.useThreePhaseUpdates = flagValue(source, appId, Flags.USE_THREE_PHASE_UPDATES);
+ this.useDirectStorageApiRpc = flagValue(source, appId, Flags.USE_DIRECT_STORAGE_API_RPC);
+ this.useFastValueTensorImplementation = flagValue(source, appId, Flags.USE_FAST_VALUE_TENSOR_IMPLEMENTATION);
+ this.feedSequencer = flagValue(source, appId, Flags.FEED_SEQUENCER_TYPE);
+ this.responseSequencer = flagValue(source, appId, Flags.RESPONSE_SEQUENCER_TYPE);
+ this.numResponseThreads = flagValue(source, appId, Flags.RESPONSE_NUM_THREADS);
+ this.skipCommunicationManagerThread = flagValue(source, appId, Flags.SKIP_COMMUNICATIONMANAGER_THREAD);
+ this.skipMbusRequestThread = flagValue(source, appId, Flags.SKIP_MBUS_REQUEST_THREAD);
+ this.skipMbusReplyThread = flagValue(source, appId, Flags.SKIP_MBUS_REPLY_THREAD);
+ this.useAccessControlTlsHandshakeClientAuth = flagValue(source, appId, Flags.USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION);
+ this.useAsyncMessageHandlingOnSchedule = flagValue(source, appId, Flags.USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE);
+ this.contentNodeBucketDBStripeBits = flagValue(source, appId, Flags.CONTENT_NODE_BUCKET_DB_STRIPE_BITS);
+ this.mergeChunkSize = flagValue(source, appId, Flags.MERGE_CHUNK_SIZE);
+ this.feedConcurrency = flagValue(source, appId, Flags.FEED_CONCURRENCY);
+ this.reconfigurableZookeeperServer = flagValue(source, appId, Flags.RECONFIGURABLE_ZOOKEEPER_SERVER_FOR_CLUSTER_CONTROLLER);
}
@Override public boolean enableAutomaticReindexing() { return enableAutomaticReindexing; }
+ @Override public double reindexerWindowSizeIncrement() { return reindexerWindowSizeIncrement; }
+ @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
+ @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; }
+ @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; }
+ @Override public boolean useFastValueTensorImplementation() { return useFastValueTensorImplementation; }
+ @Override public String feedSequencerType() { return feedSequencer; }
+ @Override public String responseSequencerType() { return responseSequencer; }
+ @Override public int defaultNumResponseThreads() { return numResponseThreads; }
+ @Override public boolean skipCommunicationManagerThread() { return skipCommunicationManagerThread; }
+ @Override public boolean skipMbusRequestThread() { return skipMbusRequestThread; }
+ @Override public boolean skipMbusReplyThread() { return skipMbusReplyThread; }
+ @Override public boolean useAccessControlTlsHandshakeClientAuth() { return useAccessControlTlsHandshakeClientAuth; }
+ @Override public boolean useAsyncMessageHandlingOnSchedule() { return useAsyncMessageHandlingOnSchedule; }
+ @Override public int contentNodeBucketDBStripeBits() { return contentNodeBucketDBStripeBits; }
+ @Override public int mergeChunkSize() { return mergeChunkSize; }
+ @Override public double feedConcurrency() { return feedConcurrency; }
+ @Override public boolean reconfigurableZookeeperServer() { return reconfigurableZookeeperServer; }
private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) {
return flag.bindTo(source)
@@ -163,6 +215,7 @@ public class ModelContextImpl implements ModelContext {
}
+ @SuppressWarnings("deprecation") // for old feature flag methods in ModelContext.Properties
public static class Properties implements ModelContext.Properties {
private final ModelContext.FeatureFlags featureFlags;
@@ -177,21 +230,24 @@ public class ModelContextImpl implements ModelContext {
private final Set<ContainerEndpoint> endpoints;
private final boolean isBootstrap;
private final boolean isFirstTimeDeployment;
+ private final Optional<EndpointCertificateSecrets> endpointCertificateSecrets;
+ private final Optional<AthenzDomain> athenzDomain;
+ private final Optional<ApplicationRoles> applicationRoles;
+ private final Quota quota;
+
+ private final String jvmGCOPtions;
+
+ // Old non-permanent feature flags. Use ModelContext.FeatureFlag instead
+ private final double defaultTermwiseLimit;
private final boolean useThreePhaseUpdates;
private final boolean useDirectStorageApiRpc;
private final boolean useFastValueTensorImplementation;
- private final Optional<EndpointCertificateSecrets> endpointCertificateSecrets;
- private final double defaultTermwiseLimit;
- private final String jvmGCOPtions;
private final String feedSequencer;
private final String responseSequencer;
private final int numResponseThreads;
private final boolean skipCommunicationManagerThread;
private final boolean skipMbusRequestThread;
private final boolean skipMbusReplyThread;
- private final Optional<AthenzDomain> athenzDomain;
- private final Optional<ApplicationRoles> applicationRoles;
- private final Quota quota;
private final boolean useAccessControlTlsHandshakeClientAuth;
private final boolean useAsyncMessageHandlingOnSchedule;
private final int contentNodeBucketDBStripeBits;
@@ -222,43 +278,28 @@ public class ModelContextImpl implements ModelContext {
this.isBootstrap = isBootstrap;
this.isFirstTimeDeployment = isFirstTimeDeployment;
this.endpointCertificateSecrets = endpointCertificateSecrets;
- defaultTermwiseLimit = Flags.DEFAULT_TERM_WISE_LIMIT.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- useThreePhaseUpdates = Flags.USE_THREE_PHASE_UPDATES.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- useDirectStorageApiRpc = Flags.USE_DIRECT_STORAGE_API_RPC.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- useFastValueTensorImplementation = Flags.USE_FAST_VALUE_TENSOR_IMPLEMENTATION.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- jvmGCOPtions = Flags.JVM_GC_OPTIONS.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- feedSequencer = Flags.FEED_SEQUENCER_TYPE.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- responseSequencer = Flags.RESPONSE_SEQUENCER_TYPE.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- numResponseThreads = Flags.RESPONSE_NUM_THREADS.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- skipCommunicationManagerThread = Flags.SKIP_COMMUNICATIONMANAGER_THREAD.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- skipMbusRequestThread = Flags.SKIP_MBUS_REQUEST_THREAD.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- skipMbusReplyThread = Flags.SKIP_MBUS_REPLY_THREAD.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
this.athenzDomain = athenzDomain;
this.applicationRoles = applicationRoles;
this.quota = maybeQuota.orElseGet(Quota::unlimited);
- this.useAccessControlTlsHandshakeClientAuth =
- Flags.USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm())
- .value();
- useAsyncMessageHandlingOnSchedule = Flags.USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- contentNodeBucketDBStripeBits = Flags.CONTENT_NODE_BUCKET_DB_STRIPE_BITS.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- mergeChunkSize = Flags.MERGE_CHUNK_SIZE.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
- feedConcurrency = Flags.FEED_CONCURRENCY.bindTo(flagSource)
- .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
+
+ jvmGCOPtions = flagValue(flagSource, applicationId, PermanentFlags.JVM_GC_OPTIONS);
+
+ // Old non-permanent feature flags. Use ModelContext.FeatureFlag instead
+ defaultTermwiseLimit = flagValue(flagSource, applicationId, Flags.DEFAULT_TERM_WISE_LIMIT);
+ useThreePhaseUpdates = flagValue(flagSource, applicationId, Flags.USE_THREE_PHASE_UPDATES);
+ useDirectStorageApiRpc = flagValue(flagSource, applicationId, Flags.USE_DIRECT_STORAGE_API_RPC);
+ useFastValueTensorImplementation = flagValue(flagSource, applicationId, Flags.USE_FAST_VALUE_TENSOR_IMPLEMENTATION);
+ feedSequencer = flagValue(flagSource, applicationId, Flags.FEED_SEQUENCER_TYPE);
+ responseSequencer = flagValue(flagSource, applicationId, Flags.RESPONSE_SEQUENCER_TYPE);
+ numResponseThreads = flagValue(flagSource, applicationId, Flags.RESPONSE_NUM_THREADS);
+ skipCommunicationManagerThread = flagValue(flagSource, applicationId, Flags.SKIP_COMMUNICATIONMANAGER_THREAD);
+ skipMbusRequestThread = flagValue(flagSource, applicationId, Flags.SKIP_MBUS_REQUEST_THREAD);
+ skipMbusReplyThread = flagValue(flagSource, applicationId, Flags.SKIP_MBUS_REPLY_THREAD);
+ this.useAccessControlTlsHandshakeClientAuth = flagValue(flagSource, applicationId, Flags.USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION);
+ useAsyncMessageHandlingOnSchedule = flagValue(flagSource, applicationId, Flags.USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE);
+ contentNodeBucketDBStripeBits = flagValue(flagSource, applicationId, Flags.CONTENT_NODE_BUCKET_DB_STRIPE_BITS);
+ mergeChunkSize = flagValue(flagSource, applicationId, Flags.MERGE_CHUNK_SIZE);
+ feedConcurrency = flagValue(flagSource, applicationId, Flags.FEED_CONCURRENCY);
}
@Override public ModelContext.FeatureFlags featureFlags() { return featureFlags; }
@@ -304,24 +345,6 @@ public class ModelContextImpl implements ModelContext {
public Optional<EndpointCertificateSecrets> endpointCertificateSecrets() { return endpointCertificateSecrets; }
@Override
- public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
-
- @Override
- public boolean useThreePhaseUpdates() {
- return useThreePhaseUpdates;
- }
-
- @Override
- public boolean useDirectStorageApiRpc() {
- return useDirectStorageApiRpc;
- }
-
- @Override
- public boolean useFastValueTensorImplementation() {
- return useFastValueTensorImplementation;
- }
-
- @Override
public Optional<AthenzDomain> athenzDomain() { return athenzDomain; }
@Override
@@ -329,19 +352,32 @@ public class ModelContextImpl implements ModelContext {
return applicationRoles;
}
+ @Override public Quota quota() { return quota; }
+
@Override public String jvmGCOptions() { return jvmGCOPtions; }
+
+ // Old non-permanent feature flags. Use ModelContext.FeatureFlag instead
+ @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
+ @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; }
+ @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; }
+ @Override public boolean useFastValueTensorImplementation() { return useFastValueTensorImplementation; }
@Override public String feedSequencerType() { return feedSequencer; }
@Override public String responseSequencerType() { return responseSequencer; }
@Override public int defaultNumResponseThreads() { return numResponseThreads; }
@Override public boolean skipCommunicationManagerThread() { return skipCommunicationManagerThread; }
@Override public boolean skipMbusRequestThread() { return skipMbusRequestThread; }
@Override public boolean skipMbusReplyThread() { return skipMbusReplyThread; }
- @Override public Quota quota() { return quota; }
@Override public boolean useAccessControlTlsHandshakeClientAuth() { return useAccessControlTlsHandshakeClientAuth; }
@Override public boolean useAsyncMessageHandlingOnSchedule() { return useAsyncMessageHandlingOnSchedule; }
@Override public int contentNodeBucketDBStripeBits() { return contentNodeBucketDBStripeBits; }
@Override public int mergeChunkSize() { return mergeChunkSize; }
@Override public double feedConcurrency() { return feedConcurrency; }
+
+ private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) {
+ return flag.bindTo(source)
+ .with(FetchVector.Dimension.APPLICATION_ID, appId.serializedForm())
+ .boxedValue();
+ }
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
index b924e07ff47..7ea53a66697 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
@@ -16,6 +16,7 @@ import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.application.BindingMatch;
import com.yahoo.jdisc.application.UriPattern;
import com.yahoo.slime.Cursor;
+import com.yahoo.text.StringUtilities;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.application.ApplicationReindexing;
import com.yahoo.vespa.config.server.application.ClusterReindexing;
@@ -28,6 +29,7 @@ import com.yahoo.vespa.config.server.http.NotFoundException;
import com.yahoo.vespa.config.server.tenant.Tenant;
import java.io.IOException;
+import java.net.URLDecoder;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
@@ -35,8 +37,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Stream;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Map.Entry.comparingByKey;
import static java.util.stream.Collectors.toList;
@@ -86,7 +90,7 @@ public class ApplicationHandler extends HttpHandler {
if (isReindexingRequest(request)) {
applicationRepository.modifyReindexing(applicationId, reindexing -> reindexing.enabled(false));
- return new JSONResponse(Response.Status.OK);
+ return createMessageResponse("Reindexing disabled");
}
if (applicationRepository.delete(applicationId))
@@ -109,7 +113,7 @@ public class ApplicationHandler extends HttpHandler {
if (isClusterControllerStatusRequest(request)) {
String hostName = getHostNameFromRequest(request);
- String pathSuffix = getPathSuffix(request);
+ String pathSuffix = URLDecoder.decode(getPathSuffix(request), UTF_8);
return applicationRepository.clusterControllerStatusPage(applicationId, hostName, pathSuffix);
}
@@ -211,27 +215,20 @@ public class ApplicationHandler extends HttpHandler {
}
if (isReindexRequest(request)) {
- triggerReindexing(request, applicationId);
- return new JSONResponse(Response.Status.OK);
+ return triggerReindexing(request, applicationId);
}
if (isReindexingRequest(request)) {
applicationRepository.modifyReindexing(applicationId, reindexing -> reindexing.enabled(true));
- return new JSONResponse(Response.Status.OK);
+ return createMessageResponse("Reindexing enabled");
}
throw new NotFoundException("Illegal POST request '" + request.getUri() + "'");
}
- private void triggerReindexing(HttpRequest request, ApplicationId applicationId) {
- List<String> clusters = Optional.ofNullable(request.getProperty("clusterId")).stream()
- .flatMap(value -> Stream.of(value.split(",")))
- .filter(cluster -> ! cluster.isBlank())
- .collect(toList());
- List<String> types = Optional.ofNullable(request.getProperty("documentType")).stream()
- .flatMap(value -> Stream.of(value.split(",")))
- .filter(type -> ! type.isBlank())
- .collect(toList());
+ private HttpResponse triggerReindexing(HttpRequest request, ApplicationId applicationId) {
+ Set<String> clusters = StringUtilities.split(request.getProperty("clusterId"));
+ Set<String> types = StringUtilities.split(request.getProperty("documentType"));
Instant now = applicationRepository.clock().instant();
applicationRepository.modifyReindexing(applicationId, reindexing -> {
if (clusters.isEmpty())
@@ -245,6 +242,14 @@ public class ApplicationHandler extends HttpHandler {
reindexing = reindexing.withReady(cluster, type, now);
return reindexing;
});
+
+ String message = "Reindexing " +
+ (clusters.isEmpty() ? ""
+ : (types.isEmpty() ? ""
+ : "document types " + String.join(", ", types) + " in ") +
+ "clusters " + String.join(", ", clusters) + " of ") +
+ "application " + applicationId;
+ return createMessageResponse(message);
}
private HttpResponse getReindexingStatus(ApplicationId applicationId) {
@@ -255,7 +260,7 @@ public class ApplicationHandler extends HttpHandler {
return new ReindexingResponse(tenant.getApplicationRepo().database()
.readReindexingStatus(applicationId)
.orElseThrow(() -> new NotFoundException("Reindexing status not found for " + applicationId)),
- Map.of()); // TODO jonmv/bjorncs: Get status of each cluster and fill in here.
+ applicationRepository.getClusterReindexingStatus(applicationId));
}
private HttpResponse restart(HttpRequest request, ApplicationId applicationId) {
@@ -481,21 +486,15 @@ public class ApplicationHandler extends HttpHandler {
private static void setStatus(Cursor object, ClusterReindexing.Status status) {
object.setLong("startedMillis", status.startedAt().toEpochMilli());
status.endedAt().ifPresent(endedAt -> object.setLong("endedMillis", endedAt.toEpochMilli()));
- status.state().map(ReindexingResponse::toString).ifPresent(state -> object.setString("state", state));
+ status.state().map(ClusterReindexing.State::asString).ifPresent(state -> object.setString("state", state));
status.message().ifPresent(message -> object.setString("message", message));
- status.progress().ifPresent(progress -> object.setString("progress", progress));
+ status.progress().ifPresent(progress -> object.setDouble("progress", progress));
}
- static String toString(ClusterReindexing.State state) {
- switch (state) {
- case PENDING: return "pending";
- case RUNNING: return "running";
- case FAILED: return "failed";
- case SUCCESSFUL: return "successful";
- default: throw new IllegalArgumentException("Unexpected state '" + state + "'");
- }
- }
+ }
+ private static JSONResponse createMessageResponse(String message) {
+ return new JSONResponse(Response.Status.OK) { { object.setString("message", message); } };
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
index aa709b3bf37..7ba8b1be491 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
@@ -38,7 +38,7 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer {
Curator curator,
Duration interval,
FlagSource flagSource) {
- super(applicationRepository, curator, flagSource, interval, interval);
+ super(applicationRepository, curator, flagSource, applicationRepository.clock().instant(), interval);
this.applicationRepository = applicationRepository;
ConfigserverConfig configserverConfig = applicationRepository.configserverConfig();
connectionPool = createConnectionPool(configserverConfig);
@@ -78,9 +78,9 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer {
}
@Override
- public void close() {
+ public void awaitShutdown() {
connectionPool.close();
- super.close();
+ super.awaitShutdown();
}
private void createLocalSessionIfMissing(ApplicationId applicationId, long sessionId) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java
index 61d411802ad..0b70fca8908 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintainer.java
@@ -5,15 +5,14 @@ import com.yahoo.concurrent.maintenance.JobControl;
import com.yahoo.concurrent.maintenance.JobControlState;
import com.yahoo.concurrent.maintenance.JobMetrics;
import com.yahoo.concurrent.maintenance.Maintainer;
-import com.yahoo.config.provision.HostName;
import com.yahoo.jdisc.Metric;
import com.yahoo.path.Path;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.ListFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import java.time.Duration;
import java.time.Instant;
@@ -40,13 +39,6 @@ public abstract class ConfigServerMaintainer extends Maintainer {
this.applicationRepository = applicationRepository;
}
- ConfigServerMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource,
- Duration initialDelay, Duration interval) {
- super(null, interval, initialDelay, new JobControl(new JobControlFlags(curator, flagSource)),
- jobMetrics(applicationRepository.metric()));
- this.applicationRepository = applicationRepository;
- }
-
private static JobMetrics jobMetrics(Metric metric) {
return new JobMetrics((job, consecutiveFailures) -> {
metric.set("maintenance.consecutiveFailures", consecutiveFailures, metric.createContext(Map.of("job", job)));
@@ -64,7 +56,7 @@ public abstract class ConfigServerMaintainer extends Maintainer {
public JobControlFlags(Curator curator, FlagSource flagSource) {
this.curator = curator;
- this.inactiveJobsFlag = Flags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
+ this.inactiveJobsFlag = PermanentFlags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
}
@Override
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java
index 21462bc4fec..837f025ec2b 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java
@@ -4,7 +4,7 @@ package com.yahoo.vespa.config.server.maintenance;
import com.google.inject.Inject;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.component.AbstractComponent;
-import com.yahoo.jdisc.Metric;
+import com.yahoo.concurrent.maintenance.Maintainer;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.ConfigServerBootstrap;
import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker;
@@ -13,6 +13,8 @@ import com.yahoo.vespa.flags.FlagSource;
import java.time.Clock;
import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Maintenance jobs of the config server.
@@ -24,11 +26,7 @@ import java.time.Duration;
*/
public class ConfigServerMaintenance extends AbstractComponent {
- private final TenantsMaintainer tenantsMaintainer;
- private final FileDistributionMaintainer fileDistributionMaintainer;
- private final SessionsMaintainer sessionsMaintainer;
- private final ApplicationPackageMaintainer applicationPackageMaintainer;
- private final ReindexingMaintainer reindexingMaintainer;
+ private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>();
@Inject
public ConfigServerMaintenance(ConfigServerBootstrap configServerBootstrap,
@@ -38,20 +36,17 @@ public class ConfigServerMaintenance extends AbstractComponent {
FlagSource flagSource,
ConfigConvergenceChecker convergence) {
DefaultTimes defaults = new DefaultTimes(configserverConfig);
- tenantsMaintainer = new TenantsMaintainer(applicationRepository, curator, flagSource, defaults.defaultInterval, Clock.systemUTC());
- fileDistributionMaintainer = new FileDistributionMaintainer(applicationRepository, curator, defaults.defaultInterval, flagSource);
- sessionsMaintainer = new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource);
- applicationPackageMaintainer = new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource);
- reindexingMaintainer = new ReindexingMaintainer(applicationRepository, curator, flagSource, Duration.ofMinutes(3), convergence, Clock.systemUTC());
+ maintainers.add(new TenantsMaintainer(applicationRepository, curator, flagSource, defaults.defaultInterval, Clock.systemUTC()));
+ maintainers.add(new FileDistributionMaintainer(applicationRepository, curator, defaults.defaultInterval, flagSource));
+ maintainers.add(new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource));
+ maintainers.add(new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource));
+ maintainers.add(new ReindexingMaintainer(applicationRepository, curator, flagSource, Duration.ofMinutes(3), convergence, Clock.systemUTC()));
}
@Override
public void deconstruct() {
- fileDistributionMaintainer.close();
- sessionsMaintainer.close();
- applicationPackageMaintainer.close();
- tenantsMaintainer.close();
- reindexingMaintainer.close();
+ maintainers.forEach(Maintainer::shutdown);
+ maintainers.forEach(Maintainer::awaitShutdown);
}
/*
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java
index 8e5069abfed..6e7fc2ebc31 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java
@@ -26,7 +26,7 @@ public class FileDistributionMaintainer extends ConfigServerMaintainer {
Curator curator,
Duration interval,
FlagSource flagSource) {
- super(applicationRepository, curator, flagSource, interval, interval);
+ super(applicationRepository, curator, flagSource, applicationRepository.clock().instant(), interval);
this.applicationRepository = applicationRepository;
this.maxUnusedFileReferenceAge = Duration.ofHours(applicationRepository.configserverConfig().keepUnusedFileReferencesHours());
this.fileReferencesDir = new File(Defaults.getDefaults().underVespaHome(applicationRepository.configserverConfig().fileReferencesDir()));
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java
index cd3e1d97b28..22eb95261bd 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java
@@ -35,8 +35,6 @@ public class ReindexingMaintainer extends ConfigServerMaintainer {
/** Timeout per service when getting config generations. */
private static final Duration timeout = Duration.ofSeconds(10);
- static final Duration reindexingInterval = Duration.ofDays(28);
-
private final ConfigConvergenceChecker convergence;
private final Clock clock;
@@ -89,11 +87,6 @@ public class ReindexingMaintainer extends ConfigServerMaintainer {
reindexing = reindexing.withReady(cluster.getKey(), pending.getKey(), now)
.withoutPending(cluster.getKey(), pending.getKey());
- // Additionally, reindex the whole application with a fixed interval.
- Instant nextPeriodicReindexing = reindexing.common().ready();
- while ((nextPeriodicReindexing = nextPeriodicReindexing.plus(reindexingInterval)).isBefore(now))
- reindexing = reindexing.withReady(nextPeriodicReindexing); // Deterministic timestamp.
-
return reindexing;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
index e59c334b89f..7482980e221 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
@@ -20,7 +20,7 @@ public class SessionsMaintainer extends ConfigServerMaintainer {
private int iteration = 0;
SessionsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, FlagSource flagSource) {
- super(applicationRepository, curator, flagSource, Duration.ofMinutes(1), interval);
+ super(applicationRepository, curator, flagSource, applicationRepository.clock().instant(), interval);
this.hostedVespa = applicationRepository.configserverConfig().hostedVespa();
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java
index 6a69665b8ad..7c01045ee72 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java
@@ -25,7 +25,7 @@ public class TenantsMaintainer extends ConfigServerMaintainer {
TenantsMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource,
Duration interval, Clock clock) {
- super(applicationRepository, curator, flagSource, interval, interval);
+ super(applicationRepository, curator, flagSource, applicationRepository.clock().instant(), interval);
this.ttlForUnusedTenant = defaultTtlForUnusedTenant;
this.clock = clock;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
index a3a8bba567a..0a81c408ef4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
@@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableSet;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelFactory;
import com.yahoo.config.model.api.Provisioned;
@@ -18,6 +19,7 @@ import com.yahoo.vespa.config.server.GlobalComponentRegistry;
import com.yahoo.vespa.config.server.ServerCache;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.application.ApplicationCuratorDatabase;
+import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.application.PermanentApplicationPackage;
import com.yahoo.vespa.config.server.deploy.ModelContextImpl;
import com.yahoo.vespa.config.server.monitoring.MetricUpdater;
@@ -33,6 +35,7 @@ import com.yahoo.vespa.config.server.tenant.TenantRepository;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.flags.FlagSource;
+import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
@@ -50,6 +53,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
private final TenantName tenant;
private final long applicationGeneration;
private final SessionZooKeeperClient zkClient;
+ private final Optional<ApplicationSet> currentActiveApplicationSet;
private final PermanentApplicationPackage permanentApplicationPackage;
private final ConfigDefinitionRepo configDefinitionRepo;
private final Metrics metrics;
@@ -60,6 +64,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
public ActivatedModelsBuilder(TenantName tenant,
long applicationGeneration,
SessionZooKeeperClient zkClient,
+ Optional<ApplicationSet> currentActiveApplicationSet,
GlobalComponentRegistry globalComponentRegistry) {
super(globalComponentRegistry.getModelFactoryRegistry(),
globalComponentRegistry.getConfigserverConfig(),
@@ -68,6 +73,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
this.tenant = tenant;
this.applicationGeneration = applicationGeneration;
this.zkClient = zkClient;
+ this.currentActiveApplicationSet = currentActiveApplicationSet;
this.permanentApplicationPackage = globalComponentRegistry.getPermanentApplicationPackage();
this.configDefinitionRepo = globalComponentRegistry.getStaticConfigDefinitionRepo();
this.metrics = globalComponentRegistry.getMetrics();
@@ -90,7 +96,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
Provisioned provisioned = new Provisioned();
ModelContext modelContext = new ModelContextImpl(
applicationPackage,
- Optional.empty(),
+ modelOf(modelFactory.version()),
permanentApplicationPackage.applicationPackage(),
new SilentDeployLogger(),
configDefinitionRepo,
@@ -110,19 +116,23 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
return new Application(modelFactory.createModel(modelContext),
serverCache,
applicationGeneration,
- applicationPackage.getMetaData().isInternalRedeploy(),
modelFactory.version(),
applicationMetricUpdater,
applicationId);
}
+ private Optional<Model> modelOf(Version version) {
+ if (currentActiveApplicationSet.isEmpty()) return Optional.empty();
+ return currentActiveApplicationSet.get().get(version).map(Application::getModel);
+ }
+
private static <T> Optional<T> getForVersionOrLatest(Map<Version, T> map, Version version) {
if (map.isEmpty()) {
return Optional.empty();
}
T value = map.get(version);
if (value == null) {
- value = map.get(map.keySet().stream().max((a, b) -> a.compareTo(b)).get());
+ value = map.get(map.keySet().stream().max(Comparator.naturalOrder()).get());
}
return Optional.of(value);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java
index 05460c8b30e..79d70f1cb4e 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/provision/ProvisionerAdapter.java
@@ -44,6 +44,4 @@ public class ProvisionerAdapter implements HostProvisioner {
return provisioner.prepare(applicationId, cluster, capacity, logger);
}
-
-
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java
index 415fa764823..8003b2a2be9 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java
@@ -26,12 +26,13 @@ public interface ConfigResponseFactory {
/**
* Creates a {@link ConfigResponse} for a given payload and generation.
- * @param payload the {@link ConfigPayload} to put in the response
- * @param generation the payload generation
- * @param internalRedeploy whether this config generation was produced by an internal redeployment
- * not a change to the application package
+ *
+ * @param payload the {@link ConfigPayload} to put in the response
+ * @param generation the payload generation
+ * @param applyOnRestart true if this config change should only be applied on restart,
+ * false if it should be applied immediately
* @return a {@link ConfigResponse} that can be sent to the client
*/
- ConfigResponse createResponse(ConfigPayload payload, long generation, boolean internalRedeploy);
+ ConfigResponse createResponse(ConfigPayload payload, long generation, boolean applyOnRestart);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java
index 62f7d3ce5d0..010640b967f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java
@@ -125,7 +125,7 @@ class GetConfigProcessor implements Runnable {
// config == null is not an error, but indicates that the config will be returned later.
if ((config != null) && (!config.hasEqualConfig(request) || config.hasNewerGeneration(request) || forceResponse)) {
// debugLog(trace, "config response before encoding:" + config.toString());
- request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), config.isInternalRedeploy(), config.getConfigMd5());
+ request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), config.applyOnRestart(), config.getConfigMd5());
if (logDebug(trace)) {
debugLog(trace, "return response: " + request.getShortDescription());
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java
index cba1316a131..619e6c0a2a2 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java
@@ -22,12 +22,12 @@ public class LZ4ConfigResponseFactory implements ConfigResponseFactory {
@Override
public ConfigResponse createResponse(ConfigPayload payload,
long generation,
- boolean internalRedeploy) {
+ boolean applyOnRestart) {
Utf8Array rawPayload = payload.toUtf8Array(true);
String configMd5 = ConfigUtils.getMd5(rawPayload);
CompressionInfo info = CompressionInfo.create(CompressionType.LZ4, rawPayload.getByteLength());
Utf8Array compressed = new Utf8Array(compressor.compress(rawPayload.getBytes()));
- return new SlimeConfigResponse(compressed, generation, internalRedeploy, configMd5, info);
+ return new SlimeConfigResponse(compressed, generation, applyOnRestart, configMd5, info);
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java
index 2de88ab44cc..8d852ebd8c9 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java
@@ -19,11 +19,11 @@ public class UncompressedConfigResponseFactory implements ConfigResponseFactory
@Override
public ConfigResponse createResponse(ConfigPayload payload,
long generation,
- boolean internalRedeploy) {
+ boolean applyOnRestart) {
Utf8Array rawPayload = payload.toUtf8Array(true);
String configMd5 = ConfigUtils.getMd5(rawPayload);
CompressionInfo info = CompressionInfo.create(CompressionType.UNCOMPRESSED, rawPayload.getByteLength());
- return new SlimeConfigResponse(rawPayload, generation, internalRedeploy, configMd5, info);
+ return new SlimeConfigResponse(rawPayload, generation, applyOnRestart, configMd5, info);
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
index 54da80a0299..49a8df3d0e4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
@@ -11,7 +11,6 @@ import com.yahoo.config.provision.security.NodeIdentifierException;
import com.yahoo.config.provision.security.NodeIdentity;
import com.yahoo.jrt.Request;
import com.yahoo.jrt.SecurityContext;
-import java.util.logging.Level;
import com.yahoo.security.tls.MixedMode;
import com.yahoo.security.tls.TransportSecurityUtils;
import com.yahoo.vespa.config.ConfigKey;
@@ -29,9 +28,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.BiConsumer;
+import java.util.logging.Level;
import java.util.logging.Logger;
-import static com.yahoo.vespa.config.server.rpc.security.AuthorizationException.*;
+import static com.yahoo.vespa.config.server.rpc.security.AuthorizationException.Type;
+import static com.yahoo.yolean.Exceptions.throwUnchecked;
/**
@@ -206,11 +207,6 @@ public class MultiTenantRpcAuthorizer implements RpcAuthorizer {
.orElseThrow(() -> new AuthorizationException(String.format("No handler exists for tenant '%s'", tenantName.value())));
}
- @SuppressWarnings("unchecked")
- private static <T extends Throwable> void throwUnchecked(Throwable t) throws T {
- throw (T)t;
- }
-
private enum JrtErrorCode {
UNAUTHORIZED(1),
AUTHORIZATION_FAILED(2);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
index f84defce635..f1775492003 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
@@ -1,7 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.session;
-import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.UncheckedTimeoutException;
import com.google.inject.Inject;
import com.yahoo.cloud.config.ConfigserverConfig;
@@ -349,11 +348,11 @@ public class SessionPreparer {
static class PrepareResult {
private final AllocatedHosts allocatedHosts;
- private final ImmutableList<PreparedModelsBuilder.PreparedModelResult> results;
+ private final List<PreparedModelsBuilder.PreparedModelResult> results;
public PrepareResult(AllocatedHosts allocatedHosts, List<PreparedModelsBuilder.PreparedModelResult> results) {
this.allocatedHosts = allocatedHosts;
- this.results = ImmutableList.copyOf(results);
+ this.results = List.copyOf(results);
}
/** Returns the results for each model as an immutable list */
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
index 93c1e4c2b50..64b757037d0 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
@@ -88,6 +88,7 @@ public class SessionRepository {
private final Path sessionsPath;
private final TenantName tenantName;
private final GlobalComponentRegistry componentRegistry;
+ private final SessionCounter sessionCounter;
public SessionRepository(TenantName tenantName,
GlobalComponentRegistry componentRegistry,
@@ -95,6 +96,7 @@ public class SessionRepository {
SessionPreparer sessionPreparer) {
this.tenantName = tenantName;
this.componentRegistry = componentRegistry;
+ sessionCounter = new SessionCounter(componentRegistry.getConfigCurator(), tenantName);
this.sessionsPath = TenantRepository.getSessionsPath(tenantName);
this.clock = componentRegistry.getClock();
this.curator = componentRegistry.getCurator();
@@ -171,7 +173,9 @@ public class SessionRepository {
* @param timeoutBudget timeout for creating session and waiting for other servers.
* @return a new session
*/
- public LocalSession createSessionFromExisting(Session existingSession, boolean internalRedeploy, TimeoutBudget timeoutBudget) {
+ public LocalSession createSessionFromExisting(Session existingSession,
+ boolean internalRedeploy,
+ TimeoutBudget timeoutBudget) {
ApplicationId existingApplicationId = existingSession.getApplicationId();
File existingApp = getSessionAppDir(existingSession.getSessionId());
LocalSession session = createSessionFromApplication(existingApp, existingApplicationId, internalRedeploy, timeoutBudget);
@@ -368,8 +372,10 @@ public class SessionRepository {
if (session.applicationSet().isPresent()) {
return session.applicationSet().get();
}
-
- ApplicationSet applicationSet = loadApplication(session);
+ Optional<Long> activeSessionId = getActiveSessionId(session.getApplicationId());
+ Optional<ApplicationSet> previousApplicationSet = activeSessionId.filter(session::isNewerThan)
+ .flatMap(this::getApplicationSet);
+ ApplicationSet applicationSet = loadApplication(session, previousApplicationSet);
RemoteSession activated = session.activated(applicationSet);
long sessionId = activated.getSessionId();
remoteSessionCache.put(sessionId, activated);
@@ -410,13 +416,14 @@ public class SessionRepository {
}
}
- private ApplicationSet loadApplication(Session session) {
+ private ApplicationSet loadApplication(Session session, Optional<ApplicationSet> previousApplicationSet) {
log.log(Level.FINE, () -> "Loading application for " + session);
SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(session.getSessionId());
ApplicationPackage applicationPackage = sessionZooKeeperClient.loadApplicationPackage();
ActivatedModelsBuilder builder = new ActivatedModelsBuilder(session.getTenantName(),
session.getSessionId(),
sessionZooKeeperClient,
+ previousApplicationSet,
componentRegistry);
// Read hosts allocated on the config server instance which created this
SettableOptional<AllocatedHosts> allocatedHosts = new SettableOptional<>(applicationPackage.getAllocatedHosts());
@@ -557,15 +564,18 @@ public class SessionRepository {
}
public Optional<ApplicationSet> getActiveApplicationSet(ApplicationId appId) {
- Optional<ApplicationSet> currentActiveApplicationSet = Optional.empty();
+ return applicationRepo.activeSessionOf(appId).flatMap(this::getApplicationSet);
+ }
+
+ private Optional<ApplicationSet> getApplicationSet(long sessionId) {
+ Optional<ApplicationSet> applicationSet = Optional.empty();
try {
- long currentActiveSessionId = applicationRepo.requireActiveSessionOf(appId);
- RemoteSession currentActiveSession = getRemoteSession(currentActiveSessionId);
- currentActiveApplicationSet = Optional.ofNullable(ensureApplicationLoaded(currentActiveSession));
+ RemoteSession session = getRemoteSession(sessionId);
+ applicationSet = Optional.ofNullable(ensureApplicationLoaded(session));
} catch (IllegalArgumentException e) {
// Do nothing if we have no currently active session
}
- return currentActiveApplicationSet;
+ return applicationSet;
}
private void copyApp(File sourceDir, File destinationDir) throws IOException {
@@ -647,7 +657,7 @@ public class SessionRepository {
}
private long getNextSessionId() {
- return new SessionCounter(componentRegistry.getConfigCurator(), tenantName).nextSessionId();
+ return sessionCounter.nextSessionId();
}
public Path getSessionPath(long sessionId) {
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
index 6694ac8c694..d094ad09bec 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
@@ -88,11 +88,11 @@ public class ModelContextImplTest {
assertEquals(Optional.empty(), context.wantedDockerImageRepo());
assertEquals(new Version(7), context.modelVespaVersion());
assertEquals(new Version(8), context.wantedNodeVespaVersion());
- assertEquals(1.0, context.properties().defaultTermwiseLimit(), 0.0);
- assertFalse(context.properties().useAsyncMessageHandlingOnSchedule());
- assertEquals(0, context.properties().contentNodeBucketDBStripeBits());
- assertEquals(0x400000, context.properties().mergeChunkSize());
- assertEquals(0.5, context.properties().feedConcurrency(), 0.0);
+ assertEquals(1.0, context.properties().featureFlags().defaultTermwiseLimit(), 0.0);
+ assertFalse(context.properties().featureFlags().useAsyncMessageHandlingOnSchedule());
+ assertEquals(0, context.properties().featureFlags().contentNodeBucketDBStripeBits());
+ assertEquals(0x400000, context.properties().featureFlags().mergeChunkSize());
+ assertEquals(0.5, context.properties().featureFlags().feedConcurrency(), 0.0);
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java
index 8b515ff837b..88f7d352ad7 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.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.config.server;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.HostInfo;
@@ -20,11 +21,17 @@ import java.util.Set;
public class ModelStub implements Model {
@Override
+ @SuppressWarnings("deprecation")
public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
return null;
}
@Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Set<ConfigKey<?>> allConfigsProduced() {
return null;
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java
index 26ef180cf8d..e33b52e5fd4 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/SuperModelRequestHandlerTest.java
@@ -125,7 +125,7 @@ public class SuperModelRequestHandlerTest {
private static class TestApplication extends Application {
TestApplication(VespaModel vespaModel, ServerCache cache, long appGeneration, ApplicationId app) {
- super(vespaModel, cache, appGeneration, false, new Version(1, 2, 3), MetricUpdater.createTestUpdater(), app);
+ super(vespaModel, cache, appGeneration, new Version(1, 2, 3), MetricUpdater.createTestUpdater(), app);
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationMapperTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationMapperTest.java
index 3270bb5cd76..9ef63b768a9 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationMapperTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationMapperTest.java
@@ -70,7 +70,7 @@ public class ApplicationMapperTest {
}
private Application createApplication(Version version) {
- return new Application(new ModelStub(), null, 0, false, version, MetricUpdater.createTestUpdater(), ApplicationId.defaultId());
+ return new Application(new ModelStub(), null, 0, version, MetricUpdater.createTestUpdater(), ApplicationId.defaultId());
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationSetTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationSetTest.java
index a5ec2583595..b37c5defbc3 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationSetTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationSetTest.java
@@ -58,6 +58,6 @@ public class ApplicationSetTest {
}
private Application createApplication(Version version) {
- return new Application(new ModelStub(), null, 0, false, version, MetricUpdater.createTestUpdater(), ApplicationId.defaultId());
+ return new Application(new ModelStub(), null, 0, version, MetricUpdater.createTestUpdater(), ApplicationId.defaultId());
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationTest.java
index 1e70304ef42..acd0acc3792 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationTest.java
@@ -57,7 +57,7 @@ public class ApplicationTest {
ApplicationName.from("foobar"), InstanceName.defaultName());
ServerCache cache = new ServerCache();
Version vespaVersion = new Version(1, 2, 3);
- Application app = new Application(new ModelStub(), cache, 1337L, false, vespaVersion, MetricUpdater.createTestUpdater(), appId);
+ Application app = new Application(new ModelStub(), cache, 1337L, vespaVersion, MetricUpdater.createTestUpdater(), appId);
assertThat(app.getApplicationGeneration(), is(1337L));
assertNotNull(app.getModel());
assertThat(app.getCache(), is(cache));
@@ -76,7 +76,7 @@ public class ApplicationTest {
ServerCache cache = createCacheAndAddContent();
VespaModel model = new VespaModel(FilesApplicationPackage.fromFile(testApp));
ApplicationId applicationId = new ApplicationId.Builder().tenant("foo").applicationName("foo").build();
- handler = new Application(model, cache, 1L, false, new Version(1, 2, 3),
+ handler = new Application(model, cache, 1L, new Version(1, 2, 3),
new MetricUpdater(Metrics.createTestMetrics(), Metrics.createDimensions(applicationId)), applicationId);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ConfigConvergenceCheckerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ConfigConvergenceCheckerTest.java
index 8a3a3b6e0ca..2fbc14dda50 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ConfigConvergenceCheckerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ConfigConvergenceCheckerTest.java
@@ -64,7 +64,6 @@ public class ConfigConvergenceCheckerTest {
application = new Application(mockModel,
new ServerCache(),
3,
- false,
new Version(0, 0, 0),
MetricUpdater.createTestUpdater(), appId);
checker = new ConfigConvergenceChecker();
@@ -137,7 +136,6 @@ public class ConfigConvergenceCheckerTest {
MockModel.createContainerHost(service2.getHost(), service2.getPort()))
);
Application application = new Application(model, new ServerCache(), 4,
- false,
new Version(0, 0, 0),
MetricUpdater.createTestUpdater(), appId);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClientTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClientTest.java
new file mode 100644
index 00000000000..7b8d5d9cc07
--- /dev/null
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/DefaultClusterReindexingStatusClientTest.java
@@ -0,0 +1,127 @@
+package com.yahoo.vespa.config.server.application;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.Model;
+import com.yahoo.config.model.api.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.vespa.config.server.modelfactory.ModelResult;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.serverError;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
+import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author bjorncs
+ */
+public class DefaultClusterReindexingStatusClientTest {
+
+ @Rule public final WireMockRule server1 = new WireMockRule(options().dynamicPort(), true);
+ @Rule public final WireMockRule server2 = new WireMockRule(options().dynamicPort(), true);
+ @Rule public final WireMockRule server3 = new WireMockRule(options().dynamicPort(), true);
+
+ @Test
+ public void combines_result_from_multiple_cluster_controller_clusters() throws IOException {
+ var client = new DefaultClusterReindexingStatusClient();
+ MockApplication app = new MockApplication();
+ String uriPath = "/reindexing/v1/status";
+ server1.stubFor(get(urlEqualTo(uriPath)).willReturn(serverError()));
+ server2.stubFor(get(urlEqualTo(uriPath)).willReturn(okJson(
+ "{" +
+ " \"clusters\": {" +
+ " \"cluster1\": {" +
+ " \"documentTypes\": {" +
+ " \"music\": {" +
+ " \"startedMillis\":0," +
+ " \"state\": \"" + ClusterReindexing.State.RUNNING.asString() + "\"" +
+ " }" +
+ " }" +
+ " }" +
+ " }" +
+ "}")));
+ server3.stubFor(get(urlEqualTo(uriPath)).willReturn(okJson(
+ "{" +
+ " \"clusters\": {" +
+ " \"cluster2\": {" +
+ " \"documentTypes\": {" +
+ " \"artist\": {" +
+ " \"startedMillis\":50," +
+ " \"endedMillis\":150," +
+ " \"progress\": 0.5," +
+ " \"state\": \"" + ClusterReindexing.State.SUCCESSFUL.asString() + "\"," +
+ " \"message\":\"success\"" +
+ " }" +
+ " }" +
+ " }" +
+ " }" +
+ "}")));
+ Map<String, ClusterReindexing> expected = Map.of("cluster1",
+ new ClusterReindexing(Map.of("music",
+ new ClusterReindexing.Status(Instant.ofEpochMilli(0),
+ null,
+ ClusterReindexing.State.RUNNING,
+ null,
+ null))),
+ "cluster2",
+ new ClusterReindexing(Map.of("artist",
+ new ClusterReindexing.Status(Instant.ofEpochMilli(50),
+ Instant.ofEpochMilli(150),
+ ClusterReindexing.State.SUCCESSFUL,
+ "success",
+ 0.5))));
+ Map<String, ClusterReindexing> result = client.getReindexingStatus(app);
+ assertEquals(expected, result);
+ }
+
+
+ private class MockApplication implements ModelResult {
+ private final Collection<HostInfo> hosts;
+
+ MockApplication() {
+ this.hosts = createHosts();
+ }
+
+ @Override
+ public Model getModel() {
+ Model model = mock(Model.class);
+ when(model.getHosts()).thenReturn(hosts);
+ return model;
+ }
+
+ private Collection<HostInfo> createHosts() {
+ return List.of(
+ createHostInfo(server1.port(), "cc1.1", "cluster1"),
+ createHostInfo(server2.port(), "cc1.2", "cluster1"),
+ createHostInfo(server3.port(), "cc2.1", "cluster2"));
+ }
+
+ private HostInfo createHostInfo(int serverPort, String serviceName, String clusterId) {
+ return new HostInfo(
+ "localhost",
+ List.of(new ServiceInfo(
+ serviceName,
+ CLUSTERCONTROLLER_CONTAINER.serviceName,
+ List.of(new PortInfo(serverPort, List.of("state"))),
+ Map.of("clustername", clusterId),
+ "myconfigId",
+ "localhost")));
+ }
+
+ }
+
+
+} \ No newline at end of file
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/FileDistributionStatusTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/FileDistributionStatusTest.java
index e425943ef59..b650e8eb291 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/FileDistributionStatusTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/FileDistributionStatusTest.java
@@ -164,7 +164,6 @@ public class FileDistributionStatusTest {
return new Application(mockModel,
new ServerCache(),
3,
- false,
new Version(0, 0, 0),
MetricUpdater.createTestUpdater(),
appId);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java
index c9f25451ea4..0288a551cd3 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.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.config.server.application;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.HostInfo;
@@ -29,6 +30,7 @@ import java.util.stream.Collectors;
* @author hakonhall
*/
public class MockModel implements Model {
+
private final Collection<HostInfo> hosts;
static MockModel createContainer(String hostname, int statePort) {
@@ -72,11 +74,17 @@ public class MockModel implements Model {
}
@Override
+ @SuppressWarnings("deprecation")
public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
@Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Set<ConfigKey<?>> allConfigsProduced() {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
index aa3f240b12e..947308962d4 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
@@ -181,7 +181,6 @@ public class TenantApplicationsTest {
applications.activateApplication(ApplicationSet.from(new Application(model,
new ServerCache(),
1,
- false,
vespaVersion,
MetricUpdater.createTestUpdater(),
applicationId)),
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
index 910c4b069e3..a0c63c8bba1 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
@@ -79,7 +79,7 @@ public class ApplicationHandlerTest {
private final static TenantName mytenantName = TenantName.from("mytenant");
private final static ApplicationId myTenantApplicationId = ApplicationId.from(mytenantName, ApplicationName.defaultName(), InstanceName.defaultName());
- private final static ApplicationId applicationId = ApplicationId.from(TenantName.defaultName(), ApplicationName.defaultName(), InstanceName.defaultName());
+ private final static ApplicationId applicationId = ApplicationId.defaultId();
private final static MockTesterClient testerClient = new MockTesterClient();
private static final MockLogRetriever logRetriever = new MockLogRetriever();
private static final Version vespaVersion = Version.fromString("7.8.9");
@@ -219,32 +219,32 @@ public class ApplicationHandlerTest {
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "");
+ reindex(applicationId, "", "{\"message\":\"Reindexing application default.default\"}");
expected = expected.withReady(clock.instant());
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
expected = expected.withReady(clock.instant());
- reindex(applicationId, "?clusterId=");
+ reindex(applicationId, "?clusterId=", "{\"message\":\"Reindexing application default.default\"}");
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
expected = expected.withReady(clock.instant());
- reindex(applicationId, "?documentType=moo");
+ reindex(applicationId, "?documentType=moo", "{\"message\":\"Reindexing application default.default\"}");
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "?clusterId=foo,boo");
+ reindex(applicationId, "?clusterId=foo,boo", "{\"message\":\"Reindexing clusters foo, boo of application default.default\"}");
expected = expected.withReady("foo", clock.instant())
.withReady("boo", clock.instant());
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "?clusterId=foo,boo&documentType=bar,baz");
+ reindex(applicationId, "?clusterId=foo,boo&documentType=bar,baz", "{\"message\":\"Reindexing document types bar, baz in clusters foo, boo of application default.default\"}");
expected = expected.withReady("foo", "bar", clock.instant())
.withReady("foo", "baz", clock.instant())
.withReady("boo", "bar", clock.instant())
@@ -252,12 +252,12 @@ public class ApplicationHandlerTest {
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
- reindexing(applicationId, DELETE);
+ reindexing(applicationId, DELETE, "{\"message\":\"Reindexing disabled\"}");
expected = expected.enabled(false);
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
- reindexing(applicationId, POST);
+ reindexing(applicationId, POST, "{\"message\":\"Reindexing enabled\"}");
expected = expected.enabled(true);
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
@@ -342,7 +342,7 @@ public class ApplicationHandlerTest {
.withHttpProxy(mockHttpProxy)
.build();
ApplicationHandler mockHandler = createApplicationHandler(applicationRepository);
- when(mockHttpProxy.get(any(), eq(host), eq(CLUSTERCONTROLLER_CONTAINER.serviceName),eq("clustercontroller-status/v1/clusterName1")))
+ when(mockHttpProxy.get(any(), eq(host), eq(CLUSTERCONTROLLER_CONTAINER.serviceName), eq("clustercontroller-status/v1/clusterName1")))
.thenReturn(new StaticResponse(200, "text/html", "<html>...</html>"));
HttpResponse response = mockHandler.handle(createTestRequest(url, GET));
@@ -440,7 +440,7 @@ public class ApplicationHandlerTest {
@Test
public void testClusterReindexingStateSerialization() {
- Stream.of(ClusterReindexing.State.values()).forEach(ReindexingResponse::toString);
+ Stream.of(ClusterReindexing.State.values()).forEach(ClusterReindexing.State::toString);
}
@Test
@@ -455,7 +455,7 @@ public class ApplicationHandlerTest {
now.plusSeconds(2),
ClusterReindexing.State.FAILED,
"message",
- "some")));
+ 0.1)));
assertJsonEquals(getRenderedString(new ReindexingResponse(applicationReindexing,
Map.of("boo", clusterReindexing,
"moo", clusterReindexing))),
@@ -476,7 +476,7 @@ public class ApplicationHandlerTest {
" \"endedMillis\": 125456,\n" +
" \"state\": \"failed\",\n" +
" \"message\": \"message\",\n" +
- " \"progress\": \"some\"\n" +
+ " \"progress\": 0.1\n" +
" }\n" +
" }\n" +
" },\n" +
@@ -498,7 +498,7 @@ public class ApplicationHandlerTest {
" \"endedMillis\": 125456,\n" +
" \"state\": \"failed\",\n" +
" \"message\": \"message\",\n" +
- " \"progress\": \"some\"\n" +
+ " \"progress\": 0.1\n" +
" },\n" +
" \"bax\": {\n" +
" \"startedMillis\": 123456\n" +
@@ -607,13 +607,9 @@ public class ApplicationHandlerTest {
reindexing(application, method, expectedBody, 200);
}
- private void reindexing(ApplicationId application, Method method) throws IOException {
- reindexing(application, method, null);
- }
-
- private void reindex(ApplicationId application, String query) throws IOException {
+ private void reindex(ApplicationId application, String query, String message) throws IOException {
String reindexUrl = toUrlPath(application, Zone.defaultZone(), true) + "/reindex" + query;
- assertHttpStatusCodeAndMessage(createApplicationHandler().handle(createTestRequest(reindexUrl, POST)), 200, "");
+ assertHttpStatusCodeAndMessage(createApplicationHandler().handle(createTestRequest(reindexUrl, POST)), 200, message);
}
private void restart(ApplicationId application, Zone zone) throws IOException {
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
index b6177a11da8..d75b91f45e3 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
@@ -30,20 +30,15 @@ public class ReindexingMaintainerTest {
withNewReady(reindexing, () -> -1L, Instant.EPOCH));
// Status for (one, a) changes, but not (two, b).
-
- assertEquals(reindexing.withReady("one", "a", Instant.EPOCH)
- .withoutPending("one", "a"),
- withNewReady(reindexing, () -> 19L, Instant.EPOCH));
-
- Instant later = Instant.EPOCH.plus(ReindexingMaintainer.reindexingInterval.multipliedBy(3));
+ Instant later = Instant.ofEpochMilli(3 << 10);
assertEquals(reindexing.withoutPending("one", "a") // Converged, no longer pending.
- .withReady(later), // Had EPOCH as previous, so is updated, overwriting all more specific status.
- withNewReady(reindexing, () -> 19L, later.plusMillis(1)));
+ .withReady("one", "a", later), // Converged, now ready.
+ withNewReady(reindexing, () -> 19L, later));
assertEquals(reindexing.withoutPending("one", "a") // Converged, no longer pending.
- .withoutPending("two", "b") // Converged, no LOnger pending.
- .withReady(later), // Had EPOCH as previous, so is updated, overwriting all more specific status.
- withNewReady(reindexing, () -> 20L, later.plusMillis(1)));
+ .withoutPending("two", "b") // Converged, no Longer pending.
+ .withReady(later), // Outsider calls withReady(later), overriding more specific status.
+ withNewReady(reindexing, () -> 20L, later).withReady(later));
// Verify generation supplier isn't called when no pending document types.
withNewReady(reindexing.withoutPending("one", "a").withoutPending("two", "b"),
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
index a0025d086f5..b5cdfa8eda2 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
@@ -1,6 +1,7 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.metrics;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.HostInfo;
@@ -33,8 +34,8 @@ public class DeploymentMetricsRetrieverTest {
public void getMetrics() {
MockModel mockModel = new MockModel(mockHosts());
MockDeploymentMetricsRetriever mockMetricsRetriever = new MockDeploymentMetricsRetriever();
- Application application = new Application(mockModel, null, 0, false,
- null, null, ApplicationId.fromSerializedForm("tenant:app:instance"));
+ Application application = new Application(mockModel, null, 0,
+ null, null, ApplicationId.fromSerializedForm("tenant:app:instance"));
DeploymentMetricsRetriever clusterMetricsRetriever = new DeploymentMetricsRetriever(mockMetricsRetriever);
clusterMetricsRetriever.getMetrics(application);
@@ -83,11 +84,17 @@ public class DeploymentMetricsRetrieverTest {
}
@Override
+ @SuppressWarnings("deprecation")
public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
@Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Set<ConfigKey<?>> allConfigsProduced() {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
index e97c4dc6682..7fab01faf3d 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
@@ -1,5 +1,6 @@
package com.yahoo.vespa.config.server.metrics;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.HostInfo;
@@ -28,8 +29,8 @@ public class ProtonMetricsRetrieverTest {
public void getMetrics() {
ProtonMetricsRetrieverTest.MockModel mockModel = new MockModel(mockHosts());
ProtonMetricsRetrieverTest.MockProtonMetricsRetriever mockMetricsRetriever = new MockProtonMetricsRetriever();
- Application application = new Application(mockModel, null, 0, false,
- null, null, ApplicationId.fromSerializedForm("tenant:app:instance"));
+ Application application = new Application(mockModel, null, 0,
+ null, null, ApplicationId.fromSerializedForm("tenant:app:instance"));
ProtonMetricsRetriever clusterMetricsRetriever = new ProtonMetricsRetriever(mockMetricsRetriever);
clusterMetricsRetriever.getMetrics(application);
@@ -76,11 +77,17 @@ public class ProtonMetricsRetrieverTest {
}
@Override
+ @SuppressWarnings("deprecation")
public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
@Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Set<ConfigKey<?>> allConfigsProduced() {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java
index 6ca3f6c67ea..7f4733f0b7c 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java
@@ -25,7 +25,7 @@ import java.util.concurrent.CompletionService;
*/
public class MockRpcServer extends RpcServer {
- public final RuntimeException exception = null;
+ public RuntimeException exception = null;
public int errorCode = 0;
public final ConfigResponse response = null;
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcServerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcServerTest.java
index 704b00c4e0b..735eae2700f 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcServerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/RpcServerTest.java
@@ -131,7 +131,6 @@ public class RpcServerTest {
Application app = new Application(new VespaModel(MockApplicationPackage.createEmpty()),
new ServerCache(),
2L,
- false,
new Version(1, 2, 3),
MetricUpdater.createTestUpdater(),
applicationId);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRepositoryTest.java
index d9d6fb01086..4900c50f1d7 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRepositoryTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRepositoryTest.java
@@ -92,7 +92,6 @@ public class TenantRepositoryTest {
applicationRepo.activateApplication(ApplicationSet.from(new Application(new VespaModel(MockApplicationPackage.createEmpty()),
new ServerCache(),
4L,
- false,
new Version(1, 2, 3),
MetricUpdater.createTestUpdater(),
id)),
diff --git a/configutil/src/lib/configstatus.cpp b/configutil/src/lib/configstatus.cpp
index 254fa94a8ec..e56da67fade 100644
--- a/configutil/src/lib/configstatus.cpp
+++ b/configutil/src/lib/configstatus.cpp
@@ -2,7 +2,6 @@
#include "configstatus.h"
#include "tags.h"
-#include <vespa/fnet/frt/frt.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vbench/http/http_result_handler.h>
#include <vbench/http/server_spec.h>
diff --git a/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java b/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java
index a3d34ae6a2c..75e9febc192 100644
--- a/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java
+++ b/container-accesslogging/src/main/java/com/yahoo/container/logging/LogFileHandler.java
@@ -125,8 +125,10 @@ public class LogFileHandler extends StreamHandler {
try {
if (currentOutputStream != null) {
long newPos = currentOutputStream.getChannel().position();
- nativeIO.dropPartialFileFromCache(currentOutputStream.getFD(), lastDropPosition, newPos, true);
- lastDropPosition = newPos;
+ if (newPos > lastDropPosition + 102400) {
+ nativeIO.dropPartialFileFromCache(currentOutputStream.getFD(), lastDropPosition, newPos, true);
+ lastDropPosition = newPos;
+ }
}
} catch (IOException e) {
logger.warning("Failed dropping from cache : " + Exceptions.toMessageString(e));
@@ -296,14 +298,7 @@ public class LogFileHandler extends StreamHandler {
if (symlinkName == null) return;
File f = new File(fileName);
File f2 = new File(f.getParent(), symlinkName);
- String canonicalPath;
- try {
- canonicalPath = f.getCanonicalPath();
- } catch (IOException e) {
- logger.warning("Got '" + e + "' while doing f.getCanonicalPath() on file '" + f.getPath() + "'.");
- return;
- }
- String [] cmd = new String[]{"/bin/ln", "-sf", canonicalPath, f2.getPath()};
+ String [] cmd = new String[]{"/bin/ln", "-sf", f.getName(), f2.getPath()};
try {
int retval = new ProcessExecuter().exec(cmd).getFirst();
// Detonator pattern: Think of all the fun we can have if ln isn't what we
diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json
index e734ceee046..a5483d12b24 100644
--- a/container-core/abi-spec.json
+++ b/container-core/abi-spec.json
@@ -181,6 +181,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.container.handler.ThreadpoolConfig build()"
],
"fields": []
diff --git a/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java b/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
index af163e88fee..26f11b98366 100644
--- a/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
+++ b/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
@@ -74,7 +74,7 @@ public class HandlersConfigurerDi {
this.vespaContainer = vespaContainer;
container = new Container(subscriberFactory, configId, deconstructor, osgiWrapper);
- getNewComponentGraph(discInjector, false);
+ getNewComponentGraph(discInjector, true);
}
private static class ContainerAndDiOsgi extends OsgiImpl implements OsgiWrapper {
@@ -128,10 +128,10 @@ public class HandlersConfigurerDi {
/**
* Wait for new config to arrive and produce the new graph
*/
- public void getNewComponentGraph(Injector discInjector, boolean restartOnRedeploy) {
+ public void getNewComponentGraph(Injector discInjector, boolean isInitializing) {
currentGraph = container.getNewComponentGraph(currentGraph,
createFallbackInjector(vespaContainer, discInjector),
- restartOnRedeploy);
+ isInitializing);
}
private Injector createFallbackInjector(com.yahoo.container.Container vespaContainer, Injector discInjector) {
diff --git a/container-di/abi-spec.json b/container-di/abi-spec.json
index a9dda2ae224..02cc29cd07f 100644
--- a/container-di/abi-spec.json
+++ b/container-di/abi-spec.json
@@ -1,15 +1,16 @@
{
"com.yahoo.container.di.componentgraph.Provider": {
"superClass": "java.lang.Object",
- "interfaces": [],
+ "interfaces": [
+ "com.yahoo.component.Deconstructable"
+ ],
"attributes": [
"public",
"interface",
"abstract"
],
"methods": [
- "public abstract java.lang.Object get()",
- "public abstract void deconstruct()"
+ "public abstract java.lang.Object get()"
],
"fields": []
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java b/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java
index 1133363be8e..d43f96c9b4a 100644
--- a/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java
+++ b/container-di/src/main/java/com/yahoo/container/di/CloudSubscriberFactory.java
@@ -30,8 +30,9 @@ public class CloudSubscriberFactory implements SubscriberFactory {
private static final Logger log = Logger.getLogger(CloudSubscriberFactory.class.getName());
private final ConfigSource configSource;
+ private final Map<CloudSubscriber, Integer> activeSubscribers = new WeakHashMap<>();
+
private Optional<Long> testGeneration = Optional.empty();
- private Map<CloudSubscriber, Integer> activeSubscribers = new WeakHashMap<>();
public CloudSubscriberFactory(ConfigSource configSource) {
this.configSource = configSource;
@@ -70,9 +71,6 @@ public class CloudSubscriberFactory implements SubscriberFactory {
// if waitNextGeneration has not yet been called, -1 should be returned
private long generation = -1L;
- // True if this reconfiguration was caused by a system-internal redeploy, not an external application change
- private boolean internalRedeploy = false;
-
private CloudSubscriber(Set<ConfigKey<ConfigInstance>> keys, ConfigSource configSource) {
this.subscriber = new ConfigSubscriber(configSource);
keys.forEach(k -> handles.put(k, subscriber.subscribe(k.getConfigClass(), k.getConfigId())));
@@ -88,11 +86,6 @@ public class CloudSubscriberFactory implements SubscriberFactory {
return generation;
}
- @Override
- public boolean internalRedeploy() {
- return internalRedeploy;
- }
-
//mapValues returns a view,, so we need to force evaluation of it here to prevent deferred evaluation.
@Override
public Map<ConfigKey<ConfigInstance>, ConfigInstance> config() {
@@ -102,7 +95,7 @@ public class CloudSubscriberFactory implements SubscriberFactory {
}
@Override
- public long waitNextGeneration() {
+ public long waitNextGeneration(boolean isInitializing) {
if (handles.isEmpty())
throw new IllegalStateException("No config keys registered");
@@ -115,7 +108,7 @@ public class CloudSubscriberFactory implements SubscriberFactory {
int numExceptions = 0;
while ( ! gotNextGen) {
try {
- if (subscriber.nextGeneration())
+ if (subscriber.nextGeneration(isInitializing))
gotNextGen = true;
}
catch (IllegalArgumentException e) {
@@ -128,7 +121,6 @@ public class CloudSubscriberFactory implements SubscriberFactory {
}
generation = subscriber.getGeneration();
- internalRedeploy = subscriber.isInternalRedeploy();
return generation;
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java b/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java
index 61497cf71bc..4e3881a6fe6 100644
--- a/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java
+++ b/container-di/src/main/java/com/yahoo/container/di/ComponentDeconstructor.java
@@ -4,6 +4,7 @@ package com.yahoo.container.di;
import org.osgi.framework.Bundle;
import java.util.Collection;
+import java.util.List;
/**
* @author gjoranv
@@ -11,6 +12,7 @@ import java.util.Collection;
*/
public interface ComponentDeconstructor {
- void deconstruct(Collection<Object> components, Collection<Bundle> bundles);
+ /** Deconstructs the given components in order, then the given bundles. */
+ void deconstruct(List<Object> components, Collection<Bundle> bundles);
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java b/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java
index f892fe410a8..a7ff6c46a8b 100644
--- a/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java
+++ b/container-di/src/main/java/com/yahoo/container/di/ConfigRetriever.java
@@ -46,11 +46,10 @@ public final class ConfigRetriever {
}
public ConfigSnapshot getConfigs(Set<ConfigKey<? extends ConfigInstance>> componentConfigKeys,
- long leastGeneration,
- boolean restartOnRedeploy) {
+ long leastGeneration, boolean isInitializing) {
// Loop until we get config.
while (true) {
- Optional<ConfigSnapshot> maybeSnapshot = getConfigsOnce(componentConfigKeys, leastGeneration, restartOnRedeploy);
+ Optional<ConfigSnapshot> maybeSnapshot = getConfigsOnce(componentConfigKeys, leastGeneration, isInitializing);
if (maybeSnapshot.isPresent()) {
var configSnapshot = maybeSnapshot.get();
resetComponentSubscriberIfBootstrap(configSnapshot);
@@ -59,13 +58,8 @@ public final class ConfigRetriever {
}
}
- ConfigSnapshot getConfigs(Set<ConfigKey<? extends ConfigInstance>> componentConfigKeys, long leastGeneration) {
- return getConfigs(componentConfigKeys, leastGeneration, false);
- }
-
Optional<ConfigSnapshot> getConfigsOnce(Set<ConfigKey<? extends ConfigInstance>> componentConfigKeys,
- long leastGeneration,
- boolean restartOnRedeploy) {
+ long leastGeneration, boolean isInitializing) {
if (!Sets.intersection(componentConfigKeys, bootstrapKeys).isEmpty()) {
throw new IllegalArgumentException(
"Component config keys [" + componentConfigKeys + "] overlaps with bootstrap config keys [" + bootstrapKeys + "]");
@@ -76,20 +70,18 @@ public final class ConfigRetriever {
allKeys.addAll(bootstrapKeys);
setupComponentSubscriber(allKeys);
- return getConfigsOptional(leastGeneration, restartOnRedeploy);
+ return getConfigsOptional(leastGeneration, isInitializing);
}
- private Optional<ConfigSnapshot> getConfigsOptional(long leastGeneration, boolean restartOnRedeploy) {
- long newestComponentGeneration = componentSubscriber.waitNextGeneration();
+ private Optional<ConfigSnapshot> getConfigsOptional(long leastGeneration, boolean isInitializing) {
+ long newestComponentGeneration = componentSubscriber.waitNextGeneration(isInitializing);
log.log(FINE, "getConfigsOptional: new component generation: " + newestComponentGeneration);
// leastGeneration is only used to ensure newer generation when the previous generation was invalidated due to an exception
if (newestComponentGeneration < leastGeneration) {
return Optional.empty();
- } else if (restartOnRedeploy && !componentSubscriber.internalRedeploy()) { // Don't reconfig - wait for restart
- return Optional.empty();
} else if (bootstrapSubscriber.generation() < newestComponentGeneration) {
- long newestBootstrapGeneration = bootstrapSubscriber.waitNextGeneration();
+ long newestBootstrapGeneration = bootstrapSubscriber.waitNextGeneration(isInitializing);
log.log(FINE, "getConfigsOptional: new bootstrap generation: " + bootstrapSubscriber.generation());
Optional<ConfigSnapshot> bootstrapConfig = bootstrapConfigIfChanged();
if (bootstrapConfig.isPresent()) {
@@ -100,8 +92,8 @@ public final class ConfigRetriever {
return componentsConfigIfChanged();
} else {
// This should not be a normal case, and hence a warning to allow investigation.
- log.warning("Did not get same generation for bootstrap (" + newestBootstrapGeneration + ") and components configs ("
- + newestComponentGeneration + ").");
+ log.warning("Did not get same generation for bootstrap (" + newestBootstrapGeneration +
+ ") and components configs (" + newestComponentGeneration + ").");
return Optional.empty();
}
}
@@ -120,7 +112,7 @@ public final class ConfigRetriever {
}
private Optional<ConfigSnapshot> configIfChanged(Subscriber subscriber,
- Function<Map<ConfigKey<? extends ConfigInstance>, ConfigInstance>, ConfigSnapshot> constructor) {
+ Function<Map<ConfigKey<? extends ConfigInstance>, ConfigInstance>, ConfigSnapshot> constructor) {
if (subscriber.configChanged()) {
return Optional.of(constructor.apply(Keys.covariantCopy(subscriber.config())));
} else {
diff --git a/container-di/src/main/java/com/yahoo/container/di/Container.java b/container-di/src/main/java/com/yahoo/container/di/Container.java
index af580767a17..82c7f65bc2a 100644
--- a/container-di/src/main/java/com/yahoo/container/di/Container.java
+++ b/container-di/src/main/java/com/yahoo/container/di/Container.java
@@ -21,6 +21,7 @@ import com.yahoo.container.di.config.SubscriberFactory;
import com.yahoo.vespa.config.ConfigKey;
import org.osgi.framework.Bundle;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -43,9 +44,9 @@ public class Container {
private static final Logger log = Logger.getLogger(Container.class.getName());
private final SubscriberFactory subscriberFactory;
- private ConfigKey<ApplicationBundlesConfig> applicationBundlesConfigKey;
- private ConfigKey<PlatformBundlesConfig> platformBundlesConfigKey;
- private ConfigKey<ComponentsConfig> componentsConfigKey;
+ private final ConfigKey<ApplicationBundlesConfig> applicationBundlesConfigKey;
+ private final ConfigKey<PlatformBundlesConfig> platformBundlesConfigKey;
+ private final ConfigKey<ComponentsConfig> componentsConfigKey;
private final ComponentDeconstructor componentDeconstructor;
private final Osgi osgi;
@@ -71,10 +72,10 @@ public class Container {
});
}
- public ComponentGraph getNewComponentGraph(ComponentGraph oldGraph, Injector fallbackInjector, boolean restartOnRedeploy) {
+ public ComponentGraph getNewComponentGraph(ComponentGraph oldGraph, Injector fallbackInjector, boolean isInitializing) {
try {
Collection<Bundle> obsoleteBundles = new HashSet<>();
- ComponentGraph newGraph = getConfigAndCreateGraph(oldGraph, fallbackInjector, restartOnRedeploy, obsoleteBundles);
+ ComponentGraph newGraph = getConfigAndCreateGraph(oldGraph, fallbackInjector, isInitializing, obsoleteBundles);
newGraph.reuseNodes(oldGraph);
constructComponents(newGraph);
deconstructObsoleteComponents(oldGraph, newGraph, obsoleteBundles);
@@ -87,12 +88,12 @@ public class Container {
private ComponentGraph getConfigAndCreateGraph(ComponentGraph graph,
Injector fallbackInjector,
- boolean restartOnRedeploy,
+ boolean isInitializing,
Collection<Bundle> obsoleteBundles) // NOTE: Return value
{
ConfigSnapshot snapshot;
while (true) {
- snapshot = configurer.getConfigs(graph.configKeys(), leastGeneration, restartOnRedeploy);
+ snapshot = configurer.getConfigs(graph.configKeys(), leastGeneration, isInitializing);
log.log(FINE, String.format("createNewGraph:\n" + "graph.configKeys = %s\n" + "graph.generation = %s\n" + "snapshot = %s\n",
graph.configKeys(), graph.generation(), snapshot));
@@ -159,10 +160,16 @@ public class Container {
private void deconstructObsoleteComponents(ComponentGraph oldGraph,
ComponentGraph newGraph,
Collection<Bundle> obsoleteBundles) {
- IdentityHashMap<Object, Object> oldComponents = new IdentityHashMap<>();
- oldGraph.allConstructedComponentsAndProviders().forEach(c -> oldComponents.put(c, null));
- newGraph.allConstructedComponentsAndProviders().forEach(oldComponents::remove);
- componentDeconstructor.deconstruct(oldComponents.keySet(), obsoleteBundles);
+ Map<Object, ?> newComponents = new IdentityHashMap<>(newGraph.size());
+ for (Object component : newGraph.allConstructedComponentsAndProviders())
+ newComponents.put(component, null);
+
+ List<Object> obsoleteComponents = new ArrayList<>();
+ for (Object component : oldGraph.allConstructedComponentsAndProviders())
+ if ( ! newComponents.containsKey(component))
+ obsoleteComponents.add(component);
+
+ componentDeconstructor.deconstruct(obsoleteComponents, obsoleteBundles);
}
private Set<Bundle> installApplicationBundles(Map<ConfigKey<? extends ConfigInstance>, ConfigInstance> configsIncludingBootstrapConfigs) {
diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java
index a2d193654ea..3fd3195e5dd 100644
--- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java
+++ b/container-di/src/main/java/com/yahoo/container/di/componentgraph/Provider.java
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.di.componentgraph;
+import com.yahoo.component.Deconstructable;
+
/**
* <p>Provides a component of the parameter type T.
* If (and only if) dependency injection does not have a component of type T,
@@ -17,9 +19,8 @@ package com.yahoo.container.di.componentgraph;
* @author Tony Vaagenes
* @author gjoranv
*/
-public interface Provider<T> {
+public interface Provider<T> extends Deconstructable {
T get();
- void deconstruct();
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java
index 256c965052a..fef2809f236 100644
--- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java
+++ b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java
@@ -166,6 +166,7 @@ public class ComponentGraph {
}
}
+ /** All constructed components and providers of this, in reverse creation order, i.e., suited for ordered deconstruction. */
public List<Object> allConstructedComponentsAndProviders() {
List<Node> orderedNodes = topologicalSort(nodes());
Collections.reverse(orderedNodes);
diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java
index 005691721c4..be80fc1616d 100644
--- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java
+++ b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/Keys.java
@@ -14,6 +14,7 @@ import java.util.Map;
* @author ollivir
*/
public class Keys {
+
static Key<?> createKey(Type instanceType, Annotation annotation) {
if (annotation == null) {
return Key.get(instanceType);
@@ -34,4 +35,5 @@ public class Keys {
configs.forEach((k, v) -> ret.put(k, v));
return ret;
}
+
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java b/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java
index 0feab7779ad..60207447bfd 100644
--- a/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java
+++ b/container-di/src/main/java/com/yahoo/container/di/config/Subscriber.java
@@ -12,9 +12,8 @@ import java.util.Map;
*/
public interface Subscriber {
- long waitNextGeneration();
+ long waitNextGeneration(boolean isInitializing);
long generation();
- boolean internalRedeploy();
boolean configChanged();
Map<ConfigKey<ConfigInstance>, ConfigInstance> config();
diff --git a/container-di/src/test/java/com/yahoo/container/di/ConfigRetrieverTest.java b/container-di/src/test/java/com/yahoo/container/di/ConfigRetrieverTest.java
index e6b0309981a..290836d7842 100644
--- a/container-di/src/test/java/com/yahoo/container/di/ConfigRetrieverTest.java
+++ b/container-di/src/test/java/com/yahoo/container/di/ConfigRetrieverTest.java
@@ -51,7 +51,7 @@ public class ConfigRetrieverTest {
public void require_that_bootstrap_configs_come_first() {
writeConfigs();
ConfigRetriever retriever = createConfigRetriever();
- ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, false);
+ ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, true);
assertThat(bootstrapConfigs, Matchers.instanceOf(BootstrapConfigs.class));
}
@@ -61,10 +61,10 @@ public class ConfigRetrieverTest {
public void require_that_components_comes_after_bootstrap() {
writeConfigs();
ConfigRetriever retriever = createConfigRetriever();
- ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, false);
+ ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, true);
ConfigKey<? extends ConfigInstance> testConfigKey = new ConfigKey<>(TestConfig.class, dirConfigSource.configId());
- ConfigSnapshot componentsConfigs = retriever.getConfigs(Collections.singleton(testConfigKey), 0);
+ ConfigSnapshot componentsConfigs = retriever.getConfigs(Collections.singleton(testConfigKey), 0, true);
if (componentsConfigs instanceof ComponentsConfigs) {
assertThat(componentsConfigs.size(), is(3));
@@ -73,22 +73,6 @@ public class ConfigRetrieverTest {
}
}
- @Test
- @SuppressWarnings("unused")
- public void require_no_reconfig_when_restart_on_redeploy() {
- // TODO
- writeConfigs();
- ConfigRetriever retriever = createConfigRetriever();
- ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, false);
-
- ConfigKey<? extends ConfigInstance> testConfigKey = new ConfigKey<>(TestConfig.class, dirConfigSource.configId());
- Optional<ConfigSnapshot> componentsConfigs = retriever.getConfigsOnce(Collections.singleton(testConfigKey), 0, true);
-
- if (componentsConfigs.isPresent()) {
- fail("Expected no configs");
- }
- }
-
@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -100,20 +84,20 @@ public class ConfigRetrieverTest {
writeConfigs();
ConfigRetriever retriever = createConfigRetriever();
ConfigKey<? extends ConfigInstance> testConfigKey = new ConfigKey<>(TestConfig.class, dirConfigSource.configId());
- ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, false);
- ConfigSnapshot componentsConfigs = retriever.getConfigs(Collections.singleton(testConfigKey), 0, false);
+ ConfigSnapshot bootstrapConfigs = retriever.getConfigs(Collections.emptySet(), 0, true);
+ ConfigSnapshot componentsConfigs = retriever.getConfigs(Collections.singleton(testConfigKey), 0, true);
Set<ConfigKey<? extends ConfigInstance>> keys = new HashSet<>();
keys.add(testConfigKey);
keys.add(new ConfigKey<>(TestConfig.class, ""));
- retriever.getConfigs(keys, 0);
+ retriever.getConfigs(keys, 0, true);
}
@Test
public void require_that_empty_components_keys_after_bootstrap_returns_components_configs() {
writeConfigs();
ConfigRetriever retriever = createConfigRetriever();
- assertThat(retriever.getConfigs(Collections.emptySet(), 0), instanceOf(BootstrapConfigs.class));
- assertThat(retriever.getConfigs(Collections.emptySet(), 0), instanceOf(ComponentsConfigs.class));
+ assertThat(retriever.getConfigs(Collections.emptySet(), 0, true), instanceOf(BootstrapConfigs.class));
+ assertThat(retriever.getConfigs(Collections.emptySet(), 0, true), instanceOf(ComponentsConfigs.class));
}
public void writeConfigs() {
diff --git a/container-di/src/test/java/com/yahoo/container/di/ContainerTest.java b/container-di/src/test/java/com/yahoo/container/di/ContainerTest.java
index 19f277ff8fb..b596246a43d 100644
--- a/container-di/src/test/java/com/yahoo/container/di/ContainerTest.java
+++ b/container-di/src/test/java/com/yahoo/container/di/ContainerTest.java
@@ -11,28 +11,22 @@ import com.yahoo.container.di.componentgraph.core.ComponentGraph;
import com.yahoo.container.di.componentgraph.core.ComponentGraphTest.SimpleComponent;
import com.yahoo.container.di.componentgraph.core.ComponentGraphTest.SimpleComponent2;
import com.yahoo.container.di.componentgraph.core.ComponentNode.ComponentConstructorException;
-import com.yahoo.container.di.componentgraph.core.Node;
import com.yahoo.container.di.config.RestApiContext;
import org.junit.Ignore;
import org.junit.Test;
import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
import java.util.Collection;
-import java.util.concurrent.ExecutionException;
+import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -51,7 +45,7 @@ public class ContainerTest extends ContainerTestBase {
Container container = newContainer(dirConfigSource);
ComponentTakingConfig component = createComponentTakingConfig(getNewComponentGraph(container));
- assertThat(component.config.stringVal(), is("myString"));
+ assertEquals("myString", component.config.stringVal());
container.shutdownConfigurer();
}
@@ -62,11 +56,10 @@ public class ContainerTest extends ContainerTestBase {
dirConfigSource.writeConfig("test", "stringVal \"original\"");
Container container = newContainer(dirConfigSource);
-
ComponentGraph componentGraph = getNewComponentGraph(container);
ComponentTakingConfig component = createComponentTakingConfig(componentGraph);
- assertThat(component.config.stringVal(), is("original"));
+ assertEquals("original", component.config.stringVal());
// Reconfigure
dirConfigSource.writeConfig("test", "stringVal \"reconfigured\"");
@@ -74,7 +67,7 @@ public class ContainerTest extends ContainerTestBase {
ComponentGraph newComponentGraph = getNewComponentGraph(container, componentGraph);
ComponentTakingConfig component2 = createComponentTakingConfig(newComponentGraph);
- assertThat(component2.config.stringVal(), is("reconfigured"));
+ assertEquals("reconfigured", component2.config.stringVal());
container.shutdownConfigurer();
}
@@ -88,7 +81,7 @@ public class ContainerTest extends ContainerTestBase {
ComponentGraph graph = getNewComponentGraph(container);
ComponentTakingConfig component = createComponentTakingConfig(graph);
- assertThat(component.getId().toString(), is("id1"));
+ assertEquals("id1", component.getId().toString());
writeBootstrapConfigs(
new ComponentEntry("id1", ComponentTakingConfig.class),
@@ -97,8 +90,8 @@ public class ContainerTest extends ContainerTestBase {
container.reloadConfig(2);
ComponentGraph newGraph = getNewComponentGraph(container, graph);
- assertThat(ComponentGraph.getNode(newGraph, "id1"), notNullValue(Node.class));
- assertThat(ComponentGraph.getNode(newGraph, "id2"), notNullValue(Node.class));
+ assertNotNull(ComponentGraph.getNode(newGraph, "id1"));
+ assertNotNull(ComponentGraph.getNode(newGraph, "id2"));
container.shutdownConfigurer();
}
@@ -240,9 +233,9 @@ public class ContainerTest extends ContainerTestBase {
RestApiContext restApiContext = componentGraph.getInstance(clazz);
assertNotNull(restApiContext);
- assertThat(restApiContext.getBundles().size(), is(1));
- assertThat(restApiContext.getBundles().get(0).symbolicName, is(MockBundle.SymbolicName));
- assertThat(restApiContext.getBundles().get(0).version, is(MockBundle.BundleVersion));
+ assertEquals(1, restApiContext.getBundles().size());
+ assertEquals(MockBundle.SymbolicName, restApiContext.getBundles().get(0).symbolicName);
+ assertEquals(MockBundle.BundleVersion, restApiContext.getBundles().get(0).version);
container.shutdownConfigurer();
}
@@ -278,7 +271,7 @@ public class ContainerTest extends ContainerTestBase {
RestApiContext restApiContext = componentGraph.getInstance(restApiClass);
assertFalse(restApiContext.getInjectableComponents().isEmpty());
- assertThat(restApiContext.getInjectableComponents().size(), is(2));
+ assertEquals(2, restApiContext.getInjectableComponents().size());
container.shutdownConfigurer();
}
@@ -380,7 +373,7 @@ public class ContainerTest extends ContainerTestBase {
public static class TestDeconstructor implements ComponentDeconstructor {
@Override
- public void deconstruct(Collection<Object> components, Collection<Bundle> bundles) {
+ public void deconstruct(List<Object> components, Collection<Bundle> bundles) {
components.forEach(component -> {
if (component instanceof DestructableComponent) {
DestructableComponent vespaComponent = (DestructableComponent) component;
@@ -401,14 +394,15 @@ public class ContainerTest extends ContainerTestBase {
}
ComponentGraph getNewComponentGraph(Container container, ComponentGraph oldGraph) {
- return container.getNewComponentGraph(oldGraph, Guice.createInjector(), false);
+ return container.getNewComponentGraph(oldGraph, Guice.createInjector(), true);
}
ComponentGraph getNewComponentGraph(Container container) {
- return container.getNewComponentGraph(new ComponentGraph(), Guice.createInjector(), false);
+ return container.getNewComponentGraph(new ComponentGraph(), Guice.createInjector(), true);
}
private ComponentTakingConfig createComponentTakingConfig(ComponentGraph componentGraph) {
return componentGraph.getInstance(ComponentTakingConfig.class);
}
+
}
diff --git a/container-di/src/test/java/com/yahoo/container/di/ContainerTestBase.java b/container-di/src/test/java/com/yahoo/container/di/ContainerTestBase.java
index f1f3c4a2ae4..2106a1f3671 100644
--- a/container-di/src/test/java/com/yahoo/container/di/ContainerTestBase.java
+++ b/container-di/src/test/java/com/yahoo/container/di/ContainerTestBase.java
@@ -23,6 +23,7 @@ import static java.util.Collections.emptySet;
* @author ollivir
*/
public class ContainerTestBase {
+
private ComponentGraph componentGraph;
protected DirConfigSource dirConfigSource = null;
@@ -70,7 +71,7 @@ public class ContainerTestBase {
throw new UnsupportedOperationException("getBundle not supported.");
}
});
- componentGraph = container.getNewComponentGraph(componentGraph, Guice.createInjector(), false);
+ componentGraph = container.getNewComponentGraph(componentGraph, Guice.createInjector(), true);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -120,4 +121,5 @@ public class ContainerTestBase {
"</config>";
}
}
+
}
diff --git a/container-disc/pom.xml b/container-disc/pom.xml
index 413af786f2c..399686bd9cc 100644
--- a/container-disc/pom.xml
+++ b/container-disc/pom.xml
@@ -190,6 +190,7 @@
<buildLegacyVespaPlatformBundle>true</buildLegacyVespaPlatformBundle>
<discPreInstallBundle>
<!-- Vespa bundles -->
+ configgen.jar,
config-bundle-jar-with-dependencies.jar,
configdefinitions-jar-with-dependencies.jar,
container-jersey2-jar-with-dependencies.jar,
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
index 3158c06b0b1..a30bcaa82e1 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
@@ -9,7 +9,6 @@ import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.config.ConfigInstance;
import com.yahoo.config.subscription.ConfigInterruptedException;
-import com.yahoo.config.subscription.ConfigSubscriber;
import com.yahoo.container.Container;
import com.yahoo.container.QrConfig;
import com.yahoo.container.core.ChainsConfig;
@@ -38,7 +37,6 @@ import com.yahoo.jrt.Supervisor;
import com.yahoo.jrt.Transport;
import com.yahoo.jrt.slobrok.api.Register;
import com.yahoo.jrt.slobrok.api.SlobrokList;
-import java.util.logging.Level;
import com.yahoo.log.LogSetup;
import com.yahoo.messagebus.network.rpc.SlobrokConfigSubscriber;
import com.yahoo.net.HostName;
@@ -135,7 +133,7 @@ public final class ConfiguredApplication implements Application {
@Override
public void start() {
- qrConfig = getConfig(QrConfig.class);
+ qrConfig = getConfig(QrConfig.class, true);
hackToInitializeServer(qrConfig);
@@ -184,7 +182,7 @@ public final class ConfiguredApplication implements Application {
slobrokList = slobrokConfigSubscriber.get().getSlobroks();
} else {
slobrokList = new SlobrokList();
- SlobroksConfig slobrokConfig = getConfig(SlobroksConfig.class);
+ SlobroksConfig slobrokConfig = getConfig(SlobroksConfig.class, true);
slobrokList.setup(slobrokConfig.slobrok().stream().map(SlobroksConfig.Slobrok::connectionspec).toArray(String[]::new));
}
return slobrokList;
@@ -209,10 +207,10 @@ public final class ConfiguredApplication implements Application {
}
}
- private <T extends ConfigInstance> T getConfig(Class<T> configClass) {
+ private <T extends ConfigInstance> T getConfig(Class<T> configClass, boolean isInitializing) {
Subscriber subscriber = subscriberFactory.getSubscriber(Collections.singleton(new ConfigKey<>(configClass, configId)));
try {
- subscriber.waitNextGeneration();
+ subscriber.waitNextGeneration(isInitializing);
return configClass.cast(first(subscriber.config().values()));
} finally {
subscriber.close();
@@ -223,7 +221,7 @@ public final class ConfiguredApplication implements Application {
Subscriber subscriber = subscriberFactory.getSubscriber(Collections.singleton(new ConfigKey<>(QrConfig.class, configId)));
try {
while (true) {
- subscriber.waitNextGeneration();
+ subscriber.waitNextGeneration(false);
QrConfig newConfig = QrConfig.class.cast(first(subscriber.config().values()));
if (qrConfig.rpc().port() != newConfig.rpc().port()) {
com.yahoo.protect.Process.logAndDie(
@@ -261,25 +259,22 @@ public final class ConfiguredApplication implements Application {
private void startReconfigurerThread() {
reconfigurerThread = new Thread(() -> {
- boolean restartOnDeploy = false;
while ( ! Thread.interrupted()) {
try {
ContainerBuilder builder = createBuilderWithGuiceBindings();
- // Restart on deploy is sticky: Once it is set no future generation should be applied until restart
- restartOnDeploy = restartOnDeploy || qrConfig.restartOnDeploy();
-
// Block until new config arrives, and it should be applied
- configurer.getNewComponentGraph(builder.guiceModules().activate(), restartOnDeploy);
+ configurer.getNewComponentGraph(builder.guiceModules().activate(), false);
initializeAndActivateContainer(builder);
} catch (ConfigInterruptedException e) {
break;
} catch (Exception | LinkageError e) { // LinkageError: OSGi problems
+ tryReportFailedComponentGraphConstructionMetric(configurer, e);
log.log(Level.SEVERE,
"Reconfiguration failed, your application package must be fixed, unless this is a " +
"JNI reload issue: " + Exceptions.toMessageString(e), e);
} catch (Error e) {
- com.yahoo.protect.Process.logAndDie("java.lang.Error on reconfiguration: We are probably in " +
+ com.yahoo.protect.Process.logAndDie("java.lang.Error on reconfiguration: We are probably in " +
"a bad state and will terminate", e);
}
}
@@ -288,6 +283,18 @@ public final class ConfiguredApplication implements Application {
reconfigurerThread.start();
}
+ private static void tryReportFailedComponentGraphConstructionMetric(HandlersConfigurerDi configurer, Throwable error) {
+ try {
+ // We need the Metric instance from previous component graph to report metric values
+ // Metric may not be available if this is the initial component graph (since metric wiring is done through the config model)
+ Metric metric = configurer.getComponent(Metric.class);
+ Metric.Context metricContext = metric.createContext(Map.of("exception", error.getClass().getSimpleName()));
+ metric.add("jdisc.application.failed_component_graphs", 1L, metricContext);
+ } catch (Exception e) {
+ log.log(Level.WARNING, "Failed to report metric for failed component graph: " + e.getMessage(), e);
+ }
+ }
+
private static void installServerProviders(ContainerBuilder builder) {
List<ServerProvider> serverProviders = Container.get().getServerProviderRegistry().allComponents();
for (ServerProvider server : serverProviders) {
@@ -328,7 +335,7 @@ public final class ConfiguredApplication implements Application {
return new HandlersConfigurerDi(subscriberFactory,
Container.get(),
configId,
- new Deconstructor(true),
+ new Deconstructor(Deconstructor.Mode.RECONFIG),
discInjector,
osgiFramework);
}
@@ -360,7 +367,7 @@ public final class ConfiguredApplication implements Application {
}
log.info("Stop: Shutting container down");
- configurer.shutdown(new Deconstructor(false));
+ configurer.shutdown(new Deconstructor(Deconstructor.Mode.SHUTDOWN));
slobrokConfigSubscriber.ifPresent(SlobrokConfigSubscriber::shutdown);
Container.get().shutdown();
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java b/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
index e60e8d407cd..d6a241c30c9 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
@@ -2,21 +2,26 @@
package com.yahoo.container.jdisc.component;
import com.yahoo.component.AbstractComponent;
+import com.yahoo.component.Deconstructable;
import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.container.di.ComponentDeconstructor;
import com.yahoo.container.di.componentgraph.Provider;
import com.yahoo.jdisc.SharedResource;
-import java.util.logging.Level;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Random;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Level.FINE;
@@ -32,18 +37,36 @@ public class Deconstructor implements ComponentDeconstructor {
private static final Logger log = Logger.getLogger(Deconstructor.class.getName());
+ private static final Duration RECONFIG_DECONSTRUCT_DELAY = Duration.ofSeconds(60);
+
+ // This must be smaller than the shutdownDeadlineExecutor delay in ConfiguredApplication
+ private static final Duration SHUTDOWN_DECONSTRUCT_TIMEOUT = Duration.ofSeconds(45);
+
+ public enum Mode {
+ RECONFIG, // Delay deconstruction to allow old components to finish processing in-flight requests.
+ SHUTDOWN // The container is shutting down. Start deconstructing immediately, and wait until all components
+ // are deconstructed, to prevent shutting down while deconstruct is in progress.
+ }
+
private final ScheduledExecutorService executor =
- Executors.newScheduledThreadPool(1, ThreadFactoryFactory.getThreadFactory("component-deconstructor"));
+ Executors.newScheduledThreadPool(2, ThreadFactoryFactory.getThreadFactory("component-deconstructor"));
+ private final Mode mode;
private final Duration delay;
- public Deconstructor(boolean delayDeconstruction) {
- this.delay = delayDeconstruction ? Duration.ofSeconds(60) : Duration.ZERO;
+ public Deconstructor(Mode mode) {
+ this(mode, (mode == Mode.RECONFIG) ? RECONFIG_DECONSTRUCT_DELAY : Duration.ZERO);
+ }
+
+ // For testing only
+ Deconstructor(Mode mode, Duration reconfigDeconstructDelay) {
+ this.mode = mode;
+ this.delay = reconfigDeconstructDelay;
}
@Override
- public void deconstruct(Collection<Object> components, Collection<Bundle> bundles) {
- Collection<AbstractComponent> destructibleComponents = new ArrayList<>();
+ public void deconstruct(List<Object> components, Collection<Bundle> bundles) {
+ Collection<Deconstructable> destructibleComponents = new ArrayList<>();
for (var component : components) {
if (component instanceof AbstractComponent) {
AbstractComponent abstractComponent = (AbstractComponent) component;
@@ -51,28 +74,43 @@ public class Deconstructor implements ComponentDeconstructor {
destructibleComponents.add(abstractComponent);
}
} else if (component instanceof Provider) {
- // TODO Providers should most likely be deconstructed similarly to AbstractComponent
- log.log(FINE, () -> "Starting deconstruction of provider " + component);
- ((Provider<?>) component).deconstruct();
- log.log(FINE, () -> "Finished deconstruction of provider " + component);
+ destructibleComponents.add((Deconstructable) component);
} else if (component instanceof SharedResource) {
log.log(FINE, () -> "Releasing container reference to resource " + component);
// No need to delay release, as jdisc does ref-counting
((SharedResource) component).release();
}
}
- if (! destructibleComponents.isEmpty() || ! bundles.isEmpty())
- executor.schedule(new DestructComponentTask(destructibleComponents, bundles),
+ if (!destructibleComponents.isEmpty() || !bundles.isEmpty()) {
+ var task = executor.schedule(new DestructComponentTask(destructibleComponents, bundles),
delay.getSeconds(), TimeUnit.SECONDS);
+ if (mode.equals(Mode.SHUTDOWN)) {
+ waitFor(task, SHUTDOWN_DECONSTRUCT_TIMEOUT);
+ }
+ }
+ }
+
+ private void waitFor(ScheduledFuture<?> task, Duration timeout) {
+ try {
+ log.info("Waiting up to " + timeout.toSeconds() + " seconds for all components to deconstruct.");
+ task.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ log.info("Interrupted while waiting for component deconstruction to finish.");
+ Thread.currentThread().interrupt();
+ } catch (ExecutionException e) {
+ log.warning("Component deconstruction threw an exception: " + e.getMessage());
+ } catch (TimeoutException e) {
+ log.warning("Component deconstruction timed out.");
+ }
}
private static class DestructComponentTask implements Runnable {
private final Random random = new Random(System.nanoTime());
- private final Collection<AbstractComponent> components;
+ private final Collection<Deconstructable> components;
private final Collection<Bundle> bundles;
- DestructComponentTask(Collection<AbstractComponent> components, Collection<Bundle> bundles) {
+ DestructComponentTask(Collection<Deconstructable> components, Collection<Bundle> bundles) {
this.components = components;
this.bundles = bundles;
}
@@ -89,10 +127,10 @@ public class Deconstructor implements ComponentDeconstructor {
@Override
public void run() {
for (var component : components) {
- log.log(FINE, () -> "Starting deconstruction of component " + component);
+ log.log(FINE, () -> "Starting deconstruction of " + component);
try {
component.deconstruct();
- log.log(FINE, () -> "Finished deconstructing of component " + component);
+ log.log(FINE, () -> "Finished deconstructing of " + component);
} catch (Exception | NoClassDefFoundError e) { // May get class not found due to it being already unloaded
log.log(WARNING, "Exception thrown when deconstructing component " + component, e);
} catch (Error e) {
diff --git a/container-disc/src/test/java/com/yahoo/container/jdisc/component/DeconstructorTest.java b/container-disc/src/test/java/com/yahoo/container/jdisc/component/DeconstructorTest.java
index efdc8f44c17..eef5b191e75 100644
--- a/container-disc/src/test/java/com/yahoo/container/jdisc/component/DeconstructorTest.java
+++ b/container-disc/src/test/java/com/yahoo/container/jdisc/component/DeconstructorTest.java
@@ -9,6 +9,11 @@ import com.yahoo.jdisc.SharedResource;
import org.junit.Before;
import org.junit.Test;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+import java.util.function.Supplier;
+
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static org.junit.Assert.assertTrue;
@@ -21,32 +26,40 @@ public class DeconstructorTest {
@Before
public void init() {
- deconstructor = new Deconstructor(false);
+ deconstructor = new Deconstructor(Deconstructor.Mode.RECONFIG, Duration.ZERO);
+ }
+
+ @Test
+ public void deconstruct_is_synchronous_in_shutdown_mode() {
+ deconstructor = new Deconstructor(Deconstructor.Mode.SHUTDOWN);
+
+ var slowDeconstructComponent = new SlowDeconstructComponent();
+ deconstructor.deconstruct(List.of(slowDeconstructComponent), emptyList());
+ assertTrue(slowDeconstructComponent.destructed);
}
@Test
public void require_abstract_component_destructed() throws InterruptedException {
TestAbstractComponent abstractComponent = new TestAbstractComponent();
- // Done by executor, so it takes some time even with a 0 delay.
- deconstructor.deconstruct(singleton(abstractComponent), emptyList());
- int cnt = 0;
- while (! abstractComponent.destructed && (cnt++ < 12000)) {
- Thread.sleep(10);
- }
+ deconstructor.deconstruct(List.of(abstractComponent), emptyList());
+
+ waitForDeconstructToComplete(() -> abstractComponent.destructed);
assertTrue(abstractComponent.destructed);
}
@Test
- public void require_provider_destructed() {
+ public void require_provider_destructed() throws InterruptedException {
TestProvider provider = new TestProvider();
- deconstructor.deconstruct(singleton(provider), emptyList());
+ deconstructor.deconstruct(List.of(provider), emptyList());
+
+ waitForDeconstructToComplete(() -> provider.destructed);
assertTrue(provider.destructed);
}
@Test
public void require_shared_resource_released() {
TestSharedResource sharedResource = new TestSharedResource();
- deconstructor.deconstruct(singleton(sharedResource), emptyList());
+ deconstructor.deconstruct(List.of(sharedResource), emptyList());
assertTrue(sharedResource.released);
}
@@ -55,11 +68,17 @@ public class DeconstructorTest {
var bundle = new UninstallableMockBundle();
// Done by executor, so it takes some time even with a 0 delay.
deconstructor.deconstruct(emptyList(), singleton(bundle));
- int cnt = 0;
- while (! bundle.uninstalled && (cnt++ < 12000)) {
+
+ waitForDeconstructToComplete(() -> bundle.uninstalled);
+ assertTrue(bundle.uninstalled);
+ }
+
+ // Deconstruct is async in RECONFIG mode, so must wait even with a zero delay.
+ private void waitForDeconstructToComplete(Supplier<Boolean> destructed) throws InterruptedException {
+ var end = Instant.now().plusSeconds(30);
+ while (! destructed.get() && Instant.now().isBefore(end)) {
Thread.sleep(10);
}
- assertTrue(bundle.uninstalled);
}
private static class TestAbstractComponent extends AbstractComponent {
@@ -67,6 +86,20 @@ public class DeconstructorTest {
@Override public void deconstruct() { destructed = true; }
}
+ private static class SlowDeconstructComponent extends AbstractComponent {
+ boolean destructed = false;
+ @Override
+ public void deconstruct() {
+ // Add delay to verify that the Deconstructor waits until this is complete before returning.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("The delayed deconstruct was interrupted.");
+ }
+ destructed = true;
+ }
+ }
+
private static class TestProvider implements Provider<Void> {
volatile boolean destructed = false;
@@ -87,4 +120,5 @@ public class DeconstructorTest {
uninstalled = true;
}
}
+
}
diff --git a/container-messagebus/src/main/java/com/yahoo/container/jdisc/messagebus/SessionCache.java b/container-messagebus/src/main/java/com/yahoo/container/jdisc/messagebus/SessionCache.java
index 68b1f5aa5db..7f67f7ec403 100644
--- a/container-messagebus/src/main/java/com/yahoo/container/jdisc/messagebus/SessionCache.java
+++ b/container-messagebus/src/main/java/com/yahoo/container/jdisc/messagebus/SessionCache.java
@@ -123,6 +123,7 @@ public final class SessionCache extends AbstractComponent {
.setListenPort(mbusConfig.port())
.setNumTargetsPerSpec(mbusConfig.numconnectionspertarget())
.setNumNetworkThreads(mbusConfig.numthreads())
+ .setTransportEventsBeforeWakeup(mbusConfig.transport_events_before_wakeup())
.setOptimization(RPCNetworkParams.Optimization.valueOf(mbusConfig.optimize_for().name()));
return SharedMessageBus.newInstance(mbusParams, netParams);
}
diff --git a/container-messagebus/src/main/resources/configdefinitions/container.jdisc.container-mbus.def b/container-messagebus/src/main/resources/configdefinitions/container.jdisc.container-mbus.def
index 9aef2b32a66..d3aa3bbdc4a 100644
--- a/container-messagebus/src/main/resources/configdefinitions/container.jdisc.container-mbus.def
+++ b/container-messagebus/src/main/resources/configdefinitions/container.jdisc.container-mbus.def
@@ -15,6 +15,9 @@ numthreads int default=2
# Optimize for latency, or throughput.
optimize_for enum {LATENCY, THROUGHPUT} default=LATENCY
+# Number of events before triggering wakeup of network thread.
+transport_events_before_wakeup int default=1
+
# Everying below is deprecated and will go away very soon.
# Dynamic throttling is used, and works better than anything else.
maxpendingcount int default=2048
diff --git a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java
index a58aabfce17..57c5e768cfb 100644
--- a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java
+++ b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java
@@ -86,7 +86,7 @@ public class ApplicationStatusHandler extends AbstractRequestHandler {
@Override
protected com.yahoo.jdisc.Response newResponse() {
com.yahoo.jdisc.Response response = new com.yahoo.jdisc.Response(com.yahoo.jdisc.Response.Status.OK);
- response.headers().add("Content-Type", Arrays.asList(new String[]{"application/json"}));
+ response.headers().add("Content-Type", List.of("application/json"));
return response;
}
}.connect(handler));
diff --git a/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js b/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js
index 5531a2a4f69..762e0882ff4 100644
--- a/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js
+++ b/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js
@@ -277,7 +277,7 @@ var EditArea_autocompletion= {
nbMatch = 0;
for( i =0; i<limit ; i++ )
{
- if( line_string.substring( limit - i - 1, limit ) == content.substring( 0, i + 1 ) )
+ if( line_string.substring( limit - i - 1, limit ).toUpperCase() === content.substring( 0, i + 1 ).toUpperCase() )
nbMatch = i + 1;
}
// if characters match, we should include them in the selection that will be replaced
diff --git a/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js b/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js
index 0a7dae862f3..545927a833a 100755
--- a/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js
+++ b/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js
@@ -72,7 +72,7 @@ editAreaLoader.load_syntax["yql"] = {
,"CASE_SENSITIVE": false
,"MAX_TEXT_LENGTH": 50 // the maximum length of the text being analyzed before the cursor position
,"KEYWORDS": {
- '': [ // the prefix of thoses items
+ '': [ // the prefix of these items
/**
* 0 : the keyword the user is typing
* 1 : (optionnal) the string inserted in code ("{@}" being the new position of the cursor, "§" beeing the equivalent to the value the typed string indicated if the previous )
diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json
index cd3f011352d..6f48ae5b41a 100644
--- a/container-search/abi-spec.json
+++ b/container-search/abi-spec.json
@@ -4264,6 +4264,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.handler.SearchWithRendererHandlerConfig build()"
],
"fields": []
@@ -4505,6 +4507,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.pagetemplates.PageTemplatesConfig build()"
],
"fields": [
@@ -4567,6 +4571,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.pagetemplates.ResolversConfig build()"
],
"fields": [
@@ -6823,6 +6829,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.query.rewrite.RewritesConfig build()"
],
"fields": [
@@ -7974,6 +7982,18 @@
],
"fields": []
},
+ "com.yahoo.search.searchers.QueryValidator": {
+ "superClass": "com.yahoo.search.Searcher",
+ "interfaces": [],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>()",
+ "public com.yahoo.search.Result search(com.yahoo.search.Query, com.yahoo.search.searchchain.Execution)"
+ ],
+ "fields": []
+ },
"com.yahoo.search.searchers.RateLimitingSearcher": {
"superClass": "com.yahoo.search.Searcher",
"interfaces": [],
@@ -8061,6 +8081,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.statistics.MeasureQpsConfig build()"
],
"fields": []
@@ -8255,6 +8277,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.search.statistics.TimingSearcherConfig build()"
],
"fields": [
diff --git a/container-search/src/main/java/com/yahoo/prelude/Index.java b/container-search/src/main/java/com/yahoo/prelude/Index.java
index 0dfbf6470ad..8915c4b42f0 100644
--- a/container-search/src/main/java/com/yahoo/prelude/Index.java
+++ b/container-search/src/main/java/com/yahoo/prelude/Index.java
@@ -44,11 +44,14 @@ public class Index {
/** The null index - don't use this for name lookups */
public static final Index nullIndex = new Index("(null)");
- private String name;
+ private final String name;
- private List<String> aliases = new ArrayList<>();
+ private String type; // TODO: Parse to a type object; do not expose this as a string
+
+ private final List<String> aliases = new ArrayList<>();
// The state resulting from adding commands to this (using addCommand)
+ private boolean tensor = false;
private boolean uriIndex = false;
private boolean hostIndex = false;
private StemMode stemMode = StemMode.NONE;
@@ -79,11 +82,11 @@ public class Index {
/** The string terminating an exact token in this index, or null to use the default (space) */
private String exactTerminator = null;
- /** Commands which are not coverted into a field */
- private Set<String> commands = new java.util.HashSet<>();
+ /** Commands which are not converted into a field */
+ private final Set<String> commands = new java.util.HashSet<>();
/** All the commands added to this, including those converted to fields above */
- private List<String> allCommands = new java.util.ArrayList<>();
+ private final List<String> allCommands = new java.util.ArrayList<>();
public Index(String name) {
this.name = name;
@@ -139,63 +142,71 @@ public class Index {
}
/** Adds a type or untyped command string to this */
- public Index addCommand(String commandString) {
- allCommands.add(commandString);
+ public Index addCommand(String command) {
+ allCommands.add(command);
- if ("fullurl".equals(commandString)) {
+ if (command.startsWith("type tensor(") || command.startsWith("type tensor<")) { // TODO: Type info can replace numerical, predicate, multivalue
+ setTensor(true);
+ } else if ("fullurl".equals(command)) {
setUriIndex(true);
- } else if ("urlhost".equals(commandString)) {
+ } else if ("urlhost".equals(command)) {
setHostIndex(true);
- } else if (commandString.startsWith("stem ")) {
- setStemMode(commandString.substring(5));
- } else if (commandString.startsWith("stem:")) {
- setStemMode(commandString.substring(5));
- } else if ("stem".equals(commandString)) {
+ } else if (command.startsWith("stem ")) {
+ setStemMode(command.substring(5));
+ } else if (command.startsWith("stem:")) {
+ setStemMode(command.substring(5));
+ } else if ("stem".equals(command)) {
setStemMode(StemMode.SHORTEST);
- } else if ("word".equals(commandString)) {
+ } else if ("word".equals(command)) {
setExact(true, null);
- } else if ("exact".equals(commandString)) {
+ } else if ("exact".equals(command)) {
setExact(true, " ");
- } else if ("dynteaser".equals(commandString)) {
+ } else if ("dynteaser".equals(command)) {
setDynamicSummary(true);
- } else if ("highlight".equals(commandString)) {
+ } else if ("highlight".equals(command)) {
setHighlightSummary(true);
- } else if ("lowercase".equals(commandString)) {
+ } else if ("lowercase".equals(command)) {
setLowercase(true);
- } else if (commandString.startsWith("exact ")) {
- setExact(true, commandString.substring(6));
- } else if (commandString.startsWith("ngram ")) {
- setNGram(true, Integer.parseInt(commandString.substring(6)));
- } else if (commandString.equals("attribute")) {
+ } else if (command.startsWith("exact ")) {
+ setExact(true, command.substring(6));
+ } else if (command.startsWith("ngram ")) {
+ setNGram(true, Integer.parseInt(command.substring(6)));
+ } else if (command.equals("attribute")) {
setAttribute(true);
- } else if (commandString.equals("default-position")) {
+ } else if (command.equals("default-position")) {
setDefaultPosition(true);
- } else if (commandString.equals("plain-tokens")) {
+ } else if (command.equals("plain-tokens")) {
setPlainTokens(true);
- } else if (commandString.equals("multivalue")) {
+ } else if (command.equals("multivalue")) {
setMultivalue(true);
- } else if (commandString.equals("fast-search")) {
+ } else if (command.equals("fast-search")) {
setFastSearch(true);
- } else if (commandString.equals("normalize")) {
+ } else if (command.equals("normalize")) {
setNormalize(true);
- } else if (commandString.equals("literal-boost")) {
+ } else if (command.equals("literal-boost")) {
setLiteralBoost(true);
- } else if (commandString.equals("numerical")) {
+ } else if (command.equals("numerical")) {
setNumerical(true);
- } else if (commandString.equals("predicate")) {
+ } else if (command.equals("predicate")) {
setPredicate(true);
- } else if (commandString.startsWith("predicate-bounds ")) {
- setPredicateBounds(commandString.substring(17));
- } else if (commandString.equals("phrase-segmenting")) {
+ } else if (command.startsWith("predicate-bounds ")) {
+ setPredicateBounds(command.substring(17));
+ } else if (command.equals("phrase-segmenting")) {
setPhraseSegmenting(true);
- } else if (commandString.startsWith("phrase-segmenting ")) {
- setPhraseSegmenting(Boolean.parseBoolean(commandString.substring("phrase-segmenting ".length())));
+ } else if (command.startsWith("phrase-segmenting ")) {
+ setPhraseSegmenting(Boolean.parseBoolean(command.substring("phrase-segmenting ".length())));
} else {
- commands.add(commandString);
+ commands.add(command);
}
return this;
}
+ private void setTensor(boolean tensor) {
+ this.tensor = tensor;
+ }
+
+ public boolean isTensor() { return tensor; }
+
private void setPredicateBounds(String bounds) {
if ( ! bounds.startsWith("[..")) {
predicateLowerBound = Long.parseLong(bounds.substring(1, bounds.indexOf("..")));
@@ -270,9 +281,7 @@ public class Index {
return "(null)".equals(name);
}
- public boolean isAttribute() {
- return isAttribute;
- }
+ public boolean isAttribute() { return isAttribute; }
public void setAttribute(boolean isAttribute) {
this.isAttribute = isAttribute;
diff --git a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java
index aa3d6a2c0f8..7b403ca3659 100644
--- a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java
+++ b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java
@@ -333,10 +333,8 @@ public class IndexFacts {
/**
* Returns the index for this name.
*
- * @param indexName the name of the index. If this is null or empty the index
- * named "default" is returned
- * @return the index best matching the input parameters or the nullIndex
- * (never null) if none is found
+ * @param indexName the name of the index. If this is null or empty the index named "default" is returned
+ * @return the index best matching the input parameters or the null Index (never null) if none is found
*/
public Index getIndex(String indexName) {
return IndexFacts.this.getIndexFromDocumentTypes(indexName, documentTypes);
diff --git a/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java b/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java
index 7859a9698d9..3d1240237e4 100644
--- a/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.java
+++ b/container-search/src/main/java/com/yahoo/prelude/SearchDefinition.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.prelude;
-import com.yahoo.prelude.Index.Attribute;
-
import java.util.HashMap;
import java.util.Map;
@@ -17,13 +15,13 @@ import static com.yahoo.text.Lowercase.toLowerCase;
// TODO: Make freezable!
public class SearchDefinition {
- private String name;
+ private final String name;
/** A map of all indices in this search definition, indexed by name */
- private Map<String, Index> indices = new HashMap<>();
+ private final Map<String, Index> indices = new HashMap<>();
/* A map of all indices in this search definition, indexed by lower cased name. */
- private Map<String, Index> lowerCase = new HashMap<>();
+ private final Map<String, Index> lowerCase = new HashMap<>();
private String defaultPosition;
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
index 2090390890e..d30e67195c3 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/VespaBackEndSearcher.java
@@ -43,7 +43,7 @@ public abstract class VespaBackEndSearcher extends PingableSearcher {
private String serverId;
/** The set of all document databases available in the backend handled by this searcher */
- private Map<String, DocumentDatabase> documentDbs = new LinkedHashMap<>();
+ private final Map<String, DocumentDatabase> documentDbs = new LinkedHashMap<>();
private DocumentDatabase defaultDocumentDb = null;
/** Default docsum class. null means "unset" and is the default value */
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/HasIndexItem.java b/container-search/src/main/java/com/yahoo/prelude/query/HasIndexItem.java
index 6641dee9780..c70ee9e4def 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/HasIndexItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/HasIndexItem.java
@@ -2,8 +2,7 @@
package com.yahoo.prelude.query;
/**
- * An interface for items where it is useful to access an associated
- * index name.
+ * An interface for items where it is useful to access an index name.
*
* @author Steinar Knutsen
*/
@@ -11,7 +10,7 @@ public interface HasIndexItem {
String getIndexName();
- /** @return how many phrase words does this item contain */
+ /** Returns how many phrase words does this item contain */
int getNumWords();
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/IndexedItem.java b/container-search/src/main/java/com/yahoo/prelude/query/IndexedItem.java
index 3dafa230eb8..cba289fa5d8 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/IndexedItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/IndexedItem.java
@@ -3,7 +3,7 @@ package com.yahoo.prelude.query;
/**
- * Interface for Items that is indexed
+ * Interface for Items that are indexed
*
* @author Lars Christian Jensen
*/
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/ToolBox.java b/container-search/src/main/java/com/yahoo/prelude/query/ToolBox.java
index 72ba012ab07..5a6d4cd6382 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/ToolBox.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/ToolBox.java
@@ -18,8 +18,7 @@ public final class ToolBox {
* {@link ToolBox#visit(QueryVisitor, Item)}. Return true to visit the
* sub-items of the given item, return false to ignore the sub-items.
*
- * @param item
- * each item in the query tree
+ * @param item each item in the query tree
* @return whether or not to visit the sub-items of the argument item
* (and then invoke the {@link #onExit()} method)
*/
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
index 399ff6194c8..90bcebb53ad 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
@@ -107,7 +107,7 @@ public class NGramSearcher extends Searcher {
*/
protected Item splitToGrams(Item term, String text, int gramSize, Query query) {
String index = ((HasIndexItem)term).getIndexName();
- CompositeItem gramsItem = createGramRoot(query);
+ CompositeItem gramsItem = createGramRoot((HasIndexItem)term, query);
gramsItem.setIndexName(index);
Substring origin = ((BlockItem)term).getOrigin();
for (Iterator<GramSplitter.Gram> i = getGramSplitter().split(text,gramSize); i.hasNext(); ) {
@@ -130,12 +130,20 @@ public class NGramSearcher extends Searcher {
* called by {@link #splitToGrams}. This hook is provided to make it easy to create a subclass which
* matches grams using a different composite item, e.g an OrItem.
* <p>
- * This default implementation return new AndItem();
+ * This default implementation returns createGramRoot(query).
*
+ * @param term the term item this gram root is replacing in the query tree,
+ * typically used to access the index name of the term when that is required by the new gram root
+ * (such as in PhraseItem)
* @param query the input query, to make it possible to return a different composite item type
* depending on the query content
* @return the composite item to add the gram items to in {@link #splitToGrams}
*/
+ protected CompositeItem createGramRoot(HasIndexItem term, Query query) {
+ return createGramRoot(query);
+ }
+
+ /** Creates the root of the query subtree without access to the term being replaced. */
protected CompositeItem createGramRoot(Query query) {
return new AndItem();
}
diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
index 8db690678bb..5df12dc2053 100644
--- a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
+++ b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
@@ -33,6 +33,7 @@ public class LocalProviderSpec {
com.yahoo.search.querytransform.RangeQueryOptimizer.class,
com.yahoo.search.querytransform.SortingDegrader.class,
com.yahoo.prelude.searcher.ValidateSortingSearcher.class,
+ com.yahoo.search.searchers.QueryValidator.class,
com.yahoo.prelude.cluster.ClusterSearcher.class,
com.yahoo.search.grouping.GroupingValidator.class,
com.yahoo.search.grouping.vespa.GroupingExecutor.class,
diff --git a/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java b/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
index 5e15a8ba14b..d8391fe08f3 100644
--- a/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
@@ -12,6 +12,8 @@ import java.util.Map;
import java.util.logging.Logger;
import java.util.logging.Level;
+
+import com.yahoo.component.chain.dependencies.Before;
import com.yahoo.metrics.simple.Counter;
import com.yahoo.metrics.simple.MetricReceiver;
import com.yahoo.prelude.query.CompositeItem;
@@ -25,14 +27,16 @@ import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.searchchain.Execution;
+import com.yahoo.search.searchchain.PhaseNames;
import com.yahoo.yolean.Exceptions;
/**
- * Check whether the query tree seems to be "well formed". In other words, run heurestics against
+ * Check whether the query tree seems to be "well formed". In other words, run heuristics against
* the input data to see whether the query should sent to the search backend.
*
* @author Steinar Knutsen
*/
+@Before(PhaseNames.BACKEND)
public class InputCheckingSearcher extends Searcher {
private final Counter utfRejections;
diff --git a/container-search/src/main/java/com/yahoo/search/searchers/QueryValidator.java b/container-search/src/main/java/com/yahoo/search/searchers/QueryValidator.java
new file mode 100644
index 00000000000..024f231f524
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/searchers/QueryValidator.java
@@ -0,0 +1,59 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.searchers;
+
+import com.yahoo.component.chain.dependencies.After;
+import com.yahoo.component.chain.dependencies.Before;
+import com.yahoo.prelude.Index;
+import com.yahoo.prelude.IndexFacts;
+import com.yahoo.prelude.query.CompositeItem;
+import com.yahoo.prelude.query.HasIndexItem;
+import com.yahoo.prelude.query.Item;
+import com.yahoo.prelude.query.ToolBox;
+import com.yahoo.search.Query;
+import com.yahoo.search.Result;
+import com.yahoo.search.Searcher;
+import com.yahoo.search.searchchain.Execution;
+import com.yahoo.search.searchchain.PhaseNames;
+
+import static com.yahoo.search.grouping.GroupingQueryParser.SELECT_PARAMETER_PARSING;
+
+/**
+ * Validation of query operators against the schema which is searched
+ *
+ * @author bratseth
+ */
+@After(SELECT_PARAMETER_PARSING)
+@Before(PhaseNames.BACKEND)
+public class QueryValidator extends Searcher {
+
+ @Override
+ public Result search(Query query, Execution execution) {
+ IndexFacts.Session session = execution.context().getIndexFacts().newSession(query);
+ ToolBox.visit(new ItemValidator(session), query.getModel().getQueryTree().getRoot());
+ return execution.search(query);
+ }
+
+ private static class ItemValidator extends ToolBox.QueryVisitor {
+
+ IndexFacts.Session session;
+
+ public ItemValidator(IndexFacts.Session session) {
+ this.session = session;
+ }
+
+ @Override
+ public boolean visit(Item item) {
+ if (item instanceof HasIndexItem) {
+ String indexName = ((HasIndexItem)item).getIndexName();
+ if (session.getIndex(indexName).isTensor())
+ throw new IllegalArgumentException("Cannot search '" + indexName + "': It is a tensor field");
+ }
+ return true;
+ }
+
+ @Override
+ public void onExit() { }
+
+ }
+
+}
diff --git a/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java b/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
index aca2998cba3..65ca4a93cc1 100644
--- a/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
@@ -33,7 +33,7 @@ import java.util.Optional;
@Before(GroupingExecutor.COMPONENT_NAME) // Must happen before query.prepare()
public class ValidateNearestNeighborSearcher extends Searcher {
- private Map<String, TensorType> validAttributes = new HashMap<>();
+ private final Map<String, TensorType> validAttributes = new HashMap<>();
public ValidateNearestNeighborSearcher(AttributesConfig attributesConfig) {
for (AttributesConfig.Attribute a : attributesConfig.attribute()) {
@@ -61,12 +61,10 @@ public class ValidateNearestNeighborSearcher extends Searcher {
public Optional<ErrorMessage> errorMessage = Optional.empty();
- private final RankProperties rankProperties;
private final Map<String, TensorType> validAttributes;
private final Query query;
public NNVisitor(RankProperties rankProperties, Map<String, TensorType> validAttributes, Query query) {
- this.rankProperties = rankProperties;
this.validAttributes = validAttributes;
this.query = query;
}
diff --git a/container-search/src/test/java/com/yahoo/prelude/searcher/test/ValidatePredicateSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/searcher/test/ValidatePredicateSearcherTestCase.java
index 2187cb89ae2..850586ba8c5 100644
--- a/container-search/src/test/java/com/yahoo/prelude/searcher/test/ValidatePredicateSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/searcher/test/ValidatePredicateSearcherTestCase.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
- * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
+ * @author Magnar Nedland
*/
public class ValidatePredicateSearcherTestCase {
diff --git a/container-search/src/test/java/com/yahoo/search/searchers/test/QueryValidatorTestCase.java b/container-search/src/test/java/com/yahoo/search/searchers/test/QueryValidatorTestCase.java
new file mode 100644
index 00000000000..543c880e525
--- /dev/null
+++ b/container-search/src/test/java/com/yahoo/search/searchers/test/QueryValidatorTestCase.java
@@ -0,0 +1,51 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.searchers.test;
+
+import com.yahoo.prelude.IndexFacts;
+import com.yahoo.prelude.IndexModel;
+import com.yahoo.prelude.SearchDefinition;
+import com.yahoo.search.Query;
+import com.yahoo.search.searchchain.Execution;
+import com.yahoo.search.searchers.QueryValidator;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * @author bratseth
+ */
+public class QueryValidatorTestCase {
+
+ @Test
+ public void testValidation() {
+ SearchDefinition sd = new SearchDefinition("test");
+ sd.addCommand("mytensor1", "type tensor(x[100]");
+ sd.addCommand("mytensor2", "type tensor<float>(x[100]");
+ sd.addCommand("mystring", "type string");
+ IndexModel model = new IndexModel(sd);
+
+ IndexFacts indexFacts = new IndexFacts(model);
+ Execution execution = new Execution(Execution.Context.createContextStub(indexFacts));
+ new QueryValidator().search(new Query("?query=mystring:foo"), execution);
+
+ try {
+ new QueryValidator().search(new Query("?query=mytensor1:foo"), execution);
+ fail("Expected validation error");
+ }
+ catch (IllegalArgumentException e) {
+ // success
+ assertEquals("Cannot search 'mytensor1': It is a tensor field", e.getMessage());
+ }
+
+ try {
+ new QueryValidator().search(new Query("?query=mytensor2:foo"), execution);
+ fail("Expected validation error");
+ }
+ catch (IllegalArgumentException e) {
+ // success
+ assertEquals("Cannot search 'mytensor2': It is a tensor field", e.getMessage());
+ }
+ }
+
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/ApplicationId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/ApplicationId.java
index c2512c2032b..3ad1d3f4d35 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/ApplicationId.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/ApplicationId.java
@@ -19,6 +19,7 @@ public class ApplicationId extends NonDefaultIdentifier {
public static void validate(String id) {
if ( ! strictPattern.matcher(id).matches())
throwInvalidId(id, strictPatternExplanation);
+ new ApplicationId(id); // validate
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/InstanceId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/InstanceId.java
index 8e14774b827..6973a142b16 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/InstanceId.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/InstanceId.java
@@ -19,6 +19,7 @@ public class InstanceId extends SerializedIdentifier {
public static void validate(String id) {
if ( ! strictPattern.matcher(id).matches())
throwInvalidId(id, strictPatternExplanation);
+ new InstanceId(id); // validate
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/TenantId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/TenantId.java
index 3ac24bac7ca..d8318470f82 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/TenantId.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/identifiers/TenantId.java
@@ -17,9 +17,9 @@ public class TenantId extends NonDefaultIdentifier {
}
public static void validate(String id) {
- if (!strictPattern.matcher(id).matches()) {
+ if ( ! strictPattern.matcher(id).matches())
throwInvalidId(id, strictPatternExplanation);
- }
+ new TenantId(id); // validate
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java
index 8f2d2161f92..4006d68ba1f 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java
@@ -19,7 +19,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueHandl
import com.yahoo.vespa.hosted.controller.api.integration.organization.Mailer;
import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipIssues;
import com.yahoo.vespa.hosted.controller.api.integration.organization.SystemMonitor;
-import com.yahoo.vespa.hosted.controller.api.integration.repair.HostRepairClient;
import com.yahoo.vespa.hosted.controller.api.integration.resource.CostReportConsumer;
import com.yahoo.vespa.hosted.controller.api.integration.resource.MeteringClient;
import com.yahoo.vespa.hosted.controller.api.integration.routing.GlobalRoutingService;
@@ -81,8 +80,6 @@ public interface ServiceRegistry {
BillingController billingController();
- HostRepairClient hostRepairClient();
-
ContainerRegistry containerRegistry();
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
index 90c4622d803..3a864fc04c6 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
@@ -16,6 +16,8 @@ public interface BillingController {
PlanId getPlan(TenantName tenant);
+ List<TenantName> tenantsWithPlan(List<TenantName> existing, PlanId planId);
+
String getPlanDisplayName(PlanId planId);
Quota getQuota(TenantName tenant);
@@ -49,7 +51,9 @@ public interface BillingController {
InstrumentList listInstruments(TenantName tenant, String userId);
- List<Invoice> getInvoices(TenantName tenant);
+ List<Invoice> getInvoicesForTenant(TenantName tenant);
+
+ List<Invoice> getInvoices();
void deleteBillingInfo(TenantName tenant, Set<User> users, boolean isPrivileged);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java
index 44f8f6e786d..39d974378b4 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller.api.integration.billing;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import java.math.BigDecimal;
@@ -13,6 +14,7 @@ import java.util.Optional;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
+import java.util.function.Function;
/**
@@ -31,13 +33,15 @@ public class Invoice {
private static final BigDecimal SCALED_ZERO = new BigDecimal("0.00");
private final Id id;
+ private final TenantName tenant;
private final List<LineItem> lineItems;
private final StatusHistory statusHistory;
private final ZonedDateTime startTime;
private final ZonedDateTime endTime;
- public Invoice(Id id, StatusHistory statusHistory, List<LineItem> lineItems, ZonedDateTime startTime, ZonedDateTime endTime) {
+ public Invoice(Id id, TenantName tenant, StatusHistory statusHistory, List<LineItem> lineItems, ZonedDateTime startTime, ZonedDateTime endTime) {
this.id = id;
+ this.tenant = tenant;
this.lineItems = List.copyOf(lineItems);
this.statusHistory = statusHistory;
this.startTime = startTime;
@@ -48,6 +52,10 @@ public class Invoice {
return id;
}
+ public TenantName tenant() {
+ return tenant;
+ }
+
public String status() {
return statusHistory.current();
}
@@ -72,6 +80,40 @@ public class Invoice {
return lineItems.stream().map(LineItem::amount).reduce(SCALED_ZERO, BigDecimal::add);
}
+ public BigDecimal sumCpuHours() {
+ return sumResourceValues(LineItem::getCpuHours);
+ }
+
+ public BigDecimal sumMemoryHours() {
+ return sumResourceValues(LineItem::getMemoryHours);
+ }
+
+ public BigDecimal sumDiskHours() {
+ return sumResourceValues(LineItem::getDiskHours);
+ }
+
+ public BigDecimal sumCpuCost() {
+ return sumResourceValues(LineItem::getCpuCost);
+ }
+
+ public BigDecimal sumMemoryCost() {
+ return sumResourceValues(LineItem::getMemoryCost);
+ }
+
+ public BigDecimal sumDiskCost() {
+ return sumResourceValues(LineItem::getDiskCost);
+ }
+
+ public BigDecimal sumAdditionalCost() {
+ // anything that is not covered by the cost for resources is "additional" costs
+ var resourceCosts = sumCpuCost().add(sumMemoryCost()).add(sumDiskCost());
+ return sum().subtract(resourceCosts);
+ }
+
+ private BigDecimal sumResourceValues(Function<LineItem, Optional<BigDecimal>> f) {
+ return lineItems.stream().flatMap(li -> f.apply(li).stream()).reduce(SCALED_ZERO, BigDecimal::add);
+ }
+
public static final class Id {
private final String value;
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
index 420b964d7aa..b24d532d4a3 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
@@ -8,11 +8,13 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* @author olaa
@@ -32,6 +34,13 @@ public class MockBillingController implements BillingController {
}
@Override
+ public List<TenantName> tenantsWithPlan(List<TenantName> tenants, PlanId planId) {
+ return tenants.stream()
+ .filter(t -> plans.getOrDefault(t, PlanId.from("trial")).equals(planId))
+ .collect(Collectors.toList());
+ }
+
+ @Override
public String getPlanDisplayName(PlanId planId) {
return "Plan with id: " + planId.value();
}
@@ -53,6 +62,7 @@ public class MockBillingController implements BillingController {
committedInvoices.computeIfAbsent(tenant, l -> new ArrayList<>())
.add(new Invoice(
invoiceId,
+ tenant,
Invoice.StatusHistory.open(),
List.of(),
startTime,
@@ -134,11 +144,16 @@ public class MockBillingController implements BillingController {
}
@Override
- public List<Invoice> getInvoices(TenantName tenant) {
+ public List<Invoice> getInvoicesForTenant(TenantName tenant) {
return committedInvoices.getOrDefault(tenant, List.of());
}
@Override
+ public List<Invoice> getInvoices() {
+ return committedInvoices.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
+ }
+
+ @Override
public void deleteBillingInfo(TenantName tenant, Set<User> users, boolean isPrivileged) {}
@Override
@@ -177,6 +192,6 @@ public class MockBillingController implements BillingController {
}
private Invoice emptyInvoice() {
- return new Invoice(Invoice.Id.of("empty"), Invoice.StatusHistory.open(), List.of(), ZonedDateTime.now(), ZonedDateTime.now());
+ return new Invoice(Invoice.Id.of("empty"), TenantName.defaultName(), Invoice.StatusHistory.open(), List.of(), ZonedDateTime.now(), ZonedDateTime.now());
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ApplicationReindexing.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ApplicationReindexing.java
index b6c7899aef1..e143cdd6d9e 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ApplicationReindexing.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ApplicationReindexing.java
@@ -64,17 +64,17 @@ public class ApplicationReindexing {
public static class Cluster {
- private final Status common;
+ private final Optional<Status> common;
private final Map<String, Long> pending;
private final Map<String, Status> ready;
public Cluster(Status common, Map<String, Long> pending, Map<String, Status> ready) {
- this.common = requireNonNull(common);
+ this.common = Optional.ofNullable(common);
this.pending = Map.copyOf(pending);
this.ready = Map.copyOf(ready);
}
- public Status common() {
+ public Optional<Status> common() {
return common;
}
@@ -120,9 +120,9 @@ public class ApplicationReindexing {
private final Instant endedAt;
private final State state;
private final String message;
- private final String progress;
+ private final Double progress;
- public Status(Instant readyAt, Instant startedAt, Instant endedAt, State state, String message, String progress) {
+ public Status(Instant readyAt, Instant startedAt, Instant endedAt, State state, String message, Double progress) {
this.readyAt = readyAt;
this.startedAt = startedAt;
this.endedAt = endedAt;
@@ -140,7 +140,7 @@ public class ApplicationReindexing {
public Optional<Instant> endedAt() { return Optional.ofNullable(endedAt); }
public Optional<State> state() { return Optional.ofNullable(state); }
public Optional<String> message() { return Optional.ofNullable(message); }
- public Optional<String> progress() { return Optional.ofNullable(progress); }
+ public Optional<Double> progress() { return Optional.ofNullable(progress); }
@Override
public boolean equals(Object o) {
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
index b384f349f92..0c9a415beab 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
@@ -53,7 +53,7 @@ public interface ConfigServer {
Map<?,?> getServiceApiResponse(DeploymentId deployment, String serviceName, String restPath);
- String getClusterControllerStatus(DeploymentId deployment, String restPath);
+ String getClusterControllerStatus(DeploymentId deployment, String node, String subPath);
/**
* Gets the Vespa logs of the given deployment.
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/FlagsV1Api.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/FlagsV1Api.java
index 1b18a9f6ee4..7187871dbf4 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/FlagsV1Api.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/FlagsV1Api.java
@@ -1,6 +1,9 @@
// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.configserver;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.yahoo.vespa.flags.json.wire.WireFlagData;
import com.yahoo.vespa.flags.json.wire.WireFlagDataList;
@@ -13,6 +16,8 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
+import java.util.List;
+import java.util.Map;
/**
* @author hakonhall
@@ -36,4 +41,15 @@ public interface FlagsV1Api {
@GET
@Path("/data")
WireFlagDataList listFlagData(@QueryParam("recursive") Boolean recursive);
+
+ @GET
+ @Path("/defined")
+ Map<String, WireFlagDefinition> listFlagDefinition();
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ class WireFlagDefinition {
+ @JsonProperty("owners") public List<String> owners;
+ @JsonProperty("expiresAt") public String expiresAt;
+ }
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
index 7d85c11789b..04f1448bec1 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java
@@ -61,6 +61,7 @@ public class Node {
private final List<NodeHistory> history;
private final Set<String> additionalIpAddresses;
private final String openStackId;
+ private final Optional<String> switchHostname;
public Node(HostName hostname, Optional<HostName> parentHostname, State state, NodeType type, NodeResources resources, Optional<ApplicationId> owner,
Version currentVersion, Version wantedVersion, Version currentOsVersion, Version wantedOsVersion,
@@ -69,7 +70,7 @@ public class Node {
int cost, String flavor, String clusterId, ClusterType clusterType, boolean wantToRetire, boolean wantToDeprovision,
Optional<TenantName> reservedTo, Optional<ApplicationId> exclusiveTo,
DockerImage wantedDockerImage, DockerImage currentDockerImage, Map<String, JsonNode> reports, List<NodeHistory> history,
- Set<String> additionalIpAddresses, String openStackId) {
+ Set<String> additionalIpAddresses, String openStackId, Optional<String> switchHostname) {
this.hostname = hostname;
this.parentHostname = parentHostname;
this.state = state;
@@ -102,6 +103,7 @@ public class Node {
this.history = history;
this.openStackId = openStackId;
this.additionalIpAddresses = additionalIpAddresses;
+ this.switchHostname = switchHostname;
}
public HostName hostname() {
@@ -226,6 +228,10 @@ public class Node {
return openStackId;
}
+ public Optional<String> switchHostname() {
+ return switchHostname;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -302,6 +308,7 @@ public class Node {
private List<NodeHistory> history = new ArrayList<>();
private Set<String> additionalIpAddresses = new HashSet<>();
private String openStackId;
+ private Optional<String> switchHostname = Optional.empty();
public Builder() { }
@@ -338,6 +345,7 @@ public class Node {
this.history = node.history;
this.additionalIpAddresses = node.additionalIpAddresses;
this.openStackId = node.openStackId;
+ this.switchHostname = node.switchHostname;
}
public Builder hostname(HostName hostname) {
@@ -495,12 +503,17 @@ public class Node {
return this;
}
+ public Builder switchHostname(String switchHostname) {
+ this.switchHostname = Optional.ofNullable(switchHostname);
+ return this;
+ }
+
public Node build() {
return new Node(hostname, parentHostname, state, type, resources, owner, currentVersion, wantedVersion,
currentOsVersion, wantedOsVersion, currentFirmwareCheck, wantedFirmwareCheck, serviceState,
suspendedSince, restartGeneration, wantedRestartGeneration, rebootGeneration, wantedRebootGeneration,
cost, flavor, clusterId, clusterType, wantToRetire, wantToDeprovision, reservedTo, exclusiveTo,
- wantedDockerImage, currentDockerImage, reports, history, additionalIpAddresses, openStackId);
+ wantedDockerImage, currentDockerImage, reports, history, additionalIpAddresses, openStackId, switchHostname);
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
index af1b3fa53fc..7bbf0fb0578 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java
@@ -137,7 +137,8 @@ public interface NodeRepository {
node.getReports(),
node.getHistory(),
node.getAdditionalIpAddresses(),
- node.getOpenStackId());
+ node.getOpenStackId(),
+ Optional.ofNullable(node.getSwitchHostname()));
}
private static String clusterIdOf(NodeMembership nodeMembership) {
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/EntityService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/EntityService.java
index b9adbf2c742..59a1f589eb0 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/EntityService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/EntityService.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.entity;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -17,6 +18,9 @@ public interface EntityService {
/** List all properties known by the service */
Map<PropertyId, Property> listProperties();
+ /** List all nodes owned by this system's property */
+ List<NodeEntity> listNodes();
+
Optional<NodeEntity> findNode(String hostname);
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/MemoryEntityService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/MemoryEntityService.java
index 7b8176c29de..0174f24c6d1 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/MemoryEntityService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/entity/MemoryEntityService.java
@@ -5,6 +5,8 @@ import com.google.common.collect.ImmutableMap;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -13,6 +15,8 @@ import java.util.Optional;
*/
public class MemoryEntityService implements EntityService {
+ private final Map<String, NodeEntity> nodeEntities = new HashMap<>();
+
@Override
public Map<PropertyId, Property> listProperties() {
return ImmutableMap.of(new PropertyId("1234"), new Property("foo"),
@@ -20,8 +24,18 @@ public class MemoryEntityService implements EntityService {
}
@Override
+ public List<NodeEntity> listNodes() {
+ return List.copyOf(nodeEntities.values());
+ }
+
+ @Override
public Optional<NodeEntity> findNode(String hostname) {
return Optional.empty();
}
+ public MemoryEntityService addNodeEntity(NodeEntity nodeEntity) {
+ nodeEntities.put(nodeEntity.hostname(), nodeEntity);
+ return this;
+ }
+
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/NodeRepositoryNode.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/NodeRepositoryNode.java
index 65d6f2a5fa6..0533d30b584 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/NodeRepositoryNode.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/NodeRepositoryNode.java
@@ -94,6 +94,8 @@ public class NodeRepositoryNode {
private String reservedTo;
@JsonProperty("exclusiveTo")
private String exclusiveTo;
+ @JsonProperty("switchHostname")
+ private String switchHostname;
public String getUrl() {
return url;
@@ -397,6 +399,14 @@ public class NodeRepositoryNode {
public void setExclusiveTo(String exclusiveTo) { this.exclusiveTo = exclusiveTo; }
+ public String getSwitchHostname() {
+ return switchHostname;
+ }
+
+ public void setSwitchHostname(String switchHostname) {
+ this.switchHostname = switchHostname;
+ }
+
@Override
public String toString() {
return "NodeRepositoryNode{" +
@@ -436,6 +446,8 @@ public class NodeRepositoryNode {
", modelName=" + modelName +
", reservedTo=" + reservedTo +
", exclusiveTo=" + exclusiveTo +
+ ", switchHostname=" + switchHostname +
'}';
}
+
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/HostRepairClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/HostRepairClient.java
deleted file mode 100644
index c3fa0890cbb..00000000000
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/HostRepairClient.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.api.integration.repair;
-
-import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.zone.ZoneApi;
-import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author olaa
- */
-public interface HostRepairClient {
-
- /* Checks current ticket status and takes appropriate action */
- void updateRepairStatus(ZoneApi zone, List<Node> nodes);
-
- /* Creates reparation ticket for given host. Returns ticket number */
- String createTicket(HostName hostname, String colo, ZoneId zoneId, String description, String category);
-
-}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/MockRepairClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/MockRepairClient.java
deleted file mode 100644
index 7a4398d69bb..00000000000
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/repair/MockRepairClient.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.api.integration.repair;
-
-import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.zone.ZoneApi;
-import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author olaa
- */
-public class MockRepairClient implements HostRepairClient {
-
- List<Node> updatedNodes = new ArrayList<>();
-
- @Override
- public void updateRepairStatus(ZoneApi zone, List<Node> nodes) {
- updatedNodes.addAll(nodes);
- }
-
- @Override
- public String createTicket(HostName hostname, String colo, ZoneId zoneId, String description, String category) {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- public List<Node> getUpdatedNodes() {
- return updatedNodes;
- }
-}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MeteringClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MeteringClient.java
index 1047e1a02a4..e8c7a9a1654 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MeteringClient.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/resource/MeteringClient.java
@@ -21,4 +21,6 @@ public interface MeteringClient {
List<ResourceSnapshot> getSnapshotHistoryForTenant(TenantName tenantName, YearMonth yearMonth);
+ void refresh();
+
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMeteringClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMeteringClient.java
index ec3f564e930..6ccab4f60fe 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMeteringClient.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMeteringClient.java
@@ -24,6 +24,7 @@ public class MockMeteringClient implements MeteringClient {
private Collection<ResourceSnapshot> resources = new ArrayList<>();
private Optional<MeteringData> meteringData;
+ private boolean isRefreshed = false;
@Override
public void consume(Collection<ResourceSnapshot> resources){
@@ -43,6 +44,11 @@ public class MockMeteringClient implements MeteringClient {
return new ArrayList<>(resources);
}
+ @Override
+ public void refresh() {
+ isRefreshed = true;
+ }
+
public Collection<ResourceSnapshot> consumedResources() {
return this.resources;
}
@@ -51,4 +57,8 @@ public class MockMeteringClient implements MeteringClient {
this.meteringData = Optional.of(meteringData);
this.resources = meteringData.getSnapshotHistory().entrySet().stream().map(Map.Entry::getValue).flatMap(List::stream).collect(Collectors.toList());
}
+
+ public boolean isRefreshed() {
+ return isRefreshed;
+ }
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
index 3fdf358a63d..2acf7c93925 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
@@ -286,6 +286,26 @@ enum PathGroup {
return EnumSet.complementOf(EnumSet.copyOf(List.of(pathGroups)));
}
+ static Set<PathGroup> allExcept(Set<PathGroup> pathGroups) {
+ return EnumSet.complementOf(EnumSet.copyOf(pathGroups));
+ }
+
+ static Set<PathGroup> billingPaths() {
+ var paths = billingPathsNoToken();
+ paths.add(PathGroup.billingToken);
+ return paths;
+ }
+
+ static Set<PathGroup> billingPathsNoToken() {
+ return EnumSet.of(
+ PathGroup.billingCollection,
+ PathGroup.billingInstrument,
+ PathGroup.billingList,
+ PathGroup.billingPlan,
+ PathGroup.hostedAccountant
+ );
+ }
+
/** Returns whether this group matches path in given context */
boolean matches(URI uri, Context context) {
return get(uri).map(p -> {
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
index 4191dbd767d..ff29725fe7c 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java
@@ -22,11 +22,14 @@ enum Policy {
/** Full access to everything. */
operator(Privilege.grant(Action.all())
- .on(PathGroup.allExcept(PathGroup.hostedAccountant))
+ .on(PathGroup.allExcept(PathGroup.billingPaths()))
.in(SystemName.all()),
- Privilege.grant(Action.read)
- .on(PathGroup.hostedAccountant)
- .in(SystemName.PublicCd)),
+ Privilege.grant(Action.read)
+ .on(PathGroup.billingPathsNoToken())
+ .in(SystemName.all()),
+ Privilege.grant(Action.read)
+ .on(PathGroup.billingToken)
+ .in(SystemName.PublicCd)),
/** Full access to everything. */
supporter(Privilege.grant(Action.read)
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
index 8f91a8127bd..57dafcd3291 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
@@ -12,6 +12,7 @@ import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagId;
import com.yahoo.vespa.flags.json.DimensionHelper;
import com.yahoo.vespa.flags.json.FlagData;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import java.io.BufferedInputStream;
import java.io.IOException;
@@ -71,7 +72,7 @@ public class SystemFlagsDataArchive {
if (!entry.isDirectory() && name.startsWith("flags/")) {
Path filePath = Paths.get(name);
String rawData = new String(zipIn.readAllBytes(), StandardCharsets.UTF_8);
- addFile(builder, rawData, filePath);
+ addFile(builder, rawData, filePath, Set.of());
}
}
return builder.build();
@@ -80,7 +81,14 @@ public class SystemFlagsDataArchive {
}
}
- public static SystemFlagsDataArchive fromDirectory(Path directory) {
+ public static SystemFlagsDataArchive fromDirectoryAndSystem(Path directory, ZoneRegistry systemDefinition) {
+ return fromDirectory(directory, systemDefinition);
+ }
+
+ public static SystemFlagsDataArchive fromDirectory(Path directory) { return fromDirectory(directory, null); }
+
+ private static SystemFlagsDataArchive fromDirectory(Path directory, ZoneRegistry systemDefinition) {
+ Set<String> filenamesForSystem = getFilenamesForSystem(systemDefinition);
Path root = directory.toAbsolutePath();
Path flagsDirectory = directory.resolve("flags");
if (!Files.isDirectory(flagsDirectory)) {
@@ -93,7 +101,7 @@ public class SystemFlagsDataArchive {
if (!Files.isDirectory(absolutePath) &&
relativePath.startsWith("flags")) {
String rawData = uncheck(() -> Files.readString(absolutePath, StandardCharsets.UTF_8));
- addFile(builder, rawData, relativePath);
+ addFile(builder, rawData, relativePath, filenamesForSystem);
}
});
return builder.build();
@@ -102,6 +110,7 @@ public class SystemFlagsDataArchive {
}
}
+
public void toZip(OutputStream out) {
ZipOutputStream zipOut = new ZipOutputStream(out);
files.forEach((flagId, fileMap) -> {
@@ -152,11 +161,21 @@ public class SystemFlagsDataArchive {
});
}
- private static void addFile(Builder builder, String rawData, Path filePath) {
+ private static Set<String> getFilenamesForSystem(ZoneRegistry systemDefinition) {
+ if (systemDefinition == null) return Set.of();
+ return FlagsTarget.getAllTargetsInSystem(systemDefinition).stream()
+ .flatMap(target -> target.flagDataFilesPrioritized().stream())
+ .collect(Collectors.toSet());
+ }
+
+ private static void addFile(Builder builder, String rawData, Path filePath, Set<String> filenamesForSystem) {
String filename = filePath.getFileName().toString();
if (filename.startsWith(".")) {
return; // Ignore files starting with '.'
}
+ if (!filenamesForSystem.isEmpty() && !filenamesForSystem.contains(filename)) {
+ return; // Ignore files irrelevant for system
+ }
if (!filename.endsWith(".json")) {
throw new IllegalArgumentException(String.format("Only JSON files are allowed in 'flags/' directory (found '%s')", filePath.toString()));
}
diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java
index 1a24b5361dd..ab72098303f 100644
--- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java
+++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java
@@ -201,7 +201,7 @@ public class RoleTest {
tester.on("/billing/v1/tenant/t1/token")
.assertAction(accountant)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
+ .assertAction(operator, Action.read)
.assertAction(reader)
.assertAction(developer)
.assertAction(admin, Action.read)
@@ -209,7 +209,7 @@ public class RoleTest {
tester.on("/billing/v1/tenant/t1/instrument")
.assertAction(accountant)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
+ .assertAction(operator, Action.read)
.assertAction(reader, Action.read, Action.delete)
.assertAction(developer, Action.read, Action.delete)
.assertAction(admin, Action.read, Action.update, Action.delete)
@@ -217,31 +217,31 @@ public class RoleTest {
tester.on("/billing/v1/tenant/t1/instrument/i1")
.assertAction(accountant)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
- .assertAction(reader, Action.read, Action.delete)
- .assertAction(developer, Action.read, Action.delete)
- .assertAction(admin, Action.read, Action.update, Action.delete)
+ .assertAction(operator, Action.read)
+ .assertAction(reader, Action.read, Action.delete)
+ .assertAction(developer, Action.read, Action.delete)
+ .assertAction(admin, Action.read, Action.update, Action.delete)
.assertAction(otherAdmin);
tester.on("/billing/v1/tenant/t1/billing")
.assertAction(accountant)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
- .assertAction(reader, Action.read)
- .assertAction(developer, Action.read)
- .assertAction(admin, Action.read)
+ .assertAction(operator, Action.read)
+ .assertAction(reader, Action.read)
+ .assertAction(developer, Action.read)
+ .assertAction(admin, Action.read)
.assertAction(otherAdmin);
tester.on("/billing/v1/tenant/t1/plan")
- .assertAction(accountant, Action.update)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
+ .assertAction(accountant, Action.update)
+ .assertAction(operator, Action.read)
.assertAction(reader)
.assertAction(developer)
- .assertAction(admin, Action.update)
+ .assertAction(admin, Action.update)
.assertAction(otherAdmin);
tester.on("/billing/v1/tenant/t1/collection")
.assertAction(accountant, Action.update)
- .assertAction(operator, Action.create, Action.read, Action.update, Action.delete)
+ .assertAction(operator, Action.read)
.assertAction(reader)
.assertAction(developer)
.assertAction(admin)
diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java
index 771e42e85f9..d29657035c4 100644
--- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java
+++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java
@@ -2,16 +2,20 @@
package com.yahoo.vespa.hosted.controller.api.systemflags.v1;
+import com.yahoo.config.provision.CloudName;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.config.provision.zone.ZoneList;
import com.yahoo.text.JSON;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagId;
import com.yahoo.vespa.flags.RawFlag;
import com.yahoo.vespa.flags.json.FlagData;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -26,6 +30,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
@@ -35,6 +40,9 @@ import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* @author bjorncs
@@ -52,6 +60,7 @@ public class SystemFlagsDataArchiveTest {
public final ExpectedException expectedException = ExpectedException.none();
private static final FlagsTarget mainControllerTarget = FlagsTarget.forController(SYSTEM);
+ private static final FlagsTarget cdControllerTarget = FlagsTarget.forController(SystemName.cd);
private static final FlagsTarget prodUsWestCfgTarget = createConfigserverTarget(Environment.prod, "us-west-1");
private static final FlagsTarget prodUsEast3CfgTarget = createConfigserverTarget(Environment.prod, "us-east-3");
private static final FlagsTarget devUsEast1CfgTarget = createConfigserverTarget(Environment.dev, "us-east-1");
@@ -260,6 +269,30 @@ public class SystemFlagsDataArchiveTest {
}
}
+ @Test
+ public void ignores_files_not_related_to_specified_system_definition() {
+ ZoneRegistry registry = createZoneRegistryMock();
+ Path testDirectory = Paths.get("src/test/resources/system-flags-for-multiple-systems/");
+ var archive = SystemFlagsDataArchive.fromDirectoryAndSystem(testDirectory, registry);
+ assertFlagDataHasValue(archive, MY_TEST_FLAG, cdControllerTarget, "default"); // Would be 'cd.controller' if files for CD system were included
+ assertFlagDataHasValue(archive, MY_TEST_FLAG, mainControllerTarget, "default");
+ assertFlagDataHasValue(archive, MY_TEST_FLAG, prodUsWestCfgTarget, "main.prod.us-west-1");
+ }
+
+ @SuppressWarnings("unchecked") // workaround for mocking a method for generic return type
+ private static ZoneRegistry createZoneRegistryMock() {
+ // Cannot use the standard registry mock as it's located in controller-server module
+ ZoneRegistry registryMock = mock(ZoneRegistry.class);
+ when(registryMock.system()).thenReturn(SystemName.main);
+ when(registryMock.getConfigServerVipUri(any())).thenReturn(URI.create("http://localhost:8080/"));
+ when(registryMock.getConfigServerHttpsIdentity(any())).thenReturn(new AthenzService("domain", "servicename"));
+ ZoneList zoneListMock = mock(ZoneList.class);
+ when(zoneListMock.reachable()).thenReturn(zoneListMock);
+ when(zoneListMock.zones()).thenReturn((List)List.of(new SimpleZone("prod.us-west-1"), new SimpleZone("prod.us-east-3")));
+ when(registryMock.zones()).thenReturn(zoneListMock);
+ return registryMock;
+ }
+
private static void assertArchiveReturnsCorrectTestFlagDataForTarget(SystemFlagsDataArchive archive) {
assertFlagDataHasValue(archive, MY_TEST_FLAG, mainControllerTarget, "main.controller");
assertFlagDataHasValue(archive, MY_TEST_FLAG, prodUsWestCfgTarget, "main.prod.us-west-1");
@@ -286,4 +319,14 @@ public class SystemFlagsDataArchiveTest {
.collect(toList());
}
+ private static class SimpleZone implements ZoneApi {
+ final ZoneId zoneId;
+ SimpleZone(String zoneId) { this.zoneId = ZoneId.from(zoneId); }
+
+ @Override public SystemName getSystemName() { return SystemName.main; }
+ @Override public ZoneId getId() { return zoneId; }
+ @Override public CloudName getCloudName() { throw new UnsupportedOperationException(); }
+ @Override public String getCloudNativeRegionName() { throw new UnsupportedOperationException(); }
+ }
+
} \ No newline at end of file
diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json
new file mode 100644
index 00000000000..ce3cdd43889
--- /dev/null
+++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json
@@ -0,0 +1,8 @@
+{
+ "id" : "my-test-flag",
+ "rules" : [
+ {
+ "value" : "cd.controller"
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json
new file mode 100644
index 00000000000..5924eb860c0
--- /dev/null
+++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json
@@ -0,0 +1,8 @@
+{
+ "id" : "my-test-flag",
+ "rules" : [
+ {
+ "value" : "default"
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json
new file mode 100644
index 00000000000..45989773df8
--- /dev/null
+++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json
@@ -0,0 +1,8 @@
+{
+ "id" : "my-test-flag",
+ "rules" : [
+ {
+ "value" : "main.prod.us-west-1"
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-server/pom.xml b/controller-server/pom.xml
index 0ddc1ecd8be..ea3bbcf1e49 100644
--- a/controller-server/pom.xml
+++ b/controller-server/pom.xml
@@ -124,6 +124,11 @@
<!-- compile -->
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-csv</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index a52ee768406..832668bf9f7 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -6,7 +6,6 @@ import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
@@ -23,6 +22,7 @@ import com.yahoo.vespa.flags.BooleanFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.flags.StringFlag;
import com.yahoo.vespa.hosted.controller.api.ActivateResult;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
@@ -36,7 +36,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingControll
import com.yahoo.vespa.hosted.controller.api.integration.billing.Quota;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMetadata;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Cluster;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ContainerEndpoint;
@@ -63,7 +62,9 @@ import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
import com.yahoo.vespa.hosted.controller.certificate.EndpointCertificateManager;
import com.yahoo.vespa.hosted.controller.concurrent.Once;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger;
+import com.yahoo.vespa.hosted.controller.deployment.JobStatus;
import com.yahoo.vespa.hosted.controller.deployment.Run;
+import com.yahoo.vespa.hosted.controller.deployment.RunStatus;
import com.yahoo.vespa.hosted.controller.deployment.Versions;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
import com.yahoo.vespa.hosted.controller.security.AccessControl;
@@ -71,16 +72,19 @@ import com.yahoo.vespa.hosted.controller.security.Credentials;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
+import com.yahoo.yolean.Exceptions;
import java.security.Principal;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -88,15 +92,20 @@ import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.active;
import static com.yahoo.vespa.hosted.controller.api.integration.configserver.Node.State.reserved;
import static java.util.Comparator.naturalOrder;
+import static java.util.function.Function.identity;
+import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toUnmodifiableMap;
/**
* A singleton owned by the Controller which contains the methods and state for controlling applications.
@@ -135,7 +144,7 @@ public class ApplicationController {
this.clock = clock;
this.artifactRepository = controller.serviceRegistry().artifactRepository();
this.applicationStore = controller.serviceRegistry().applicationStore();
- this.dockerImageRepoFlag = Flags.DOCKER_IMAGE_REPO.bindTo(flagSource);
+ this.dockerImageRepoFlag = PermanentFlags.DOCKER_IMAGE_REPO.bindTo(flagSource);
this.provisionApplicationRoles = Flags.PROVISION_APPLICATION_ROLES.bindTo(flagSource);
this.billingController = billingController;
@@ -249,26 +258,50 @@ public class ApplicationController {
public ApplicationStore applicationStore() { return applicationStore; }
- /** Returns all content clusters in all current deployments of the given application. */
- public Map<ZoneId, List<String>> contentClustersByZone(Collection<DeploymentId> ids) {
+ /** Returns all currently reachable content clusters among the given deployments. */
+ public Map<ZoneId, List<String>> reachableContentClustersByZone(Collection<DeploymentId> ids) {
Map<ZoneId, List<String>> clusters = new TreeMap<>(Comparator.comparing(ZoneId::value));
for (DeploymentId id : ids)
- clusters.put(id.zoneId(), List.copyOf(configServer.getContentClusters(id)));
+ if (isHealthy(id))
+ clusters.put(id.zoneId(), List.copyOf(configServer.getContentClusters(id)));
+
return Collections.unmodifiableMap(clusters);
}
+ /** Reads the oldest installed platform for the given application and zone from job history, or a node repo. */
+ private Optional<Version> oldestInstalledPlatform(JobStatus job) {
+ Version oldest = null;
+ for (Run run : job.runs().descendingMap().values()) {
+ Version version = run.versions().targetPlatform();
+ if (oldest == null || version.isBefore(oldest))
+ oldest = version;
+
+ if (run.status() == RunStatus.success)
+ return Optional.of(oldest);
+ }
+ // If no successful run was found, ask the node repository in the relevant zone.
+ return oldestInstalledPlatform(job.id());
+ }
+
+ /** Reads the oldest installed platform for the given application and zone from the node repo of that zone. */
+ private Optional<Version> oldestInstalledPlatform(JobId job) {
+ return configServer.nodeRepository().list(job.type().zone(controller.system()),
+ job.application(),
+ EnumSet.of(active, reserved))
+ .stream()
+ .map(Node::currentVersion)
+ .filter(version -> ! version.isEmpty())
+ .min(naturalOrder());
+ }
+
/** Returns the oldest Vespa version installed on any active or reserved production node for the given application. */
public Version oldestInstalledPlatform(TenantAndApplicationId id) {
- return requireApplication(id).instances().values().stream()
- .flatMap(instance -> instance.productionDeployments().keySet().stream()
- .flatMap(zone -> configServer.nodeRepository().list(zone,
- id.instance(instance.name()),
- EnumSet.of(active, reserved))
- .stream())
- .map(Node::currentVersion)
- .filter(version -> ! version.isEmpty()))
- .min(naturalOrder())
- .orElseGet(controller::readSystemVersion);
+ return controller.jobController().deploymentStatus(requireApplication(id)).jobs()
+ .production().asList().stream()
+ .map(this::oldestInstalledPlatform)
+ .flatMap(Optional::stream)
+ .min(naturalOrder())
+ .orElse(controller.readSystemVersion());
}
/**
@@ -740,6 +773,20 @@ public class ApplicationController {
}
/**
+ * Asks the config server whether this deployment is currently healthy, i.e., serving traffic as usual.
+ * If this cannot be ascertained, we must assumed it is not.
+ */
+ public boolean isHealthy(DeploymentId deploymentId) {
+ try {
+ return ! isSuspended(deploymentId); // consider adding checks again global routing status, etc.?
+ }
+ catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed getting suspension status of " + deploymentId + ": " + Exceptions.toMessageString(e));
+ return false;
+ }
+ }
+
+ /**
* Asks the config server whether this deployment is currently <i>suspended</i>:
* Not in a state where it should receive traffic.
*/
@@ -749,7 +796,8 @@ public class ApplicationController {
}
catch (ConfigServerException e) {
if (e.getErrorCode() == ConfigServerException.ErrorCode.NOT_FOUND)
- return false;
+ return false; // If the application wasn't found, it's not suspended.
+
throw e;
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
index bc6886eae58..5560796a97d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.curator.Lock;
+import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId;
import com.yahoo.vespa.hosted.controller.athenz.impl.AthenzFacade;
import com.yahoo.vespa.hosted.controller.concurrent.Once;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
@@ -97,6 +98,7 @@ public class TenantController {
public void create(TenantSpec tenantSpec, Credentials credentials) {
try (Lock lock = lock(tenantSpec.tenant())) {
requireNonExistent(tenantSpec.tenant());
+ TenantId.validate(tenantSpec.tenant().value());
curator.writeTenant(accessControl.createTenant(tenantSpec, credentials, asList()));
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
index 3e72936575d..bb2d8b3c553 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
@@ -18,8 +18,10 @@ import com.yahoo.vespa.hosted.controller.deployment.DeploymentSteps;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -46,6 +48,7 @@ public class ApplicationPackageValidator {
validateSteps(applicationPackage.deploymentSpec());
validateEndpointRegions(applicationPackage.deploymentSpec());
validateEndpointChange(application, applicationPackage, instant);
+ validateCompactedEndpoint(applicationPackage);
validateSecurityClientsPem(applicationPackage);
}
@@ -98,6 +101,25 @@ public class ApplicationPackageValidator {
instant));
}
+ /** Verify that compactable endpoint parts (instance aname nd endpoint ID) do not clash */
+ private void validateCompactedEndpoint(ApplicationPackage applicationPackage) {
+ Map<List<String>, InstanceEndpoint> instanceEndpoints = new HashMap<>();
+ for (var instanceSpec : applicationPackage.deploymentSpec().instances()) {
+ for (var endpoint : instanceSpec.endpoints()) {
+ List<String> nonCompactableIds = nonCompactableIds(instanceSpec.name(), endpoint);
+ InstanceEndpoint instanceEndpoint = new InstanceEndpoint(instanceSpec.name(), endpoint.endpointId());
+ InstanceEndpoint existingEndpoint = instanceEndpoints.get(nonCompactableIds);
+ if (existingEndpoint != null) {
+ throw new IllegalArgumentException("Endpoint with ID '" + endpoint.endpointId() + "' in instance '"
+ + instanceSpec.name().value() +
+ "' clashes with endpoint '" + existingEndpoint.endpointId +
+ "' in instance '" + existingEndpoint.instance + "'");
+ }
+ instanceEndpoints.put(nonCompactableIds, instanceEndpoint);
+ }
+ }
+ }
+
/** Verify changes to endpoint configuration by comparing given application package to the existing one, if any */
private void validateEndpointChange(Application application, InstanceName instanceName, ApplicationPackage applicationPackage, Instant instant) {
var validationId = ValidationId.globalEndpointChange;
@@ -161,4 +183,28 @@ public class ApplicationPackageValidator {
});
}
+ /** Returns a list of the non-compactable IDs of given instance and endpoint */
+ private static List<String> nonCompactableIds(InstanceName instance, Endpoint endpoint) {
+ List<String> ids = new ArrayList<>(2);
+ if (!instance.isDefault()) {
+ ids.add(instance.value());
+ }
+ if (!"default".equals(endpoint.endpointId())) {
+ ids.add(endpoint.endpointId());
+ }
+ return ids;
+ }
+
+ private static class InstanceEndpoint {
+
+ private final InstanceName instance;
+ private final String endpointId;
+
+ public InstanceEndpoint(InstanceName instance, String endpointId) {
+ this.instance = instance;
+ this.endpointId = endpointId;
+ }
+
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
index b4904ca3cf8..0c4a666ce59 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
@@ -194,8 +194,14 @@ public class DeploymentStatus {
return instances.build();
}
- /** The step status for all steps in the deployment spec of this, in the same order as in the deployment spec. */
- public List<StepStatus> allSteps() { return allSteps; }
+ /** The step status for all relevant steps in the deployment spec of this, in the same order as in the deployment spec. */
+ public List<StepStatus> allSteps() {
+ List<JobId> firstTestJobs = List.of(firstDeclaredOrElseImplicitTest(systemTest),
+ firstDeclaredOrElseImplicitTest(stagingTest));
+ return allSteps.stream()
+ .filter(step -> step.isDeclared() || firstTestJobs.contains(step.job().orElseThrow()))
+ .collect(toUnmodifiableList());
+ }
public Optional<Deployment> deploymentFor(JobId job) {
return Optional.ofNullable(application.require(job.application().instance())
@@ -273,7 +279,6 @@ public class DeploymentStatus {
&& testJobs.get(test).contains(versions)))
testJobs.merge(firstDeclaredOrElseImplicitTest(testType), List.of(versions), DeploymentStatus::union);
});
- // Add runs for declared tests in instances without production jobs, if no successes exist for given change.
}
return ImmutableMap.copyOf(testJobs);
}
@@ -281,7 +286,7 @@ public class DeploymentStatus {
private JobId firstDeclaredOrElseImplicitTest(JobType testJob) {
return application.deploymentSpec().instanceNames().stream()
.map(name -> new JobId(application.id().instance(name), testJob))
- .min(comparing(id -> !jobSteps.get(id).isDeclared())).orElseThrow();
+ .min(comparing(id -> ! jobSteps.get(id).isDeclared())).orElseThrow();
}
/** JobId of any declared test of the given type, for the given instance. */
@@ -381,7 +386,7 @@ public class DeploymentStatus {
public enum StepType {
- /** An instance — completion marks a change as ready for the jobs contained in it. */
+ /** An instance — completion marks a change as ready for the jobs contained in it. */
instance,
/** A timed delay. */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
index 25a6b119671..c602ebd856a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
@@ -285,7 +285,7 @@ public class DeploymentTrigger {
status.jobSteps().get(job).readyAt(status.application().require(job.application().instance()).change())
.filter(readyAt -> ! clock.instant().isBefore(readyAt))
.filter(__ -> ! status.jobs().get(job).get().isRunning())
- .filter(__ -> ! (job.type().isProduction() && isSuspendedInAnotherZone(status.application(), job)))
+ .filter(__ -> ! (job.type().isProduction() && isUnhealthyInAnotherZone(status.application(), job)))
.ifPresent(readyAt -> {
jobs.add(deploymentJob(status.application().require(job.application().instance()),
versions,
@@ -297,11 +297,11 @@ public class DeploymentTrigger {
return Collections.unmodifiableList(jobs);
}
- /** Returns whether given job should be triggered */
- private boolean isSuspendedInAnotherZone(Application application, JobId job) {
+ /** Returns whether the application is healthy in all other production zones. */
+ private boolean isUnhealthyInAnotherZone(Application application, JobId job) {
for (Deployment deployment : application.require(job.application().instance()).productionDeployments().values()) {
if ( ! deployment.zone().equals(job.type().zone(controller.system()))
- && controller.applications().isSuspended(new DeploymentId(job.application(), deployment.zone())))
+ && ! controller.applications().isHealthy(new DeploymentId(job.application(), deployment.zone())))
return true;
}
return false;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
index ed1e442f266..373967df6c4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
@@ -184,9 +184,7 @@ public class InternalStepRunner implements StepRunner {
}
private Optional<RunStatus> deployReal(RunId id, boolean setTheStage, DualLogger logger) {
- return deploy(id.application(),
- id.type(),
- () -> controller.applications().deploy2(id.job(), setTheStage),
+ return deploy(() -> controller.applications().deploy2(id.job(), setTheStage),
controller.jobController().run(id).get()
.stepInfo(setTheStage ? deployInitialReal : deployReal).get()
.startTime().get(),
@@ -196,9 +194,7 @@ public class InternalStepRunner implements StepRunner {
private Optional<RunStatus> deployTester(RunId id, DualLogger logger) {
Version platform = testerPlatformVersion(id);
logger.log("Deploying the tester container on platform " + platform + " ...");
- return deploy(id.tester().id(),
- id.type(),
- () -> controller.applications().deployTester(id.tester(),
+ return deploy(() -> controller.applications().deployTester(id.tester(),
testerPackage(id),
id.type().zone(controller.system()),
platform),
@@ -208,8 +204,7 @@ public class InternalStepRunner implements StepRunner {
logger);
}
- private Optional<RunStatus> deploy(ApplicationId id, JobType type, Supplier<ActivateResult> deployment,
- Instant startTime, DualLogger logger) {
+ private Optional<RunStatus> deploy(Supplier<ActivateResult> deployment, Instant startTime, DualLogger logger) {
try {
PrepareResponse prepareResponse = deployment.get().prepareResponse();
if (prepareResponse.log != null)
@@ -232,9 +227,9 @@ public class InternalStepRunner implements StepRunner {
? Optional.of(deploymentFailed) : Optional.empty();
switch (e.getErrorCode()) {
case CERTIFICATE_NOT_READY:
- logger.log("Waiting for provisioned web certificate — new application, or old one has expired");
+ logger.log("Waiting for certificate to become ready on config server: New application, or old one has expired");
if (startTime.plus(timeouts.endpointCertificate()).isBefore(controller.clock().instant())) {
- logger.log("Deployment failed to find provisioned endpoint certificate after " + timeouts.endpointCertificate());
+ logger.log("Certificate did not become available on config server within (" + timeouts.endpointCertificate() + ")");
return Optional.of(RunStatus.endpointCertificateTimeout);
}
return result;
@@ -264,9 +259,10 @@ public class InternalStepRunner implements StepRunner {
switch (e.type()) {
case CERT_NOT_AVAILABLE:
// Same as CERTIFICATE_NOT_READY above, only from the controller
- logger.log("Waiting for provisioned web certificate — new application, or old one has expired");
+ logger.log("Waiting for certificate to become valid: New application, or old one has expired");
if (startTime.plus(timeouts.endpointCertificate()).isBefore(controller.clock().instant())) {
- logger.log("Deployment failed to find provisioned endpoint certificate after " + timeouts.endpointCertificate());
+ logger.log("Controller could not validate certificate within " +
+ timeouts.endpointCertificate() + ": " + Exceptions.toMessageString(e));
return Optional.of(RunStatus.endpointCertificateTimeout);
}
return Optional.empty();
@@ -582,7 +578,7 @@ public class InternalStepRunner implements StepRunner {
id.type(),
true,
endpoints,
- controller.applications().contentClustersByZone(deployments));
+ controller.applications().reachableContentClustersByZone(deployments));
controller.jobController().cloud().startTests(getTesterDeploymentId(id), suite, config);
return Optional.of(running);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
index 82f37c9bc93..ff2a1963967 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.google.inject.Inject;
import com.yahoo.component.AbstractComponent;
+import com.yahoo.concurrent.maintenance.Maintainer;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.jdisc.Metric;
@@ -13,6 +14,7 @@ import java.time.temporal.TemporalUnit;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import static java.time.temporal.ChronoUnit.HOURS;
@@ -28,89 +30,47 @@ import static java.time.temporal.ChronoUnit.SECONDS;
*/
public class ControllerMaintenance extends AbstractComponent {
- private final DeploymentExpirer deploymentExpirer;
- private final DeploymentIssueReporter deploymentIssueReporter;
- private final MetricsReporter metricsReporter;
- private final OutstandingChangeDeployer outstandingChangeDeployer;
- private final VersionStatusUpdater versionStatusUpdater;
private final Upgrader upgrader;
- private final ReadyJobsTrigger readyJobsTrigger;
- private final DeploymentMetricsMaintainer deploymentMetricsMaintainer;
- private final ApplicationOwnershipConfirmer applicationOwnershipConfirmer;
- private final SystemUpgrader systemUpgrader;
- private final List<OsUpgrader> osUpgraders;
- private final OsVersionStatusUpdater osVersionStatusUpdater;
- private final JobRunner jobRunner;
- private final ContactInformationMaintainer contactInformationMaintainer;
- private final CostReportMaintainer costReportMaintainer;
- private final ResourceMeterMaintainer resourceMeterMaintainer;
- private final NameServiceDispatcher nameServiceDispatcher;
- private final CloudEventReporter cloudEventReporter;
- private final RotationStatusUpdater rotationStatusUpdater;
- private final ResourceTagMaintainer resourceTagMaintainer;
- private final SystemRoutingPolicyMaintainer systemRoutingPolicyMaintainer;
- private final ApplicationMetaDataGarbageCollector applicationMetaDataGarbageCollector;
- private final HostRepairMaintainer hostRepairMaintainer;
- private final ContainerImageExpirer containerImageExpirer;
+ private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>();
@Inject
@SuppressWarnings("unused") // instantiated by Dependency Injection
public ControllerMaintenance(Controller controller, Metric metric) {
Intervals intervals = new Intervals(controller.system());
- deploymentExpirer = new DeploymentExpirer(controller, intervals.defaultInterval);
- deploymentIssueReporter = new DeploymentIssueReporter(controller, controller.serviceRegistry().deploymentIssues(), intervals.defaultInterval);
- metricsReporter = new MetricsReporter(controller, metric);
- outstandingChangeDeployer = new OutstandingChangeDeployer(controller, intervals.outstandingChangeDeployer);
- versionStatusUpdater = new VersionStatusUpdater(controller, intervals.versionStatusUpdater);
upgrader = new Upgrader(controller, intervals.defaultInterval);
- readyJobsTrigger = new ReadyJobsTrigger(controller, intervals.readyJobsTrigger);
- deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, intervals.deploymentMetricsMaintainer);
- applicationOwnershipConfirmer = new ApplicationOwnershipConfirmer(controller, intervals.applicationOwnershipConfirmer, controller.serviceRegistry().ownershipIssues());
- systemUpgrader = new SystemUpgrader(controller, intervals.systemUpgrader);
- jobRunner = new JobRunner(controller, intervals.jobRunner);
- osUpgraders = osUpgraders(controller, intervals.osUpgrader);
- osVersionStatusUpdater = new OsVersionStatusUpdater(controller, intervals.defaultInterval);
- contactInformationMaintainer = new ContactInformationMaintainer(controller, intervals.contactInformationMaintainer);
- nameServiceDispatcher = new NameServiceDispatcher(controller, intervals.nameServiceDispatcher);
- costReportMaintainer = new CostReportMaintainer(controller, intervals.costReportMaintainer, controller.serviceRegistry().costReportConsumer());
- resourceMeterMaintainer = new ResourceMeterMaintainer(controller, intervals.resourceMeterMaintainer, metric, controller.serviceRegistry().meteringService());
- cloudEventReporter = new CloudEventReporter(controller, intervals.cloudEventReporter, metric);
- rotationStatusUpdater = new RotationStatusUpdater(controller, intervals.defaultInterval);
- resourceTagMaintainer = new ResourceTagMaintainer(controller, intervals.resourceTagMaintainer, controller.serviceRegistry().resourceTagger());
- systemRoutingPolicyMaintainer = new SystemRoutingPolicyMaintainer(controller, intervals.systemRoutingPolicyMaintainer);
- applicationMetaDataGarbageCollector = new ApplicationMetaDataGarbageCollector(controller, intervals.applicationMetaDataGarbageCollector);
- hostRepairMaintainer = new HostRepairMaintainer(controller, intervals.hostRepairMaintainer);
- containerImageExpirer = new ContainerImageExpirer(controller, intervals.containerImageExpirer);
+ maintainers.add(upgrader);
+ maintainers.addAll(osUpgraders(controller, intervals.osUpgrader));
+ maintainers.add(new DeploymentExpirer(controller, intervals.defaultInterval));
+ maintainers.add(new DeploymentIssueReporter(controller, controller.serviceRegistry().deploymentIssues(), intervals.defaultInterval));
+ maintainers.add(new MetricsReporter(controller, metric));
+ maintainers.add(new OutstandingChangeDeployer(controller, intervals.outstandingChangeDeployer));
+ maintainers.add(new VersionStatusUpdater(controller, intervals.versionStatusUpdater));
+ maintainers.add(new ReadyJobsTrigger(controller, intervals.readyJobsTrigger));
+ maintainers.add(new DeploymentMetricsMaintainer(controller, intervals.deploymentMetricsMaintainer));
+ maintainers.add(new ApplicationOwnershipConfirmer(controller, intervals.applicationOwnershipConfirmer, controller.serviceRegistry().ownershipIssues()));
+ maintainers.add(new SystemUpgrader(controller, intervals.systemUpgrader));
+ maintainers.add(new JobRunner(controller, intervals.jobRunner));
+ maintainers.add(new OsVersionStatusUpdater(controller, intervals.defaultInterval));
+ maintainers.add(new ContactInformationMaintainer(controller, intervals.contactInformationMaintainer));
+ maintainers.add(new NameServiceDispatcher(controller, intervals.nameServiceDispatcher));
+ maintainers.add(new CostReportMaintainer(controller, intervals.costReportMaintainer, controller.serviceRegistry().costReportConsumer()));
+ maintainers.add(new ResourceMeterMaintainer(controller, intervals.resourceMeterMaintainer, metric, controller.serviceRegistry().meteringService()));
+ maintainers.add(new CloudEventReporter(controller, intervals.cloudEventReporter, metric));
+ maintainers.add(new RotationStatusUpdater(controller, intervals.defaultInterval));
+ maintainers.add(new ResourceTagMaintainer(controller, intervals.resourceTagMaintainer, controller.serviceRegistry().resourceTagger()));
+ maintainers.add(new SystemRoutingPolicyMaintainer(controller, intervals.systemRoutingPolicyMaintainer));
+ maintainers.add(new ApplicationMetaDataGarbageCollector(controller, intervals.applicationMetaDataGarbageCollector));
+ maintainers.add(new ContainerImageExpirer(controller, intervals.containerImageExpirer));
+ maintainers.add(new HostSwitchUpdater(controller, intervals.hostSwitchUpdater));
+ maintainers.add(new ReindexingTriggerer(controller, intervals.reindexingTriggerer));
}
public Upgrader upgrader() { return upgrader; }
@Override
public void deconstruct() {
- deploymentExpirer.close();
- deploymentIssueReporter.close();
- metricsReporter.close();
- outstandingChangeDeployer.close();
- versionStatusUpdater.close();
- upgrader.close();
- readyJobsTrigger.close();
- deploymentMetricsMaintainer.close();
- applicationOwnershipConfirmer.close();
- systemUpgrader.close();
- osUpgraders.forEach(ControllerMaintainer::close);
- osVersionStatusUpdater.close();
- jobRunner.close();
- contactInformationMaintainer.close();
- costReportMaintainer.close();
- resourceMeterMaintainer.close();
- nameServiceDispatcher.close();
- cloudEventReporter.close();
- rotationStatusUpdater.close();
- resourceTagMaintainer.close();
- systemRoutingPolicyMaintainer.close();
- applicationMetaDataGarbageCollector.close();
- hostRepairMaintainer.close();
- containerImageExpirer.close();
+ maintainers.forEach(Maintainer::shutdown);
+ maintainers.forEach(Maintainer::awaitShutdown);
}
/** Create one OS upgrader per cloud found in the zone registry of controller */
@@ -146,8 +106,9 @@ public class ControllerMaintenance extends AbstractComponent {
private final Duration resourceTagMaintainer;
private final Duration systemRoutingPolicyMaintainer;
private final Duration applicationMetaDataGarbageCollector;
- private final Duration hostRepairMaintainer;
private final Duration containerImageExpirer;
+ private final Duration hostSwitchUpdater;
+ private final Duration reindexingTriggerer;
public Intervals(SystemName system) {
this.system = Objects.requireNonNull(system);
@@ -168,8 +129,9 @@ public class ControllerMaintenance extends AbstractComponent {
this.resourceTagMaintainer = duration(30, MINUTES);
this.systemRoutingPolicyMaintainer = duration(10, MINUTES);
this.applicationMetaDataGarbageCollector = duration(12, HOURS);
- this.hostRepairMaintainer = duration(12, HOURS);
this.containerImageExpirer = duration(2, HOURS);
+ this.hostSwitchUpdater = duration(12, HOURS);
+ this.reindexingTriggerer = duration(1, HOURS);
}
private Duration duration(long amount, TemporalUnit unit) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainer.java
deleted file mode 100644
index 57727e64e30..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainer.java
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.maintenance;
-
-import com.yahoo.config.provision.CloudName;
-import com.yahoo.config.provision.SystemName;
-import com.yahoo.config.provision.zone.ZoneApi;
-import com.yahoo.vespa.hosted.controller.Controller;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository;
-import com.yahoo.vespa.hosted.controller.api.integration.repair.RepairTicketReport;
-import com.yahoo.vespa.hosted.controller.api.integration.repair.HostRepairClient;
-import com.yahoo.yolean.Exceptions;
-
-import java.time.Duration;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Predicate;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import static com.yahoo.yolean.Exceptions.uncheck;
-
-/**
- *
- * Responsible for keeping track of hosts under repair.
- *
- * @author olaa
- */
-public class HostRepairMaintainer extends ControllerMaintainer {
-
- private final NodeRepository nodeRepository;
- private final HostRepairClient repairClient;
-
- private static final Logger log = Logger.getLogger(HostRepairMaintainer.class.getName());
-
-
- public HostRepairMaintainer(Controller controller, Duration interval) {
- super(controller, interval, null, SystemName.allOf(Predicate.not(SystemName::isPublic)));
- this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository();
- this.repairClient = controller.serviceRegistry().hostRepairClient();
- }
-
-
- @Override
- protected boolean maintain() {
- AtomicInteger exceptions = new AtomicInteger(0);
-
- controller().zoneRegistry().zones()
- .reachable().zones().stream()
- .forEach(zoneApi -> {
- var breakfixedNodes = nodeRepository.list((zoneApi).getId())
- .stream()
- .filter(node -> node.state() == Node.State.breakfixed)
- .collect(Collectors.toList());
- try {
- repairClient.updateRepairStatus(zoneApi, breakfixedNodes);
- } catch (Exception e) {
- log.warning("Failed to update repair status; " + Exceptions.toMessageString(e));
- exceptions.incrementAndGet();
- }
- }
- );
-
- return exceptions.get() == 0;
- }
-
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdater.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdater.java
new file mode 100644
index 00000000000..8e7a364b5f3
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdater.java
@@ -0,0 +1,80 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository;
+import com.yahoo.vespa.hosted.controller.api.integration.entity.EntityService;
+import com.yahoo.vespa.hosted.controller.api.integration.entity.NodeEntity;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
+
+import java.time.Duration;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Ensures that the switch information for all hosts is up to date.
+ *
+ * @author mpolden
+ */
+public class HostSwitchUpdater extends ControllerMaintainer {
+
+ private static final Logger LOG = Logger.getLogger(HostSwitchUpdater.class.getName());
+ private static final Pattern HOST_PATTERN = Pattern.compile("^(proxy|cfg|controller)host(.+)$");
+
+ private final NodeRepository nodeRepository;
+
+ public HostSwitchUpdater(Controller controller, Duration interval) {
+ super(controller, interval, null, EnumSet.of(SystemName.cd, SystemName.main));
+ this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository();
+ }
+
+ @Override
+ protected boolean maintain() {
+ Map<String, NodeEntity> nodeEntities = controller().serviceRegistry().entityService().listNodes().stream()
+ .collect(Collectors.toMap(NodeEntity::hostname,
+ Function.identity()));
+ int nodesUpdated = 0;
+ try {
+ for (var zone : controller().zoneRegistry().zones().controllerUpgraded().all().ids()) {
+ for (var node : nodeRepository.list(zone)) {
+ if (!node.type().isHost()) continue;
+ NodeEntity nodeEntity = nodeEntities.get(registeredHostnameOf(node));
+ if (!shouldUpdate(node, nodeEntity)) continue;
+
+ NodeRepositoryNode updatedNode = new NodeRepositoryNode();
+ updatedNode.setSwitchHostname(nodeEntity.switchHostname().get());
+ nodeRepository.patchNode(zone, node.hostname().value(), updatedNode);
+ nodesUpdated++;
+ }
+ }
+ } finally {
+ if (nodesUpdated > 0) {
+ LOG.info("Updated switch hostname for " + nodesUpdated + " node(s)");
+ }
+ }
+ return true;
+ }
+
+ /** Returns the hostname that given host is registered under in the {@link EntityService} */
+ private static String registeredHostnameOf(Node host) {
+ String hostname = host.hostname().value();
+ if (!host.type().isHost()) return hostname;
+ Matcher matcher = HOST_PATTERN.matcher(hostname);
+ if (!matcher.matches()) return hostname;
+ return matcher.replaceFirst("$1$2");
+ }
+
+ private static boolean shouldUpdate(Node node, NodeEntity nodeEntity) {
+ if (nodeEntity == null) return false;
+ if (nodeEntity.switchHostname().isEmpty()) return false;
+ return !node.switchHostname().equals(nodeEntity.switchHostname());
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
index f08a23ab8ed..d6739581c79 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
@@ -56,9 +56,14 @@ public class JobRunner extends ControllerMaintainer {
}
@Override
- public void close() {
- super.close();
+ public void shutdown() {
+ super.shutdown();
executors.shutdown();
+ }
+
+ @Override
+ public void awaitShutdown() {
+ super.awaitShutdown();
try {
if ( ! executors.awaitTermination(10, TimeUnit.SECONDS)) {
executors.shutdownNow();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java
new file mode 100644
index 00000000000..96e9f087a67
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java
@@ -0,0 +1,79 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.Application;
+import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing;
+import com.yahoo.vespa.hosted.controller.application.Deployment;
+import com.yahoo.yolean.Exceptions;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Periodically triggers reindexing for all hosted Vespa applications.
+ *
+ * Since reindexing is meant to be a background effort, exactly when things are triggered is not critical,
+ * and a hash of id of each deployment is used to spread triggering out across the reindexing period.
+ * Only deployments within a window of opportunity of two maintainer periods are considered in each run.
+ * Reindexing is triggered for a deployment if it was last triggered more than half a period ago, and
+ * if no reindexing is currently ongoing. This means an application may skip reindexing during a period
+ * if it happens to reindex, e.g., a particular document type in its window of opportunity. This is fine.
+ *
+ * @author jonmv
+ */
+public class ReindexingTriggerer extends ControllerMaintainer {
+
+ static final Duration reindexingPeriod = Duration.ofDays(91); // 13 weeks — four times a year.
+
+ private static final Logger log = Logger.getLogger(ReindexingTriggerer.class.getName());
+
+ public ReindexingTriggerer(Controller controller, Duration duration) {
+ super(controller, duration);
+ }
+
+ @Override
+ protected boolean maintain() {
+ try {
+ Instant now = controller().clock().instant();
+ for (Application application : controller().applications().asList())
+ application.productionDeployments().forEach((name, deployments) -> {
+ ApplicationId id = application.id().instance(name);
+ for (Deployment deployment : deployments)
+ if ( inWindowOfOpportunity(now, interval(), id, deployment.zone())
+ && reindexingIsReady(controller().applications().applicationReindexing(id, deployment.zone()), now))
+ controller().applications().reindex(id, deployment.zone(), List.of(), List.of());
+ });
+ return true;
+ }
+ catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to trigger reindexing: " + Exceptions.toMessageString(e));
+ return false;
+ }
+ }
+
+ static boolean inWindowOfOpportunity(Instant now, Duration interval, ApplicationId id, ZoneId zone) {
+ long lastPeriodStartMillis = now.toEpochMilli() - (now.toEpochMilli() % reindexingPeriod.toMillis());
+ Instant windowCenter = Instant.ofEpochMilli(lastPeriodStartMillis).plus(offset(id, zone));
+ return windowCenter.minus(interval).isBefore(now) && now.isBefore(windowCenter.plus(interval));
+ }
+
+ static Duration offset(ApplicationId id, ZoneId zone) {
+ double relativeOffset = ((id.serializedForm() + zone.value()).hashCode() & (-1 >>> 1)) / (double) (-1 >>> 1);
+ return Duration.ofMillis((long) (reindexingPeriod.toMillis() * relativeOffset));
+ }
+
+ static boolean reindexingIsReady(ApplicationReindexing reindexing, Instant now) {
+ if (reindexing.clusters().values().stream().flatMap(cluster -> cluster.ready().values().stream())
+ .anyMatch(status -> status.startedAt().isPresent() && status.endedAt().isEmpty()))
+ return false;
+
+ return reindexing.common().readyAt().orElse(Instant.EPOCH).isBefore(now.minus(reindexingPeriod.dividedBy(2)));
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
index f460561df08..5496eab049f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainer.java
@@ -11,14 +11,17 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository;
import com.yahoo.vespa.hosted.controller.api.integration.resource.MeteringClient;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
+import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
import com.yahoo.yolean.Exceptions;
import java.time.Clock;
import java.time.Duration;
+import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -33,9 +36,11 @@ public class ResourceMeterMaintainer extends ControllerMaintainer {
private final Metric metric;
private final NodeRepository nodeRepository;
private final MeteringClient meteringClient;
+ private final CuratorDb curator;
private static final String METERING_LAST_REPORTED = "metering_last_reported";
private static final String METERING_TOTAL_REPORTED = "metering_total_reported";
+ private static final int METERING_REFRESH_INTERVAL_SECONDS = 1800;
@SuppressWarnings("WeakerAccess")
public ResourceMeterMaintainer(Controller controller,
@@ -47,6 +52,7 @@ public class ResourceMeterMaintainer extends ControllerMaintainer {
this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository();
this.metric = metric;
this.meteringClient = meteringClient;
+ this.curator = controller.curator();
}
@Override
@@ -71,6 +77,15 @@ public class ResourceMeterMaintainer extends ControllerMaintainer {
resourceSnapshots.stream()
.mapToDouble(r -> r.getCpuCores() + r.getMemoryGb() + r.getDiskGb()).sum(),
metric.createContext(Collections.emptyMap()));
+
+ try (var lock = curator.lockMeteringRefreshTime()) {
+ if (needsRefresh(curator.readMeteringRefreshTime())) {
+ meteringClient.refresh();
+ curator.writeMeteringRefreshTime(clock.millis());
+ }
+ } catch (TimeoutException ignored) {
+ // If it's locked, it means we're currently refreshing
+ }
}
private Collection<ResourceSnapshot> getAllResourceSnapshots() {
@@ -117,4 +132,10 @@ public class ResourceMeterMaintainer extends ControllerMaintainer {
return METERABLE_NODE_STATES.contains(node.state());
}
+ private boolean needsRefresh(long lastRefreshTimestamp) {
+ return clock.instant()
+ .minusSeconds(METERING_REFRESH_INTERVAL_SECONDS)
+ .isAfter(Instant.ofEpochMilli(lastRefreshTimestamp));
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
index eda4f713732..bc0170ee695 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
@@ -188,6 +188,10 @@ public class CuratorDb {
return curator.lock(lockRoot.append("nameServiceQueue"), defaultLockTimeout);
}
+ public Lock lockMeteringRefreshTime() throws TimeoutException {
+ return tryLock(lockRoot.append("meteringRefreshTime"));
+ }
+
// -------------- Helpers ------------------------------------------
/** Try locking with a low timeout, meaning it is OK to fail lock acquisition.
@@ -519,6 +523,18 @@ public class CuratorDb {
return allEndpointCertificateMetadata;
}
+ // -------------- Metering view refresh times ----------------------------
+
+ public void writeMeteringRefreshTime(long timestamp) {
+ curator.set(meteringRefreshPath(), Long.toString(timestamp).getBytes());
+ }
+
+ public long readMeteringRefreshTime() {
+ return curator.getData(meteringRefreshPath())
+ .map(String::new).map(Long::parseLong)
+ .orElse(0l);
+ }
+
// -------------- Paths ---------------------------------------------------
private Path lockPath(TenantName tenant) {
@@ -640,4 +656,8 @@ public class CuratorDb {
return endpointCertificateRoot.append(id.serializedForm());
}
+ private static Path meteringRefreshPath() {
+ return root.append("meteringRefreshTime");
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/JobControlFlags.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/JobControlFlags.java
index 1cb23d0c515..109e761f925 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/JobControlFlags.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/JobControlFlags.java
@@ -4,8 +4,8 @@ package com.yahoo.vespa.hosted.controller.persistence;
import com.yahoo.concurrent.maintenance.JobControlState;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.ListFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import java.util.Set;
@@ -21,7 +21,7 @@ public class JobControlFlags implements JobControlState {
public JobControlFlags(CuratorDb curator, FlagSource flagSource) {
this.curator = curator;
- this.inactiveJobsFlag = Flags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
+ this.inactiveJobsFlag = PermanentFlags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 29e9ec53577..22dd098adfb 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -666,7 +666,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse nodes(String tenantName, String applicationName, String instanceName, String environment, String region) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
List<Node> nodes = controller.serviceRegistry().configServer().nodeRepository().list(zone, id);
Slime slime = new Slime();
@@ -689,7 +689,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse clusters(String tenantName, String applicationName, String instanceName, String environment, String region) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
Application application = controller.serviceRegistry().configServer().nodeRepository().getApplication(zone, id);
Slime slime = new Slime();
@@ -699,7 +699,9 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
toSlime(cluster.min(), clusterObject.setObject("min"));
toSlime(cluster.max(), clusterObject.setObject("max"));
toSlime(cluster.current(), clusterObject.setObject("current"));
- cluster.target().ifPresent(target -> toSlime(target, clusterObject.setObject("target")));
+ if (cluster.target().isPresent()
+ && ! cluster.target().get().justNumbers().equals(cluster.current().justNumbers()))
+ toSlime(cluster.target().get(), clusterObject.setObject("target"));
cluster.suggested().ifPresent(suggested -> toSlime(suggested, clusterObject.setObject("suggested")));
scalingEventsToSlime(cluster.scalingEvents(), clusterObject.setArray("scalingEvents"));
clusterObject.setString("autoscalingStatus", cluster.autoscalingStatus());
@@ -760,7 +762,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse logs(String tenantName, String applicationName, String instanceName, String environment, String region, Map<String, String> queryParameters) {
ApplicationId application = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
DeploymentId deployment = new DeploymentId(application, zone);
InputStream logStream = controller.serviceRegistry().configServer().getLogs(deployment, queryParameters);
return new HttpResponse(200) {
@@ -773,7 +775,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse metrics(String tenantName, String applicationName, String instanceName, String environment, String region) {
ApplicationId application = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
DeploymentId deployment = new DeploymentId(application, zone);
List<ProtonMetrics> protonMetrics = controller.serviceRegistry().configServer().getProtonMetrics(deployment);
return buildResponseFromProtonMetrics(protonMetrics);
@@ -1081,13 +1083,14 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
application.deploymentIssueId().ifPresent(issueId -> object.setString("deploymentIssueId", issueId.value()));
}
- private HttpResponse deployment(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
+ private HttpResponse deployment(String tenantName, String applicationName, String instanceName, String environment,
+ String region, HttpRequest request) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
Instance instance = controller.applications().getInstance(id)
.orElseThrow(() -> new NotExistsException(id + " not found"));
DeploymentId deploymentId = new DeploymentId(instance.id(),
- ZoneId.from(environment, region));
+ requireZone(environment, region));
Deployment deployment = instance.deployments().get(deploymentId.zoneId());
if (deployment == null)
@@ -1137,6 +1140,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
toSlime(endpoint, endpointArray.addObject());
}
+ response.setString("clusters", withPath(toPath(deploymentId) + "/clusters", request.getUri()).toString());
response.setString("nodes", withPathAndQuery("/zone/v2/" + deploymentId.zoneId().environment() + "/" + deploymentId.zoneId().region() + "/nodes/v2/node/", "recursive=true&application=" + deploymentId.applicationId().tenant() + "." + deploymentId.applicationId().application() + "." + deploymentId.applicationId().instance(), request.getUri()).toString());
response.setString("yamasUrl", monitoringSystemUri(deploymentId).toString());
response.setString("version", deployment.version().toFullString());
@@ -1253,7 +1257,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse setGlobalRotationOverride(String tenantName, String applicationName, String instanceName, String environment, String region, boolean inService, HttpRequest request) {
Instance instance = controller.applications().requireInstance(ApplicationId.from(tenantName, applicationName, instanceName));
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
Deployment deployment = instance.deployments().get(zone);
if (deployment == null) {
throw new NotExistsException(instance + " has no deployment in " + zone);
@@ -1289,7 +1293,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse getGlobalRotationOverride(String tenantName, String applicationName, String instanceName, String environment, String region) {
DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
- ZoneId.from(environment, region));
+ requireZone(environment, region));
Slime slime = new Slime();
Cursor array = slime.setObject().setArray("globalrotationoverride");
controller.routing().globalRotationStatus(deploymentId)
@@ -1307,7 +1311,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse rotationStatus(String tenantName, String applicationName, String instanceName, String environment, String region, Optional<String> endpointId) {
ApplicationId applicationId = ApplicationId.from(tenantName, applicationName, instanceName);
Instance instance = controller.applications().requireInstance(applicationId);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
RotationId rotation = findRotationId(instance, endpointId);
Deployment deployment = instance.deployments().get(zone);
if (deployment == null) {
@@ -1396,7 +1400,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse suspended(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
- ZoneId.from(environment, region));
+ requireZone(environment, region));
boolean suspended = controller.applications().isSuspended(deploymentId);
Slime slime = new Slime();
Cursor response = slime.setObject();
@@ -1406,19 +1410,21 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse services(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationView applicationView = controller.getApplicationView(tenantName, applicationName, instanceName, environment, region);
- ServiceApiResponse response = new ServiceApiResponse(ZoneId.from(environment, region),
+ ZoneId zone = requireZone(environment, region);
+ ServiceApiResponse response = new ServiceApiResponse(zone,
new ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(),
- controller.zoneRegistry().getConfigServerApiUris(ZoneId.from(environment, region)),
+ controller.zoneRegistry().getConfigServerApiUris(zone),
request.getUri());
response.setResponse(applicationView);
return response;
}
private HttpResponse service(String tenantName, String applicationName, String instanceName, String environment, String region, String serviceName, String restPath, HttpRequest request) {
- DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), ZoneId.from(environment, region));
+ DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), requireZone(environment, region));
if ("container-clustercontroller".equals((serviceName)) && restPath.contains("/status/")) {
- String result = controller.serviceRegistry().configServer().getClusterControllerStatus(deploymentId, restPath);
+ String[] parts = restPath.split("/status/");
+ String result = controller.serviceRegistry().configServer().getClusterControllerStatus(deploymentId, parts[0], parts[1]);
return new HtmlResponse(result);
}
@@ -1432,7 +1438,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
}
private HttpResponse content(String tenantName, String applicationName, String instanceName, String environment, String region, String restPath, HttpRequest request) {
- DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), ZoneId.from(environment, region));
+ DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), requireZone(environment, region));
return controller.serviceRegistry().configServer().getApplicationPackageContent(deploymentId, "/" + restPath, request.getUri());
}
@@ -1540,7 +1546,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
/** Schedule reindexing of an application, or a subset of clusters, possibly on a subset of documents. */
private HttpResponse reindex(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
List<String> clusterNames = Optional.ofNullable(request.getProperty("clusterId")).stream()
.flatMap(clusters -> Stream.of(clusters.split(",")))
.filter(cluster -> ! cluster.isBlank())
@@ -1559,7 +1565,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
/** Gets reindexing status of an application in a zone. */
private HttpResponse getReindexing(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
ApplicationReindexing reindexing = controller.applications().applicationReindexing(id, zone);
Slime slime = new Slime();
@@ -1573,7 +1579,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
.forEach(cluster -> {
Cursor clusterObject = clustersArray.addObject();
clusterObject.setString("name", cluster.getKey());
- setStatus(clusterObject.setObject("status"), cluster.getValue().common());
+ cluster.getValue().common().ifPresent(common -> setStatus(clusterObject.setObject("status"), common));
Cursor pendingArray = clusterObject.setArray("pending");
cluster.getValue().pending().entrySet().stream().sorted(comparingByKey())
@@ -1600,7 +1606,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
status.endedAt().ifPresent(endedAt -> statusObject.setLong("endedAtMillis", endedAt.toEpochMilli()));
status.state().map(ApplicationApiHandler::toString).ifPresent(state -> statusObject.setString("state", state));
status.message().ifPresent(message -> statusObject.setString("message", message));
- status.progress().ifPresent(progress -> statusObject.setString("progress", progress));
+ status.progress().ifPresent(progress -> statusObject.setDouble("progress", progress));
}
private static String toString(ApplicationReindexing.State state) {
@@ -1616,7 +1622,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
/** Enables reindexing of an application in a zone. */
private HttpResponse enableReindexing(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
controller.applications().enableReindexing(id, zone);
return new MessageResponse("Enabled reindexing of " + id + " in " + zone);
}
@@ -1624,7 +1630,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
/** Disables reindexing of an application in a zone. */
private HttpResponse disableReindexing(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
controller.applications().disableReindexing(id, zone);
return new MessageResponse("Disabled reindexing of " + id + " in " + zone);
}
@@ -1632,7 +1638,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
/** Schedule restart of deployment, or specific host in a deployment */
private HttpResponse restart(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
- ZoneId.from(environment, region));
+ requireZone(environment, region));
RestartFilter restartFilter = new RestartFilter()
.withHostName(Optional.ofNullable(request.getProperty("hostname")).map(HostName::from))
.withClusterType(Optional.ofNullable(request.getProperty("clusterType")).map(ClusterSpec.Type::from))
@@ -1674,7 +1680,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse deploy(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
ApplicationId applicationId = ApplicationId.from(tenantName, applicationName, instanceName);
- ZoneId zone = ZoneId.from(environment, region);
+ ZoneId zone = requireZone(environment, region);
// Get deployOptions
Map<String, byte[]> dataParts = parseDataParts(request);
@@ -1811,7 +1817,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse deactivate(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) {
DeploymentId id = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
- ZoneId.from(environment, region));
+ requireZone(environment, region));
// Attempt to deactivate application even if the deployment is not known by the controller
controller.applications().deactivate(id.applicationId(), id.zoneId());
return new MessageResponse("Deactivated " + id);
@@ -1837,7 +1843,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
type,
false,
controller.routing().zoneEndpointsOf(deployments),
- controller.applications().contentClustersByZone(deployments)));
+ controller.applications().reachableContentClustersByZone(deployments)));
}
private static SourceRevision toSourceRevision(Inspector object) {
@@ -1981,6 +1987,15 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return withPathAndQuery(newPath, null, uri);
}
+ private String toPath(DeploymentId id) {
+ return path("/application", "v4",
+ "tenant", id.applicationId().tenant(),
+ "application", id.applicationId().application(),
+ "instance", id.applicationId().instance(),
+ "environment", id.zoneId().environment(),
+ "region", id.zoneId().region());
+ }
+
private long asLong(String valueOrNull, long defaultWhenNull) {
if (valueOrNull == null) return defaultWhenNull;
try {
@@ -2190,6 +2205,18 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
return new MessageResponse("All deployments removed");
}
+ private ZoneId requireZone(String environment, String region) {
+ ZoneId zone = ZoneId.from(environment, region);
+ // TODO(mpolden): Find a way to not hardcode this. Some APIs allow this "virtual" zone, e.g. /logs
+ if (zone.environment() == Environment.prod && zone.region().value().equals("controller")) {
+ return zone;
+ }
+ if (!controller.zoneRegistry().hasZone(zone)) {
+ throw new IllegalArgumentException("Zone " + zone + " does not exist in this system");
+ }
+ return zone;
+ }
+
private static Map<String, byte[]> parseDataParts(HttpRequest request) {
String contentHash = request.getHeader("X-Content-Hash");
if (contentHash == null)
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
index d6c6f5ff167..cedae5b5a46 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
@@ -27,11 +27,14 @@ import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingControll
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.yolean.Exceptions;
+import org.apache.commons.csv.CSVFormat;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.NotFoundException;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.security.Principal;
import java.time.LocalDate;
@@ -44,6 +47,7 @@ import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.logging.Level;
+import java.util.stream.Collectors;
/**
* @author andreer
@@ -101,10 +105,29 @@ public class BillingApiHandler extends LoggingRequestHandler {
if (path.matches("/billing/v1/tenant/{tenant}/billing")) return getBilling(path.get("tenant"), request.getProperty("until"));
if (path.matches("/billing/v1/tenant/{tenant}/plan")) return getPlan(path.get("tenant"));
if (path.matches("/billing/v1/billing")) return getBillingAllTenants(request.getProperty("until"));
+ if (path.matches("/billing/v1/invoice/export")) return getAllInvoices();
if (path.matches("/billing/v1/invoice/tenant/{tenant}/line-item")) return getLineItems(path.get("tenant"));
return ErrorResponse.notFoundError("Nothing at " + path);
}
+ private HttpResponse getAllInvoices() {
+ var invoices = billingController.getInvoices();
+ var headers = new String[]{ "ID", "Tenant", "From", "To", "CpuHours", "MemoryHours", "DiskHours", "Cpu", "Memory", "Disk", "Additional" };
+ var rows = invoices.stream()
+ .map(invoice -> {
+ return new Object[] {
+ invoice.id().value(), invoice.tenant().value(),
+ invoice.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE),
+ invoice.getEndTime().format(DateTimeFormatter.ISO_LOCAL_DATE),
+ invoice.sumCpuHours(), invoice.sumMemoryHours(), invoice.sumDiskHours(),
+ invoice.sumCpuCost(), invoice.sumMemoryCost(), invoice.sumDiskCost(),
+ invoice.sumAdditionalCost()
+ };
+ })
+ .collect(Collectors.toList());
+ return new CsvResponse(headers, rows);
+ }
+
private HttpResponse handlePATCH(HttpRequest request, Path path, String userId) {
if (path.matches("/billing/v1/tenant/{tenant}/instrument")) return patchActiveInstrument(request, path.get("tenant"), userId);
if (path.matches("/billing/v1/tenant/{tenant}/plan")) return patchPlan(request, path.get("tenant"));
@@ -330,7 +353,7 @@ public class BillingApiHandler extends LoggingRequestHandler {
}
private List<Invoice> getInvoicesForTenant(TenantName tenant) {
- return billingController.getInvoices(tenant);
+ return billingController.getInvoicesForTenant(tenant);
}
private void renderInvoices(Cursor cursor, List<Invoice> invoices) {
@@ -462,4 +485,27 @@ public class BillingApiHandler extends LoggingRequestHandler {
.count() > 0;
}
+ private static class CsvResponse extends HttpResponse {
+ private final String[] header;
+ private final List<Object[]> rows;
+
+ CsvResponse(String[] header, List<Object[]> rows) {
+ super(200);
+ this.header = header;
+ this.rows = rows;
+ }
+
+ @Override
+ public void render(OutputStream outputStream) throws IOException {
+ var writer = new OutputStreamWriter(outputStream);
+ var printer = CSVFormat.DEFAULT.withRecordSeparator('\n').withHeader(this.header).print(writer);
+ for (var row : this.rows) printer.printRecord(row);
+ printer.flush();
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/csv; encoding=utf-8";
+ }
+ }
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
index 1b3c216c1f3..e097b82b7d0 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
@@ -22,8 +22,11 @@ import com.yahoo.vespa.flags.BooleanFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.IntFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.LockedTenant;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.integration.user.Roles;
import com.yahoo.vespa.hosted.controller.api.integration.user.User;
import com.yahoo.vespa.hosted.controller.api.integration.user.UserId;
@@ -34,6 +37,7 @@ import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
import com.yahoo.vespa.hosted.controller.api.role.TenantRole;
import com.yahoo.vespa.hosted.controller.restapi.application.EmptyResponse;
+import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.yolean.Exceptions;
import java.security.PublicKey;
@@ -65,13 +69,15 @@ public class UserApiHandler extends LoggingRequestHandler {
private final UserManagement users;
private final Controller controller;
private final BooleanFlag enable_public_signup_flow;
+ private final IntFlag maxTrialTenants;
@Inject
public UserApiHandler(Context parentCtx, UserManagement users, Controller controller, FlagSource flagSource) {
super(parentCtx);
this.users = users;
this.controller = controller;
- this.enable_public_signup_flow = Flags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
+ this.enable_public_signup_flow = PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
+ this.maxTrialTenants = Flags.MAX_TRIAL_TENANTS.bindTo(flagSource);
}
@Override
@@ -159,6 +165,7 @@ public class UserApiHandler extends LoggingRequestHandler {
root.setBool("isCd", controller.system().isCd());
root.setBool(enable_public_signup_flow.id().toString(),
enable_public_signup_flow.with(FetchVector.Dimension.CONSOLE_USER_EMAIL, user.email()).value());
+ root.setBool("hasTrialCapacity", hasTrialCapacity());
toSlime(root.setObject("user"), user);
@@ -342,6 +349,13 @@ public class UserApiHandler extends LoggingRequestHandler {
return new MessageResponse(user + " is no longer a member of " + role);
}
+ private boolean hasTrialCapacity() {
+ if (! controller.system().isPublic()) return true;
+ var existing = controller.tenants().asList().stream().map(Tenant::name).collect(Collectors.toList());
+ var trialTenants = controller.serviceRegistry().billingController().tenantsWithPlan(existing, PlanId.from("trial"));
+ return maxTrialTenants.value() < 0 || trialTenants.size() < maxTrialTenants.value();
+ }
+
private static Inspector bodyInspector(HttpRequest request) {
return Exceptions.uncheck(() -> SlimeUtils.jsonToSlime(IOUtils.readBytes(request.getData(), 1 << 10)).get());
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
index 6d2b2d58e78..d37e1e05030 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
@@ -7,9 +7,12 @@ import com.yahoo.vespa.flags.BooleanFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.IntFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.integration.ServiceRegistry;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.integration.user.Roles;
import com.yahoo.vespa.hosted.controller.api.integration.user.UserId;
import com.yahoo.vespa.hosted.controller.api.integration.user.UserManagement;
@@ -24,7 +27,9 @@ import javax.ws.rs.ForbiddenException;
import java.util.List;
import java.util.stream.Collectors;
-import static com.yahoo.vespa.hosted.controller.api.role.RoleDefinition.*;
+import static com.yahoo.vespa.hosted.controller.api.role.RoleDefinition.administrator;
+import static com.yahoo.vespa.hosted.controller.api.role.RoleDefinition.hostedOperator;
+import static com.yahoo.vespa.hosted.controller.api.role.RoleDefinition.hostedSupporter;
/**
* @author jonmv
@@ -34,18 +39,21 @@ public class CloudAccessControl implements AccessControl {
private final UserManagement userManagement;
private final BooleanFlag enablePublicSignup;
+ private final IntFlag maxTrialTenants;
private final BillingController billingController;
@Inject
public CloudAccessControl(UserManagement userManagement, FlagSource flagSource, ServiceRegistry serviceRegistry) {
this.userManagement = userManagement;
- this.enablePublicSignup = Flags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
+ this.enablePublicSignup = PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
+ this.maxTrialTenants = Flags.MAX_TRIAL_TENANTS.bindTo(flagSource);
billingController = serviceRegistry.billingController();
}
@Override
public CloudTenant createTenant(TenantSpec tenantSpec, Credentials credentials, List<Tenant> existing) {
requireTenantCreationAllowed((Auth0Credentials) credentials);
+ requireTenantTrialLimitNotReached(existing);
CloudTenantSpec spec = (CloudTenantSpec) tenantSpec;
CloudTenant tenant = CloudTenant.create(spec.tenant(), credentials.user());
@@ -62,6 +70,16 @@ public class CloudAccessControl implements AccessControl {
return tenant;
}
+ private void requireTenantTrialLimitNotReached(List<Tenant> existing) {
+ var trialPlanId = PlanId.from("trial");
+ var tenantNames = existing.stream().map(Tenant::name).collect(Collectors.toList());
+ var trialTenants = billingController.tenantsWithPlan(tenantNames, trialPlanId).size();
+
+ if (maxTrialTenants.value() >= 0 && maxTrialTenants.value() <= trialTenants) {
+ throw new ForbiddenException("Too many tenants with trial plans, please contact the Vespa support team");
+ }
+ }
+
private void requireTenantCreationAllowed(Auth0Credentials auth0Credentials) {
if (allowedByPrivilegedRole(auth0Credentials)) return;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
index a3b22ccd649..569c22d8bf6 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java
@@ -977,4 +977,34 @@ public class ControllerTest {
app1.submit().deploy();
}
+ @Test
+ public void testClashingEndpointIdAndInstanceName() {
+ String deploymentXml = "<deployment version='1.0' athenz-domain='domain' athenz-service='service'>\n" +
+ " <instance id=\"default\">\n" +
+ " <prod>\n" +
+ " <region active=\"true\">us-west-1</region>\n" +
+ " </prod>\n" +
+ " <endpoints>\n" +
+ " <endpoint id=\"dev\" container-id=\"qrs\"/>\n" +
+ " </endpoints>\n" +
+ " </instance>\n" +
+ " <instance id=\"dev\">\n" +
+ " <prod>\n" +
+ " <region active=\"true\">us-west-1</region>\n" +
+ " </prod>\n" +
+ " <endpoints>\n" +
+ " <endpoint id=\"default\" container-id=\"qrs\"/>\n" +
+ " </endpoints>\n" +
+ " </instance>\n" +
+ "</deployment>\n";
+ ApplicationPackage applicationPackage = ApplicationPackageBuilder.fromDeploymentXml(deploymentXml);
+ try {
+ tester.newDeploymentContext().submit(applicationPackage);
+ fail("Expected exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Endpoint with ID 'default' in instance 'dev' clashes with endpoint 'dev' in instance 'default'",
+ e.getMessage());
+ }
+ }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
index a42dbe7fbde..ec303c069f1 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
@@ -1,6 +1,8 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.AthenzDomain;
@@ -73,23 +75,25 @@ import static org.junit.Assert.assertTrue;
*/
public class DeploymentContext {
- public static final ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ // Application packages are expensive to construct, and a given test typically only needs to the test in the context
+ // of a single system. Construct them lazily.
+ private static final Supplier<ApplicationPackage> applicationPackage = Suppliers.memoize(() -> new ApplicationPackageBuilder()
.athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service"))
.upgradePolicy("default")
.region("us-central-1")
.parallel("us-west-1", "us-east-3")
.emailRole("author")
.emailAddress("b@a")
- .build();
+ .build());
- public static final ApplicationPackage publicCdApplicationPackage = new ApplicationPackageBuilder()
+ private static final Supplier<ApplicationPackage> publicCdApplicationPackage = Suppliers.memoize(() -> new ApplicationPackageBuilder()
.athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service"))
.upgradePolicy("default")
.region("aws-us-east-1c")
.emailRole("author")
.emailAddress("b@a")
.trust(generateCertificate())
- .build();
+ .build());
public static final SourceRevision defaultSourceRevision = new SourceRevision("repository1", "master", "commit1");
@@ -113,6 +117,14 @@ public class DeploymentContext {
createTenantAndApplication();
}
+ public static ApplicationPackage applicationPackage() {
+ return applicationPackage.get();
+ }
+
+ public static ApplicationPackage publicApplicationPackage() {
+ return publicCdApplicationPackage.get();
+ }
+
private void createTenantAndApplication() {
try {
var tenant = tester.controllerTester().createTenant(instanceId.tenant().value());
@@ -251,7 +263,7 @@ public class DeploymentContext {
/** Submit the default application package for deployment */
public DeploymentContext submit() {
- return submit(tester.controller().system().isPublic() ? publicCdApplicationPackage : applicationPackage);
+ return submit(tester.controller().system().isPublic() ? publicApplicationPackage() : applicationPackage());
}
/** Trigger all outstanding jobs, if any */
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index d54971f5b1d..9f246f44a81 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -54,7 +54,6 @@ import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.er
import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.info;
import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.warning;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.applicationPackage;
-import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.publicCdApplicationPackage;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.instanceId;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.deploymentFailed;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.installationFailed;
@@ -110,7 +109,7 @@ public class InternalStepRunnerTest {
ConfigServerException.ErrorCode.APPLICATION_LOCK_FAILURE,
new RuntimeException("Retry me"));
tester.configServer().throwOnNextPrepare(exception);
- tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage);
+ tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage());
assertEquals(unfinished, tester.jobs().last(app.instanceId(), JobType.devUsEast1).get().stepStatuses().get(Step.deployReal));
tester.configServer().throwOnNextPrepare(exception);
@@ -346,14 +345,14 @@ public class InternalStepRunnerTest {
@Test
public void deployToDev() {
ZoneId zone = JobType.devUsEast1.zone(system());
- tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage);
+ tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage());
tester.runner().run();
RunId id = tester.jobs().last(app.instanceId(), JobType.devUsEast1).get().id();
assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
Version version = new Version("7.8.9");
Future<?> concurrentDeployment = Executors.newSingleThreadExecutor().submit(() -> {
- tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.of(version), applicationPackage);
+ tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.of(version), applicationPackage());
});
while ( ! concurrentDeployment.isDone())
tester.runner().run();
@@ -365,7 +364,7 @@ public class InternalStepRunnerTest {
tester.runner().run(); // Job run order determined by JobType enum order per application.
tester.configServer().convergeServices(app.instanceId(), zone);
assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
- assertEquals(applicationPackage.hash(), tester.configServer().application(app.instanceId(), zone).get().applicationPackage().hash());
+ assertEquals(applicationPackage().hash(), tester.configServer().application(app.instanceId(), zone).get().applicationPackage().hash());
assertEquals(otherPackage.hash(), tester.configServer().application(app.instanceId(), JobType.perfUsEast3.zone(system())).get().applicationPackage().hash());
tester.configServer().setVersion(version, app.instanceId(), zone);
@@ -423,7 +422,7 @@ public class InternalStepRunnerTest {
tester.configServer().bootstrap(tester.controllerTester().zoneRegistry().zones().all().ids(), SystemApplication.values());
RunId id = app.startSystemTestTests();
- List<X509Certificate> trusted = new ArrayList<>(publicCdApplicationPackage.trustedCertificates());
+ List<X509Certificate> trusted = new ArrayList<>(DeploymentContext.publicApplicationPackage().trustedCertificates());
trusted.add(tester.jobs().run(id).get().testerCertificate().get());
assertEquals(trusted, tester.configServer().application(app.instanceId(), id.type().zone(system())).get().applicationPackage().trustedCertificates());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
index 2b9bad4899f..37254fa0d13 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
@@ -436,7 +436,7 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
Instant.ofEpochMilli(567),
ApplicationReindexing.State.FAILED,
"(#`д´)ノ",
- "some"))))));
+ 0.1))))));
}
@@ -519,7 +519,7 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
}
@Override
- public String getClusterControllerStatus(DeploymentId deployment, String restPath) {
+ public String getClusterControllerStatus(DeploymentId deployment, String node, String subPath) {
return "<h1>OK</h1>";
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
index 61bd7858da2..ca478905893 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java
@@ -41,6 +41,8 @@ public class NodeRepositoryMock implements NodeRepository {
private final Map<ZoneId, TargetVersions> targetVersions = new HashMap<>();
private final Map<Integer, Duration> osUpgradeBudgets = new HashMap<>();
+ private boolean allowPatching = false;
+
/** Add or update given nodes in zone */
public void putNodes(ZoneId zone, List<Node> nodes) {
nodeRepository.putIfAbsent(zone, new HashMap<>());
@@ -230,7 +232,14 @@ public class NodeRepositoryMock implements NodeRepository {
@Override
public void patchNode(ZoneId zoneId, String hostName, NodeRepositoryNode node) {
- throw new UnsupportedOperationException();
+ if (!allowPatching) throw new UnsupportedOperationException();
+ List<Node> existing = list(zoneId, List.of(HostName.from(hostName)));
+ if (existing.size() != 1) throw new IllegalArgumentException("Node " + hostName + " not found in " + zoneId);
+
+ // Note: Only supports switchHostname
+ Node newNode = new Node.Builder(existing.get(0)).switchHostname(node.getSwitchHostname())
+ .build();
+ putNodes(zoneId, newNode);
}
@Override
@@ -280,4 +289,9 @@ public class NodeRepositoryMock implements NodeRepository {
nodeRepository.get(zoneId).get(hostName).reports().put(reportId, report);
}
+ public NodeRepositoryMock allowPatching(boolean allowPatching) {
+ this.allowPatching = allowPatching;
+ return this;
+ }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
index ea31667d249..ae1e2c38e6a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
@@ -15,12 +15,10 @@ import com.yahoo.vespa.hosted.controller.api.integration.aws.ResourceTagger;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMock;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer;
import com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService;
import com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockIssueHandler;
-import com.yahoo.vespa.hosted.controller.api.integration.repair.MockRepairClient;
import com.yahoo.vespa.hosted.controller.api.integration.resource.CostReportConsumerMock;
import com.yahoo.vespa.hosted.controller.api.integration.routing.GlobalRoutingService;
import com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService;
@@ -62,7 +60,6 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
private final MockResourceTagger mockResourceTagger = new MockResourceTagger();
private final ApplicationRoleService applicationRoleService = new NoopApplicationRoleService();
private final BillingController billingController = new MockBillingController();
- private final MockRepairClient repairClient = new MockRepairClient();
private final ContainerRegistryMock containerRegistry = new ContainerRegistryMock();
public ServiceRegistryMock(SystemName system) {
@@ -81,7 +78,7 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
}
@Override
- public ConfigServer configServer() {
+ public ConfigServerMock configServer() {
return configServerMock;
}
@@ -196,11 +193,6 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
}
@Override
- public MockRepairClient hostRepairClient() {
- return repairClient;
- }
-
- @Override
public ContainerRegistryMock containerRegistry() {
return containerRegistry;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainerTest.java
deleted file mode 100644
index ab6e13bb5a2..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostRepairMaintainerTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.yahoo.vespa.hosted.controller.maintenance;
-
-import com.yahoo.config.provision.HostName;
-import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.ControllerTester;
-import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
-import org.junit.Test;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.List;
-
-import static org.junit.Assert.*;
-
-/**
- * @author olaa
- */
-public class HostRepairMaintainerTest {
-
- private final ControllerTester tester = new ControllerTester();
- private final HostRepairMaintainer maintainer = new HostRepairMaintainer(tester.controller(), Duration.ofHours(12));
-
- @Test
- public void maintain() {
- var zoneId = ZoneId.from("dev.us-east-1");
- var hostname1 = HostName.from("node-1-tenant-host-dev.us-east-1");
- var hostname2 = HostName.from("node-2-tenant-host-dev.us-east-1");
- var timestamp = Instant.now().toEpochMilli();
-
- var node1 = new Node.Builder()
- .state(Node.State.active)
- .hostname(hostname1)
- .build();
- var node2 = new Node.Builder()
- .state(Node.State.breakfixed)
- .hostname(hostname2)
- .build();
- tester.configServer().nodeRepository().putNodes(zoneId, List.of(node1, node2));
- maintainer.maintain();
- var updatedNodes = tester.serviceRegistry().hostRepairClient().getUpdatedNodes();
- assertEquals(1, updatedNodes.size());
- assertEquals(hostname2, updatedNodes.get(0).hostname());
- }
-} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdaterTest.java
new file mode 100644
index 00000000000..4dcacb3934b
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/HostSwitchUpdaterTest.java
@@ -0,0 +1,110 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
+import com.yahoo.vespa.hosted.controller.api.integration.entity.NodeEntity;
+import org.junit.Test;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author mpolden
+ */
+public class HostSwitchUpdaterTest {
+
+ @Test
+ public void maintain() {
+ ControllerTester tester = new ControllerTester();
+ tester.serviceRegistry().configServer().nodeRepository().allowPatching(true);
+ addNodeEntities(tester);
+
+ // First iteration patches all hosts
+ HostSwitchUpdater maintainer = new HostSwitchUpdater(tester.controller(), Duration.ofDays(1));
+ maintainer.maintain();
+ List<Node> nodes = allNodes(tester);
+ assertFalse(nodes.isEmpty());
+ for (var node : nodes) {
+ assertEquals("Node " + node.hostname().value() + (node.type().isHost() ? " has" : " does not have")
+ + " switch hostname", node.type().isHost(), node.switchHostname().isPresent());
+ if (node.type().isHost()) {
+ assertEquals("tor-" + node.hostname().value(), node.switchHostname().get());
+ }
+ }
+
+ // Second iteration does not patch anything as all switch information is current
+ tester.serviceRegistry().configServer().nodeRepository().allowPatching(false);
+ maintainer.maintain();
+
+ // One host is moved to a different switch
+ Node host = allNodes(tester).stream().filter(node -> node.type().isHost()).findFirst().get();
+ String newSwitch = "tor2-" + host.hostname().value();
+ NodeEntity nodeEntity = new NodeEntity(host.hostname().value(), "", "", newSwitch);
+ tester.serviceRegistry().entityService().addNodeEntity(nodeEntity);
+
+ // Host is updated
+ tester.serviceRegistry().configServer().nodeRepository().allowPatching(true);
+ maintainer.maintain();
+ assertEquals(newSwitch, getNode(host.hostname(), tester).switchHostname().get());
+
+ // Host keeps old switch hostname if removed from the node entity
+ nodeEntity = new NodeEntity(host.hostname().value(), "", "", "");
+ tester.serviceRegistry().entityService().addNodeEntity(nodeEntity);
+ maintainer.maintain();
+ assertEquals(newSwitch, getNode(host.hostname(), tester).switchHostname().get());
+
+ // Updates node registered under a different hostname
+ ZoneId zone = tester.zoneRegistry().zones().controllerUpgraded().all().ids().get(0);
+ String hostnameSuffix = ".prod." + zone.value();
+ Node configNode = new Node.Builder().hostname(HostName.from("cfg3" + hostnameSuffix))
+ .type(NodeType.config)
+ .build();
+ Node configHost = new Node.Builder().hostname(HostName.from("cfghost3" + hostnameSuffix))
+ .type(NodeType.confighost)
+ .build();
+ tester.serviceRegistry().configServer().nodeRepository().putNodes(zone, List.of(configNode, configHost));
+ String switchHostname = switchHostname(configHost);
+ NodeEntity configNodeEntity = new NodeEntity("cfg3" + hostnameSuffix, "", "", switchHostname);
+ tester.serviceRegistry().entityService().addNodeEntity(configNodeEntity);
+ maintainer.maintain();
+ assertEquals(switchHostname, getNode(configHost.hostname(), tester).switchHostname().get());
+ assertTrue("Switch hostname is not set for non-host", getNode(configNode.hostname(), tester).switchHostname().isEmpty());
+ }
+
+ private static Node getNode(HostName hostname, ControllerTester tester) {
+ return allNodes(tester).stream()
+ .filter(node -> node.hostname().equals(hostname))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("No such node: " + hostname));
+ }
+
+ private static List<Node> allNodes(ControllerTester tester) {
+ List<Node> nodes = new ArrayList<>();
+ for (var zone : tester.zoneRegistry().zones().controllerUpgraded().all().ids()) {
+ nodes.addAll(tester.serviceRegistry().configServer().nodeRepository().list(zone));
+ }
+ return nodes;
+ }
+
+ private static String switchHostname(Node node) {
+ return "tor-" + node.hostname().value();
+ }
+
+ private static void addNodeEntities(ControllerTester tester) {
+ for (var node : allNodes(tester)) {
+ if (!node.type().isHost()) continue;
+ NodeEntity nodeEntity = new NodeEntity(node.hostname().value(), "", "", switchHostname(node));
+ tester.serviceRegistry().entityService().addNodeEntity(nodeEntity);
+ }
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java
new file mode 100644
index 00000000000..c12b82524e4
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java
@@ -0,0 +1,78 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing.Cluster;
+import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing.Status;
+import org.junit.Test;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Map;
+
+import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.inWindowOfOpportunity;
+import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.reindexingIsReady;
+import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.reindexingPeriod;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ReindexingTriggererTest {
+
+ @Test
+ public void testWindowOfOpportunity() {
+ Duration interval = Duration.ofHours(1);
+ Instant now = Instant.now();
+ Instant doom = now.plus(ReindexingTriggerer.reindexingPeriod);
+ int triggered = 0;
+ while (now.isBefore(doom)) {
+ if (inWindowOfOpportunity(now, interval, ApplicationId.defaultId(), ZoneId.defaultId()))
+ triggered++;
+ now = now.plus(interval);
+ }
+ assertEquals("Should be in window of opportunity exactly twice each period", 2, triggered);
+ }
+
+ @Test
+ public void testReindexingIsReady() {
+ Instant then = Instant.now();
+ ApplicationReindexing reindexing = new ApplicationReindexing(true,
+ new Status(then),
+ Map.of());
+
+ Instant now = then;
+ assertFalse("Should not be ready less than one half-period after last triggering",
+ reindexingIsReady(reindexing, now));
+
+ now = now.plus(reindexingPeriod.dividedBy(2));
+ assertFalse("Should not be ready one half-period after last triggering",
+ reindexingIsReady(reindexing, now));
+
+ now = now.plusMillis(1);
+ assertTrue("Should be ready more than one half-period after last triggering",
+ reindexingIsReady(reindexing, now));
+
+ reindexing = new ApplicationReindexing(true,
+ new Status(then),
+ Map.of("cluster",
+ new Cluster(new Status(then),
+ Map.of(),
+ Map.of("type",
+ new Status(then, then, null, null, null, null)))));
+ assertFalse("Should not be ready when reindexing is already running",
+ reindexingIsReady(reindexing, now));
+
+ reindexing = new ApplicationReindexing(true,
+ new Status(then),
+ Map.of("cluster",
+ new Cluster(new Status(then),
+ Map.of("type", 123L),
+ Map.of("type",
+ new Status(then, then, now, null, null, null)))));
+ assertTrue("Should be ready when reindexing is no longer running",
+ reindexingIsReady(reindexing, now));
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
index ffc735c1990..34d461c6152 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ResourceMeterMaintainerTest.java
@@ -15,12 +15,13 @@ import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock;
import org.junit.Test;
import java.time.Duration;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
/**
* @author olaa
@@ -34,8 +35,9 @@ public class ResourceMeterMaintainerTest {
@Test
public void testMaintainer() {
setUpZones();
-
ResourceMeterMaintainer resourceMeterMaintainer = new ResourceMeterMaintainer(tester.controller(), Duration.ofMinutes(5), metrics, snapshotConsumer);
+ long lastRefreshTime = tester.clock().millis();
+ tester.curator().writeMeteringRefreshTime(lastRefreshTime);
resourceMeterMaintainer.maintain();
Collection<ResourceSnapshot> consumedResources = snapshotConsumer.consumedResources();
@@ -54,6 +56,16 @@ public class ResourceMeterMaintainerTest {
assertEquals(tester.clock().millis()/1000, metrics.getMetric("metering_last_reported"));
assertEquals(2224.0d, (Double) metrics.getMetric("metering_total_reported"), Double.MIN_VALUE);
+
+ // Metering is not refreshed
+ assertFalse(snapshotConsumer.isRefreshed());
+ assertEquals(lastRefreshTime, tester.curator().readMeteringRefreshTime());
+
+ var millisAdvanced = 3600 * 1000;
+ tester.clock().advance(Duration.ofMillis(millisAdvanced));
+ resourceMeterMaintainer.maintain();
+ assertTrue(snapshotConsumer.isRefreshed());
+ assertEquals(lastRefreshTime + millisAdvanced, tester.curator().readMeteringRefreshTime());
}
private void setUpZones() {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
index a6acfce877a..484b471cbaa 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
@@ -448,10 +448,11 @@ public class UpgraderTest {
// Multiple application changes are triggered and fail, but does not affect version confidence as upgrade has
// completed successfully
- default0.submit(applicationPackage("default")).failDeployment(systemTest);
- default1.submit(applicationPackage("default")).failDeployment(stagingTest);
- default2.submit(applicationPackage("default")).failDeployment(systemTest);
- default3.submit(applicationPackage("default")).failDeployment(stagingTest);
+ ApplicationPackage applicationPackage = applicationPackage("default");
+ default0.submit(applicationPackage).failDeployment(systemTest);
+ default1.submit(applicationPackage).failDeployment(stagingTest);
+ default2.submit(applicationPackage).failDeployment(systemTest);
+ default3.submit(applicationPackage).failDeployment(stagingTest);
tester.controllerTester().computeVersionStatus();
assertEquals(VespaVersion.Confidence.high, tester.controller().readVersionStatus().systemVersion().get().confidence());
}
@@ -629,7 +630,7 @@ public class UpgraderTest {
// Dev deployment which should be ignored
var dev0 = tester.newDeploymentContext("tenant1", "dev0", "default")
- .runJob(devUsEast1, DeploymentContext.applicationPackage);
+ .runJob(devUsEast1, DeploymentContext.applicationPackage());
// New version is released and canaries upgrade
version = Version.fromString("6.3");
@@ -739,7 +740,7 @@ public class UpgraderTest {
// Setup applications
var canary0 = tester.newDeploymentContext("tenant1", "canary0", "default").submit(version7CanaryApplicationPackage).deploy();
var default0 = tester.newDeploymentContext("tenant1", "default0", "default").submit(version7DefaultApplicationPackage).deploy();
- var default1 = tester.newDeploymentContext("tenant1", "default1", "default").submit(DeploymentContext.applicationPackage).deploy();
+ var default1 = tester.newDeploymentContext("tenant1", "default1", "default").submit(DeploymentContext.applicationPackage()).deploy();
// New major version is released, but we don't want to upgrade to it yet
tester.upgrader().setTargetMajorVersion(Optional.of(6));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
index 62b52d0d087..bda5a708a94 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
@@ -78,9 +78,13 @@ public class ContainerTester {
}
public void assertResponse(Request request, File responseFile, int expectedStatusCode) {
+ assertResponse(request, responseFile, expectedStatusCode, true);
+ }
+
+ public void assertResponse(Request request, File responseFile, int expectedStatusCode, boolean removeWhitespace) {
String expectedResponse = readTestFile(responseFile.toString());
expectedResponse = include(expectedResponse);
- expectedResponse = expectedResponse.replaceAll("(\"[^\"]*\")|\\s*", "$1"); // Remove whitespace
+ if (removeWhitespace) expectedResponse = expectedResponse.replaceAll("(\"[^\"]*\")|\\s*", "$1"); // Remove whitespace
FilterResult filterResult = invokeSecurityFilters(request);
request = filterResult.request;
Response response = filterResult.response != null ? filterResult.response : container.handleRequest(request);
@@ -95,11 +99,11 @@ public class ContainerTester {
// until the first stop character
String stopCharacters = "[^,:\\\\[\\\\]{}]";
String expectedResponsePattern = Pattern.quote(expectedResponse)
- .replaceAll("\"?\\(ignore\\)\"?", "\\\\E" +
- stopCharacters + "*\\\\Q");
+ .replaceAll("\"?\\(ignore\\)\"?", "\\\\E" +
+ stopCharacters + "*\\\\Q");
if (!Pattern.matches(expectedResponsePattern, responseString)) {
throw new ComparisonFailure(responseFile.toString() + " (with ignored fields)",
- expectedResponsePattern, responseString);
+ expectedResponsePattern, responseString);
}
} else {
assertEquals(responseFile.toString(), expectedResponse, responseString);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index 5b33f989163..6f0afffbee9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -2,11 +2,12 @@
package com.yahoo.vespa.hosted.controller.restapi.application;
import com.yahoo.config.provision.ApplicationName;
-import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -19,13 +20,16 @@ import com.yahoo.vespa.hosted.controller.security.Credentials;
import org.junit.Before;
import org.junit.Test;
+import javax.ws.rs.ForbiddenException;
import java.util.Collections;
import java.util.Set;
import static com.yahoo.application.container.handler.Request.Method.GET;
-import static com.yahoo.application.container.handler.Request.Method.PUT;
import static com.yahoo.application.container.handler.Request.Method.POST;
+import static com.yahoo.application.container.handler.Request.Method.PUT;
import static com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiTest.createApplicationSubmissionData;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
@@ -41,7 +45,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
public void before() {
tester = new ContainerTester(container, responseFiles);
((InMemoryFlagSource) tester.controller().flagSource())
- .withBooleanFlag(Flags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true);
+ .withBooleanFlag(PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true);
deploymentTester = new DeploymentTester(new ControllerTester(tester));
deploymentTester.controllerTester().computeVersionStatus();
setupTenantAndApplication();
@@ -94,6 +98,24 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
tester.assertResponse(infoRequest, fullInfo, 200);
}
+ @Test
+ public void trial_tenant_limit_reached() {
+ ((InMemoryFlagSource) tester.controller().flagSource()).withIntFlag(Flags.MAX_TRIAL_TENANTS.id(), 1);
+ tester.controller().serviceRegistry().billingController().setPlan(tenantName, PlanId.from("pay-as-you-go"), false);
+
+ // tests that we can create the one trial tenant the flag says we can have -- and that the tenant created
+ // in @Before does not count towards that limit.
+ tester.controller().tenants().create(tenantSpec("tenant1"), credentials("administrator"));
+
+ // tests that exceeding the limit throws a ForbiddenException
+ try {
+ tester.controller().tenants().create(tenantSpec("tenant2"), credentials("administrator"));
+ fail("Should not be allowed to create tenant that exceed trial limit");
+ } catch (ForbiddenException e) {
+ assertEquals("Too many tenants with trial plans, please contact the Vespa support team", e.getMessage());
+ }
+ }
+
private ApplicationPackageBuilder prodBuilder() {
return new ApplicationPackageBuilder()
.instances("default")
@@ -108,6 +130,10 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
tester.controller().applications().createApplication(appId, credentials("developer@scoober"));
}
+ private static CloudTenantSpec tenantSpec(String name) {
+ return new CloudTenantSpec(TenantName.from(name), "");
+ }
+
private static Credentials credentials(String name) {
return new Auth0Credentials(() -> name, Collections.emptySet());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index d303d1a9b83..3d1375601ad 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -490,22 +490,27 @@ public class ApplicationApiTest extends ControllerContainerTest {
new File("application-clusters.json"));
// GET logs
- tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-central-1/instance/default/logs?from=1233&to=3214", GET)
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/logs?from=1233&to=3214", GET)
.userIdentity(USER_ID),
"INFO - All good");
+ // GET controller logs
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/prod/region/controller/instance/default/logs?from=1233&to=3214", GET)
+ .userIdentity(USER_ID),
+ "INFO - All good");
+
// Get content - root
- tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/instance/default/environment/dev/region/us-central-1/content/", GET).userIdentity(USER_ID),
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/instance/default/environment/dev/region/us-east-1/content/", GET).userIdentity(USER_ID),
"{\"path\":\"/\"}");
// Get content - ignore query params
- tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/instance/default/environment/dev/region/us-central-1/content/bar/file.json?query=param", GET).userIdentity(USER_ID),
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/instance/default/environment/dev/region/us-east-1/content/bar/file.json?query=param", GET).userIdentity(USER_ID),
"{\"path\":\"/bar/file.json\"}");
updateMetrics();
// GET metrics
- tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-central-1/instance/default/metrics", GET)
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/metrics", GET)
.userIdentity(USER_ID),
new File("proton-metrics.json"));
@@ -608,7 +613,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// GET to get reindexing status
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/reindexing", GET)
.userIdentity(USER_ID),
- "{\"enabled\":true,\"status\":{\"readyAtMillis\":123},\"clusters\":[{\"name\":\"cluster\",\"status\":{\"readyAtMillis\":234},\"pending\":[{\"type\":\"type\",\"requiredGeneration\":100}],\"ready\":[{\"type\":\"type\",\"readyAtMillis\":345,\"startedAtMillis\":456,\"endedAtMillis\":567,\"state\":\"failed\",\"message\":\"(#`д´)ノ\",\"progress\":\"some\"}]}]}");
+ "{\"enabled\":true,\"status\":{\"readyAtMillis\":123},\"clusters\":[{\"name\":\"cluster\",\"status\":{\"readyAtMillis\":234},\"pending\":[{\"type\":\"type\",\"requiredGeneration\":100}],\"ready\":[{\"type\":\"type\",\"readyAtMillis\":345,\"startedAtMillis\":456,\"endedAtMillis\":567,\"state\":\"failed\",\"message\":\"(#`д´)ノ\",\"progress\":0.1}]}]}");
// POST a 'restart application' command
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/restart", POST)
@@ -622,20 +627,20 @@ public class ApplicationApiTest extends ControllerContainerTest {
addUserToHostedOperatorRole(HostedAthenzIdentities.from(SCREWDRIVER_ID));
- // POST a 'restart application' in staging environment command
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/staging/region/us-central-1/instance/instance1/restart", POST)
+ // POST a 'restart application' in staging environment
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/staging/region/us-east-3/instance/instance1/restart", POST)
.screwdriverIdentity(SCREWDRIVER_ID),
- "{\"message\":\"Requested restart of tenant1.application1.instance1 in staging.us-central-1\"}");
+ "{\"message\":\"Requested restart of tenant1.application1.instance1 in staging.us-east-3\"}");
- // POST a 'restart application' in staging test command
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/test/region/us-central-1/instance/instance1/restart", POST)
+ // POST a 'restart application' in test environment
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/test/region/us-east-1/instance/instance1/restart", POST)
.screwdriverIdentity(SCREWDRIVER_ID),
- "{\"message\":\"Requested restart of tenant1.application1.instance1 in test.us-central-1\"}");
+ "{\"message\":\"Requested restart of tenant1.application1.instance1 in test.us-east-1\"}");
- // POST a 'restart application' in staging dev command
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-central-1/instance/instance1/restart", POST)
+ // POST a 'restart application' in dev environment
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/restart", POST)
.userIdentity(USER_ID),
- "{\"message\":\"Requested restart of tenant1.application1.instance1 in dev.us-central-1\"}");
+ "{\"message\":\"Requested restart of tenant1.application1.instance1 in dev.us-east-1\"}");
// POST a 'restart application' command with a host filter (other filters not supported yet)
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/restart", POST)
@@ -1158,28 +1163,28 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST (deploy) an application with an invalid application package
MultiPartStreamer entity = createApplicationDeployData(applicationPackageInstance1, true);
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-west-1/instance/instance1/deploy", POST)
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
new File("deploy-failure.json"), 400);
// POST (deploy) an application without available capacity
configServer.throwOnNextPrepare(new ConfigServerException(new URI("server-url"), "Failed to prepare application", "Out of capacity", ConfigServerException.ErrorCode.OUT_OF_CAPACITY, null));
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-west-1/instance/instance1/deploy", POST)
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
new File("deploy-out-of-capacity.json"), 400);
// POST (deploy) an application where activation fails
configServer.throwOnNextPrepare(new ConfigServerException(new URI("server-url"), "Failed to activate application", "Activation conflict", ConfigServerException.ErrorCode.ACTIVATION_CONFLICT, null));
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-west-1/instance/instance1/deploy", POST)
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
new File("deploy-activation-conflict.json"), 409);
// POST (deploy) an application where we get an internal server error
configServer.throwOnNextPrepare(new ConfigServerException(new URI("server-url"), "Failed to deploy application", "Internal server error", ConfigServerException.ErrorCode.INTERNAL_SERVER_ERROR, null));
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-west-1/instance/instance1/deploy", POST)
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
new File("deploy-internal-server-error.json"), 500);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
index b3ffb54b255..828e2856cae 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
@@ -152,7 +152,7 @@ public class JobControllerApiHandlerHelperTest {
tester.clock().setInstant(Instant.EPOCH);
ZoneId zone = JobType.devUsEast1.zone(tester.controller().system());
- tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage);
+ tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage());
tester.configServer().setLogStream("1554970337.935104\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tERROR: Bundle canary-application [71] Unable to get module class path. (java.lang.NullPointerException)\n");
assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(app.instanceId(), devUsEast1).get().id(), null), "dev-us-east-1-log-first-part.json");
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
index 36aa8a87689..961d36bd2f3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
@@ -550,32 +550,6 @@
}
},
{
- "type": "test",
- "dependencies": [],
- "declared": false,
- "instance": "instance2",
- "readyAt": 0,
- "jobName": "system-test",
- "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance2/job/system-test",
- "environment": "test",
- "region": "test.us-east-1",
- "toRun": [],
- "runs": []
- },
- {
- "type": "test",
- "dependencies": [],
- "declared": false,
- "instance": "instance2",
- "readyAt": 0,
- "jobName": "staging-test",
- "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance2/job/staging-test",
- "environment": "staging",
- "region": "staging.us-east-3",
- "toRun": [],
- "runs": []
- },
- {
"type": "deployment",
"dependencies": [
6
@@ -604,7 +578,7 @@
{
"type": "deployment",
"dependencies": [
- 9
+ 7
],
"declared": true,
"instance": "instance2",
@@ -630,7 +604,7 @@
{
"type": "deployment",
"dependencies": [
- 9
+ 7
],
"declared": true,
"instance": "instance2",
@@ -655,3 +629,4 @@
}
]
}
+
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
index d41cd2691b0..6b3c316a485 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
@@ -20,6 +20,7 @@
"routingMethod": "shared"
}
],
+ "clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/clusters",
"nodes": "http://localhost:8080/zone/v2/prod/us-west-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-west-1&application=tenant1.application1.instance1",
"version": "(ignore)",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
index 1c06991a3a7..66fe28a95ad 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-without-shared-endpoints.json
@@ -13,6 +13,7 @@
"routingMethod": "exclusive"
}
],
+ "clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/clusters",
"nodes": "http://localhost:8080/zone/v2/prod/us-west-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-west-1&application=tenant1.application1.instance1",
"version": "6.1.0",
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 d9a6824bfbb..a7755278a39 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
@@ -20,6 +20,7 @@
"routingMethod": "shared"
}
],
+ "clusters": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/clusters",
"nodes": "http://localhost:8080/zone/v2/prod/us-central-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "(ignore)",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
index 675109f1c41..7ba63e1664d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
@@ -13,6 +13,7 @@
"routingMethod": "shared"
}
],
+ "clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/dev/region/us-east-1/clusters",
"nodes": "http://localhost:8080/zone/v2/dev/us-east-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=dev&region=us-east-1&application=tenant1.application1.instance1",
"version": "(ignore)",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json
index f0859fbf5b9..4d387f626a1 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json
@@ -23,6 +23,7 @@
"routingMethod": "shared"
}
],
+ "clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/clusters",
"nodes": "http://localhost:8080/zone/v2/prod/us-central-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "(ignore)",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
index 1d0f0935c05..5b46df1ad1f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
@@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.controller.restapi.billing;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.integration.billing.CollectionMethod;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Invoice;
import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
@@ -12,15 +11,12 @@ import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest;
import com.yahoo.vespa.hosted.controller.security.Auth0Credentials;
import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec;
-import com.yahoo.vespa.hosted.controller.security.Credentials;
-import com.yahoo.vespa.hosted.controller.security.TenantSpec;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.math.BigDecimal;
-import java.security.Principal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -110,7 +106,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
@Test
public void test_invoice_creation() {
- var invoices = billingController.getInvoices(tenant);
+ var invoices = billingController.getInvoicesForTenant(tenant);
assertEquals(0, invoices.size());
String requestBody = "{\"tenant\":\"tenant1\", \"startTime\":\"2020-04-20\", \"endTime\":\"2020-05-20\"}";
@@ -122,7 +118,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
request.roles(financeAdmin);
tester.assertResponse(request, new File("invoice-creation-response"));
- invoices = billingController.getInvoices(tenant);
+ invoices = billingController.getInvoicesForTenant(tenant);
assertEquals(1, invoices.size());
Invoice invoice = invoices.get(0);
assertEquals(invoice.getStartTime().toString(), "2020-04-20T00:00Z[UTC]");
@@ -165,7 +161,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
.roles(financeAdmin);
tester.assertResponse(request, "{\"message\":\"Updated status of invoice id-1\"}");
- var invoice = billingController.getInvoices(tenant).get(0);
+ var invoice = billingController.getInvoicesForTenant(tenant).get(0);
assertEquals("DONE", invoice.status());
}
@@ -196,6 +192,14 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
}
@Test
+ public void csv_export() {
+ var invoice = createInvoice();
+ billingController.addInvoice(tenant, invoice, true);
+ var csvRequest = request("/billing/v1/invoice/export", GET).roles(financeAdmin);
+ tester.assertResponse(csvRequest.get(), new File("billing-all-invoices"), 200, false);
+ }
+
+ @Test
public void patch_collection_method() {
test_patch_collection_with_field_name("collectionMethod");
test_patch_collection_with_field_name("collection");
@@ -222,6 +226,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
var statusHistory = new Invoice.StatusHistory(new TreeMap<>(Map.of(start, "OPEN")));
return new Invoice(
Invoice.Id.of("id-1"),
+ TenantName.defaultName(),
statusHistory,
List.of(createLineItem(start)),
start,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-invoices b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-invoices
new file mode 100644
index 00000000000..957ed858951
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/billing-all-invoices
@@ -0,0 +1,2 @@
+ID,Tenant,From,To,CpuHours,MemoryHours,DiskHours,Cpu,Memory,Disk,Additional
+id-1,default,2020-05-23,2020-05-28,0.00,0.00,0.00,0.00,0.00,0.00,123.00
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
index c061bfed21a..5523ce8dd9f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
@@ -6,8 +6,8 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceSnapshot;
import com.yahoo.vespa.hosted.controller.auditlog.AuditLogger;
import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
@@ -42,7 +42,7 @@ public class ControllerApiTest extends ControllerContainerTest {
public void testControllerApi() {
tester.assertResponse(authenticatedRequest("http://localhost:8080/controller/v1/", "", Request.Method.GET), new File("root.json"));
- ((InMemoryFlagSource) tester.controller().flagSource()).withListFlag(Flags.INACTIVE_MAINTENANCE_JOBS.id(), List.of("DeploymentExpirer"), String.class);
+ ((InMemoryFlagSource) tester.controller().flagSource()).withListFlag(PermanentFlags.INACTIVE_MAINTENANCE_JOBS.id(), List.of("DeploymentExpirer"), String.class);
// GET a list of all maintenance jobs
tester.assertResponse(authenticatedRequest("http://localhost:8080/controller/v1/maintenance/", "", Request.Method.GET),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json
index c1ee1489cd4..5af91e17bb7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json
@@ -31,7 +31,7 @@
"name": "DeploymentMetricsMaintainer"
},
{
- "name": "HostRepairMaintainer"
+ "name": "HostSwitchUpdater"
},
{
"name": "JobRunner"
@@ -52,6 +52,9 @@
"name": "ReadyJobsTrigger"
},
{
+ "name": "ReindexingTriggerer"
+ },
+ {
"name": "ResourceMeterMaintainer"
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
index d9ad30020db..3357e5ca8a4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.integration.user.User;
import com.yahoo.vespa.hosted.controller.api.role.Role;
@@ -19,7 +20,6 @@ import java.util.Set;
import static com.yahoo.application.container.handler.Request.Method.DELETE;
import static com.yahoo.application.container.handler.Request.Method.POST;
-import static com.yahoo.application.container.handler.Request.Method.PUT;
import static org.junit.Assert.assertEquals;
/**
@@ -203,7 +203,7 @@ public class UserApiTest extends ControllerContainerCloudTest {
public void userMetadataTest() {
ContainerTester tester = new ContainerTester(container, responseFiles);
((InMemoryFlagSource) tester.controller().flagSource())
- .withBooleanFlag(Flags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true);
+ .withBooleanFlag(PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true);
ControllerTester controller = new ControllerTester(tester);
Set<Role> operator = Set.of(Role.hostedOperator(), Role.hostedSupporter(), Role.hostedAccountant());
User user = new User("dev@domail", "Joe Developer", "dev", null);
@@ -245,4 +245,21 @@ public class UserApiTest extends ControllerContainerCloudTest {
.user(user),
new File("user-with-applications-cloud.json"));
}
+
+ @Test
+ public void maxTrialTenants() {
+ ContainerTester tester = new ContainerTester(container, responseFiles);
+ ((InMemoryFlagSource) tester.controller().flagSource())
+ .withIntFlag(Flags.MAX_TRIAL_TENANTS.id(), 1)
+ .withBooleanFlag(PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.id(), true);
+ ControllerTester controller = new ControllerTester(tester);
+ Set<Role> operator = Set.of(Role.hostedOperator(), Role.hostedSupporter(), Role.hostedAccountant());
+ User user = new User("dev@domail", "Joe Developer", "dev", null);
+
+ controller.createTenant("tenant1", Tenant.Type.cloud);
+
+ tester.assertResponse(
+ request("/api/user/v1/user").user(user),
+ new File("user-without-trial-capacity-cloud.json"));
+ }
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
index 36918c743fa..2ae3514bec3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
@@ -2,6 +2,7 @@
"isPublic": false,
"isCd": false,
"enable-public-signup-flow": (ignore),
+ "hasTrialCapacity": (ignore),
"user": {
"name": "Joe Developer",
"email": "dev@domail",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
index 27398352e53..2d2a137c2ca 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
@@ -1,7 +1,8 @@
{
-"isPublic": true,
-"isCd": false,
-"enable-public-signup-flow": (ignore),
+ "isPublic": true,
+ "isCd": false,
+ "enable-public-signup-flow": (ignore),
+ "hasTrialCapacity": true,
"user": {
"name": "Joe Developer",
"email": "dev@domail",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
index b62a70d1871..e03a18a1949 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
@@ -2,6 +2,7 @@
"isPublic": (ignore),
"isCd": (ignore),
"enable-public-signup-flow": (ignore),
+ "hasTrialCapacity": (ignore),
"user": {
"name": "Joe Developer",
"email": "dev@domail",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json
new file mode 100644
index 00000000000..a7410b14850
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json
@@ -0,0 +1,12 @@
+{
+ "isPublic": true,
+ "isCd": false,
+ "enable-public-signup-flow": true,
+ "hasTrialCapacity": false,
+ "user": {
+ "name": "Joe Developer",
+ "email": "dev@domail",
+ "nickname": "dev"
+ },
+ "tenants": {}
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
index 76dc1bb582a..77ce86f1664 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
@@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.controller.versions;
import com.yahoo.component.Version;
import com.yahoo.component.Vtag;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.vespa.hosted.controller.Controller;
@@ -220,52 +219,52 @@ public class VersionStatusTest {
var builder = new ApplicationPackageBuilder().region("us-west-1").region("us-east-3");
// Setup applications - all running on version0
- builder.upgradePolicy("canary");
+ ApplicationPackage canaryPolicy = builder.upgradePolicy("canary").build();
var canary0 = tester.newDeploymentContext("tenant1", "canary0", "default")
- .submit(builder.build())
+ .submit(canaryPolicy)
.deploy();
var canary1 = tester.newDeploymentContext("tenant1", "canary1", "default")
- .submit(builder.build())
+ .submit(canaryPolicy)
.deploy();
var canary2 = tester.newDeploymentContext("tenant1", "canary2", "default")
- .submit(builder.build())
+ .submit(canaryPolicy)
.deploy();
- builder.upgradePolicy("default");
+ ApplicationPackage defaultPolicy = builder.upgradePolicy("default").build();
var default0 = tester.newDeploymentContext("tenant1", "default0", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default1 = tester.newDeploymentContext("tenant1", "default1", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default2 = tester.newDeploymentContext("tenant1", "default2", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default3 = tester.newDeploymentContext("tenant1", "default3", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default4 = tester.newDeploymentContext("tenant1", "default4", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default5 = tester.newDeploymentContext("tenant1", "default5", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default6 = tester.newDeploymentContext("tenant1", "default6", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default7 = tester.newDeploymentContext("tenant1", "default7", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default8 = tester.newDeploymentContext("tenant1", "default8", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
var default9 = tester.newDeploymentContext("tenant1", "default9", "default")
- .submit(builder.build())
+ .submit(defaultPolicy)
.deploy();
- builder.upgradePolicy("conservative");
+ ApplicationPackage conservativePolicy = builder.upgradePolicy("conservative").build();
var conservative0 = tester.newDeploymentContext("tenant1", "conservative0", "default")
- .submit(builder.build())
+ .submit(conservativePolicy)
.deploy();
// Applications that do not affect confidence calculation:
diff --git a/default_build_settings.cmake b/default_build_settings.cmake
index 23c78861fc7..d8bbf21605a 100644
--- a/default_build_settings.cmake
+++ b/default_build_settings.cmake
@@ -31,7 +31,7 @@ endfunction()
function(setup_vespa_default_build_settings_centos_8)
message("-- Setting up default build settings for centos 8")
set(DEFAULT_EXTRA_INCLUDE_DIRECTORY "${VESPA_DEPS}/include" "/usr/include/openblas" PARENT_SCOPE)
- set(DEFAULT_VESPA_LLVM_VERSION "9" PARENT_SCOPE)
+ set(DEFAULT_VESPA_LLVM_VERSION "10" PARENT_SCOPE)
endfunction()
function(setup_vespa_default_build_settings_darwin)
@@ -57,19 +57,6 @@ function(setup_vespa_default_build_settings_darwin)
list(APPEND DEFAULT_EXTRA_INCLUDE_DIRECTORY "/usr/local/include")
set(DEFAULT_EXTRA_INCLUDE_DIRECTORY "${DEFAULT_EXTRA_INCLUDE_DIRECTORY}" PARENT_SCOPE)
endfunction()
-
-function(setup_vespa_default_build_settings_fedora_30)
- message("-- Setting up default build settings for fedora 30")
- set(DEFAULT_EXTRA_INCLUDE_DIRECTORY "${VESPA_DEPS}/include" "/usr/include/openblas" PARENT_SCOPE)
- set(DEFAULT_VESPA_LLVM_VERSION "8" PARENT_SCOPE)
-endfunction()
-
-function(setup_vespa_default_build_settings_fedora_31)
- message("-- Setting up default build settings for fedora 31")
- set(DEFAULT_EXTRA_INCLUDE_DIRECTORY "${VESPA_DEPS}/include" "/usr/include/openblas" PARENT_SCOPE)
- set(DEFAULT_VESPA_LLVM_VERSION "9" PARENT_SCOPE)
-endfunction()
-
function(setup_vespa_default_build_settings_fedora_32)
message("-- Setting up default build settings for fedora 32")
set(DEFAULT_EXTRA_INCLUDE_DIRECTORY "${VESPA_DEPS}/include" "/usr/include/openblas" PARENT_SCOPE)
@@ -186,10 +173,6 @@ function(vespa_use_default_build_settings)
setup_vespa_default_build_settings_centos_8()
elseif(VESPA_OS_DISTRO STREQUAL "darwin")
setup_vespa_default_build_settings_darwin()
- elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "fedora 30")
- setup_vespa_default_build_settings_fedora_30()
- elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "fedora 31")
- setup_vespa_default_build_settings_fedora_31()
elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "fedora 32")
setup_vespa_default_build_settings_fedora_32()
elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "fedora 33")
diff --git a/dist/vespa.spec b/dist/vespa.spec
index 93f8842acec..b4bbb13e7d6 100644
--- a/dist/vespa.spec
+++ b/dist/vespa.spec
@@ -64,7 +64,11 @@ BuildRequires: vespa-libzstd-devel >= 1.4.5-2
%endif
%if 0%{?el8}
BuildRequires: cmake >= 3.11.4-3
+%if 0%{?centos}
+BuildRequires: llvm-devel >= 10.0.1
+%else
BuildRequires: llvm-devel >= 9.0.1
+%endif
BuildRequires: boost-devel >= 1.66
BuildRequires: openssl-devel
BuildRequires: vespa-gtest >= 1.8.1-1
@@ -80,13 +84,6 @@ BuildRequires: openssl-devel
BuildRequires: vespa-lz4-devel >= 1.9.2-2
BuildRequires: vespa-onnxruntime-devel = 1.4.0
BuildRequires: vespa-libzstd-devel >= 1.4.5-2
-%if 0%{?fc31}
-BuildRequires: vespa-protobuf-devel >= 3.7.0-4
-BuildRequires: llvm-devel >= 9.0.0
-BuildRequires: boost-devel >= 1.69
-BuildRequires: gtest-devel
-BuildRequires: gmock-devel
-%endif
%if 0%{?fc32}
BuildRequires: protobuf-devel
BuildRequires: llvm-devel >= 10.0.0
@@ -180,8 +177,13 @@ Requires: vespa-zstd >= 1.4.5-2
%define _extra_include_directory /usr/include/llvm7.0;%{_vespa_deps_prefix}/include;/usr/include/openblas
%endif
%if 0%{?el8}
+%if 0%{?centos}
+Requires: llvm-libs >= 10.0.1
+%define _vespa_llvm_version 10
+%else
Requires: llvm-libs >= 9.0.1
%define _vespa_llvm_version 9
+%endif
Requires: openssl-libs
Requires: vespa-lz4 >= 1.9.2-2
Requires: vespa-onnxruntime = 1.4.0
@@ -195,11 +197,6 @@ Requires: openssl-libs
Requires: vespa-lz4 >= 1.9.2-2
Requires: vespa-onnxruntime = 1.4.0
Requires: vespa-zstd >= 1.4.5-2
-%if 0%{?fc31}
-Requires: vespa-protobuf >= 3.7.0-4
-Requires: llvm-libs >= 9.0.0
-%define _vespa_llvm_version 9
-%endif
%if 0%{?fc32}
Requires: protobuf
Requires: llvm-libs >= 10.0.0
@@ -469,7 +466,6 @@ fi
%{_prefix}/lib/jars/athenz-identity-provider-service-jar-with-dependencies.jar
%{_prefix}/lib/jars/cloud-tenant-cd-jar-with-dependencies.jar
%{_prefix}/lib/jars/clustercontroller-apps-jar-with-dependencies.jar
-%{_prefix}/lib/jars/clustercontroller-apputil-jar-with-dependencies.jar
%{_prefix}/lib/jars/clustercontroller-core-jar-with-dependencies.jar
%{_prefix}/lib/jars/clustercontroller-reindexer-jar-with-dependencies.jar
%{_prefix}/lib/jars/clustercontroller-utils-jar-with-dependencies.jar
@@ -609,6 +605,7 @@ fi
%{_prefix}/lib/jars/component-jar-with-dependencies.jar
%{_prefix}/lib/jars/config-bundle-jar-with-dependencies.jar
%{_prefix}/lib/jars/configdefinitions-jar-with-dependencies.jar
+%{_prefix}/lib/jars/configgen.jar
%{_prefix}/lib/jars/config-model-api-jar-with-dependencies.jar
%{_prefix}/lib/jars/config-model-jar-with-dependencies.jar
%{_prefix}/lib/jars/config-provisioning-jar-with-dependencies.jar
diff --git a/docproc/src/main/java/com/yahoo/docproc/jdisc/RequestContext.java b/docproc/src/main/java/com/yahoo/docproc/jdisc/RequestContext.java
index 48b58c12456..ec479c73bcc 100644
--- a/docproc/src/main/java/com/yahoo/docproc/jdisc/RequestContext.java
+++ b/docproc/src/main/java/com/yahoo/docproc/jdisc/RequestContext.java
@@ -40,9 +40,8 @@ public interface RequestContext {
//fatal:
ERROR_PROCESSING_FAILURE(Response.Status.INTERNAL_SERVER_ERROR, DocumentProtocol.ERROR_PROCESSING_FAILURE);
-
- private int discStatus;
- private int documentProtocolStatus;
+ private final int discStatus;
+ private final int documentProtocolStatus;
ErrorCode(int discStatus, int documentProtocolStatus) {
this.discStatus = discStatus;
diff --git a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java
index 2b9042bafac..f712231e939 100644
--- a/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java
+++ b/docproc/src/main/java/com/yahoo/docproc/jdisc/messagebus/MbusRequestContext.java
@@ -77,7 +77,7 @@ public class MbusRequestContext implements RequestContext, ResponseHandler {
public void skip() {
if (deserialized.get())
throw new IllegalStateException("Can not skip processing after deserialization");
- dispatchRequest(requestMsg, request.getUri().getPath(), responseHandler);
+ dispatchRequest(requestMsg, getUri().getPath(), responseHandler);
}
@Override
@@ -183,7 +183,9 @@ public class MbusRequestContext implements RequestContext, ResponseHandler {
@Override
protected Request newRequest() {
- return new MbusRequest(request, resolveUri(uriPath), msg);
+ return new MbusRequest(request,
+ uriCache.computeIfAbsent(uriPath, __ -> URI.create("mbus://remotehost" + uriPath)),
+ msg);
}
@Override
@@ -203,12 +205,4 @@ public class MbusRequestContext implements RequestContext, ResponseHandler {
return new MessageFactory(message);
}
- private static URI resolveUri(String path) {
- URI uri = uriCache.get(path);
- if (uri == null) {
- uri = URI.create("mbus://remotehost" + path);
- uriCache.put(path, uri);
- }
- return uri;
- }
}
diff --git a/document/CMakeLists.txt b/document/CMakeLists.txt
index 8c49f7bd7bf..46da458fe6d 100644
--- a/document/CMakeLists.txt
+++ b/document/CMakeLists.txt
@@ -38,6 +38,9 @@ vespa_define_module(
src/tests/serialization
src/tests/struct_anno
src/tests/tensor_fieldvalue
+ src/tests/tensor_fieldvalue/partial_add
+ src/tests/tensor_fieldvalue/partial_modify
+ src/tests/tensor_fieldvalue/partial_remove
)
install_java_artifact(document)
diff --git a/document/abi-spec.json b/document/abi-spec.json
index 903b7a897df..03a336ad36e 100644
--- a/document/abi-spec.json
+++ b/document/abi-spec.json
@@ -619,6 +619,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.document.DocumenttypesConfig build()"
],
"fields": [
diff --git a/document/src/main/java/com/yahoo/document/BucketIdFactory.java b/document/src/main/java/com/yahoo/document/BucketIdFactory.java
index 8ae769dbb11..ba9f7064865 100644
--- a/document/src/main/java/com/yahoo/document/BucketIdFactory.java
+++ b/document/src/main/java/com/yahoo/document/BucketIdFactory.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.document;
-import com.yahoo.document.idstring.*;
-
/**
* A bucket id contains bit used for various purposes. In most use cases, these can use the default
* settings, but the number of bits used for the different purposes is configurable, to allow for
@@ -13,7 +11,7 @@ import com.yahoo.document.idstring.*;
*
* For more information about what the sub parts of a bucket id actually is, read the bucket splitting documentation.
*
- * @author <a href="mailto:humbe@yahoo-inc.com">H&aring;kon Humberset</a>
+ * @author HÃ¥kon Humberset
*/
public class BucketIdFactory {
diff --git a/document/src/main/java/com/yahoo/document/datatypes/Array.java b/document/src/main/java/com/yahoo/document/datatypes/Array.java
index 660e58efa25..ee97bbc6669 100644
--- a/document/src/main/java/com/yahoo/document/datatypes/Array.java
+++ b/document/src/main/java/com/yahoo/document/datatypes/Array.java
@@ -131,19 +131,26 @@ public final class Array<T extends FieldValue> extends CollectionFieldValue<T> i
return hashCode;
}
+ private boolean equalsWithListWrapper(List<? extends FieldValue> a, ListWrapper<? extends FieldValue> b) {
+ for (int i = 0; i < a.size(); i++) {
+ if ( ! b.myvalues.get(i).equals(a.get(i).getWrappedValue()) ) return false;
+ }
+ return true;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Array)) return false;
if (!super.equals(o)) return false;
Array a = (Array) o;
- // Compare independent of container used.
- Iterator it1 = values.iterator();
- Iterator it2 = a.values.iterator();
- while (it1.hasNext() && it2.hasNext()) {
- if (!it1.next().equals(it2.next())) return false;
+ if (values.size() != a.values.size()) return false;
+ if (values instanceof ListWrapper && !(a.values instanceof ListWrapper)) {
+ return equalsWithListWrapper(a.values, (ListWrapper<? extends FieldValue>) values);
+ } else if (a.values instanceof ListWrapper && !(values instanceof ListWrapper)) {
+ return equalsWithListWrapper(values, (ListWrapper<? extends FieldValue>) a.values);
}
- return !(it1.hasNext() || it2.hasNext());
+ return values.equals(a.values);
}
// List implementation
diff --git a/document/src/main/java/com/yahoo/document/datatypes/MapFieldValue.java b/document/src/main/java/com/yahoo/document/datatypes/MapFieldValue.java
index 4777622be1f..089b3a53d67 100644
--- a/document/src/main/java/com/yahoo/document/datatypes/MapFieldValue.java
+++ b/document/src/main/java/com/yahoo/document/datatypes/MapFieldValue.java
@@ -81,7 +81,10 @@ public class MapFieldValue<K extends FieldValue, V extends FieldValue> extends C
*/
public boolean equals(Object o) {
if (!(o instanceof MapFieldValue)) return false;
- return super.equals(o) && entrySet().equals(((MapFieldValue) o).entrySet());
+ MapFieldValue m = (MapFieldValue) o;
+ if (size() != m.size()) return false;
+ if ( ! super.equals(m)) return false;
+ return entrySet().equals(m.entrySet());
}
@Override
diff --git a/document/src/main/java/com/yahoo/document/datatypes/WeightedSet.java b/document/src/main/java/com/yahoo/document/datatypes/WeightedSet.java
index d505380523f..2d78deb9479 100644
--- a/document/src/main/java/com/yahoo/document/datatypes/WeightedSet.java
+++ b/document/src/main/java/com/yahoo/document/datatypes/WeightedSet.java
@@ -252,7 +252,10 @@ public final class WeightedSet<K extends FieldValue> extends CollectionFieldValu
*/
public boolean equals(Object o) {
if (!(o instanceof WeightedSet)) return false;
- return (super.equals(o) && map.equals(((WeightedSet<K>)o).map));
+ WeightedSet w = (WeightedSet) o;
+ if (size() != w.size()) return false;
+ if ( ! super.equals(o)) return false;
+ return map.equals(((WeightedSet)o).map);
}
/**
@@ -314,12 +317,12 @@ public final class WeightedSet<K extends FieldValue> extends CollectionFieldValu
*
*/
class WeightedSetWrapper extends MapFieldValue<K, IntegerFieldValue> {
- Map<Object, Integer> map = new HashMap<Object, Integer>();
- private DataType keyTypeVespa = getDataType().getKeyType();
- private DataType valTypeVespa = DataType.INT;
+ private final Map<Object, Integer> map;
+ private final DataType keyTypeVespa;
public WeightedSetWrapper(Map map, MapDataType dt) {
super(dt);
+ keyTypeVespa = getDataType().getKeyType();
this.map=map;
}
@@ -335,7 +338,11 @@ public final class WeightedSet<K extends FieldValue> extends CollectionFieldValu
private IntegerFieldValue wrapValue(Object o) {
if (o==null) return null;
- return (IntegerFieldValue)valTypeVespa.createFieldValue(o);
+ if (o instanceof IntegerFieldValue) return (IntegerFieldValue) o;
+ if (o instanceof Integer) return new IntegerFieldValue((Integer) o);
+ IntegerFieldValue value = new IntegerFieldValue();
+ value.assign(o);
+ return value;
}
@Override
diff --git a/document/src/test/java/com/yahoo/document/datatypes/ArrayTestCase.java b/document/src/test/java/com/yahoo/document/datatypes/ArrayTestCase.java
index ce250c67658..c3c69e55a4b 100755
--- a/document/src/test/java/com/yahoo/document/datatypes/ArrayTestCase.java
+++ b/document/src/test/java/com/yahoo/document/datatypes/ArrayTestCase.java
@@ -283,6 +283,7 @@ public class ArrayTestCase {
b.add(new StringFieldValue("mumbo jumbo 1"));
b.add(new StringFieldValue("mumbo jumbo 2"));
assertEquals(a, b);
+ assertEquals(b, a);
assertEquals(0, a.compareTo(b));
assertEquals(0, b.compareTo(a));
@@ -292,6 +293,7 @@ public class ArrayTestCase {
l.add("mumbo jumbo 2");
b.assign(l);
assertEquals(a, b);
+ assertEquals(b, a);
assertEquals(0, a.compareTo(b));
assertEquals(0, b.compareTo(a));
}
@@ -305,6 +307,7 @@ public class ArrayTestCase {
b.add(new StringFieldValue("mumbo jumbo 1"));
b.add(new StringFieldValue("mumbo jumbo 2"));
assertNotEquals(a, b);
+ assertNotEquals(b, a);
assertEquals(1, a.compareTo(b));
assertEquals(-1, b.compareTo(a));
@@ -314,6 +317,7 @@ public class ArrayTestCase {
l.add("mumbo jumbo 2");
b.assign(l);
assertNotEquals(a, b);
+ assertNotEquals(b, a);
assertEquals(1, a.compareTo(b));
assertEquals(-1, b.compareTo(a));
}
diff --git a/document/src/tests/documentselectparsertest.cpp b/document/src/tests/documentselectparsertest.cpp
index 30b2bfbb1b4..0830c84fe39 100644
--- a/document/src/tests/documentselectparsertest.cpp
+++ b/document/src/tests/documentselectparsertest.cpp
@@ -37,8 +37,8 @@ protected:
~DocumentSelectParserTest();
Document::SP createDoc(
- const std::string& doctype, const std::string& id, uint32_t hint,
- double hfloat, const std::string& hstr, const std::string& cstr,
+ vespalib::stringref doctype, vespalib::stringref id, uint32_t hint,
+ double hfloat, vespalib::stringref hstr, vespalib::stringref cstr,
uint64_t hlong = 0);
DocumentUpdate::SP createUpdate(
@@ -105,8 +105,8 @@ void DocumentSelectParserTest::SetUp()
}
Document::SP DocumentSelectParserTest::createDoc(
- const std::string& doctype, const std::string& id, uint32_t hint,
- double hfloat, const std::string& hstr, const std::string& cstr,
+ vespalib::stringref doctype, vespalib::stringref id, uint32_t hint,
+ double hfloat, vespalib::stringref hstr, vespalib::stringref cstr,
uint64_t hlong)
{
const DocumentType* type = _repo->getDocumentType(doctype);
@@ -117,8 +117,8 @@ Document::SP DocumentSelectParserTest::createDoc(
doc->setValue(doc->getField("headerlongval"), LongFieldValue(hlong));
}
doc->setValue(doc->getField("hfloatval"), FloatFieldValue(hfloat));
- doc->setValue(doc->getField("hstringval"), StringFieldValue(hstr.c_str()));
- doc->setValue(doc->getField("content"), StringFieldValue(cstr.c_str()));
+ doc->setValue(doc->getField("hstringval"), StringFieldValue(hstr));
+ doc->setValue(doc->getField("content"), StringFieldValue(cstr));
return doc;
}
@@ -1232,10 +1232,26 @@ TEST_F(DocumentSelectParserTest, testDocumentIdsInRemoves)
PARSE("testdoctype1 and testdoctype1.headerval == 0", DocumentId("id:ns:testdoctype1::1"), Invalid);
}
+namespace {
+
+#if defined(__cpp_char8_t)
+const char *
+char_from_u8(const char8_t * p) {
+ return reinterpret_cast<const char *>(p);
+}
+#else
+const char *
+char_from_u8(const char * p) {
+ return p;
+}
+#endif
+
+}
+
TEST_F(DocumentSelectParserTest, testUtf8)
{
createDocs();
- std::string utf8name(u8"H\u00e5kon");
+ vespalib::string utf8name = char_from_u8(u8"H\u00e5kon");
EXPECT_EQ(size_t(6), utf8name.size());
/// \todo TODO (was warning): UTF8 test for glob/regex support in selection language disabled. Known not to work
diff --git a/document/src/tests/documentupdatetestcase.cpp b/document/src/tests/documentupdatetestcase.cpp
index b88a0437fc2..3faec14ea7b 100644
--- a/document/src/tests/documentupdatetestcase.cpp
+++ b/document/src/tests/documentupdatetestcase.cpp
@@ -21,7 +21,8 @@
#include <vespa/document/update/tensor_remove_update.h>
#include <vespa/document/update/valueupdate.h>
#include <vespa/document/util/bytebuffer.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -35,9 +36,9 @@
using namespace document::config_builder;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
using vespalib::nbostream;
namespace document {
@@ -775,7 +776,7 @@ TEST(DocumentUpdateTest, testMapValueUpdate)
std::unique_ptr<vespalib::eval::Value>
makeTensor(const TensorSpec &spec)
{
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
std::unique_ptr<TensorFieldValue>
diff --git a/document/src/tests/serialization/vespadocumentserializer_test.cpp b/document/src/tests/serialization/vespadocumentserializer_test.cpp
index 05f1e9251db..0c9dfaf2e56 100644
--- a/document/src/tests/serialization/vespadocumentserializer_test.cpp
+++ b/document/src/tests/serialization/vespadocumentserializer_test.cpp
@@ -36,8 +36,9 @@
#include <vespa/document/serialization/vespadocumentdeserializer.h>
#include <vespa/document/serialization/vespadocumentserializer.h>
#include <vespa/document/serialization/annotationserializer.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/vespalib/io/fileutil.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -51,7 +52,7 @@ using vespalib::nbostream;
using vespalib::nbostream_longlivedbuf;
using vespalib::slime::Cursor;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using vespalib::compression::CompressionConfig;
using namespace document;
using std::string;
@@ -772,7 +773,7 @@ namespace
{
vespalib::eval::Value::UP createTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
}
@@ -838,7 +839,7 @@ void checkDeserialization(const string &name, std::unique_ptr<vespalib::eval::Va
TensorDataType valueType(tensor ? tensor->type() : vespalib::eval::ValueType::error_type());
TensorFieldValue value(valueType);
if (tensor) {
- value = EngineOrFactory::get().copy(*tensor);
+ value = std::move(tensor);
}
serializeToFile(value, data_dir + name + "__cpp");
deserializeAndCheck(data_dir + name + "__cpp", value);
@@ -877,7 +878,7 @@ TensorDocFixture::TensorDocFixture(const DocumentTypeRepo &docTypeRepo,
_blob()
{
auto fv = _doc.getField(tensor_field_name).createValue();
- dynamic_cast<TensorFieldValue &>(*fv) = EngineOrFactory::get().copy(*_tensor);
+ dynamic_cast<TensorFieldValue &>(*fv) = SimpleValue::from_value(*_tensor);
_doc.setValue(tensor_field_name, *fv);
_doc.serialize(_blob);
}
diff --git a/eval/src/tests/tensor/partial_add/CMakeLists.txt b/document/src/tests/tensor_fieldvalue/partial_add/CMakeLists.txt
index f0d07a8e9cf..862e5152758 100644
--- a/eval/src/tests/tensor/partial_add/CMakeLists.txt
+++ b/document/src/tests/tensor_fieldvalue/partial_add/CMakeLists.txt
@@ -1,9 +1,9 @@
# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_partial_add_test_app TEST
+vespa_add_executable(document_partial_add_test_app TEST
SOURCES
partial_add_test.cpp
DEPENDS
- vespaeval
+ document
GTest::GTest
)
-vespa_add_test(NAME eval_partial_add_test_app COMMAND eval_partial_add_test_app)
+vespa_add_test(NAME document_partial_add_test_app COMMAND document_partial_add_test_app)
diff --git a/eval/src/tests/tensor/partial_add/partial_add_test.cpp b/document/src/tests/tensor_fieldvalue/partial_add/partial_add_test.cpp
index 046306b467e..95597204657 100644
--- a/eval/src/tests/tensor/partial_add/partial_add_test.cpp
+++ b/document/src/tests/tensor_fieldvalue/partial_add/partial_add_test.cpp
@@ -3,13 +3,12 @@
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
+#include <vespa/document/update/tensor_partial_update.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <optional>
+using namespace document;
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
@@ -45,7 +44,7 @@ Value::UP try_partial_add(const TensorSpec &a, const TensorSpec &b) {
const auto &factory = SimpleValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
auto rhs = value_from_spec(b, factory);
- return tensor::TensorPartialUpdate::add(*lhs, *rhs, factory);
+ return TensorPartialUpdate::add(*lhs, *rhs, factory);
}
TensorSpec perform_partial_add(const TensorSpec &a, const TensorSpec &b) {
@@ -54,15 +53,6 @@ TensorSpec perform_partial_add(const TensorSpec &a, const TensorSpec &b) {
return spec_from_value(*up);
}
-TensorSpec perform_old_add(const TensorSpec &a, const TensorSpec &b) {
- const auto &engine = tensor::DefaultTensorEngine::ref();
- auto lhs = engine.from_spec(a);
- auto rhs = engine.from_spec(b);
- auto up = tensor::TensorPartialUpdate::add(*lhs, *rhs, engine);
- EXPECT_TRUE(up);
- return engine.to_spec(*up);
-}
-
TEST(PartialAddTest, partial_add_works_for_simple_values) {
ASSERT_TRUE((add_layouts.size() % 2) == 0);
for (size_t i = 0; i < add_layouts.size(); i += 2) {
@@ -75,18 +65,6 @@ TEST(PartialAddTest, partial_add_works_for_simple_values) {
}
}
-TEST(PartialAddTest, partial_add_works_like_old_add) {
- ASSERT_TRUE((add_layouts.size() % 2) == 0);
- for (size_t i = 0; i < add_layouts.size(); i += 2) {
- TensorSpec lhs = spec(add_layouts[i], N());
- TensorSpec rhs = spec(add_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto expect = perform_old_add(lhs, rhs);
- auto actual = perform_partial_add(lhs, rhs);
- EXPECT_EQ(actual, expect);
- }
-}
-
std::vector<Layout> bad_layouts = {
{x(3)}, {x(3),y(1)},
{x(3),y(1)}, {x(3)},
diff --git a/eval/src/tests/tensor/partial_modify/CMakeLists.txt b/document/src/tests/tensor_fieldvalue/partial_modify/CMakeLists.txt
index 42a08acaae6..1c7479c6d93 100644
--- a/eval/src/tests/tensor/partial_modify/CMakeLists.txt
+++ b/document/src/tests/tensor_fieldvalue/partial_modify/CMakeLists.txt
@@ -1,9 +1,9 @@
# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_partial_modify_test_app TEST
+vespa_add_executable(document_partial_modify_test_app TEST
SOURCES
partial_modify_test.cpp
DEPENDS
- vespaeval
+ document
GTest::GTest
)
-vespa_add_test(NAME eval_partial_modify_test_app COMMAND eval_partial_modify_test_app)
+vespa_add_test(NAME document_partial_modify_test_app COMMAND document_partial_modify_test_app)
diff --git a/eval/src/tests/tensor/partial_modify/partial_modify_test.cpp b/document/src/tests/tensor_fieldvalue/partial_modify/partial_modify_test.cpp
index 3236a8ac127..fbb9ed75e46 100644
--- a/eval/src/tests/tensor/partial_modify/partial_modify_test.cpp
+++ b/document/src/tests/tensor_fieldvalue/partial_modify/partial_modify_test.cpp
@@ -3,13 +3,12 @@
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
+#include <vespa/document/update/tensor_partial_update.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <optional>
+using namespace document;
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
@@ -60,7 +59,7 @@ Value::UP try_partial_modify(const TensorSpec &a, const TensorSpec &b, join_fun_
const auto &factory = SimpleValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
auto rhs = value_from_spec(b, factory);
- return tensor::TensorPartialUpdate::modify(*lhs, fun, *rhs, factory);
+ return TensorPartialUpdate::modify(*lhs, fun, *rhs, factory);
}
TensorSpec perform_partial_modify(const TensorSpec &a, const TensorSpec &b, join_fun_t fun) {
@@ -69,17 +68,6 @@ TensorSpec perform_partial_modify(const TensorSpec &a, const TensorSpec &b, join
return spec_from_value(*up);
}
-TensorSpec perform_old_modify(const TensorSpec &a, const TensorSpec &b, join_fun_t fun) {
- const auto &engine = tensor::DefaultTensorEngine::ref();
- auto lhs = engine.from_spec(a);
- auto rhs = engine.from_spec(b);
- EXPECT_TRUE(tensor::TensorPartialUpdate::check_suitably_sparse(*rhs, engine));
- auto up = tensor::TensorPartialUpdate::modify(*lhs, fun, *rhs, engine);
- EXPECT_TRUE(up);
- return engine.to_spec(*up);
-}
-
-
TEST(PartialModifyTest, partial_modify_works_for_simple_values) {
ASSERT_TRUE((modify_layouts.size() % 2) == 0);
for (size_t i = 0; i < modify_layouts.size(); i += 2) {
@@ -98,20 +86,6 @@ TEST(PartialModifyTest, partial_modify_works_for_simple_values) {
}
}
-TEST(PartialModifyTest, partial_modify_works_like_old_modify) {
- ASSERT_TRUE((modify_layouts.size() % 2) == 0);
- for (size_t i = 0; i < modify_layouts.size(); i += 2) {
- TensorSpec lhs = spec(modify_layouts[i], N());
- TensorSpec rhs = spec(modify_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- for (auto fun: {operation::Add::f, operation::Mul::f, operation::Sub::f}) {
- auto expect = perform_old_modify(lhs, rhs, fun);
- auto actual = perform_partial_modify(lhs, rhs, fun);
- EXPECT_EQ(actual, expect);
- }
- }
-}
-
std::vector<Layout> bad_layouts = {
{x(3)}, {x(3)},
{x(3),y({"a"})}, {x(3),y({"a"})},
diff --git a/eval/src/tests/tensor/partial_remove/CMakeLists.txt b/document/src/tests/tensor_fieldvalue/partial_remove/CMakeLists.txt
index 1680324f574..ef04f3749a1 100644
--- a/eval/src/tests/tensor/partial_remove/CMakeLists.txt
+++ b/document/src/tests/tensor_fieldvalue/partial_remove/CMakeLists.txt
@@ -1,9 +1,9 @@
# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_partial_remove_test_app TEST
+vespa_add_executable(document_partial_remove_test_app TEST
SOURCES
partial_remove_test.cpp
DEPENDS
- vespaeval
+ document
GTest::GTest
)
-vespa_add_test(NAME eval_partial_remove_test_app COMMAND eval_partial_remove_test_app)
+vespa_add_test(NAME document_partial_remove_test_app COMMAND document_partial_remove_test_app)
diff --git a/eval/src/tests/tensor/partial_remove/partial_remove_test.cpp b/document/src/tests/tensor_fieldvalue/partial_remove/partial_remove_test.cpp
index 5af2396f5ec..79237963475 100644
--- a/eval/src/tests/tensor/partial_remove/partial_remove_test.cpp
+++ b/document/src/tests/tensor_fieldvalue/partial_remove/partial_remove_test.cpp
@@ -3,13 +3,12 @@
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
+#include <vespa/document/update/tensor_partial_update.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <optional>
+using namespace document;
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
@@ -53,7 +52,7 @@ Value::UP try_partial_remove(const TensorSpec &a, const TensorSpec &b) {
const auto &factory = SimpleValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
auto rhs = value_from_spec(b, factory);
- return tensor::TensorPartialUpdate::remove(*lhs, *rhs, factory);
+ return TensorPartialUpdate::remove(*lhs, *rhs, factory);
}
TensorSpec perform_partial_remove(const TensorSpec &a, const TensorSpec &b) {
@@ -62,16 +61,6 @@ TensorSpec perform_partial_remove(const TensorSpec &a, const TensorSpec &b) {
return spec_from_value(*up);
}
-TensorSpec perform_old_remove(const TensorSpec &a, const TensorSpec &b) {
- const auto &engine = tensor::DefaultTensorEngine::ref();
- auto lhs = engine.from_spec(a);
- auto rhs = engine.from_spec(b);
- EXPECT_TRUE(tensor::TensorPartialUpdate::check_suitably_sparse(*rhs, engine));
- auto up = tensor::TensorPartialUpdate::remove(*lhs, *rhs, engine);
- EXPECT_TRUE(up);
- return engine.to_spec(*up);
-}
-
TEST(PartialRemoveTest, partial_remove_works_for_simple_values) {
ASSERT_TRUE((remove_layouts.size() % 2) == 0);
for (size_t i = 0; i < remove_layouts.size(); i += 2) {
@@ -84,18 +73,6 @@ TEST(PartialRemoveTest, partial_remove_works_for_simple_values) {
}
}
-TEST(PartialRemoveTest, partial_remove_works_like_old_remove) {
- ASSERT_TRUE((remove_layouts.size() % 2) == 0);
- for (size_t i = 0; i < remove_layouts.size(); i += 2) {
- TensorSpec lhs = spec(remove_layouts[i], N());
- TensorSpec rhs = spec(remove_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto expect = perform_old_remove(lhs, rhs);
- auto actual = perform_partial_remove(lhs, rhs);
- EXPECT_EQ(actual, expect);
- }
-}
-
std::vector<Layout> bad_layouts = {
{x(3)}, {x(3)},
{x(3),y({"a"})}, {x(3)},
diff --git a/document/src/tests/tensor_fieldvalue/tensor_fieldvalue_test.cpp b/document/src/tests/tensor_fieldvalue/tensor_fieldvalue_test.cpp
index 231fba93d10..092190a427b 100644
--- a/document/src/tests/tensor_fieldvalue/tensor_fieldvalue_test.cpp
+++ b/document/src/tests/tensor_fieldvalue/tensor_fieldvalue_test.cpp
@@ -7,18 +7,16 @@ LOG_SETUP("fieldvalue_test");
#include <vespa/document/base/exceptions.h>
#include <vespa/document/datatype/tensor_data_type.h>
#include <vespa/document/fieldvalue/tensorfieldvalue.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/test/test_utils.h>
#include <vespa/vespalib/testkit/testapp.h>
using namespace document;
-using namespace vespalib::tensor;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
-using vespalib::tensor::test::makeTensor;
namespace
{
@@ -27,14 +25,14 @@ TensorDataType xSparseTensorDataType(ValueType::from_spec("tensor(x{})"));
TensorDataType xySparseTensorDataType(ValueType::from_spec("tensor(x{},y{})"));
vespalib::eval::Value::UP createTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
std::unique_ptr<vespalib::eval::Value>
makeSimpleTensor()
{
- return makeTensor<vespalib::eval::Value>(TensorSpec("tensor(x{},y{})").
- add({{"x", "4"}, {"y", "5"}}, 7));
+ return SimpleValue::from_spec(TensorSpec("tensor(x{},y{})").
+ add({{"x", "4"}, {"y", "5"}}, 7));
}
FieldValue::UP clone(FieldValue &fv) {
diff --git a/document/src/vespa/document/annotation/span.h b/document/src/vespa/document/annotation/span.h
index b42bfe5d52d..051db3d54c0 100644
--- a/document/src/vespa/document/annotation/span.h
+++ b/document/src/vespa/document/annotation/span.h
@@ -24,11 +24,11 @@ public:
void accept(SpanTreeVisitor &visitor) const override;
};
-inline bool operator==(const Span &span1, const Span &span2) {
+inline bool operator==(const Span &span1, const Span &span2) noexcept {
return span1.from() == span2.from() && span1.length() == span2.length();
}
-inline bool operator<(const Span &span1, const Span &span2) {
+inline bool operator<(const Span &span1, const Span &span2) noexcept {
if (span1.from() != span2.from()) {
return span1.from() < span2.from();
} else {
diff --git a/document/src/vespa/document/bucket/bucketid.cpp b/document/src/vespa/document/bucket/bucketid.cpp
index ddea0d4ba85..668798d6c39 100644
--- a/document/src/vespa/document/bucket/bucketid.cpp
+++ b/document/src/vespa/document/bucket/bucketid.cpp
@@ -93,14 +93,10 @@ void BucketId::throwFailedSetUsedBits(uint32_t used, uint32_t availBits) {
BucketId::Type
BucketId::reverse(Type id)
{
- Type retVal;
- int bytes = sizeof(Type);
-
- for (int i = 0; i < bytes; i++) {
- ((unsigned char*)&retVal)[bytes - i - 1] = reverseBitTable[((const unsigned char*)&id)[i]];
- }
-
- return retVal;
+ id = ((id & 0x5555555555555555l) << 1) | ((id & 0xaaaaaaaaaaaaaaaal) >> 1);
+ id = ((id & 0x3333333333333333l) << 2) | ((id & 0xccccccccccccccccl) >> 2);
+ id = ((id & 0x0f0f0f0f0f0f0f0fl) << 4) | ((id & 0xf0f0f0f0f0f0f0f0l) >> 4);
+ return __builtin_bswap64(id);
}
BucketId::Type
diff --git a/document/src/vespa/document/bucket/bucketselector.cpp b/document/src/vespa/document/bucket/bucketselector.cpp
index 26afc1f2e66..7e7f93b9ef4 100644
--- a/document/src/vespa/document/bucket/bucketselector.cpp
+++ b/document/src/vespa/document/bucket/bucketselector.cpp
@@ -31,6 +31,8 @@ using namespace document::select;
BucketVisitor(const BucketIdFactory& factory)
: _factory(factory), _buckets(), _unknown(true) {}
+ ~BucketVisitor() override;
+
void visitAndBranch(const document::select::And& node) override {
BucketVisitor left(_factory);
node.getLeft().visit(left);
@@ -155,6 +157,9 @@ using namespace document::select;
void visitNullValueNode(const NullValueNode &) override {}
void visitInvalidValueNode(const InvalidValueNode &) override {}
};
+
+BucketVisitor::~BucketVisitor() = default;
+
//}
BucketSelector::BucketSelector(const document::BucketIdFactory& factory)
diff --git a/document/src/vespa/document/datatype/documenttype.h b/document/src/vespa/document/datatype/documenttype.h
index fae65addb48..5aff0a91f75 100644
--- a/document/src/vespa/document/datatype/documenttype.h
+++ b/document/src/vespa/document/datatype/documenttype.h
@@ -87,6 +87,7 @@ public:
std::unique_ptr<FieldValue> createFieldValue() const override;
void print(std::ostream&, bool verbose, const std::string& indent) const override;
bool operator==(const DataType& type) const override;
+ bool operator==(const DocumentType& type) const { return operator==(static_cast<const DataType&>(type)); }
uint32_t getFieldCount() const override {
return _fields->getFieldCount();
}
diff --git a/document/src/vespa/document/datatype/referencedatatype.h b/document/src/vespa/document/datatype/referencedatatype.h
index bc7db7800aa..8f3d2a366cc 100644
--- a/document/src/vespa/document/datatype/referencedatatype.h
+++ b/document/src/vespa/document/datatype/referencedatatype.h
@@ -26,6 +26,7 @@ public:
void onBuildFieldPath(FieldPath & path, vespalib::stringref remainingFieldName) const override;
bool operator==(const DataType &type) const override;
+ bool operator==(const ReferenceDataType& type) const { return operator==(static_cast<const DataType&>(type)); }
};
} // document
diff --git a/document/src/vespa/document/datatype/structureddatatype.h b/document/src/vespa/document/datatype/structureddatatype.h
index e940629553f..5bfcbcd19f0 100644
--- a/document/src/vespa/document/datatype/structureddatatype.h
+++ b/document/src/vespa/document/datatype/structureddatatype.h
@@ -37,6 +37,7 @@ public:
virtual StructuredDataType* clone() const override = 0;
bool operator==(const DataType& type) const override;
+ bool operator==(const StructuredDataType& type) const { return operator==(static_cast<const DataType&>(type)); }
static int32_t createId(vespalib::stringref name);
diff --git a/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp b/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp
index 2a66ea61966..cc3aed67387 100644
--- a/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp
+++ b/document/src/vespa/document/fieldvalue/tensorfieldvalue.cpp
@@ -4,14 +4,14 @@
#include <vespa/document/base/exceptions.h>
#include <vespa/document/datatype/tensor_data_type.h>
#include <vespa/vespalib/util/xmlstream.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <ostream>
#include <cassert>
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::TensorSpec;
using vespalib::eval::ValueType;
using namespace vespalib::xml;
@@ -51,7 +51,7 @@ TensorFieldValue::TensorFieldValue(const TensorFieldValue &rhs)
_altered(true)
{
if (rhs._tensor) {
- _tensor = EngineOrFactory::get().copy(*rhs._tensor);
+ _tensor = FastValueBuilderFactory::get().copy(*rhs._tensor);
}
}
@@ -78,7 +78,7 @@ TensorFieldValue::operator=(const TensorFieldValue &rhs)
if (&_dataType == &rhs._dataType || !rhs._tensor ||
_dataType.isAssignableType(rhs._tensor->type())) {
if (rhs._tensor) {
- _tensor = EngineOrFactory::get().copy(*rhs._tensor);
+ _tensor = FastValueBuilderFactory::get().copy(*rhs._tensor);
} else {
_tensor.reset();
}
@@ -109,7 +109,7 @@ TensorFieldValue::make_empty_if_not_existing()
{
if (!_tensor) {
TensorSpec empty_spec(_dataType.getTensorType().to_spec());
- _tensor = EngineOrFactory::get().from_spec(empty_spec);
+ _tensor = value_from_spec(empty_spec, FastValueBuilderFactory::get());
}
}
@@ -157,7 +157,7 @@ TensorFieldValue::print(std::ostream& out, bool verbose,
(void) indent;
out << "{TensorFieldValue: ";
if (_tensor) {
- out << EngineOrFactory::get().to_spec(*_tensor).to_string();
+ out << spec_from_value(*_tensor).to_string();
} else {
out << "null";
}
@@ -228,9 +228,8 @@ TensorFieldValue::compare(const FieldValue &other) const
// Compare the actual tensors by converting to TensorSpec strings.
// TODO: this can be very slow, check if it might be used for anything
// performance-critical.
- auto engine = EngineOrFactory::get();
- auto lhs_spec = engine.to_spec(*_tensor).to_string();
- auto rhs_spec = engine.to_spec(*rhs._tensor).to_string();
+ auto lhs_spec = spec_from_value(*_tensor).to_string();
+ auto rhs_spec = spec_from_value(*rhs._tensor).to_string();
return lhs_spec.compare(rhs_spec);
}
diff --git a/document/src/vespa/document/fieldvalue/tensorfieldvalue.h b/document/src/vespa/document/fieldvalue/tensorfieldvalue.h
index 2840ff8fc3e..e6af697e696 100644
--- a/document/src/vespa/document/fieldvalue/tensorfieldvalue.h
+++ b/document/src/vespa/document/fieldvalue/tensorfieldvalue.h
@@ -4,7 +4,6 @@
#include "fieldvalue.h"
-namespace vespalib { namespace tensor { class Tensor; } }
namespace vespalib::eval { struct Value; }
namespace document {
diff --git a/document/src/vespa/document/serialization/vespadocumentdeserializer.cpp b/document/src/vespa/document/serialization/vespadocumentdeserializer.cpp
index eaa5a484ad1..6567b8cb6b5 100644
--- a/document/src/vespa/document/serialization/vespadocumentdeserializer.cpp
+++ b/document/src/vespa/document/serialization/vespadocumentdeserializer.cpp
@@ -22,7 +22,8 @@
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/backtrace.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/document/util/serializableexceptions.h>
#include <vespa/document/base/exceptions.h>
@@ -41,7 +42,7 @@ using vespalib::nbostream;
using vespalib::Memory;
using vespalib::stringref;
using vespalib::compression::CompressionConfig;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
namespace document {
@@ -372,7 +373,7 @@ VespaDocumentDeserializer::readTensor()
std::unique_ptr<vespalib::eval::Value> tensor;
if (length != 0) {
nbostream wrapStream(_stream.peek(), length);
- tensor = EngineOrFactory::get().decode(wrapStream);
+ tensor = vespalib::eval::decode_value(wrapStream, FastValueBuilderFactory::get());
if (wrapStream.size() != 0) {
throw DeserializeException("Leftover bytes deserializing tensor field value.", VESPA_STRLOC);
}
diff --git a/document/src/vespa/document/serialization/vespadocumentserializer.cpp b/document/src/vespa/document/serialization/vespadocumentserializer.cpp
index 882dc4e83f3..9b8fe6b120a 100644
--- a/document/src/vespa/document/serialization/vespadocumentserializer.cpp
+++ b/document/src/vespa/document/serialization/vespadocumentserializer.cpp
@@ -27,7 +27,7 @@
#include <vespa/document/update/updates.h>
#include <vespa/document/util/bytebuffer.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/data/databuffer.h>
#include <vespa/vespalib/data/slime/binary_format.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -371,7 +371,7 @@ VespaDocumentSerializer::write(const TensorFieldValue &value) {
vespalib::nbostream tmpStream;
auto tensor = value.getAsTensorPtr();
if (tensor) {
- vespalib::eval::EngineOrFactory::get().encode(*tensor, tmpStream);
+ encode_value(*tensor, tmpStream);
assert( ! tmpStream.empty());
_stream.putInt1_4Bytes(tmpStream.size());
_stream.write(tmpStream.peek(), tmpStream.size());
diff --git a/document/src/vespa/document/update/CMakeLists.txt b/document/src/vespa/document/update/CMakeLists.txt
index a587d8e3e2d..b0ffa056e1a 100644
--- a/document/src/vespa/document/update/CMakeLists.txt
+++ b/document/src/vespa/document/update/CMakeLists.txt
@@ -15,6 +15,7 @@ vespa_add_library(document_updates OBJECT
removevalueupdate.cpp
tensor_add_update.cpp
tensor_modify_update.cpp
+ tensor_partial_update.cpp
tensor_remove_update.cpp
valueupdate.cpp
DEPENDS
diff --git a/document/src/vespa/document/update/tensor_add_update.cpp b/document/src/vespa/document/update/tensor_add_update.cpp
index 3ae599f22a0..c8ce728172e 100644
--- a/document/src/vespa/document/update/tensor_add_update.cpp
+++ b/document/src/vespa/document/update/tensor_add_update.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_add_update.h"
+#include "tensor_partial_update.h"
#include <vespa/document/base/exceptions.h>
#include <vespa/document/base/field.h>
#include <vespa/document/datatype/tensor_data_type.h>
@@ -9,9 +10,7 @@
#include <vespa/document/serialization/vespadocumentdeserializer.h>
#include <vespa/document/util/serializableexceptions.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -21,8 +20,7 @@
using vespalib::IllegalArgumentException;
using vespalib::IllegalStateException;
using vespalib::make_string;
-using vespalib::eval::EngineOrFactory;
-using vespalib::tensor::TensorPartialUpdate;
+using vespalib::eval::FastValueBuilderFactory;
namespace document {
@@ -87,8 +85,8 @@ TensorAddUpdate::applyTo(const vespalib::eval::Value &tensor) const
{
auto addTensor = _tensor->getAsTensorPtr();
if (addTensor) {
- auto engine = EngineOrFactory::get();
- return TensorPartialUpdate::add(tensor, *addTensor, engine);
+ const auto &factory = FastValueBuilderFactory::get();
+ return TensorPartialUpdate::add(tensor, *addTensor, factory);
}
return {};
}
diff --git a/document/src/vespa/document/update/tensor_modify_update.cpp b/document/src/vespa/document/update/tensor_modify_update.cpp
index 2ff45b11b07..f7fca784ab2 100644
--- a/document/src/vespa/document/update/tensor_modify_update.cpp
+++ b/document/src/vespa/document/update/tensor_modify_update.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_modify_update.h"
+#include "tensor_partial_update.h"
#include <vespa/document/base/exceptions.h>
#include <vespa/document/base/field.h>
#include <vespa/document/datatype/tensor_data_type.h>
@@ -10,10 +11,7 @@
#include <vespa/document/util/serializableexceptions.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/cell_values.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -24,8 +22,7 @@ using vespalib::IllegalArgumentException;
using vespalib::IllegalStateException;
using vespalib::make_string;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
-using vespalib::tensor::TensorPartialUpdate;
+using vespalib::eval::FastValueBuilderFactory;
using join_fun_t = double (*)(double, double);
@@ -165,8 +162,8 @@ TensorModifyUpdate::applyTo(const vespalib::eval::Value &tensor) const
{
auto cellsTensor = _tensor->getAsTensorPtr();
if (cellsTensor) {
- auto engine = EngineOrFactory::get();
- return TensorPartialUpdate::modify(tensor, getJoinFunction(_operation), *cellsTensor, engine);
+ const auto &factory = FastValueBuilderFactory::get();
+ return TensorPartialUpdate::modify(tensor, getJoinFunction(_operation), *cellsTensor, factory);
}
return {};
}
@@ -215,8 +212,7 @@ verifyCellsTensorIsSparse(const vespalib::eval::Value *cellsTensor)
if (cellsTensor == nullptr) {
return;
}
- auto engine = EngineOrFactory::get();
- if (TensorPartialUpdate::check_suitably_sparse(*cellsTensor, engine)) {
+ if (cellsTensor->type().is_sparse()) {
return;
}
vespalib::string err = make_string("Expected cells tensor to be sparse, but has type '%s'",
diff --git a/eval/src/vespa/eval/tensor/partial_update.cpp b/document/src/vespa/document/update/tensor_partial_update.cpp
index fa15b2a38ae..fbc60cc09af 100644
--- a/eval/src/vespa/eval/tensor/partial_update.cpp
+++ b/document/src/vespa/document/update/tensor_partial_update.cpp
@@ -1,22 +1,20 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "partial_update.h"
+#include "tensor_partial_update.h"
#include <vespa/eval/eval/operation.h>
#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/util/visit_ranges.h>
#include <cassert>
#include <set>
-#include "tensor.h"
-#include "cell_values.h"
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
#include <vespa/log/log.h>
LOG_SETUP(".eval.tensor.partial_update");
+using namespace vespalib;
using namespace vespalib::eval;
-namespace vespalib::tensor {
+namespace document {
namespace {
@@ -419,62 +417,4 @@ TensorPartialUpdate::remove(const Value &input, const Value &remove_spec, const
input, remove_spec, factory);
}
-Value::UP
-TensorPartialUpdate::modify(const Value &input, join_fun_t function,
- const Value &modifier, EngineOrFactory engine)
-{
- if (engine.is_engine()) {
- auto inp_ptr = dynamic_cast<const tensor::Tensor *>(&input);
- auto mod_ptr = dynamic_cast<const SparseTensor *>(&modifier);
- if (inp_ptr && mod_ptr) {
- vespalib::tensor::CellValues cellValues(*mod_ptr);
- return inp_ptr->modify(function, cellValues);
- }
- return {};
- } else {
- return modify(input, function, modifier, engine.factory());
- }
-}
-
-Value::UP
-TensorPartialUpdate::add(const Value &input, const Value &add_cells, EngineOrFactory engine)
-{
- if (engine.is_engine()) {
- auto inp_ptr = dynamic_cast<const tensor::Tensor *>(&input);
- auto add_ptr = dynamic_cast<const tensor::Tensor *>(&add_cells);
- if (inp_ptr && add_ptr) {
- return inp_ptr->add(*add_ptr);
- }
- return {};
- } else {
- return add(input, add_cells, engine.factory());
- }
-}
-
-Value::UP
-TensorPartialUpdate::remove(const Value &input, const Value &remove_spec, EngineOrFactory engine)
-{
- if (engine.is_engine()) {
- auto inp_ptr = dynamic_cast<const tensor::Tensor *>(&input);
- auto rem_ptr = dynamic_cast<const SparseTensor *>(&remove_spec);
- if (inp_ptr && rem_ptr) {
- vespalib::tensor::CellValues cellAddresses(*rem_ptr);
- return inp_ptr->remove(cellAddresses);
- }
- return {};
- } else {
- return remove(input, remove_spec, engine.factory());
- }
-}
-
-bool
-TensorPartialUpdate::check_suitably_sparse(const Value &modifier, const EngineOrFactory engine)
-{
- if (engine.is_engine()) {
- return (dynamic_cast<const SparseTensor *>(&modifier) != nullptr);
- } else {
- return modifier.type().is_sparse();
- }
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/tensor/partial_update.h b/document/src/vespa/document/update/tensor_partial_update.h
index 6bbef6a8189..55340de18f8 100644
--- a/eval/src/vespa/eval/tensor/partial_update.h
+++ b/document/src/vespa/document/update/tensor_partial_update.h
@@ -2,11 +2,11 @@
#pragma once
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
-namespace vespalib::tensor {
+namespace document {
struct TensorPartialUpdate {
using join_fun_t = vespalib::eval::operation::op2_t;
@@ -39,15 +39,6 @@ struct TensorPartialUpdate {
* Returns null pointer if these constraints are violated.
**/
static Value::UP remove(const Value &input, const Value &remove_spec, const ValueBuilderFactory &factory);
-
- /* Backwards compatibility adapters. TODO: remove */
- using EngineOrFactory = vespalib::eval::EngineOrFactory;
- static Value::UP modify(const Value &input, join_fun_t function,
- const Value &modifier, EngineOrFactory factory);
- static Value::UP add(const Value &input, const Value &add_cells, EngineOrFactory factory);
- static Value::UP remove(const Value &input, const Value &remove_spec, EngineOrFactory factory);
- /** Check if the given value can be used as a modifier or remove_spec */
- static bool check_suitably_sparse(const Value &modifier, EngineOrFactory factory);
};
} // namespace
diff --git a/document/src/vespa/document/update/tensor_remove_update.cpp b/document/src/vespa/document/update/tensor_remove_update.cpp
index 688f9cf5399..b3a7e93c86a 100644
--- a/document/src/vespa/document/update/tensor_remove_update.cpp
+++ b/document/src/vespa/document/update/tensor_remove_update.cpp
@@ -1,16 +1,13 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_remove_update.h"
+#include "tensor_partial_update.h"
#include <vespa/document/base/exceptions.h>
#include <vespa/document/datatype/tensor_data_type.h>
#include <vespa/document/fieldvalue/document.h>
#include <vespa/document/fieldvalue/tensorfieldvalue.h>
#include <vespa/document/serialization/vespadocumentdeserializer.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/partial_update.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/xmlstream.h>
@@ -22,8 +19,7 @@ using vespalib::IllegalStateException;
using vespalib::make_string;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
-using vespalib::tensor::TensorPartialUpdate;
+using vespalib::eval::FastValueBuilderFactory;
namespace document {
@@ -113,8 +109,8 @@ TensorRemoveUpdate::applyTo(const vespalib::eval::Value &tensor) const
{
auto addressTensor = _tensor->getAsTensorPtr();
if (addressTensor) {
- auto engine = EngineOrFactory::get();
- return TensorPartialUpdate::remove(tensor, *addressTensor, engine);
+ const auto &factory = FastValueBuilderFactory::get();
+ return TensorPartialUpdate::remove(tensor, *addressTensor, factory);
}
return {};
}
@@ -163,8 +159,7 @@ verifyAddressTensorIsSparse(const Value *addressTensor)
if (addressTensor == nullptr) {
throw IllegalStateException("Address tensor is not set", VESPA_STRLOC);
}
- auto engine = EngineOrFactory::get();
- if (TensorPartialUpdate::check_suitably_sparse(*addressTensor, engine)) {
+ if (addressTensor->type().is_sparse()) {
return;
}
auto err = make_string("Expected address tensor to be sparse, but has type '%s'",
diff --git a/documentapi/CMakeLists.txt b/documentapi/CMakeLists.txt
index 86d29732399..855fd7ad0e6 100644
--- a/documentapi/CMakeLists.txt
+++ b/documentapi/CMakeLists.txt
@@ -15,7 +15,6 @@ vespa_define_module(
LIBS
src/vespa/documentapi
- src/vespa/documentapi/loadtypes
src/vespa/documentapi/messagebus
src/vespa/documentapi/messagebus/messages
src/vespa/documentapi/messagebus/policies
@@ -24,7 +23,6 @@ vespa_define_module(
messagebus_messagebus-test
TESTS
- src/tests/loadtypes
src/tests/messagebus
src/tests/messages
src/tests/policies
diff --git a/documentapi/abi-spec.json b/documentapi/abi-spec.json
index 337cff774c5..a70f59bb9fb 100644
--- a/documentapi/abi-spec.json
+++ b/documentapi/abi-spec.json
@@ -1934,6 +1934,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig build()"
],
"fields": [
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusDocumentAccess.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusDocumentAccess.java
index 9832529c157..eaa35047c2d 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusDocumentAccess.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusDocumentAccess.java
@@ -67,7 +67,7 @@ public class MessageBusDocumentAccess extends DocumentAccess {
if (params.getRPCNetworkParams().getSlobroksConfig() != null && mbusParams.getMessageBusConfig() != null)
bus = new RPCMessageBus(mbusParams, params.getRPCNetworkParams());
else {
- log.log(Level.FINE, () -> "Setting up self-subscription to config because explicit config was missing; try to avoid this in containers");
+ log.log(Level.FINE, () -> "Setting up self-subscription to config because explicit config was missing; try to avoid this in containers");
bus = new RPCMessageBus(mbusParams, params.getRPCNetworkParams(), params.getRoutingConfigId());
}
}
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
index 0ad791a3213..a838f3b8723 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
@@ -7,7 +7,7 @@ import com.yahoo.messagebus.SourceSessionParams;
import com.yahoo.messagebus.network.rpc.RPCNetworkParams;
/**
- * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ * @author Einar M R Rosenvinge
*/
public class MessageBusParams extends DocumentAccessParams {
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
index 29db9e318d8..ca32c5722e6 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
@@ -90,7 +90,7 @@ public class DocumentProtocol implements Protocol {
* longer be guaranteed.
*/
- /** Used by policies to indicate an inappropriate message. */
+ /** Used by policies to indicate an inappropriate message. */
public static final int ERROR_MESSAGE_IGNORED = ErrorCode.APP_FATAL_ERROR + 1;
/** Used for error policy when policy creation failed. */
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocolRoutingPolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocolRoutingPolicy.java
index 450f53c4440..e6ef169cba2 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocolRoutingPolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocolRoutingPolicy.java
@@ -6,5 +6,4 @@ import com.yahoo.messagebus.routing.RoutingPolicy;
/**
* @author thomasg
*/
-public interface DocumentProtocolRoutingPolicy extends RoutingPolicy {
-}
+public interface DocumentProtocolRoutingPolicy extends RoutingPolicy { }
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LoadBalancerPolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LoadBalancerPolicy.java
index 3c670299f3e..e59d253b851 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LoadBalancerPolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LoadBalancerPolicy.java
@@ -21,7 +21,7 @@ import java.util.Map;
*
* If both slobroks and config is specified, the list from slobroks is used.
*
- * @author <a href="mailto:humbe@yahoo-inc.com">Haakon Humberset</a>
+ * @author Haakon Humberset
*/
public class LoadBalancerPolicy extends SlobrokPolicy {
private final String session;
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
index 15967f9e693..6ea5020607e 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
@@ -14,7 +14,7 @@ public interface RoutingPolicyFactory {
/**
* This method creates and returns a routing policy that corresponds to the implementing class, using the given
* parameter string. There is only ever one instance of a routing policy for a given name and parameter combination,
- * and because of this the policies must be state-less beyond what can be derived from the parameter string. Because
+ * and because of this the policies must be stateless beyond what can be derived from the parameter string. Because
* there is only a single thread running route resolution within message bus, it is not necessary to make policies
* thread-safe. For more information see {@link RoutingPolicy}.
*
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/StoragePolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/StoragePolicy.java
index 5594b9f9db4..b74f7431531 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/StoragePolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/StoragePolicy.java
@@ -40,7 +40,6 @@ import java.util.logging.Logger;
*
* cluster=[clusterName] (Mandatory, determines the cluster name)
* config=[config] (Optional, a comma separated list of config servers to use. Used to talk to clusters not defined in this vespa application)
- * slobrokconfigid=[id] (Optional, use given config id for slobrok instead of default)
* clusterconfigid=[id] (Optional, use given config id for distribution instead of default)
*
* @author Haakon Humberset
diff --git a/documentapi/src/tests/loadtypes/.gitignore b/documentapi/src/tests/loadtypes/.gitignore
deleted file mode 100644
index 497fe4d4b3f..00000000000
--- a/documentapi/src/tests/loadtypes/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.depend
-Makefile
-documentapi_loadtype_test_app
diff --git a/documentapi/src/tests/loadtypes/CMakeLists.txt b/documentapi/src/tests/loadtypes/CMakeLists.txt
deleted file mode 100644
index bac42f9a27e..00000000000
--- a/documentapi/src/tests/loadtypes/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(documentapi_loadtype_test_app TEST
- SOURCES
- loadtypetest.cpp
- DEPENDS
- documentapi
- vdstestlib
- GTest::GTest
-)
-vespa_add_test(NAME documentapi_loadtype_test_app COMMAND documentapi_loadtype_test_app)
diff --git a/documentapi/src/tests/loadtypes/loadtypetest.cpp b/documentapi/src/tests/loadtypes/loadtypetest.cpp
deleted file mode 100644
index 178b9f9227b..00000000000
--- a/documentapi/src/tests/loadtypes/loadtypetest.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
-#include <vespa/config/config.h>
-#include <vespa/config/common/exceptions.h>
-#include <vespa/vespalib/gtest/gtest.h>
-
-namespace documentapi {
-
-void
-assertConfigFailure(const vespalib::string &configId, const vespalib::string &expError)
-{
- try {
- LoadTypeSet createdFromConfigId(configId);
- FAIL() << "Config was expected to fail with error: " << expError;
- } catch (config::InvalidConfigException &e) {
- EXPECT_TRUE(e.getMessage().find(expError) != std::string::npos);
- }
-}
-
-TEST(LoadTypeTest, testConfig)
-{
- // Using id 0 is illegal. Reserved for default type.
- assertConfigFailure(
- "raw:"
- "type[1]\n"
- "type[0].id 0\n"
- "type[0].name \"foo\"\n"
- "type[0].priority \"\"",
- "Load type identifiers need to be");
- // Using name "default" is illegal. Reserved for default type.
- assertConfigFailure(
- "raw:"
- "type[1]\n"
- "type[0].id 1\n"
- "type[0].name \"default\"\n"
- "type[0].priority \"\"", "Load type names need to be");
- // Identifiers need to be unique.
- assertConfigFailure(
- "raw:"
- "type[2]\n"
- "type[0].id 1\n"
- "type[0].name \"test\"\n"
- "type[0].priority \"\"\n"
- "type[1].id 1\n"
- "type[1].name \"testa\"\n"
- "type[1].priority \"\"", "Load type identifiers need to be");
- // Names need to be unique.
- assertConfigFailure(
- "raw:"
- "type[2]\n"
- "type[0].id 1\n"
- "type[0].name \"test\"\n"
- "type[0].priority \"\"\n"
- "type[1].id 2\n"
- "type[1].name \"test\"\n"
- "type[1].priority \"\"" , "Load type names need to be");
- LoadTypeSet set("raw:"
- "type[3]\n"
- "type[0].id 1\n"
- "type[0].name \"user\"\n"
- "type[0].priority \"\"\n"
- "type[1].id 2\n"
- "type[1].name \"maintenance\"\n"
- "type[1].priority \"\"\n"
- "type[2].id 3\n"
- "type[2].name \"put\"\n"
- "type[2].priority \"\""
- );
-}
-
-} // documentapi
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/documentapi/src/tests/messagebus/messagebus_test.cpp b/documentapi/src/tests/messagebus/messagebus_test.cpp
index 3406db966f0..8f60bbc78e4 100644
--- a/documentapi/src/tests/messagebus/messagebus_test.cpp
+++ b/documentapi/src/tests/messagebus/messagebus_test.cpp
@@ -2,12 +2,9 @@
#include <vespa/document/base/testdocrepo.h>
#include <vespa/document/datatype/documenttype.h>
-#include <vespa/document/fieldvalue/document.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/update/documentupdate.h>
#include <vespa/documentapi/documentapi.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
-#include <vespa/vdslib/state/clusterstate.h>
#include <vespa/vespalib/testkit/testapp.h>
using document::DocumentTypeRepo;
@@ -66,8 +63,7 @@ void Test::testMessage() {
EXPECT_TRUE(upd1.getType() == DocumentProtocol::MESSAGE_UPDATEDOCUMENT);
EXPECT_TRUE(upd1.getProtocol() == "document");
- LoadTypeSet set;
- DocumentProtocol protocol(set, _repo);
+ DocumentProtocol protocol(_repo);
Blob blob = protocol.encode(vespalib::Version(6,221), upd1);
EXPECT_TRUE(blob.size() > 0);
@@ -89,8 +85,7 @@ void Test::testMessage() {
}
void Test::testProtocol() {
- LoadTypeSet set;
- DocumentProtocol protocol(set, _repo);
+ DocumentProtocol protocol(_repo);
EXPECT_TRUE(protocol.getName() == "document");
IRoutingPolicy::UP policy = protocol.createPolicy(string("DocumentRouteSelector"), string("file:documentrouteselectorpolicy.cfg"));
diff --git a/documentapi/src/tests/messages/testbase.cpp b/documentapi/src/tests/messages/testbase.cpp
index 18902cb39a7..967c9990800 100644
--- a/documentapi/src/tests/messages/testbase.cpp
+++ b/documentapi/src/tests/messages/testbase.cpp
@@ -19,11 +19,9 @@ TestBase::TestBase() :
_repo(new DocumentTypeRepo(readDocumenttypesConfig(
TEST_PATH("../../../test/cfg/testdoctypes.cfg")))),
_dataPath(TEST_PATH("../../../test/crosslanguagefiles")),
- _loadTypes(),
- _protocol(_loadTypes, _repo),
+ _protocol(_repo),
_tests()
{
- _loadTypes.addLoadType(34, "foo", Priority::PRI_NORMAL_2);
}
int
diff --git a/documentapi/src/tests/messages/testbase.h b/documentapi/src/tests/messages/testbase.h
index e87f9104189..89398552f63 100644
--- a/documentapi/src/tests/messages/testbase.h
+++ b/documentapi/src/tests/messages/testbase.h
@@ -2,10 +2,10 @@
#pragma once
#include <vespa/documentapi/messagebus/documentprotocol.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/messagebus/routable.h>
#include <vespa/vespalib/component/version.h>
#include <vespa/vespalib/testkit/testapp.h>
+#include <map>
using namespace documentapi;
@@ -24,8 +24,7 @@ typedef bool (TestBase::*TEST_METHOD_PT)();
class TestBase : public vespalib::TestApp {
std::shared_ptr<const document::DocumentTypeRepo> _repo;
protected:
- const string _dataPath;
- LoadTypeSet _loadTypes;
+ const string _dataPath;
DocumentProtocol _protocol;
std::map<uint32_t, TEST_METHOD_PT> _tests;
diff --git a/documentapi/src/tests/policies/policies_test.cpp b/documentapi/src/tests/policies/policies_test.cpp
index a4eaf54c1dc..0c659f589d6 100644
--- a/documentapi/src/tests/policies/policies_test.cpp
+++ b/documentapi/src/tests/policies/policies_test.cpp
@@ -45,7 +45,6 @@ using namespace std::chrono_literals;
class Test : public vespalib::TestApp {
private:
- LoadTypeSet _loadTypes;
std::shared_ptr<const DocumentTypeRepo> _repo;
const DataType *_docType;
@@ -140,7 +139,7 @@ Test::Main() {
void
Test::testProtocol()
{
- mbus::IProtocol::SP protocol(new DocumentProtocol(_loadTypes, _repo));
+ mbus::IProtocol::SP protocol(new DocumentProtocol(_repo));
mbus::IRoutingPolicy::UP policy = protocol->createPolicy("AND", "");
ASSERT_TRUE(dynamic_cast<ANDPolicy*>(policy.get()) != nullptr);
@@ -220,7 +219,7 @@ Test::requireThatExternPolicySelectsFromExternSlobrok()
for (uint32_t i = 0; i < 10; ++i) {
mbus::TestServer *server = new mbus::TestServer(
mbus::Identity(make_string("docproc/cluster.default/%d", i)), mbus::RoutingSpec(), slobrok,
- mbus::IProtocol::SP(new DocumentProtocol(_loadTypes, _repo)));
+ mbus::IProtocol::SP(new DocumentProtocol(_repo)));
servers.push_back(server);
server->net.registerSession("chain.default");
}
@@ -247,7 +246,7 @@ Test::requireThatExternPolicyMergesOneReplyAsProtocol()
frame.setMessage(newPutDocumentMessage("id:ns:testdoc::"));
mbus::Slobrok slobrok;
mbus::TestServer server(mbus::Identity("docproc/cluster.default/0"), mbus::RoutingSpec(), slobrok,
- mbus::IProtocol::SP(new DocumentProtocol(_loadTypes, _repo)));
+ mbus::IProtocol::SP(new DocumentProtocol(_repo)));
server.net.registerSession("chain.default");
setupExternPolicy(frame, slobrok, "docproc/cluster.default/0/chain.default", 1);
EXPECT_TRUE(frame.testMergeOneReply(server.net.getConnectionSpec() + "/chain.default"));
@@ -310,7 +309,7 @@ Test::testExternSend()
// Setup local source node.
mbus::Slobrok local;
mbus::TestServer src(mbus::Identity("src"), mbus::RoutingSpec(), local,
- std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ std::make_shared<DocumentProtocol>(_repo));
mbus::Receptor sr;
mbus::SourceSession::UP ss = src.mb.createSourceSession(sr, mbus::SourceSessionParams().setTimeout(60s));
@@ -319,12 +318,12 @@ Test::testExternSend()
.addTable(mbus::RoutingTableSpec(DocumentProtocol::NAME)
.addRoute(mbus::RouteSpec("default").addHop("dst"))
.addHop(mbus::HopSpec("dst", "dst/session"))),
- slobrok, std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ slobrok, std::make_shared<DocumentProtocol>(_repo));
mbus::Receptor ir;
mbus::IntermediateSession::UP is = itr.mb.createIntermediateSession("session", true, ir, ir);
mbus::TestServer dst(mbus::Identity("dst"), mbus::RoutingSpec(), slobrok,
- std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ std::make_shared<DocumentProtocol>(_repo));
mbus::Receptor dr;
mbus::DestinationSession::UP ds = dst.mb.createDestinationSession("session", true, dr);
@@ -351,7 +350,7 @@ Test::testExternMultipleSlobroks()
{
mbus::Slobrok local;
mbus::TestServer src(mbus::Identity("src"), mbus::RoutingSpec(), local,
- std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ std::make_shared<DocumentProtocol>(_repo));
mbus::Receptor sr;
mbus::SourceSession::UP ss = src.mb.createSourceSession(sr, mbus::SourceSessionParams().setTimeout(60s));
@@ -362,7 +361,7 @@ Test::testExternMultipleSlobroks()
spec.append(vespalib::make_string("tcp/localhost:%d", ext.port()));
mbus::TestServer dst(mbus::Identity("dst"), mbus::RoutingSpec(), ext,
- std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ std::make_shared<DocumentProtocol>(_repo));
mbus::DestinationSession::UP ds = dst.mb.createDestinationSession("session", true, dr);
mbus::Message::UP msg = std::make_unique<GetDocumentMessage>(DocumentId("id:ns:testdoc::"));
@@ -378,7 +377,7 @@ Test::testExternMultipleSlobroks()
spec.append(vespalib::make_string(",tcp/localhost:%d", ext.port()));
mbus::TestServer dst(mbus::Identity("dst"), mbus::RoutingSpec(), ext,
- std::make_shared<DocumentProtocol>(_loadTypes, _repo));
+ std::make_shared<DocumentProtocol>(_repo));
mbus::DestinationSession::UP ds = dst.mb.createDestinationSession("session", true, dr);
mbus::Message::UP msg = std::make_unique<GetDocumentMessage>(DocumentId("id:ns:testdoc::"));
@@ -592,12 +591,12 @@ Test::testDocumentRouteSelector()
"route[0].selector \"foo bar\"\n"
"route[0].feed \"baz\"\n";
{
- DocumentProtocol protocol(_loadTypes, _repo, okConfig);
+ DocumentProtocol protocol(_repo, okConfig);
EXPECT_TRUE(dynamic_cast<DocumentRouteSelectorPolicy*>(protocol.createPolicy("DocumentRouteSelector", "").get()) != nullptr);
EXPECT_TRUE(dynamic_cast<ErrorPolicy*>(protocol.createPolicy("DocumentRouteSelector", errConfig).get()) != nullptr);
}
{
- DocumentProtocol protocol(_loadTypes, _repo, errConfig);
+ DocumentProtocol protocol(_repo, errConfig);
EXPECT_TRUE(dynamic_cast<ErrorPolicy*>(protocol.createPolicy("DocumentRouteSelector", "").get()) != nullptr);
EXPECT_TRUE(dynamic_cast<DocumentRouteSelectorPolicy*>(protocol.createPolicy("DocumentRouteSelector", okConfig).get()) != nullptr);
}
@@ -802,7 +801,7 @@ Test::requireThatStoragePolicyIsRandomWithoutState()
mbus::TestServer *srv = new mbus::TestServer(
mbus::Identity(vespalib::make_string("storage/cluster.mycluster/distributor/%d", i)),
mbus::RoutingSpec(), slobrok,
- mbus::IProtocol::SP(new DocumentProtocol(_loadTypes, _repo)));
+ mbus::IProtocol::SP(new DocumentProtocol(_repo)));
servers.push_back(srv);
srv->net.registerSession("default");
}
@@ -857,7 +856,7 @@ Test::requireThatStoragePolicyIsTargetedWithState()
mbus::TestServer *srv = new mbus::TestServer(
mbus::Identity(vespalib::make_string("storage/cluster.mycluster/distributor/%d", i)),
mbus::RoutingSpec(), slobrok,
- make_shared<DocumentProtocol>(_loadTypes, _repo));
+ make_shared<DocumentProtocol>(_repo));
servers.push_back(srv);
srv->net.registerSession("default");
}
@@ -897,7 +896,7 @@ Test::requireThatStoragePolicyCombinesSystemAndSlobrokState()
mbus::Slobrok slobrok;
mbus::TestServer server(mbus::Identity("storage/cluster.mycluster/distributor/0"),
mbus::RoutingSpec(), slobrok,
- make_shared<DocumentProtocol>(_loadTypes, _repo));
+ make_shared<DocumentProtocol>(_repo));
server.net.registerSession("default");
string param = vespalib::make_string(
@@ -1053,7 +1052,7 @@ Test::trySelect(TestFrame &frame, uint32_t numSelects, const std::vector<string>
bool
Test::isErrorPolicy(const string &name, const string &param)
{
- DocumentProtocol protocol(_loadTypes, _repo);
+ DocumentProtocol protocol(_repo);
mbus::IRoutingPolicy::UP policy = protocol.createPolicy(name, param);
return policy && dynamic_cast<ErrorPolicy*>(policy.get()) != nullptr;
diff --git a/documentapi/src/tests/policies/testframe.cpp b/documentapi/src/tests/policies/testframe.cpp
index 585885b7c4b..16ee97ce7f4 100644
--- a/documentapi/src/tests/policies/testframe.cpp
+++ b/documentapi/src/tests/policies/testframe.cpp
@@ -60,9 +60,8 @@ public:
TestFrame::TestFrame(const std::shared_ptr<const DocumentTypeRepo> &repo, const string &ident) :
_identity(ident),
_slobrok(std::make_shared<mbus::Slobrok>()),
- _set(),
_net(std::make_shared<MyNetwork>(mbus::RPCNetworkParams(_slobrok->config()).setIdentity(mbus::Identity(ident)))),
- _mbus(std::make_shared<mbus::MessageBus>(*_net, mbus::MessageBusParams().addProtocol(std::make_shared<DocumentProtocol>(_set, repo)))),
+ _mbus(std::make_shared<mbus::MessageBus>(*_net, mbus::MessageBusParams().addProtocol(std::make_shared<DocumentProtocol>(repo)))),
_msg(),
_hop(mbus::HopSpec("foo", "bar")),
_handler()
diff --git a/documentapi/src/tests/policies/testframe.h b/documentapi/src/tests/policies/testframe.h
index d85cde129c0..41f953922f9 100644
--- a/documentapi/src/tests/policies/testframe.h
+++ b/documentapi/src/tests/policies/testframe.h
@@ -7,7 +7,6 @@
#include <vespa/messagebus/network/inetwork.h>
#include <vespa/messagebus/testlib/receptor.h>
#include <vespa/messagebus/testlib/slobrok.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
using documentapi::string;
@@ -15,7 +14,6 @@ class TestFrame : public mbus::IReplyHandler {
private:
string _identity;
std::shared_ptr<mbus::Slobrok> _slobrok;
- documentapi::LoadTypeSet _set;
std::shared_ptr<mbus::INetwork> _net;
std::shared_ptr<mbus::MessageBus> _mbus;
mbus::Message::UP _msg;
diff --git a/documentapi/src/tests/policyfactory/policyfactory.cpp b/documentapi/src/tests/policyfactory/policyfactory.cpp
index 729818c5c4a..8c38e93e659 100644
--- a/documentapi/src/tests/policyfactory/policyfactory.cpp
+++ b/documentapi/src/tests/policyfactory/policyfactory.cpp
@@ -2,7 +2,6 @@
#include <vespa/documentapi/messagebus/iroutingpolicyfactory.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/documentapi/messagebus/documentprotocol.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/documentapi/messagebus/messages/removedocumentmessage.h>
#include <vespa/messagebus/testlib/receptor.h>
#include <vespa/messagebus/testlib/slobrok.h>
@@ -82,9 +81,8 @@ Test::Main()
std::shared_ptr<const DocumentTypeRepo> repo(new DocumentTypeRepo);
mbus::Slobrok slobrok;
- LoadTypeSet loadTypes;
mbus::TestServer
- srv(mbus::MessageBusParams().addProtocol(std::make_shared<DocumentProtocol>(loadTypes, repo)),
+ srv(mbus::MessageBusParams().addProtocol(std::make_shared<DocumentProtocol>(repo)),
mbus::RPCNetworkParams(slobrok.config()));
mbus::Receptor handler;
mbus::SourceSession::UP src = srv.mb.createSourceSession(mbus::SourceSessionParams().setReplyHandler(handler));
diff --git a/documentapi/src/tests/routablefactory/routablefactory.cpp b/documentapi/src/tests/routablefactory/routablefactory.cpp
index 32a36ef0b59..92e982b2be4 100644
--- a/documentapi/src/tests/routablefactory/routablefactory.cpp
+++ b/documentapi/src/tests/routablefactory/routablefactory.cpp
@@ -6,7 +6,6 @@
#include <vespa/messagebus/testlib/slobrok.h>
#include <vespa/messagebus/testlib/testserver.h>
#include <vespa/vespalib/testkit/testapp.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
using document::DocumentTypeRepo;
using namespace documentapi;
@@ -87,7 +86,6 @@ class TestData {
public:
mbus::Slobrok _slobrok;
- LoadTypeSet _loadTypes;
DocumentProtocol::SP _srcProtocol;
mbus::TestServer _srcServer;
mbus::SourceSession::UP _srcSession;
@@ -116,13 +114,12 @@ TEST_APPHOOK(Test);
TestData::TestData() :
_repo(std::make_shared<DocumentTypeRepo>()),
_slobrok(),
- _loadTypes(),
- _srcProtocol(std::make_shared<DocumentProtocol>(_loadTypes, _repo)),
+ _srcProtocol(std::make_shared<DocumentProtocol>(_repo)),
_srcServer(mbus::MessageBusParams().addProtocol(_srcProtocol),
mbus::RPCNetworkParams(_slobrok.config())),
_srcSession(),
_srcHandler(),
- _dstProtocol(std::make_shared<DocumentProtocol>(_loadTypes, _repo)),
+ _dstProtocol(std::make_shared<DocumentProtocol>(_repo)),
_dstServer(mbus::MessageBusParams().addProtocol(_dstProtocol),
mbus::RPCNetworkParams(_slobrok.config()).setIdentity(mbus::Identity("dst"))),
_dstSession(),
diff --git a/documentapi/src/vespa/documentapi/CMakeLists.txt b/documentapi/src/vespa/documentapi/CMakeLists.txt
index 46bc0239834..3011259f856 100644
--- a/documentapi/src/vespa/documentapi/CMakeLists.txt
+++ b/documentapi/src/vespa/documentapi/CMakeLists.txt
@@ -4,7 +4,6 @@ vespa_add_library(documentapi
$<TARGET_OBJECTS:documentapi_documentapimessagebus>
$<TARGET_OBJECTS:documentapi_documentapimessages>
$<TARGET_OBJECTS:documentapi_documentapipolicies>
- $<TARGET_OBJECTS:documentapi_documentapiloadtypes>
INSTALL lib64
DEPENDS
)
diff --git a/documentapi/src/vespa/documentapi/loadtypes/CMakeLists.txt b/documentapi/src/vespa/documentapi/loadtypes/CMakeLists.txt
deleted file mode 100644
index 42f4d66af07..00000000000
--- a/documentapi/src/vespa/documentapi/loadtypes/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_library(documentapi_documentapiloadtypes OBJECT
- SOURCES
- loadtype.cpp
- loadtypeset.cpp
- DEPENDS
-)
diff --git a/documentapi/src/vespa/documentapi/loadtypes/loadtype.cpp b/documentapi/src/vespa/documentapi/loadtypes/loadtype.cpp
deleted file mode 100644
index 5dfdfb0bc09..00000000000
--- a/documentapi/src/vespa/documentapi/loadtypes/loadtype.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "loadtype.h"
-#include <vespa/vespalib/stllike/asciistream.h>
-
-namespace documentapi {
-
-const LoadType LoadType::DEFAULT(0, "default", Priority::PRI_NORMAL_3);
-
-void
-LoadType::print(vespalib::asciistream & os) const
-{
- os << "LoadType(" << getId() << ": " << getName() << ")";
-}
-
-} // documentapi
diff --git a/documentapi/src/vespa/documentapi/loadtypes/loadtype.h b/documentapi/src/vespa/documentapi/loadtypes/loadtype.h
deleted file mode 100644
index a18142e78bd..00000000000
--- a/documentapi/src/vespa/documentapi/loadtypes/loadtype.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * \class LoadType
- * \ingroup loadtype
- *
- * \brief Class used to identify a given load type.
- *
- * A load type is a type given to a Vespa operation that is independent of the
- * message type, priority or such information. Load types are given by clients
- * to external load (if not given, default load type is used), and might also be
- * set by the system itself for maintenance load.
- */
-
-#pragma once
-
-#include <vespa/metrics/loadtype.h>
-#include <vespa/documentapi/messagebus/priority.h>
-
-namespace vespalib {
- class asciistream;
-}
-
-namespace documentapi {
-
-// Inherit metrics loadtype so it is easy to use load types in load metrics.
-class LoadType : public metrics::LoadType {
- Priority::Value _priority;
-
-public:
- using UP = std::unique_ptr<LoadType>;
-
- LoadType(uint32_t id, const string& name, Priority::Value priority)
- : metrics::LoadType(id, name), _priority(priority) {}
- static const LoadType DEFAULT;
-
- Priority::Value getPriority() const { return _priority; }
-private:
- void print(vespalib::asciistream & os) const;
-};
-
-}
diff --git a/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.cpp b/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.cpp
deleted file mode 100644
index 42aa79332db..00000000000
--- a/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "loadtypeset.h"
-#include <vespa/config-load-type.h>
-#include <vespa/config/config.h>
-#include <vespa/config/common/exceptions.h>
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <vespa/config/helper/configgetter.hpp>
-
-
-namespace documentapi {
-
-void LoadTypeSet::configure(const LoadTypeConfig& config) {
- // This configure does not support live reconfig
- if (!_types.empty()) return;
-
- addLoadType(0, LoadType::DEFAULT.getName(), LoadType::DEFAULT.getPriority());
-
- for (uint32_t i=0; i<config.type.size(); ++i) {
- addLoadType(config.type[i].id, config.type[i].name, Priority::getPriority(config.type[i].priority));
- }
-}
-
-LoadTypeSet::LoadTypeSet()
-{
- addLoadType(0, LoadType::DEFAULT.getName(), LoadType::DEFAULT.getPriority());
-}
-
-LoadTypeSet::LoadTypeSet(const config::ConfigUri & configUri)
-{
- std::unique_ptr<LoadTypeConfig> cfg = config::ConfigGetter<LoadTypeConfig>::getConfig(configUri.getConfigId(), configUri.getContext());
- configure(*cfg);
-}
-
-LoadTypeSet::LoadTypeSet(const LoadTypeConfig& config)
-{
- configure(config);
-}
-
-LoadTypeSet::~LoadTypeSet() = default;
-
-void
-LoadTypeSet::addLoadType(uint32_t id, const string& name, Priority::Value priority) {
- auto it(_types.find(id));
- if (it != _types.end()) {
- throw config::InvalidConfigException("Load type identifiers need to be non-overlapping, 1+ and without gaps.\n", VESPA_STRLOC);
- }
- if (_nameMap.find(name) != _nameMap.end()) {
- throw config::InvalidConfigException("Load type names need to be unique and different from the reserved name \"default\".", VESPA_STRLOC);
- }
- _types[id] = std::make_unique<LoadType>(id, name, priority);
- _nameMap[name] = _types[id].get();
-}
-
-metrics::LoadTypeSet
-LoadTypeSet::getMetricLoadTypes() const {
- metrics::LoadTypeSet result;
- for (const auto & entry : _types) {
- result.push_back(metrics::LoadType(entry.first, entry.second->getName()));
- }
- return result;
-}
-
-const LoadType&
-LoadTypeSet::operator[](uint32_t id) const {
- auto it(_types.find(id));
- return (it == _types.end() ? LoadType::DEFAULT : *it->second);
-}
-
-const LoadType&
-LoadTypeSet::operator[](const string& name) const {
- auto it(_nameMap.find(name));
-
- return (it == _nameMap.end() ? LoadType::DEFAULT : *it->second);
-}
-
-const LoadType*
-LoadTypeSet::findLoadType(const string& name) const {
- auto it(_nameMap.find(name));
- return (it == _nameMap.end() ? 0 : it->second);
-}
-
-}
diff --git a/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.h b/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.h
deleted file mode 100644
index f593935e8b3..00000000000
--- a/documentapi/src/vespa/documentapi/loadtypes/loadtypeset.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * \class LoadTypeSet
- * \ingroup loadtype
- *
- * \brief Class containing all the various load types that have been configured.
- *
- * The load type set makes configured load types available in an easy way for
- * different parts of Vespa to access it.
- */
-#pragma once
-
-#include "loadtype.h"
-#include <vespa/vespalib/stllike/hash_map.h>
-#include <map>
-
-namespace config {
- class ConfigUri;
-}
-
-namespace vespa {
-namespace config {
-namespace content {
-namespace internal {
- class InternalLoadTypeType;
-}
-}
-}
-}
-
-namespace documentapi {
-
-class LoadTypeSet
-{
- using LoadTypeConfig = const vespa::config::content::internal::InternalLoadTypeType;
- vespalib::hash_map<uint32_t, std::unique_ptr<LoadType>> _types;
- // Want order to be ~ alphabetical.
- std::map<string, LoadType*> _nameMap;
-
- void configure(const LoadTypeConfig& config);
-public:
- typedef std::unique_ptr<LoadTypeSet> UP;
- typedef std::shared_ptr<LoadTypeSet> SP;
-
- LoadTypeSet(const LoadTypeSet&) = delete;
- LoadTypeSet& operator=(const LoadTypeSet&) = delete;
-
- LoadTypeSet();
- LoadTypeSet(const config::ConfigUri & configUri);
- LoadTypeSet(const LoadTypeConfig& config);
- ~LoadTypeSet();
-
- void addLoadType(uint32_t id, const string& name, Priority::Value priority);
-
- const std::map<string, LoadType*>& getLoadTypes() const { return _nameMap; }
- metrics::LoadTypeSet getMetricLoadTypes() const;
-
- const LoadType& operator[](uint32_t id) const;
- const LoadType& operator[](const string& name) const;
- uint32_t size() const { return uint32_t(_types.size()); }
-
- /**
- * Attempts to locate a load type with given name. Returns 0 if none found.
- */
- const LoadType* findLoadType(const string& name) const;
-};
-
-} // documentapi
-
diff --git a/documentapi/src/vespa/documentapi/messagebus/documentprotocol.cpp b/documentapi/src/vespa/documentapi/messagebus/documentprotocol.cpp
index a957ce5e4ff..560f2f28f0e 100644
--- a/documentapi/src/vespa/documentapi/messagebus/documentprotocol.cpp
+++ b/documentapi/src/vespa/documentapi/messagebus/documentprotocol.cpp
@@ -21,11 +21,9 @@ namespace documentapi {
const mbus::string DocumentProtocol::NAME = "document";
-DocumentProtocol::DocumentProtocol(const LoadTypeSet& loadTypes,
- std::shared_ptr<const DocumentTypeRepo> repo,
- const string &configId) :
+DocumentProtocol::DocumentProtocol(std::shared_ptr<const DocumentTypeRepo> repo, const string &configId) :
_routingPolicyRepository(std::make_unique<RoutingPolicyRepository>()),
- _routableRepository(std::make_unique<RoutableRepository>(loadTypes)),
+ _routableRepository(std::make_unique<RoutableRepository>()),
_repo(std::move(repo))
{
// Prepare config string for routing policy factories.
diff --git a/documentapi/src/vespa/documentapi/messagebus/documentprotocol.h b/documentapi/src/vespa/documentapi/messagebus/documentprotocol.h
index eeae4553b3b..f35c6dd0810 100644
--- a/documentapi/src/vespa/documentapi/messagebus/documentprotocol.h
+++ b/documentapi/src/vespa/documentapi/messagebus/documentprotocol.h
@@ -17,7 +17,6 @@ namespace document {
namespace documentapi {
-class LoadTypeSet;
class RoutingPolicyRepository;
class RoutableRepository;
class IRoutingPolicyFactory;
@@ -194,9 +193,7 @@ public:
*
* @param configId The id to use when subscribing to config.
*/
- DocumentProtocol(const LoadTypeSet& loadTypes,
- std::shared_ptr<const document::DocumentTypeRepo> repo,
- const string &configId = "");
+ DocumentProtocol(std::shared_ptr<const document::DocumentTypeRepo> repo, const string &configId = "");
~DocumentProtocol() override;
/**
diff --git a/documentapi/src/vespa/documentapi/messagebus/iroutablefactory.h b/documentapi/src/vespa/documentapi/messagebus/iroutablefactory.h
index 2b492dea240..9a41960b852 100644
--- a/documentapi/src/vespa/documentapi/messagebus/iroutablefactory.h
+++ b/documentapi/src/vespa/documentapi/messagebus/iroutablefactory.h
@@ -8,8 +8,6 @@
namespace documentapi {
-class LoadTypeSet;
-
/**
* This interface defines the necessary methods of a routable factory that can be plugged into a {@link
* DocumentProtocol} using the {@link DocumentProtocol#putRoutableFactory(int, RoutableFactory,
@@ -59,7 +57,7 @@ public:
* @param loadTypes The set of configured load types.
* @return The decoded routable.
*/
- virtual mbus::Routable::UP decode(document::ByteBuffer &in, const LoadTypeSet& loadTypes) const = 0;
+ virtual mbus::Routable::UP decode(document::ByteBuffer &in) const = 0;
};
}
diff --git a/documentapi/src/vespa/documentapi/messagebus/policies/externpolicy.cpp b/documentapi/src/vespa/documentapi/messagebus/policies/externpolicy.cpp
index 25112a00b99..312cd2d89cb 100644
--- a/documentapi/src/vespa/documentapi/messagebus/policies/externpolicy.cpp
+++ b/documentapi/src/vespa/documentapi/messagebus/policies/externpolicy.cpp
@@ -2,10 +2,11 @@
#include "externpolicy.h"
#include <boost/tokenizer.hpp>
#include <vespa/documentapi/messagebus/documentprotocol.h>
-#include <vespa/messagebus/emptyreply.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/slobrok/sbmirror.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fastos/thread.h>
#include <vespa/log/log.h>
LOG_SETUP(".externpolicy");
@@ -52,13 +53,13 @@ ExternPolicy::ExternPolicy(const string &param) :
spec.push_back(*it);
}
- if (spec.size() == 0) {
+ if (spec.empty()) {
_error = vespalib::make_string("Extern policy needs at least one slobrok: Slobrok list '%s' resolved to no slobroks", lst.c_str());
return;
}
slobrok::ConfiguratorFactory config(spec);
- _mirror.reset(new MirrorAPI(*_orb, config));
+ _mirror = std::make_unique<MirrorAPI>(*_orb, config);
_started = _transport->Start(_threadPool.get());
if (!_started) {
_error = "Failed to start FNET supervisor.";
diff --git a/documentapi/src/vespa/documentapi/messagebus/policies/externslobrokpolicy.cpp b/documentapi/src/vespa/documentapi/messagebus/policies/externslobrokpolicy.cpp
index 800aa8c4520..9eb28432234 100644
--- a/documentapi/src/vespa/documentapi/messagebus/policies/externslobrokpolicy.cpp
+++ b/documentapi/src/vespa/documentapi/messagebus/policies/externslobrokpolicy.cpp
@@ -4,10 +4,10 @@
#include <vespa/messagebus/routing/routingcontext.h>
#include <vespa/config/common/configcontext.h>
#include <vespa/vespalib/text/stringtokenizer.h>
-#include <vespa/vespalib/util/time.h>
-#include <vespa/fnet/frt/frt.h>
#include <vespa/slobrok/sbmirror.h>
+#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/transport.h>
+#include <vespa/fastos/thread.h>
#include <thread>
using slobrok::api::IMirrorAPI;
diff --git a/documentapi/src/vespa/documentapi/messagebus/routablefactories60.cpp b/documentapi/src/vespa/documentapi/messagebus/routablefactories60.cpp
index 26e609c79fa..8202e938bde 100644
--- a/documentapi/src/vespa/documentapi/messagebus/routablefactories60.cpp
+++ b/documentapi/src/vespa/documentapi/messagebus/routablefactories60.cpp
@@ -7,7 +7,6 @@
#include <vespa/document/select/parser.h>
#include <vespa/document/update/documentupdate.h>
#include <vespa/documentapi/documentapi.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/vespalib/objects/nbostream.h>
using document::FixedBucketSpaces;
@@ -22,12 +21,12 @@ RoutableFactories60::DocumentMessageFactory::encode(const mbus::Routable &obj, v
{
const auto &msg = static_cast<const DocumentMessage&>(obj);
out.putByte(msg.getPriority());
- out.putInt(LoadType::DEFAULT.getId());
+ out.putInt(0); // LoadType
return doEncode(msg, out);
}
mbus::Routable::UP
-RoutableFactories60::DocumentMessageFactory::decode(document::ByteBuffer &in, const LoadTypeSet&) const
+RoutableFactories60::DocumentMessageFactory::decode(document::ByteBuffer &in) const
{
uint8_t pri;
in.getByte(pri);
@@ -50,7 +49,7 @@ RoutableFactories60::DocumentReplyFactory::encode(const mbus::Routable &obj, ves
}
mbus::Routable::UP
-RoutableFactories60::DocumentReplyFactory::decode(document::ByteBuffer &in, const LoadTypeSet&) const
+RoutableFactories60::DocumentReplyFactory::decode(document::ByteBuffer &in) const
{
uint8_t pri;
in.getByte(pri);
diff --git a/documentapi/src/vespa/documentapi/messagebus/routablefactories60.h b/documentapi/src/vespa/documentapi/messagebus/routablefactories60.h
index 579abbda291..7e8156ee071 100644
--- a/documentapi/src/vespa/documentapi/messagebus/routablefactories60.h
+++ b/documentapi/src/vespa/documentapi/messagebus/routablefactories60.h
@@ -87,7 +87,7 @@ public:
public:
bool encode(const mbus::Routable &obj, vespalib::GrowableByteBuffer &out) const override;
- mbus::Routable::UP decode(document::ByteBuffer &in, const LoadTypeSet& loadTypes) const override;
+ mbus::Routable::UP decode(document::ByteBuffer &in) const override;
};
/**
@@ -121,7 +121,7 @@ public:
public:
bool encode(const mbus::Routable &obj, vespalib::GrowableByteBuffer &out) const override;
- mbus::Routable::UP decode(document::ByteBuffer &in, const LoadTypeSet& loadTypes) const override;
+ mbus::Routable::UP decode(document::ByteBuffer &in) const override;
};
////////////////////////////////////////////////////////////////////////////////
diff --git a/documentapi/src/vespa/documentapi/messagebus/routablerepository.cpp b/documentapi/src/vespa/documentapi/messagebus/routablerepository.cpp
index 6ed33cda060..60cdbb3a5e8 100644
--- a/documentapi/src/vespa/documentapi/messagebus/routablerepository.cpp
+++ b/documentapi/src/vespa/documentapi/messagebus/routablerepository.cpp
@@ -1,9 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "routablerepository.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/document/util/stringutil.h>
-#include <vespa/vespalib/util/exceptions.h>
#include <sstream>
#include <algorithm>
@@ -44,11 +42,10 @@ RoutableRepository::VersionMap::getFactory(const vespalib::Version &version) con
[](auto & lhs, auto & rhs) { return lhs.first.compareTo(rhs.first) <= 0; })->second;
}
-RoutableRepository::RoutableRepository(const LoadTypeSet& loadTypes) :
+RoutableRepository::RoutableRepository() :
_lock(),
_factoryTypes(),
- _cache(),
- _loadTypes(loadTypes)
+ _cache()
{
}
@@ -69,7 +66,7 @@ RoutableRepository::decode(const vespalib::Version &version, mbus::BlobRef data)
type, version.toString().c_str());
return mbus::Routable::UP();
}
- mbus::Routable::UP ret = factory->decode(in, _loadTypes);
+ mbus::Routable::UP ret = factory->decode(in);
if (!ret) {
LOG(error, "Routable factory failed to deserialize routable of type %d (version %s).",
type, version.toString().c_str());
diff --git a/documentapi/src/vespa/documentapi/messagebus/routablerepository.h b/documentapi/src/vespa/documentapi/messagebus/routablerepository.h
index 7e73f3929b8..1b043e2b6f8 100644
--- a/documentapi/src/vespa/documentapi/messagebus/routablerepository.h
+++ b/documentapi/src/vespa/documentapi/messagebus/routablerepository.h
@@ -9,8 +9,6 @@
namespace documentapi {
-class LoadTypeSet;
-
/**
* This class encapsulates the logic required to map routable type and version to a corresponding {@link
* RoutableFactory}. It is owned and accessed through a {@link DocumentProtocol} instance. This class uses a
@@ -40,7 +38,6 @@ private:
mutable std::mutex _lock;
TypeMap _factoryTypes;
mutable FactoryCache _cache;
- const LoadTypeSet& _loadTypes;
public:
RoutableRepository(const RoutableRepository &) = delete;
@@ -48,7 +45,7 @@ public:
/**
* Constructs a new routable repository.
*/
- explicit RoutableRepository(const LoadTypeSet& loadTypes);
+ RoutableRepository();
/**
* Decodes a {@link Routable} from the given byte array. This uses the content of the byte array to
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index ee8509fcf19..9f9818000fb 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -15,7 +15,6 @@ vespa_define_module(
src/tests/eval/array_array_map
src/tests/eval/compile_cache
src/tests/eval/compiled_function
- src/tests/eval/engine_or_factory
src/tests/eval/fast_sparse_map
src/tests/eval/fast_value
src/tests/eval/function
@@ -28,7 +27,8 @@ vespa_define_module(
src/tests/eval/node_tools
src/tests/eval/node_types
src/tests/eval/param_usage
- src/tests/eval/simple_tensor
+ src/tests/eval/reference_evaluation
+ src/tests/eval/reference_operations
src/tests/eval/simple_value
src/tests/eval/tensor_function
src/tests/eval/tensor_lambda
@@ -36,6 +36,7 @@ vespa_define_module(
src/tests/eval/value_cache
src/tests/eval/value_codec
src/tests/eval/value_type
+ src/tests/eval/typed_cells
src/tests/gp/ponder_nov2017
src/tests/instruction/dense_xw_product_function
src/tests/instruction/generic_concat
@@ -53,35 +54,21 @@ vespa_define_module(
src/tests/instruction/dense_tensor_peek_function
src/tests/instruction/index_lookup_table
src/tests/instruction/join_with_number
+ src/tests/instruction/dense_add_dimension_optimizer
+ src/tests/instruction/dense_fast_rename_optimizer
+ src/tests/instruction/dense_inplace_join_function
+ src/tests/instruction/dense_pow_as_map_optimizer
+ src/tests/instruction/dense_remove_dimension_optimizer
+ src/tests/instruction/dense_replace_type_function
+ src/tests/instruction/dense_simple_join_function
+ src/tests/instruction/dense_simple_map_function
+ src/tests/instruction/dense_single_reduce_function
+ src/tests/instruction/dense_tensor_create_function
+ src/tests/instruction/vector_from_doubles_function
src/tests/streamed/value
- src/tests/tensor/dense_add_dimension_optimizer
- src/tests/tensor/dense_dimension_combiner
- src/tests/tensor/dense_fast_rename_optimizer
- src/tests/tensor/dense_generic_join
- src/tests/tensor/dense_inplace_join_function
- src/tests/tensor/dense_number_join_function
- src/tests/tensor/dense_pow_as_map_optimizer
- src/tests/tensor/dense_remove_dimension_optimizer
- src/tests/tensor/dense_replace_type_function
- src/tests/tensor/dense_simple_join_function
- src/tests/tensor/dense_simple_map_function
- src/tests/tensor/dense_single_reduce_function
- src/tests/tensor/dense_tensor_create_function
- src/tests/tensor/direct_dense_tensor_builder
- src/tests/tensor/direct_sparse_tensor_builder
src/tests/tensor/instruction_benchmark
src/tests/tensor/onnx_wrapper
- src/tests/tensor/partial_add
- src/tests/tensor/partial_modify
- src/tests/tensor/partial_remove
- src/tests/tensor/tensor_add_operation
- src/tests/tensor/tensor_address
src/tests/tensor/tensor_conformance
- src/tests/tensor/tensor_modify_operation
- src/tests/tensor/tensor_remove_operation
- src/tests/tensor/tensor_serialization
- src/tests/tensor/typed_cells
- src/tests/tensor/vector_from_doubles_function
LIBS
src/vespa/eval
@@ -91,9 +78,6 @@ vespa_define_module(
src/vespa/eval/eval/value_cache
src/vespa/eval/gp
src/vespa/eval/instruction
+ src/vespa/eval/onnx
src/vespa/eval/streamed
- src/vespa/eval/tensor
- src/vespa/eval/tensor/dense
- src/vespa/eval/tensor/serialization
- src/vespa/eval/tensor/sparse
)
diff --git a/eval/src/apps/eval_expr/eval_expr.cpp b/eval/src/apps/eval_expr/eval_expr.cpp
index 4e6fec926e7..f5e5c5d0dfd 100644
--- a/eval/src/apps/eval_expr/eval_expr.cpp
+++ b/eval/src/apps/eval_expr/eval_expr.cpp
@@ -3,7 +3,6 @@
#include <vespa/eval/eval/function.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
using namespace vespalib::eval;
@@ -19,17 +18,14 @@ int main(int argc, char **argv) {
fprintf(stderr, "expression error: %s\n", function->get_error().c_str());
return 1;
}
- InterpretedFunction interpreted(SimpleTensorEngine::ref(), *function, NodeTypes());
- InterpretedFunction::Context ctx(interpreted);
- SimpleParams params({});
- const Value &result = interpreted.eval(ctx, params);
- if (result.is_double()) {
+ auto result = TensorSpec::from_expr(argv[1]);
+ auto type = ValueType::from_spec(result.type());
+ if (type.is_error()) {
+ fprintf(stdout, "error\n");
+ } else if (type.is_scalar()) {
fprintf(stdout, "%.32g\n", result.as_double());
- } else if (result.is_tensor()) {
- vespalib::string str = SimpleTensorEngine::ref().to_spec(result).to_string();
- fprintf(stdout, "%s\n", str.c_str());
} else {
- fprintf(stdout, "error\n");
+ fprintf(stdout, "%s\n", result.to_string().c_str());
}
return 0;
}
diff --git a/eval/src/apps/tensor_conformance/tensor_conformance.cpp b/eval/src/apps/tensor_conformance/tensor_conformance.cpp
index 1f8069db06d..4e0b5d62b9a 100644
--- a/eval/src/apps/tensor_conformance/tensor_conformance.cpp
+++ b/eval/src/apps/tensor_conformance/tensor_conformance.cpp
@@ -7,14 +7,15 @@
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/tensor.h>
#include <vespa/eval/eval/function.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/eval/tensor_engine.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/eval/eval/value_type.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/streamed/streamed_value_builder_factory.h>
+#include <vespa/eval/eval/test/reference_evaluation.h>
#include <vespa/eval/eval/test/test_io.h>
#include <unistd.h>
#include <functional>
@@ -28,11 +29,16 @@ using namespace vespalib::slime::convenience;
using vespalib::slime::inject;
using vespalib::slime::SlimeInserter;
using slime::JsonFormat;
-using tensor::DefaultTensorEngine;
using namespace std::placeholders;
//-----------------------------------------------------------------------------
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
+const ValueBuilderFactory &simple_factory = SimpleValueBuilderFactory::get();
+const ValueBuilderFactory &streamed_factory = StreamedValueBuilderFactory::get();
+
+//-----------------------------------------------------------------------------
+
uint8_t unhex(char c) {
if (c >= '0' && c <= '9') {
return (c - '0');
@@ -67,15 +73,25 @@ nbostream extract_data(const Inspector &value) {
void insert_value(Cursor &cursor, const vespalib::string &name, const TensorSpec &spec) {
nbostream data;
- Value::UP value = SimpleTensorEngine::ref().from_spec(spec);
- SimpleTensorEngine::ref().encode(*value, data);
+ Value::UP value = value_from_spec(spec, simple_factory);
+ encode_value(*value, data);
cursor.setData(name, Memory(data.peek(), data.size()));
}
TensorSpec extract_value(const Inspector &inspector) {
nbostream data = extract_data(inspector);
- const auto &engine = SimpleTensorEngine::ref();
- return engine.to_spec(*engine.decode(data));
+ return spec_from_value(*decode_value(data, simple_factory));
+}
+
+//-----------------------------------------------------------------------------
+
+TensorSpec ref_eval(const Inspector &test) {
+ auto fun = Function::parse(test["expression"].asString().make_string());
+ std::vector<TensorSpec> params;
+ for (size_t i = 0; i < fun->num_params(); ++i) {
+ params.push_back(extract_value(test["inputs"][fun->param_name(i)]));
+ }
+ return ReferenceEvaluation::eval(*fun, params);
}
//-----------------------------------------------------------------------------
@@ -88,23 +104,21 @@ std::vector<ValueType> get_types(const std::vector<Value::UP> &param_values) {
return param_types;
}
-TensorSpec eval_expr(const Inspector &test, EngineOrFactory engine, bool typed) {
+TensorSpec eval_expr(const Inspector &test, const ValueBuilderFactory &factory) {
auto fun = Function::parse(test["expression"].asString().make_string());
std::vector<Value::UP> param_values;
std::vector<Value::CREF> param_refs;
for (size_t i = 0; i < fun->num_params(); ++i) {
- param_values.emplace_back(engine.from_spec(extract_value(test["inputs"][fun->param_name(i)])));
+ param_values.emplace_back(value_from_spec(extract_value(test["inputs"][fun->param_name(i)]), factory));
param_refs.emplace_back(*param_values.back());
}
- NodeTypes types = typed ? NodeTypes(*fun, get_types(param_values)) : NodeTypes();
- InterpretedFunction ifun(engine, *fun, types);
+ NodeTypes types = NodeTypes(*fun, get_types(param_values));
+ InterpretedFunction ifun(factory, *fun, types);
InterpretedFunction::Context ctx(ifun);
SimpleObjectParams params(param_refs);
const Value &result = ifun.eval(ctx, params);
- if (typed) {
- ASSERT_EQUAL(result.type(), types.get_type(fun->root()));
- }
- return engine.to_spec(result);
+ ASSERT_EQUAL(result.type(), types.get_type(fun->root()));
+ return spec_from_value(result);
}
//-----------------------------------------------------------------------------
@@ -138,8 +152,7 @@ private:
if (expect != nullptr) {
insert_value(test.setObject("result"), "expect", *expect);
} else {
- insert_value(test.setObject("result"), "expect",
- eval_expr(test, SimpleTensorEngine::ref(), false));
+ insert_value(test.setObject("result"), "expect", ref_eval(test));
}
}
public:
@@ -168,11 +181,11 @@ void evaluate(Input &in, Output &out) {
auto handle_test = [&out](Slime &slime)
{
insert_value(slime["result"], "cpp_prod",
- eval_expr(slime.get(), DefaultTensorEngine::ref(), true));
- insert_value(slime["result"], "cpp_prod_untyped",
- eval_expr(slime.get(), DefaultTensorEngine::ref(), false));
- insert_value(slime["result"], "cpp_ref_typed",
- eval_expr(slime.get(), SimpleTensorEngine::ref(), true));
+ eval_expr(slime.get(), prod_factory));
+ insert_value(slime["result"], "cpp_simple_value",
+ eval_expr(slime.get(), simple_factory));
+ insert_value(slime["result"], "cpp_streamed_value",
+ eval_expr(slime.get(), streamed_factory));
write_compact(slime, out);
};
auto handle_summary = [&out](Slime &slime)
@@ -196,7 +209,7 @@ void verify(Input &in, Output &out) {
std::map<vespalib::string,size_t> result_map;
auto handle_test = [&result_map](Slime &slime)
{
- TensorSpec reference_result = eval_expr(slime.get(), SimpleTensorEngine::ref(), false);
+ TensorSpec reference_result = ref_eval(slime.get());
for (const auto &result: extract_fields(slime["result"])) {
++result_map[result];
TEST_STATE(make_string("verifying result: '%s'", result.c_str()).c_str());
diff --git a/eval/src/apps/tensor_conformance/test_spec.json b/eval/src/apps/tensor_conformance/test_spec.json
deleted file mode 100644
index 6ee9f3aa083..00000000000
--- a/eval/src/apps/tensor_conformance/test_spec.json
+++ /dev/null
@@ -1,1988 +0,0 @@
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004000000000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004000000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02010179054018000000000000401C000000000000402000000000000040220000000000004024000000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x020101780340080000000000004020000000000000402A000000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02004020000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017905017A074042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C00000000000405100000000000040514000000000004051800000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017A07402E00000000000040300000000000004031000000000000403200000000000040330000000000004034000000000000403500000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C00000000000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x02020178030179054010000000000000402600000000000040320000000000004039000000000000404000000000000040438000000000004047000000000000404A800000000000404E0000000000004050C000000000004052800000000000405440000000000040560000000000004057C000000000004059800000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0200404A800000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017905017A07421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017803017A07417000004180000041880000419000004198000041A0000041A8000042480000424C0000425000004254000042580000425C00004260000042AA000042AC000042AE000042B0000042B2000042B4000042B60000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x06010201780301790540800000413000004190000041C8000042000000421C0000423800004254000042700000428600004294000042A2000042B0000042BE000042CC0000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x0200404A800000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004000000000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004000000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101790203626172401000000000000003666F6F4008000000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101780301613FF80000000000000162400C00000000000001634016000000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x0200400C000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020179017A08036261720169402A00000000000003626172016A402C00000000000003626172016B402E00000000000003626172016C403000000000000003666F6F0169402200000000000003666F6F016A402400000000000003666F6F016B402600000000000003666F6F016C4028000000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017A0C0161016940080000000000000161016A40100000000000000161016B40140000000000000161016C40180000000000000162016940260000000000000162016A40280000000000000162016B402A0000000000000162016C402C0000000000000163016940330000000000000163016A40340000000000000163016B40350000000000000163016C4036000000000000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017906016103626172401A000000000000016103666F6F4004000000000000016203626172402D000000000000016203666F6F40250000000000000163036261724036800000000000016303666F6F4032800000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x02004029000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020179017A080362617201694150000003626172016A4160000003626172016B4170000003626172016C4180000003666F6F01694110000003666F6F016A4120000003666F6F016B4130000003666F6F016C41400000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020178017A0C01610169404000000161016A408000000161016B40A000000161016C40C0000001620169413000000162016A414000000162016B415000000162016C4160000001630169419800000163016A41A000000163016B41A800000163016C41B00000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x050102017801790601610362617240D00000016103666F6F4020000001620362617241680000016203666F6F4128000001630362617241B40000016303666F6F41940000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x02004029000000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017A0702036261724036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C00000000000003666F6F402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0202017803017A0740120000000000004016000000000000401A000000000000401E000000000000402100000000000040230000000000004025000000000000403280000000000040338000000000004034800000000000403580000000000040368000000000004037800000000000403880000000000040404000000000004040C0000000000040414000000000004041C0000000000040424000000000004042C000000000004043400000000000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017803020362617240260000000000004039000000000000404380000000000003666F6F401000000000000040320000000000004040000000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x02004035800000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0301017A0101790504016940350000000000004039000000000000403D00000000000040408000000000004042800000000000016A4036000000000000403A000000000000403E00000000000040410000000000004043000000000000016B4037000000000000403B000000000000403F00000000000040418000000000004043800000000000016C4038000000000000403C000000000000404000000000000040420000000000004044000000000000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x01020178017A0C0161016940220000000000000161016A40240000000000000161016B40260000000000000161016C402800000000000001620169403D0000000000000162016A403E0000000000000162016B403F0000000000000162016C40400000000000000163016940488000000000000163016A40490000000000000163016B40498000000000000163016C404A000000000000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03010178010179050301614004000000000000401A0000000000004025000000000000402D000000000000403280000000000001624036800000000000403A800000000000403E800000000000404140000000000040434000000000000163404540000000000040474000000000004049400000000000404B400000000000404D400000000000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0200403E800000000000"}}
-{"expression":"reduce(a,avg,x)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x070101017A0101790504016941A8000041C8000041E800004204000042140000016A41B0000041D0000041F000004208000042180000016B41B8000041D8000041F80000420C0000421C0000016C41C0000041E00000420000004210000042200000"}}
-{"expression":"reduce(a,avg,y)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0501020178017A0C01610169411000000161016A412000000161016B413000000161016C414000000162016941E800000162016A41F000000162016B41F800000162016C4200000001630169424400000163016A424800000163016B424C00000163016C42500000"}}
-{"expression":"reduce(a,avg,z)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701010178010179050301614020000040D00000412800004168000041940000016241B4000041D4000041F40000420A0000421A00000163422A0000423A0000424A0000425A0000426A0000"}}
-{"expression":"reduce(a,avg)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0200403E800000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x020101790540080000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0201017803401400000000000040140000000000004014000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0200402E000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017905017A0740080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017A07401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017905401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0200405A400000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017905017A074040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017803017A0740A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A00000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x06010201780301790540E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E00000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x0200405A400000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101790203626172400800000000000003666F6F4008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x0101017803016140000000000000000162400000000000000001634000000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020179017A08036261720169400800000000000003626172016A400800000000000003626172016B400800000000000003626172016C400800000000000003666F6F0169400800000000000003666F6F016A400800000000000003666F6F016B400800000000000003666F6F016C4008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017A0C0161016940000000000000000161016A40000000000000000161016B40000000000000000161016C40000000000000000162016940000000000000000162016A40000000000000000162016B40000000000000000162016C40000000000000000163016940000000000000000163016A40000000000000000163016B40000000000000000163016C4000000000000000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x010201780179060161036261724010000000000000016103666F6F40100000000000000162036261724010000000000000016203666F6F40100000000000000163036261724010000000000000016303666F6F4010000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x02004038000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020179017A080362617201694040000003626172016A4040000003626172016B4040000003626172016C4040000003666F6F01694040000003666F6F016A4040000003666F6F016B4040000003666F6F016C40400000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020178017A0C01610169400000000161016A400000000161016B400000000161016C4000000001620169400000000162016A400000000162016B400000000162016C4000000001630169400000000163016A400000000163016B400000000163016C40000000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x050102017801790601610362617240800000016103666F6F4080000001620362617240800000016203666F6F4080000001630362617240800000016303666F6F40800000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x02004038000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017A070203626172400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000003666F6F4008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0202017803017A07400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x03010179010178030203626172401C000000000000401C000000000000401C00000000000003666F6F401C000000000000401C000000000000401C000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x02004045000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0301017A0101790504016940080000000000004008000000000000400800000000000040080000000000004008000000000000016A40080000000000004008000000000000400800000000000040080000000000004008000000000000016B40080000000000004008000000000000400800000000000040080000000000004008000000000000016C40080000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x01020178017A0C0161016940140000000000000161016A40140000000000000161016B40140000000000000161016C40140000000000000162016940140000000000000162016A40140000000000000162016B40140000000000000162016C40140000000000000163016940140000000000000163016A40140000000000000163016B40140000000000000163016C4014000000000000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x030101780101790503016140100000000000004010000000000000401000000000000040100000000000004010000000000000016240100000000000004010000000000000401000000000000040100000000000004010000000000000016340100000000000004010000000000000401000000000000040100000000000004010000000000000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0200404E000000000000"}}
-{"expression":"reduce(a,count,x)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x070101017A010179050401694040000040400000404000004040000040400000016A4040000040400000404000004040000040400000016B4040000040400000404000004040000040400000016C4040000040400000404000004040000040400000"}}
-{"expression":"reduce(a,count,y)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0501020178017A0C0161016940A000000161016A40A000000161016B40A000000161016C40A000000162016940A000000162016A40A000000162016B40A000000162016C40A000000163016940A000000163016A40A000000163016B40A000000163016C40A00000"}}
-{"expression":"reduce(a,count,z)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x07010101780101790503016140800000408000004080000040800000408000000162408000004080000040800000408000004080000001634080000040800000408000004080000040800000"}}
-{"expression":"reduce(a,count)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0200404E000000000000"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x02010178033FE764D5000000003FEC2F7D600000003FEE7B7CC0000000"},"result":{"expect":"0x02003FE3A0C6E59280EA"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x02010178033FE764D5000000003FEC2F7D600000003FEE7B7CC0000000"},"result":{"expect":"0x02003FE3A0C6E59280EA"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x02020178030179053FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF60000000"},"result":{"expect":"0x02010179053FE755EC926559383FEC28DF2C10E16A3FEE78DA543B581D3FEF6BA84F8540D83FEFC8CCE446A530"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x02020178030179053FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF60000000"},"result":{"expect":"0x02010178033FE325600168F45C3FEFE02F0DE8C3243FEFFFC9001920DD"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x02020178030179053FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF60000000"},"result":{"expect":"0x02003FE312360128D14A"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x0203017803017905017A073FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0202017905017A073FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x0203017803017905017A073FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0202017803017A073FE762D26D20DF963FEC2E993FA306D03FEE7B21E5F38A7C3FEF6C85C1281D003FEFC91F560F3F203FEFEBB9C301B9003FEFF887A0687CC03FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x0203017803017905017A073FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02020178030179053FE314CD21F656DC3FEFFBA88881F6443FEFFFFF000002203FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x0203017803017905017A073FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02003FE31235C7F22F6F"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x060103017803017905017A073F3B26A83F617BEB3F73DBE63F7B65413F7E49613F7F5DF43F7FC44B3F7FEA063F7FF7EA3F7FFD063F7FFEE83F7FFF993F7FFFDA3F7FFFF23F7FFFFB3F7FFFFE3F7FFFFF3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x060102017905017A073F3B26A83F617BEB3F73DBE63F7B65413F7E49613F7F5DF43F7FC44B3F7FEA063F7FF7EA3F7FFD063F7FFEE83F7FFF993F7FFFDA3F7FFFF23F7FFFFB3F7FFFFE3F7FFFFF3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x060103017803017905017A073F3B26A83F617BEB3F73DBE63F7B65413F7E49613F7F5DF43F7FC44B3F7FEA063F7FF7EA3F7FFD063F7FFEE83F7FFF993F7FFFDA3F7FFFF23F7FFFFB3F7FFFFE3F7FFFFF3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x060102017803017A073F3B16933F6174CA3F73D90F3F7B642E3F7E48FB3F7F5DCE3F7FC43D3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x060103017803017905017A073F3B26A83F617BEB3F73DBE63F7B65413F7E49613F7F5DF43F7FC44B3F7FEA063F7FF7EA3F7FFD063F7FFEE83F7FFF993F7FFFDA3F7FFFF23F7FFFFB3F7FFFFE3F7FFFFF3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x0601020178030179053F18A6693F7FDD443F7FFFF83F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x060103017803017905017A073F3B26A83F617BEB3F73DBE63F7B65413F7E49613F7F5DF43F7FC44B3F7FEA063F7FF7EA3F7FFD063F7FFEE83F7FFF993F7FFFDA3F7FFFF23F7FFFFB3F7FFFFE3F7FFFFF3F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x02003FE31235C7F22F6F"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x010101780301613FE764D50000000001623FEC2F7D6000000001633FEE7B7CC0000000"},"result":{"expect":"0x02003FE3A0C6E59280EA"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x010101780301613FE764D50000000001623FEC2F7D6000000001633FEE7B7CC0000000"},"result":{"expect":"0x02003FE3A0C6E59280EA"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x010201780179060161036261723FEC2F7D60000000016103666F6F3FE764D5000000000162036261723FEF6CA820000000016203666F6F3FEE7B7CC00000000163036261723FEFEBBE80000000016303666F6F3FEFC92C20000000"},"result":{"expect":"0x0101017902036261723FEB9C30987284AF03666F6F3FE622A00D5893C0"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x010201780179060161036261723FEC2F7D60000000016103666F6F3FE764D5000000000162036261723FEF6CA820000000016203666F6F3FEE7B7CC00000000163036261723FEFEBBE80000000016303666F6F3FEFC92C20000000"},"result":{"expect":"0x010101780301613FE49AF220E6870001623FEDEF21C5D26CC001633FEFB50D54A5AE80"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x010201780179060161036261723FEC2F7D60000000016103666F6F3FE764D5000000000162036261723FEF6CA820000000016203666F6F3FEE7B7CC00000000163036261723FEFEBBE80000000016303666F6F3FEFC92C20000000"},"result":{"expect":"0x02003FE3194174E78FE1"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x010301780179017A1801610362617201693FEFC92C20000000016103626172016A3FEFEBBE80000000016103626172016B3FEFF88960000000016103626172016C3FEFFD40C0000000016103666F6F01693FE764D500000000016103666F6F016A3FEC2F7D60000000016103666F6F016B3FEE7B7CC0000000016103666F6F016C3FEF6CA82000000001620362617201693FEFFFFB40000000016203626172016A3FEFFFFE40000000016203626172016B3FEFFFFF60000000016203626172016C3FEFFFFFC0000000016203666F6F01693FEFFEFD40000000016203666F6F016A3FEFFFA0C0000000016203666F6F016B3FEFFFDD00000000016203666F6F016C3FEFFFF32000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FEFFFFFE0000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x01020179017A080362617201693FEFC9276823734003626172016A3FEFEBBCC11B950003626172016B3FEFF888C025512003626172016C3FEFFD4080057E8003666F6F01693FE76417BF499A2903666F6F016A3FEC2F297AA4D04003666F6F016B3FEE7B5B68EF8E0003666F6F016C3FEF6C9B7B485B20"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x010301780179017A1801610362617201693FEFC92C20000000016103626172016A3FEFEBBE80000000016103626172016B3FEFF88960000000016103626172016C3FEFFD40C0000000016103666F6F01693FE764D500000000016103666F6F016A3FEC2F7D60000000016103666F6F016B3FEE7B7CC0000000016103666F6F016C3FEF6CA82000000001620362617201693FEFFFFB40000000016203626172016A3FEFFFFE40000000016203626172016B3FEFFFFF60000000016203626172016C3FEFFFFFC0000000016203666F6F01693FEFFEFD40000000016203666F6F016A3FEFFFA0C0000000016203666F6F016B3FEFFFDD00000000016203666F6F016C3FEFFFF32000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FEFFFFFE0000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x01020178017A0C016101693FE73CBFF3F1B5000161016A3FEC1DA6006F5F800161016B3FEE7460BCF08C400161016C3FEF69F5861930C0016201693FEFFEF8802668800162016A3FEFFF9F000535800162016B3FEFFFDC6000AF000162016C3FEFFFF2E00019C0016301693FEFFFFFE00000000163016A3FF00000000000000163016B3FF00000000000000163016C3FF0000000000000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x010301780179017A1801610362617201693FEFC92C20000000016103626172016A3FEFEBBE80000000016103626172016B3FEFF88960000000016103626172016C3FEFFD40C0000000016103666F6F01693FE764D500000000016103666F6F016A3FEC2F7D60000000016103666F6F016B3FEE7B7CC0000000016103666F6F016C3FEF6CA82000000001620362617201693FEFFFFB40000000016203626172016A3FEFFFFE40000000016203626172016B3FEFFFFF60000000016203626172016C3FEFFFFFC0000000016203666F6F01693FEFFEFD40000000016203666F6F016A3FEFFFA0C0000000016203666F6F016B3FEFFFDD00000000016203666F6F016C3FEFFFF32000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FEFFFFFE0000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x010201780179060161036261723FEFAAF0012E9A25016103666F6F3FE346666D61B77C0162036261723FEFFFF8A0007140016203666F6F3FEFFE6E2521DD640163036261723FF0000000000000016303666F6F3FEFFFFFE0000000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x010301780179017A1801610362617201693FEFC92C20000000016103626172016A3FEFEBBE80000000016103626172016B3FEFF88960000000016103626172016C3FEFFD40C0000000016103666F6F01693FE764D500000000016103666F6F016A3FEC2F7D60000000016103666F6F016B3FEE7B7CC0000000016103666F6F016C3FEF6CA82000000001620362617201693FEFFFFB40000000016203626172016A3FEFFFFE40000000016203626172016B3FEFFFFF60000000016203626172016C3FEFFFFFC0000000016203666F6F01693FEFFEFD40000000016203666F6F016A3FEFFFA0C0000000016203666F6F016B3FEFFFDD00000000016203666F6F016C3FEFFFF32000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FEFFFFFE0000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x02003FE31235C7F22F6F"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x05010301780179017A1801610362617201693F7E4961016103626172016A3F7F5DF4016103626172016B3F7FC44B016103626172016C3F7FEA06016103666F6F01693F3B26A8016103666F6F016A3F617BEB016103666F6F016B3F73DBE6016103666F6F016C3F7B654101620362617201693F7FFFDA016203626172016A3F7FFFF2016203626172016B3F7FFFFB016203626172016C3F7FFFFE016203666F6F01693F7FF7EA016203666F6F016A3F7FFD06016203666F6F016B3F7FFEE8016203666F6F016C3F7FFF9901630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F7FFFFF016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"},"result":{"expect":"0x0501020179017A080362617201693F7E493B03626172016A3F7F5DE603626172016B3F7FC44603626172016C3F7FEA0403666F6F01693F3B20BE03666F6F016A3F61794C03666F6F016B3F73DADB03666F6F016C3F7B64DC"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x05010301780179017A1801610362617201693F7E4961016103626172016A3F7F5DF4016103626172016B3F7FC44B016103626172016C3F7FEA06016103666F6F01693F3B26A8016103666F6F016A3F617BEB016103666F6F016B3F73DBE6016103666F6F016C3F7B654101620362617201693F7FFFDA016203626172016A3F7FFFF2016203626172016B3F7FFFFB016203626172016C3F7FFFFE016203666F6F01693F7FF7EA016203666F6F016A3F7FFD06016203666F6F016B3F7FFEE8016203666F6F016C3F7FFF9901630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F7FFFFF016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"},"result":{"expect":"0x0501020178017A0C016101693F39E6000161016A3F60ED300161016B3F73A3060161016C3F7B4FAC016201693F7FF7C40162016A3F7FFCF80162016B3F7FFEE30162016C3F7FFF97016301693F7FFFFF0163016A3F8000000163016B3F8000000163016C3F800000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x05010301780179017A1801610362617201693F7E4961016103626172016A3F7F5DF4016103626172016B3F7FC44B016103626172016C3F7FEA06016103666F6F01693F3B26A8016103666F6F016A3F617BEB016103666F6F016B3F73DBE6016103666F6F016C3F7B654101620362617201693F7FFFDA016203626172016A3F7FFFF2016203626172016B3F7FFFFB016203626172016C3F7FFFFE016203666F6F01693F7FF7EA016203666F6F016A3F7FFD06016203666F6F016B3F7FFEE8016203666F6F016C3F7FFF9901630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F7FFFFF016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"},"result":{"expect":"0x05010201780179060161036261723F7D5780016103666F6F3F1A33330162036261723F7FFFC5016203666F6F3F7FF3710163036261723F800000016303666F6F3F7FFFFF"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x05010301780179017A1801610362617201693F7E4961016103626172016A3F7F5DF4016103626172016B3F7FC44B016103626172016C3F7FEA06016103666F6F01693F3B26A8016103666F6F016A3F617BEB016103666F6F016B3F73DBE6016103666F6F016C3F7B654101620362617201693F7FFFDA016203626172016A3F7FFFF2016203626172016B3F7FFFFB016203626172016C3F7FFFFE016203666F6F01693F7FF7EA016203666F6F016A3F7FFD06016203666F6F016B3F7FFEE8016203666F6F016C3F7FFF9901630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F7FFFFF016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"},"result":{"expect":"0x02003FE31235C7F22F6F"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x0301017902017803017A0702036261723FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0301017901017A0702036261723FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE4000000003666F6F3FE764D48B07D7003FEC2F7D27A105403FEE7B7CA18483403FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF88960000000"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x0301017902017803017A0702036261723FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0202017803017A073FE762D2E20EFE003FEC2E99780039C03FEE7B22046EAC803FEF6C85C1281D003FEFC91F560F3F203FEFEBB9C301B9003FEFF887A0687CC03FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x0301017902017803017A0702036261723FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x030101790101780302036261723FEFFBA88881F6443FF00000000000003FF000000000000003666F6F3FE314CD21F656DB3FEFFFFF000002203FF0000000000000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x0301017902017803017A0702036261723FEFFD40C00000003FEFFEFD400000003FEFFFA0C00000003FEFFFDD000000003FEFFFF3200000003FEFFFFB400000003FEFFFFE400000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FE764D5000000003FEC2F7D600000003FEE7B7CC00000003FEF6CA8200000003FEFC92C200000003FEFEBBE800000003FEFF889600000003FEFFFFF600000003FEFFFFFC00000003FEFFFFFE00000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02003FE31235C7F22F6E"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x03020178017A010179050C016101693FE764D5000000003FEFC92C200000003FEFFEFD400000003FEFFFFB400000003FEFFFFFE00000000161016A3FEC2F7D600000003FEFEBBE800000003FEFFFA0C00000003FEFFFFE400000003FF00000000000000161016B3FEE7B7CC00000003FEFF889600000003FEFFFDD000000003FEFFFFF600000003FF00000000000000161016C3FEF6CA8200000003FEFFD40C00000003FEFFFF3200000003FEFFFFFC00000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0301017A010179050401693FE764D5000000003FEFC92C200000003FEFFEFD400000003FEFFFFB400000003FEFFFFFE0000000016A3FEC2F7D600000003FEFEBBE800000003FEFFFA0C00000003FEFFFFE400000003FF0000000000000016B3FEE7B7CC00000003FEFF889600000003FEFFFDD000000003FEFFFFF600000003FF0000000000000016C3FEF6CA8200000003FEFFD40C00000003FEFFFF3200000003FEFFFFFC00000003FF0000000000000"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x03020178017A010179050C016101693FE764D5000000003FEFC92C200000003FEFFEFD400000003FEFFFFB400000003FEFFFFFE00000000161016A3FEC2F7D600000003FEFEBBE800000003FEFFFA0C00000003FEFFFFE400000003FF00000000000000161016B3FEE7B7CC00000003FEFF889600000003FEFFFDD000000003FEFFFFF600000003FF00000000000000161016C3FEF6CA8200000003FEFFD40C00000003FEFFFF3200000003FEFFFFFC00000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x01020178017A0C016101693FE73C008494FBB00161016A3FEC1D50C694C1D20161016B3FEE743ED56180740161016C3FEF69E8A3A39606016201693FF00000000000000162016A3FF00000000000000162016B3FF00000000000000162016C3FF0000000000000016301693FF00000000000000163016A3FF00000000000000163016B3FF00000000000000163016C3FF0000000000000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x03020178017A010179050C016101693FE764D5000000003FEFC92C200000003FEFFEFD400000003FEFFFFB400000003FEFFFFFE00000000161016A3FEC2F7D600000003FEFEBBE800000003FEFFFA0C00000003FEFFFFE400000003FF00000000000000161016B3FEE7B7CC00000003FEFF889600000003FEFFFDD000000003FEFFFFF600000003FF00000000000000161016C3FEF6CA8200000003FEFFD40C00000003FEFFFF3200000003FEFFFFFC00000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x03010178010179050301613FE346666D61B77C3FEFAAF0012E9A253FEFFE6E2521DD643FEFFFF8A00071403FEFFFFFE000000001623FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001633FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x03020178017A010179050C016101693FE764D5000000003FEFC92C200000003FEFFEFD400000003FEFFFFB400000003FEFFFFFE00000000161016A3FEC2F7D600000003FEFEBBE800000003FEFFFA0C00000003FEFFFFE400000003FF00000000000000161016B3FEE7B7CC00000003FEFF889600000003FEFFFDD000000003FEFFFFF600000003FF00000000000000161016C3FEF6CA8200000003FEFFD40C00000003FEFFFF3200000003FEFFFFFC00000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02003FE31235C7F22F6E"}}
-{"expression":"reduce(a,prod,x)","inputs":{"a":"0x0701020178017A010179050C016101693F3B26A83F7E49613F7FF7EA3F7FFFDA3F7FFFFF0161016A3F617BEB3F7F5DF43F7FFD063F7FFFF23F8000000161016B3F73DBE63F7FC44B3F7FFEE83F7FFFFB3F8000000161016C3F7B65413F7FEA063F7FFF993F7FFFFE3F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F8000003F8000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F8000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x070101017A010179050401693F3B26A83F7E49613F7FF7EA3F7FFFDA3F7FFFFF016A3F617BEB3F7F5DF43F7FFD063F7FFFF23F800000016B3F73DBE63F7FC44B3F7FFEE83F7FFFFB3F800000016C3F7B65413F7FEA063F7FFF993F7FFFFE3F800000"}}
-{"expression":"reduce(a,prod,y)","inputs":{"a":"0x0701020178017A010179050C016101693F3B26A83F7E49613F7FF7EA3F7FFFDA3F7FFFFF0161016A3F617BEB3F7F5DF43F7FFD063F7FFFF23F8000000161016B3F73DBE63F7FC44B3F7FFEE83F7FFFFB3F8000000161016C3F7B65413F7FEA063F7FFF993F7FFFFE3F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F8000003F8000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F8000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x0501020178017A0C016101693F39E0040161016A3F60EA860161016B3F73A1F70161016C3F7B4F45016201693F8000000162016A3F8000000162016B3F8000000162016C3F800000016301693F8000000163016A3F8000000163016B3F8000000163016C3F800000"}}
-{"expression":"reduce(a,prod,z)","inputs":{"a":"0x0701020178017A010179050C016101693F3B26A83F7E49613F7FF7EA3F7FFFDA3F7FFFFF0161016A3F617BEB3F7F5DF43F7FFD063F7FFFF23F8000000161016B3F73DBE63F7FC44B3F7FFEE83F7FFFFB3F8000000161016C3F7B65413F7FEA063F7FFF993F7FFFFE3F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F8000003F8000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F8000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x0701010178010179050301613F1A33333F7D57803F7FF3713F7FFFC53F7FFFFF01623F8000003F8000003F8000003F8000003F80000001633F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"reduce(a,prod)","inputs":{"a":"0x0701020178017A010179050C016101693F3B26A83F7E49613F7FF7EA3F7FFFDA3F7FFFFF0161016A3F617BEB3F7F5DF43F7FFD063F7FFFF23F8000000161016B3F73DBE63F7FC44B3F7FFEE83F7FFFFB3F8000000161016C3F7B65413F7FEA063F7FFF993F7FFFFE3F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F8000003F8000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F8000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"},"result":{"expect":"0x02003FE31235C7F22F6E"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0201017905403200000000000040350000000000004038000000000000403B000000000000403E000000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0201017803402E00000000000040440000000000004050400000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0200405E000000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017905017A07405B000000000000405BC00000000000405C800000000000405D400000000000405E000000000000405EC00000000000405F800000000000406020000000000040608000000000004060E0000000000040614000000000004061A00000000000406200000000000040626000000000004062C00000000000406320000000000040638000000000004063E0000000000040644000000000004064A00000000000406500000000000040656000000000004065C00000000000406620000000000040668000000000004066E0000000000040674000000000004067A00000000000406800000000000040686000000000004068C00000000000406920000000000040698000000000004069E00000000000406A400000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017A074052C000000000004054000000000000405540000000000040568000000000004057C000000000004059000000000000405A400000000000406F400000000000406FE00000000000407040000000000040709000000000004070E0000000000040713000000000004071800000000000407A900000000000407AE00000000000407B300000000000407B800000000000407BD00000000000407C200000000000407C700000000000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017905403C0000000000004053400000000000405F8000000000004065E00000000000406C000000000000407110000000000040742000000000004077300000000000407A400000000000407D50000000000040803000000000004081B8000000000040834000000000004084C800000000004086500000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x020040B5BD0000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017905017A0742D8000042DE000042E4000042EA000042F0000042F6000042FC0000430100004304000043070000430A0000430D000043100000431300004316000043190000431C0000431F0000432200004325000043280000432B0000432E0000433100004334000043370000433A0000433D000043400000434300004346000043490000434C0000434F000043520000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017803017A074296000042A0000042AA000042B4000042BE000042C8000042D20000437A0000437F000043820000438480004387000043898000438C000043D4800043D7000043D9800043DC000043DE800043E1000043E38000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x06010201780301790541E00000429A000042FC0000432F0000436000004388800043A1000043B9800043D2000043EA800044018000440DC000441A00004426400044328000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x020040B5BD0000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101790203626172402800000000000003666F6F4022000000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x0101017803016140080000000000000162401C00000000000001634026000000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x02004035000000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020179017A08036261720169404380000000000003626172016A404500000000000003626172016B404680000000000003626172016C404800000000000003666F6F0169403B00000000000003666F6F016A403E00000000000003666F6F016B404080000000000003666F6F016C4042000000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017A0C0161016940180000000000000161016A40200000000000000161016B40240000000000000161016C40280000000000000162016940360000000000000162016A40380000000000000162016B403A0000000000000162016C403C0000000000000163016940430000000000000163016A40440000000000000163016B40450000000000000163016C4046000000000000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017906016103626172403A000000000000016103666F6F4024000000000000016203626172404D000000000000016203666F6F40450000000000000163036261724056800000000000016303666F6F4052800000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x02004072C00000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020179017A08036261720169421C000003626172016A4228000003626172016B4234000003626172016C4240000003666F6F016941D8000003666F6F016A41F0000003666F6F016B4204000003666F6F016C42100000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020178017A0C0161016940C000000161016A410000000161016B412000000161016C414000000162016941B000000162016A41C000000162016B41D000000162016C41E0000001630169421800000163016A422000000163016B422800000163016C42300000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x050102017801790601610362617241D00000016103666F6F4120000001620362617242680000016203666F6F4228000001630362617242B40000016303666F6F42940000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x02004072C00000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017A0702036261724050800000000000405140000000000040520000000000004052C0000000000040538000000000004054400000000000405500000000000003666F6F404680000000000040480000000000004049800000000000404B000000000000404C800000000000404E000000000000404F800000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0202017803017A0740220000000000004026000000000000402A000000000000402E000000000000403100000000000040330000000000004035000000000000404280000000000040438000000000004044800000000000404580000000000040468000000000004047800000000000404880000000000040504000000000004050C0000000000040514000000000004051C0000000000040524000000000004052C000000000004053400000000000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017803020362617240534000000000004065E00000000000407110000000000003666F6F403C000000000000405F800000000000406C000000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0200408C380000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0301017A01017905040169404F8000000000004052C000000000004055C000000000004058C00000000000405BC00000000000016A4050800000000000405380000000000040568000000000004059800000000000405C800000000000016B405140000000000040544000000000004057400000000000405A400000000000405D400000000000016C405200000000000040550000000000004058000000000000405B000000000000405E000000000000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x01020178017A0C0161016940468000000000000161016A40490000000000000161016B404B8000000000000161016C404E0000000000000162016940622000000000000162016A4062C000000000000162016B40636000000000000162016C406400000000000001630169406EA000000000000163016A406F4000000000000163016B406FE000000000000163016C4070400000000000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03010178010179050301614024000000000000403A0000000000004045000000000000404D000000000000405280000000000001624056800000000000405A800000000000405E800000000000406140000000000040634000000000000163406540000000000040674000000000004069400000000000406B400000000000406D400000000000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0200409C980000000000"}}
-{"expression":"reduce(a,sum,x)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x070101017A01017905040169427C00004296000042AE000042C6000042DE0000016A42840000429C000042B4000042CC000042E40000016B428A000042A2000042BA000042D2000042EA0000016C4290000042A8000042C0000042D8000042F00000"}}
-{"expression":"reduce(a,sum,y)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0501020178017A0C01610169423400000161016A424800000161016B425C00000161016C4270000001620169431100000162016A431600000162016B431B00000162016C4320000001630169437500000163016A437A00000163016B437F00000163016C43820000"}}
-{"expression":"reduce(a,sum,z)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701010178010179050301614120000041D00000422800004268000042940000016242B4000042D4000042F40000430A0000431A00000163432A0000433A0000434A0000435A0000436A0000"}}
-{"expression":"reduce(a,sum)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0200409C980000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x020101790540260000000000004028000000000000402A000000000000402C000000000000402E000000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x020101780340140000000000004024000000000000402E000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x0200402E000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017905017A074051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017A07403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017905401C000000000000402C0000000000004035000000000000403C000000000000404180000000000040450000000000004048800000000000404C000000000000404F8000000000004051800000000000405340000000000040550000000000004056C000000000004058800000000000405A400000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0200405A400000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017905017A07428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017803017A0741E8000041F0000041F80000420000004204000042080000420C00004280000042820000428400004286000042880000428A0000428C000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x06010201780301790540E000004160000041A8000041E00000420C0000422800004244000042600000427C0000428C0000429A000042A8000042B6000042C4000042D20000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x0200405A400000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02004008000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101790203626172401800000000000003666F6F4014000000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x0101017803016140000000000000000162401000000000000001634018000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x02004018000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020179017A08036261720169403500000000000003626172016A403600000000000003626172016B403700000000000003626172016C403800000000000003666F6F0169403100000000000003666F6F016A403200000000000003666F6F016B403300000000000003666F6F016C4034000000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017A0C0161016940140000000000000161016A40180000000000000161016B401C0000000000000161016C402000000000000001620169402A0000000000000162016A402C0000000000000162016B402E0000000000000162016C40300000000000000163016940350000000000000163016A40360000000000000163016B40370000000000000163016C4038000000000000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x010201780179060161036261724020000000000000016103666F6F40100000000000000162036261724030000000000000016203666F6F40280000000000000163036261724038000000000000016303666F6F4034000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x02004038000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020179017A0803626172016941A8000003626172016A41B0000003626172016B41B8000003626172016C41C0000003666F6F01694188000003666F6F016A4190000003666F6F016B4198000003666F6F016C41A00000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020178017A0C0161016940A000000161016A40C000000161016B40E000000161016C4100000001620169415000000162016A416000000162016B417000000162016C418000000163016941A800000163016A41B000000163016B41B800000163016C41C00000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x050102017801790601610362617241000000016103666F6F4080000001620362617241800000016203666F6F4140000001630362617241C00000016303666F6F41A00000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x02004038000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017A070203626172404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0202017803017A0740200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C0000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x03010179010178030203626172402C000000000000403C000000000000404500000000000003666F6F401C00000000000040350000000000004041800000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x02004045000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0301017A01017905040169404480000000000040468000000000004048800000000000404A800000000000404C800000000000016A404500000000000040470000000000004049000000000000404B000000000000404D000000000000016B404580000000000040478000000000004049800000000000404B800000000000404D800000000000016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x01020178017A0C0161016940310000000000000161016A40320000000000000161016B40330000000000000161016C40340000000000000162016940428000000000000162016A40430000000000000162016B40438000000000000162016C404400000000000001630169404C8000000000000163016A404D0000000000000163016B404D8000000000000163016C404E000000000000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03010178010179050301614010000000000000402000000000000040280000000000004030000000000000403400000000000001624038000000000000403C000000000000404000000000000040420000000000004044000000000000016340460000000000004048000000000000404A000000000000404C000000000000404E000000000000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0200404E000000000000"}}
-{"expression":"reduce(a,max,x)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x070101017A010179050401694224000042340000424400004254000042640000016A4228000042380000424800004258000042680000016B422C0000423C0000424C0000425C0000426C0000016C4230000042400000425000004260000042700000"}}
-{"expression":"reduce(a,max,y)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0501020178017A0C01610169418800000161016A419000000161016B419800000161016C41A0000001620169421400000162016A421800000162016B421C00000162016C4220000001630169426400000163016A426800000163016B426C00000163016C42700000"}}
-{"expression":"reduce(a,max,z)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701010178010179050301614080000041000000414000004180000041A00000016241C0000041E0000042000000421000004220000001634230000042400000425000004260000042700000"}}
-{"expression":"reduce(a,max)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0200404E000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02010179053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02010178033FF000000000000040180000000000004026000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0202017803017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040420000000000004042800000000000404300000000000040438000000000004044000000000000404480000000000040450000000000004051C000000000004052000000000000405240000000000040528000000000004052C0000000000040530000000000004053400000000000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x02020178030179053FF00000000000004020000000000000402E0000000000004036000000000000403D000000000000404200000000000040458000000000004049000000000000404C80000000000040500000000000004051C000000000004053800000000000405540000000000040570000000000004058C00000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060102017803017A073F80000040000000404000004080000040A0000040C0000040E00000421000004214000042180000421C0000422000004224000042280000428E00004290000042920000429400004296000042980000429A0000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x0601020178030179053F800000410000004170000041B0000041E8000042100000422C0000424800004264000042800000428E0000429C000042AA000042B8000042C60000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101790203626172400000000000000003666F6F3FF0000000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162400800000000000001634014000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020179017A08036261720169401400000000000003626172016A401800000000000003626172016B401C00000000000003626172016C402000000000000003666F6F01693FF000000000000003666F6F016A400000000000000003666F6F016B400800000000000003666F6F016C4010000000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x01020178017A0C016101693FF00000000000000161016A40000000000000000161016B40080000000000000161016C40100000000000000162016940220000000000000162016A40240000000000000162016B40260000000000000162016C40280000000000000163016940310000000000000163016A40320000000000000163016B40330000000000000163016C4034000000000000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x010201780179060161036261724014000000000000016103666F6F3FF0000000000000016203626172402A000000000000016203666F6F40220000000000000163036261724035000000000000016303666F6F4031000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020179017A0803626172016940A0000003626172016A40C0000003626172016B40E0000003626172016C4100000003666F6F01693F80000003666F6F016A4000000003666F6F016B4040000003666F6F016C40800000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x0501020178017A0C016101693F8000000161016A400000000161016B404000000161016C4080000001620169411000000162016A412000000162016B413000000162016C4140000001630169418800000163016A419000000163016B419800000163016C41A00000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x050102017801790601610362617240A00000016103666F6F3F80000001620362617241500000016203666F6F4110000001630362617241A80000016303666F6F41880000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C00000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0202017803017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017901017803020362617240200000000000004036000000000000404200000000000003666F6F3FF0000000000000402E000000000000403D000000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x0301017A010179050401693FF000000000000040140000000000004022000000000000402A0000000000004031000000000000016A400000000000000040180000000000004024000000000000402C0000000000004032000000000000016B4008000000000000401C0000000000004026000000000000402E0000000000004033000000000000016C40100000000000004020000000000000402800000000000040300000000000004034000000000000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x01020178017A0C016101693FF00000000000000161016A40000000000000000161016B40080000000000000161016C40100000000000000162016940350000000000000162016A40360000000000000162016B40370000000000000162016C40380000000000000163016940448000000000000163016A40450000000000000163016B40458000000000000163016C4046000000000000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03010178010179050301613FF000000000000040140000000000004022000000000000402A0000000000004031000000000000016240350000000000004039000000000000403D000000000000404080000000000040428000000000000163404480000000000040468000000000004048800000000000404A800000000000404C800000000000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"reduce(a,min,x)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x070101017A010179050401693F80000040A00000411000004150000041880000016A4000000040C00000412000004160000041900000016B4040000040E00000413000004170000041980000016C4080000041000000414000004180000041A00000"}}
-{"expression":"reduce(a,min,y)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0501020178017A0C016101693F8000000161016A400000000161016B404000000161016C408000000162016941A800000162016A41B000000162016B41B800000162016C41C0000001630169422400000163016A422800000163016B422C00000163016C42300000"}}
-{"expression":"reduce(a,min,z)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701010178010179050301613F80000040A00000411000004150000041880000016241A8000041C8000041E80000420400004214000001634224000042340000424400004254000042640000"}}
-{"expression":"reduce(a,min)","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"-a","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02003FFF000000000000"}}
-{"expression":"-a","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x02010178033FFF0000000000003FFE0000000000003FFD000000000000"}}
-{"expression":"-a","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x02020178030179053FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FF1000000000000"}}
-{"expression":"-a","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A073FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FF10000000000003FF00000000000003FEE0000000000003FEC0000000000003FEA0000000000003FE80000000000003FE60000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000008000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE000000000000BFFF000000000000C000000000000000C000800000000000C001000000000000C001800000000000C002000000000000C002800000000000C003000000000000C003800000000000C004000000000000C004800000000000C005000000000000C005800000000000C006000000000000C006800000000000C007000000000000C007800000000000C008000000000000C008800000000000C009000000000000C009800000000000C00A000000000000C00A800000000000C00B000000000000C00B800000000000C00C000000000000C00C800000000000C00D000000000000C00D800000000000C00E000000000000C00E800000000000C00F000000000000C00F800000000000C010000000000000C010400000000000C010800000000000C010C00000000000C011000000000000C011400000000000C011800000000000C011C00000000000C012000000000000C012400000000000"}}
-{"expression":"-a","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A073FF800003FF000003FE800003FE000003FD800003FD000003FC800003FC000003FB800003FB000003FA800003FA000003F9800003F9000003F8800003F8000003F7000003F6000003F5000003F4000003F3000003F2000003F1000003F0000003EE000003EC000003EA000003E8000003E4000003E0000003D80000080000000BD800000BE000000BE400000BE800000BEA00000BEC00000BEE00000BF000000BF100000BF200000BF300000BF400000BF500000BF600000BF700000BF800000BF880000BF900000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC80000BFD00000BFD80000BFE00000BFE80000BFF00000BFF80000C0000000C0040000C0080000C00C0000C0100000C0140000C0180000C01C0000C0200000C0240000C0280000C02C0000C0300000C0340000C0380000C03C0000C0400000C0440000C0480000C04C0000C0500000C0540000C0580000C05C0000C0600000C0640000C0680000C06C0000C0700000C0740000C0780000C07C0000C0800000C0820000C0840000C0860000C0880000C08A0000C08C0000C08E0000C0900000C0920000"}}
-{"expression":"-a","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x010101780301613FFF00000000000001623FFE00000000000001633FFD000000000000"}}
-{"expression":"-a","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261723FFE000000000000016103666F6F3FFF0000000000000162036261723FFC000000000000016203666F6F3FFD0000000000000163036261723FFA000000000000016303666F6F3FFB000000000000"}}
-{"expression":"-a","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FFB000000000000016103626172016A3FFA000000000000016103626172016B3FF9000000000000016103626172016C3FF8000000000000016103666F6F01693FFF000000000000016103666F6F016A3FFE000000000000016103666F6F016B3FFD000000000000016103666F6F016C3FFC00000000000001620362617201693FF3000000000000016203626172016A3FF2000000000000016203626172016B3FF1000000000000016203626172016C3FF0000000000000016203666F6F01693FF7000000000000016203666F6F016A3FF6000000000000016203666F6F016B3FF5000000000000016203666F6F016C3FF400000000000001630362617201693FE6000000000000016303626172016A3FE4000000000000016303626172016B3FE2000000000000016303626172016C3FE0000000000000016303666F6F01693FEE000000000000016303666F6F016A3FEC000000000000016303666F6F016B3FEA000000000000016303666F6F016C3FE8000000000000"}}
-{"expression":"-a","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A1801610362617201693FD80000016103626172016A3FD00000016103626172016B3FC80000016103626172016C3FC00000016103666F6F01693FF80000016103666F6F016A3FF00000016103666F6F016B3FE80000016103666F6F016C3FE0000001620362617201693F980000016203626172016A3F900000016203626172016B3F880000016203626172016C3F800000016203666F6F01693FB80000016203666F6F016A3FB00000016203666F6F016B3FA80000016203666F6F016C3FA0000001630362617201693F300000016303626172016A3F200000016303626172016B3F100000016303626172016C3F000000016303666F6F01693F700000016303666F6F016A3F600000016303666F6F016B3F500000016303666F6F016C3F400000"}}
-{"expression":"-a","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD0000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE400000000000003666F6F3FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF10000000000003FF00000000000003FEE0000000000003FEC0000000000003FEA0000000000003FE80000000000003FE60000000000003FC80000000000003FC00000000000003FB00000000000008000000000000000BFB0000000000000BFC0000000000000BFC8000000000000"}}
-{"expression":"-a","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FFF0000000000003FFB0000000000003FF70000000000003FF30000000000003FEE0000000000000161016A3FFE0000000000003FFA0000000000003FF60000000000003FF20000000000003FEC0000000000000161016B3FFD0000000000003FF90000000000003FF50000000000003FF10000000000003FEA0000000000000161016C3FFC0000000000003FF80000000000003FF40000000000003FF00000000000003FE8000000000000016201693FE60000000000003FDC0000000000003FC8000000000000BFB0000000000000BFD40000000000000162016A3FE40000000000003FD80000000000003FC0000000000000BFC0000000000000BFD80000000000000162016B3FE20000000000003FD40000000000003FB0000000000000BFC8000000000000BFDC0000000000000162016C3FE00000000000003FD00000000000008000000000000000BFD0000000000000BFE000000000000001630169BFE2000000000000BFEA000000000000BFF1000000000000BFF5000000000000BFF90000000000000163016ABFE4000000000000BFEC000000000000BFF2000000000000BFF6000000000000BFFA0000000000000163016BBFE6000000000000BFEE000000000000BFF3000000000000BFF7000000000000BFFB0000000000000163016CBFE8000000000000BFF0000000000000BFF4000000000000BFF8000000000000BFFC000000000000"}}
-{"expression":"-a","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C016101693FF800003FD800003FB800003F9800003F7000000161016A3FF000003FD000003FB000003F9000003F6000000161016B3FE800003FC800003FA800003F8800003F5000000161016C3FE000003FC000003FA000003F8000003F400000016201693F3000003EE000003E400000BD800000BEA000000162016A3F2000003EC000003E000000BE000000BEC000000162016B3F1000003EA000003D800000BE400000BEE000000162016C3F0000003E80000080000000BE800000BF00000001630169BF100000BF500000BF880000BFA80000BFC800000163016ABF200000BF600000BF900000BFB00000BFD000000163016BBF300000BF700000BF980000BFB80000BFD800000163016CBF400000BF800000BFA00000BFC00000BFE00000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02003FFF000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x02010178033FFF0000000000003FFE0000000000003FFD000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x02020178030179053FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FF1000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A073FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FF10000000000003FF00000000000003FEE0000000000003FEC0000000000003FEA0000000000003FE80000000000003FE60000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000008000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE000000000000BFFF000000000000C000000000000000C000800000000000C001000000000000C001800000000000C002000000000000C002800000000000C003000000000000C003800000000000C004000000000000C004800000000000C005000000000000C005800000000000C006000000000000C006800000000000C007000000000000C007800000000000C008000000000000C008800000000000C009000000000000C009800000000000C00A000000000000C00A800000000000C00B000000000000C00B800000000000C00C000000000000C00C800000000000C00D000000000000C00D800000000000C00E000000000000C00E800000000000C00F000000000000C00F800000000000C010000000000000C010400000000000C010800000000000C010C00000000000C011000000000000C011400000000000C011800000000000C011C00000000000C012000000000000C012400000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A073FF800003FF000003FE800003FE000003FD800003FD000003FC800003FC000003FB800003FB000003FA800003FA000003F9800003F9000003F8800003F8000003F7000003F6000003F5000003F4000003F3000003F2000003F1000003F0000003EE000003EC000003EA000003E8000003E4000003E0000003D80000080000000BD800000BE000000BE400000BE800000BEA00000BEC00000BEE00000BF000000BF100000BF200000BF300000BF400000BF500000BF600000BF700000BF800000BF880000BF900000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC80000BFD00000BFD80000BFE00000BFE80000BFF00000BFF80000C0000000C0040000C0080000C00C0000C0100000C0140000C0180000C01C0000C0200000C0240000C0280000C02C0000C0300000C0340000C0380000C03C0000C0400000C0440000C0480000C04C0000C0500000C0540000C0580000C05C0000C0600000C0640000C0680000C06C0000C0700000C0740000C0780000C07C0000C0800000C0820000C0840000C0860000C0880000C08A0000C08C0000C08E0000C0900000C0920000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x010101780301613FFF00000000000001623FFE00000000000001633FFD000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261723FFE000000000000016103666F6F3FFF0000000000000162036261723FFC000000000000016203666F6F3FFD0000000000000163036261723FFA000000000000016303666F6F3FFB000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FFB000000000000016103626172016A3FFA000000000000016103626172016B3FF9000000000000016103626172016C3FF8000000000000016103666F6F01693FFF000000000000016103666F6F016A3FFE000000000000016103666F6F016B3FFD000000000000016103666F6F016C3FFC00000000000001620362617201693FF3000000000000016203626172016A3FF2000000000000016203626172016B3FF1000000000000016203626172016C3FF0000000000000016203666F6F01693FF7000000000000016203666F6F016A3FF6000000000000016203666F6F016B3FF5000000000000016203666F6F016C3FF400000000000001630362617201693FE6000000000000016303626172016A3FE4000000000000016303626172016B3FE2000000000000016303626172016C3FE0000000000000016303666F6F01693FEE000000000000016303666F6F016A3FEC000000000000016303666F6F016B3FEA000000000000016303666F6F016C3FE8000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A1801610362617201693FD80000016103626172016A3FD00000016103626172016B3FC80000016103626172016C3FC00000016103666F6F01693FF80000016103666F6F016A3FF00000016103666F6F016B3FE80000016103666F6F016C3FE0000001620362617201693F980000016203626172016A3F900000016203626172016B3F880000016203626172016C3F800000016203666F6F01693FB80000016203666F6F016A3FB00000016203666F6F016B3FA80000016203666F6F016C3FA0000001630362617201693F300000016303626172016A3F200000016303626172016B3F100000016303626172016C3F000000016303666F6F01693F700000016303666F6F016A3F600000016303666F6F016B3F500000016303666F6F016C3F400000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF80000000000003FF70000000000003FF60000000000003FF50000000000003FF40000000000003FF30000000000003FF20000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD0000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE400000000000003666F6F3FFF0000000000003FFE0000000000003FFD0000000000003FFC0000000000003FFB0000000000003FFA0000000000003FF90000000000003FF10000000000003FF00000000000003FEE0000000000003FEC0000000000003FEA0000000000003FE80000000000003FE60000000000003FC80000000000003FC00000000000003FB00000000000008000000000000000BFB0000000000000BFC0000000000000BFC8000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FFF0000000000003FFB0000000000003FF70000000000003FF30000000000003FEE0000000000000161016A3FFE0000000000003FFA0000000000003FF60000000000003FF20000000000003FEC0000000000000161016B3FFD0000000000003FF90000000000003FF50000000000003FF10000000000003FEA0000000000000161016C3FFC0000000000003FF80000000000003FF40000000000003FF00000000000003FE8000000000000016201693FE60000000000003FDC0000000000003FC8000000000000BFB0000000000000BFD40000000000000162016A3FE40000000000003FD80000000000003FC0000000000000BFC0000000000000BFD80000000000000162016B3FE20000000000003FD40000000000003FB0000000000000BFC8000000000000BFDC0000000000000162016C3FE00000000000003FD00000000000008000000000000000BFD0000000000000BFE000000000000001630169BFE2000000000000BFEA000000000000BFF1000000000000BFF5000000000000BFF90000000000000163016ABFE4000000000000BFEC000000000000BFF2000000000000BFF6000000000000BFFA0000000000000163016BBFE6000000000000BFEE000000000000BFF3000000000000BFF7000000000000BFFB0000000000000163016CBFE8000000000000BFF0000000000000BFF4000000000000BFF8000000000000BFFC000000000000"}}
-{"expression":"map(a,f(a)(-a))","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C016101693FF800003FD800003FB800003F9800003F7000000161016A3FF000003FD000003FB000003F9000003F6000000161016B3FE800003FC800003FA800003F8800003F5000000161016C3FE000003FC000003FA000003F8000003F400000016201693F3000003EE000003E400000BD800000BEA000000162016A3F2000003EC000003E000000BE000000BEC000000162016B3F1000003EA000003D800000BE400000BEE000000162016C3F0000003E80000080000000BE800000BF00000001630169BF100000BF500000BF880000BFA80000BFC800000163016ABF200000BF600000BF900000BFB00000BFD000000163016BBF300000BF700000BF980000BFB80000BFD800000163016CBF400000BF800000BFA00000BFC00000BFE00000"}}
-{"expression":"!a","inputs":{"a":"0x02000000000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"!a","inputs":{"a":"0x020101780300000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02020178030179053FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A073FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x060103017803017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000"},"result":{"expect":"0x060103017803017905017A073F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F8000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A0000000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201693FF0000000000000016303626172016A0000000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B0000000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A3FF0000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B3FF0000000000000016303666F6F016C0000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B00000000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C00000000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C00000000016203666F6F01693F800000016203666F6F016A00000000016203666F6F016B3F800000016203666F6F016C3F80000001630362617201693F800000016303626172016A00000000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B00000000016303666F6F016C3F800000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C3F80000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A3F800000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B3F800000016303666F6F016C00000000"}}
-{"expression":"!a","inputs":{"a":"0x0301017902017803017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000161016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016A00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000162016B3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000162016C3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016301693FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016A3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000163016B00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016C3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016B00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016C3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016C00000000000000003FF0000000000000000000000000000000000000000000003FF000000000000001630169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"!a","inputs":{"a":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A3F8000003F800000000000003F8000003F8000000161016B3F800000000000003F8000003F800000000000000161016C000000003F8000003F800000000000003F800000016201693F800000000000003F8000003F800000000000000162016A000000003F8000003F800000000000003F8000000162016B3F8000003F800000000000003F8000003F8000000162016C3F800000000000003F8000003F80000000000000016301693F8000003F800000000000003F8000003F8000000163016A3F800000000000003F8000003F800000000000000163016B000000003F8000003F800000000000003F8000000163016C3F8000003F800000000000003F8000003F800000"},"result":{"expect":"0x0701020178017A010179050C016101693F80000000000000000000003F800000000000000161016A00000000000000003F80000000000000000000000161016B000000003F80000000000000000000003F8000000161016C3F80000000000000000000003F8000000000000001620169000000003F80000000000000000000003F8000000162016A3F80000000000000000000003F800000000000000162016B00000000000000003F80000000000000000000000162016C000000003F80000000000000000000003F8000000163016900000000000000003F80000000000000000000000163016A000000003F80000000000000000000003F8000000163016B3F80000000000000000000003F800000000000000163016C00000000000000003F8000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x02000000000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x020101780300000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02020178030179053FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A073FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x060103017803017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000"},"result":{"expect":"0x060103017803017905017A073F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F8000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A0000000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201693FF0000000000000016303626172016A0000000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B0000000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A3FF0000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B3FF0000000000000016303666F6F016C0000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B00000000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C00000000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C00000000016203666F6F01693F800000016203666F6F016A00000000016203666F6F016B3F800000016203666F6F016C3F80000001630362617201693F800000016303626172016A00000000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B00000000016303666F6F016C3F800000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C3F80000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A3F800000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B3F800000016303666F6F016C00000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x0301017902017803017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000161016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016A00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000162016B3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000162016C3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016301693FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016A3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000163016B00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016C3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016B00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016C3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016C00000000000000003FF0000000000000000000000000000000000000000000003FF000000000000001630169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(!a))","inputs":{"a":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A3F8000003F800000000000003F8000003F8000000161016B3F800000000000003F8000003F800000000000000161016C000000003F8000003F800000000000003F800000016201693F800000000000003F8000003F800000000000000162016A000000003F8000003F800000000000003F8000000162016B3F8000003F800000000000003F8000003F8000000162016C3F800000000000003F8000003F80000000000000016301693F8000003F800000000000003F8000003F8000000163016A3F800000000000003F8000003F800000000000000163016B000000003F8000003F800000000000003F8000000163016C3F8000003F800000000000003F8000003F800000"},"result":{"expect":"0x0701020178017A010179050C016101693F80000000000000000000003F800000000000000161016A00000000000000003F80000000000000000000000161016B000000003F80000000000000000000003F8000000161016C3F80000000000000000000003F8000000000000001620169000000003F80000000000000000000003F8000000162016A3F80000000000000000000003F800000000000000162016B00000000000000003F80000000000000000000000162016C000000003F80000000000000000000003F8000000163016900000000000000003F80000000000000000000000163016A000000003F80000000000000000000003F8000000163016B3F80000000000000000000003F800000000000000163016C00000000000000003F8000000000000000000000"}}
-{"expression":"cos(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEFF0015549F4D3"}}
-{"expression":"cos(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C"}}
-{"expression":"cos(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FE2F011326420E4"}}
-{"expression":"cos(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FE2F011326420E43FE14A280FB5068C3FDF25EC6B852FC23FDB9865639D05963FD7EF4842F0BCCD3FD42E3DD88BD9523FD05906DEC537DA3FC8E6F075A987D63FC102EE507FF5F03FB21BD54FC5F9A73F80FD9D5C093DF5BFABBD1AFE4369EFBFBDCEF1441CB33CBFC6D0C449D3E98ABFCEA34113FA728FBFD32B8E9548FCE1BFD6F252AAE8625BBFDAA22657537205BFDE375A15821AB9BFE0D72C7F114E12BFE281D62E1A3938BFE419FF91B9BA6DBFE59E10A28E82EDBFE70C856FDD6B67BFE863EFA361DC25BFE9A2F7EF858B7DBFEAC85F6691793EBFEBD300B98112C3BFECC1D15D38C71CBFED93E294FAED14BFEE486261109C75BFEEDE9C50B7E58FBFEF55FA36858A40BFEFAE04BE85E5D2BFEFE663E586EF52BFEFFEDF51141634BFEFF75E87CC04E0BFEFCFE909D7F7F8BFEF88A6496C3517BFEF21DD83591FF9BFEE9BF577D4599DBFEDF77403C11A5FBFED34FD9ADE7622BFEC5554A3615112BFEB5958B39E5D69BFEA4205B28667F7BFE91072DBD4648DBFE7C5D1A8E8F73EBFE6636C9F6A87A7BFE4EAA606DB24C1BFE35CF6866E87CCBFE1BBEBAC8242CFBFE009266130831CBFDC8CB28B1567F5BFD8EA8E02394848BFD52F80FED50D4CBFD15F463E585762BFCAFB5B54583D6ABFC31D31103535F6BFB657D66570F13FBF997BD2C2A556593FA34096E1D37B743FB995EC1460ADC73FC4B8FC76C25C0F3FCC924BA0E3EC983FD22785706B4AD93FD5F3BF0E326A233FD9AA06C12BA6E03FDD46A690D2085E3FE06301153054093FE2124D3E6C39153FE3AF889BE348313FE5391614A681983FE6AD6C3C07D4483FE80B16DAE604223FE950B863C4C78F3FEA7D0B503D23AA3FEB8EE36668B3943FEC852EE5028ADD3FED5EF79511AB1A3FEE1B63C00B78FB3FEEB9B7097822F53FEF39532B3F67403FEF99B893E17BFF3FEFDA86E5FDEDF63FEFFB7D58A8F9753FEFFC7AF82F103A3FEFDD7EC705CE193FEF9EA7BEC96E463FEF4034B145C3C83FEEC28409A9A9A9"}}
-{"expression":"cos(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F7F800B3F7E00AB3F7B835F3F780AA53F7399F53F6E35BF3F67E3683F60A9403F588E823F4F9B473F45D8833F3B4FF63F300C293F24185F3F17808A3F0A51403EF92F633EDCC32B3EBF7A423EA171EF3E82C8373E4737843E0817733D90DEAA3C07ECEBBD5DE8D8BDEE778ABE368622BE751A09BE995C75BEB79295BED51133BEF1BAD1BF06B964BF140EB1BF20CFFDBF2CF085BF38642BBF431F7DBF4D17BFBF5642FBBF5E9806BF660E8BBF6C9F15BF724313BF76F4E3BF7AAFD2BF7D7026BF7F331FBF7FF6FBBF7FBAF4BF7E7F48BF7C4532BF790EECBF74DFACBF6FBBA0BF69A7EDBF62AAA5BF5ACAC6BF52102EBF488397BF3E2E8DBF331B65BF275530BF1AE7B4BF0DDF5DBF004933BEE46594BEC75470BEA97C08BE8AFA32BE57DADBBE18E989BDB2BEB3BCCBDE963D1A04B73DCCAF613E25C7E43E64925D3E913C2C3EAF9DF83ECD50363EEA35353F0318093F10926A3F1D7C453F29C8B13F356B623F4058B73F4A85C33F53E85B3F5C771B3F6429773F6AF7BD3F70DB1E3F75CDB83F79CA993F7CCDC53F7ED4373F7FDBEB3F7FE3D83F7EEBF63F7CF53E3F7A01A63F761420"}}
-{"expression":"cos(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEFF0015549F4D301623FEFC015527D5BD301633FEF706BDF9ECE1C"}}
-{"expression":"cos(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FEFC015527D5BD3016103666F6F3FEFF0015549F4D30162036261723FEF01549F7DEEA1016203666F6F3FEF706BDF9ECE1C0163036261723FEDC6B7EB995912016303666F6F3FEE733EA0193D40"}}
-{"expression":"cos(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FEE733EA0193D40016103626172016A3FEDC6B7EB995912016103626172016B3FECFC6CFA52AD9F016103626172016C3FEC1528065B7D50016103666F6F01693FEFF0015549F4D3016103666F6F016A3FEFC015527D5BD3016103666F6F016B3FEF706BDF9ECE1C016103666F6F016C3FEF01549F7DEEA101620362617201693FE6018526F563DF016203626172016A3FE4830BD7D4CEB3016203626172016B3FE2F011326420E4016203626172016C3FE14A280FB5068C016203666F6F01693FEB11D04162A4C6016203666F6F016A3FE9F368ED912F85016203666F6F016B3FE8BB105A5DC900016203666F6F016C3FE769FEC655211F01630362617201693FD05906DEC537DA016303626172016A3FC8E6F075A987D6016303626172016B3FC102EE507FF5F0016303626172016C3FB21BD54FC5F9A7016303666F6F01693FDF25EC6B852FC2016303666F6F016A3FDB9865639D0596016303666F6F016B3FD7EF4842F0BCCD016303666F6F016C3FD42E3DD88BD952"}}
-{"expression":"cos(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F7399F5016103626172016A3F6E35BF016103626172016B3F67E368016103626172016C3F60A940016103666F6F01693F7F800B016103666F6F016A3F7E00AB016103666F6F016B3F7B835F016103666F6F016C3F780AA501620362617201693F300C29016203626172016A3F24185F016203626172016B3F17808A016203626172016C3F0A5140016203666F6F01693F588E82016203666F6F016A3F4F9B47016203666F6F016B3F45D883016203666F6F016C3F3B4FF601630362617201693E82C837016303626172016A3E473784016303626172016B3E081773016303626172016C3D90DEAA016303666F6F01693EF92F63016303666F6F016A3EDCC32B016303666F6F016B3EBF7A42016303666F6F016C3EA171EF"}}
-{"expression":"cos(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FC8E6F075A987D63FC102EE507FF5F03FB21BD54FC5F9A73F80FD9D5C093DF5BFABBD1AFE4369EFBFBDCEF1441CB33CBFC6D0C449D3E98ABFE419FF91B9BA6DBFE59E10A28E82EDBFE70C856FDD6B67BFE863EFA361DC25BFE9A2F7EF858B7DBFEAC85F6691793EBFEBD300B98112C303666F6F3FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FE2F011326420E43FE14A280FB5068C3FDF25EC6B852FC23FDB9865639D05963FD7EF4842F0BCCD3FD42E3DD88BD9523FD05906DEC537DABFCEA34113FA728FBFD32B8E9548FCE1BFD6F252AAE8625BBFDAA22657537205BFDE375A15821AB9BFE0D72C7F114E12BFE281D62E1A3938"}}
-{"expression":"cos(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEFF0015549F4D33FEE733EA0193D403FEB11D04162A4C63FE6018526F563DF3FDF25EC6B852FC20161016A3FEFC015527D5BD33FEDC6B7EB9959123FE9F368ED912F853FE4830BD7D4CEB33FDB9865639D05960161016B3FEF706BDF9ECE1C3FECFC6CFA52AD9F3FE8BB105A5DC9003FE2F011326420E43FD7EF4842F0BCCD0161016C3FEF01549F7DEEA13FEC1528065B7D503FE769FEC655211F3FE14A280FB5068C3FD42E3DD88BD952016201693FD05906DEC537DA3F80FD9D5C093DF5BFCEA34113FA728FBFDE375A15821AB9BFE59E10A28E82ED0162016A3FC8E6F075A987D6BFABBD1AFE4369EFBFD32B8E9548FCE1BFE0D72C7F114E12BFE70C856FDD6B670162016B3FC102EE507FF5F0BFBDCEF1441CB33CBFD6F252AAE8625BBFE281D62E1A3938BFE863EFA361DC250162016C3FB21BD54FC5F9A7BFC6D0C449D3E98ABFDAA22657537205BFE419FF91B9BA6DBFE9A2F7EF858B7D01630169BFEAC85F6691793EBFEE486261109C75BFEFE663E586EF52BFEF88A6496C3517BFED34FD9ADE76220163016ABFEBD300B98112C3BFEEDE9C50B7E58FBFEFFEDF51141634BFEF21DD83591FF9BFEC5554A36151120163016BBFECC1D15D38C71CBFEF55FA36858A40BFEFF75E87CC04E0BFEE9BF577D4599DBFEB5958B39E5D690163016CBFED93E294FAED14BFEFAE04BE85E5D2BFEFCFE909D7F7F8BFEDF77403C11A5FBFEA4205B28667F7"}}
-{"expression":"cos(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F7F800B3F7399F53F588E823F300C293EF92F630161016A3F7E00AB3F6E35BF3F4F9B473F24185F3EDCC32B0161016B3F7B835F3F67E3683F45D8833F17808A3EBF7A420161016C3F780AA53F60A9403F3B4FF63F0A51403EA171EF016201693E82C8373C07ECEBBE751A09BEF1BAD1BF2CF0850162016A3E473784BD5DE8D8BE995C75BF06B964BF38642B0162016B3E081773BDEE778ABEB79295BF140EB1BF431F7D0162016C3D90DEAABE368622BED51133BF20CFFDBF4D17BF01630169BF5642FBBF724313BF7F331FBF7C4532BF69A7ED0163016ABF5E9806BF76F4E3BF7FF6FBBF790EECBF62AAA50163016BBF660E8BBF7AAFD2BF7FBAF4BF74DFACBF5ACAC60163016CBF6C9F15BF7D7026BF7E7F48BF6FBBA0BF52102E"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEFF0015549F4D3"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FE2F011326420E4"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FE2F011326420E43FE14A280FB5068C3FDF25EC6B852FC23FDB9865639D05963FD7EF4842F0BCCD3FD42E3DD88BD9523FD05906DEC537DA3FC8E6F075A987D63FC102EE507FF5F03FB21BD54FC5F9A73F80FD9D5C093DF5BFABBD1AFE4369EFBFBDCEF1441CB33CBFC6D0C449D3E98ABFCEA34113FA728FBFD32B8E9548FCE1BFD6F252AAE8625BBFDAA22657537205BFDE375A15821AB9BFE0D72C7F114E12BFE281D62E1A3938BFE419FF91B9BA6DBFE59E10A28E82EDBFE70C856FDD6B67BFE863EFA361DC25BFE9A2F7EF858B7DBFEAC85F6691793EBFEBD300B98112C3BFECC1D15D38C71CBFED93E294FAED14BFEE486261109C75BFEEDE9C50B7E58FBFEF55FA36858A40BFEFAE04BE85E5D2BFEFE663E586EF52BFEFFEDF51141634BFEFF75E87CC04E0BFEFCFE909D7F7F8BFEF88A6496C3517BFEF21DD83591FF9BFEE9BF577D4599DBFEDF77403C11A5FBFED34FD9ADE7622BFEC5554A3615112BFEB5958B39E5D69BFEA4205B28667F7BFE91072DBD4648DBFE7C5D1A8E8F73EBFE6636C9F6A87A7BFE4EAA606DB24C1BFE35CF6866E87CCBFE1BBEBAC8242CFBFE009266130831CBFDC8CB28B1567F5BFD8EA8E02394848BFD52F80FED50D4CBFD15F463E585762BFCAFB5B54583D6ABFC31D31103535F6BFB657D66570F13FBF997BD2C2A556593FA34096E1D37B743FB995EC1460ADC73FC4B8FC76C25C0F3FCC924BA0E3EC983FD22785706B4AD93FD5F3BF0E326A233FD9AA06C12BA6E03FDD46A690D2085E3FE06301153054093FE2124D3E6C39153FE3AF889BE348313FE5391614A681983FE6AD6C3C07D4483FE80B16DAE604223FE950B863C4C78F3FEA7D0B503D23AA3FEB8EE36668B3943FEC852EE5028ADD3FED5EF79511AB1A3FEE1B63C00B78FB3FEEB9B7097822F53FEF39532B3F67403FEF99B893E17BFF3FEFDA86E5FDEDF63FEFFB7D58A8F9753FEFFC7AF82F103A3FEFDD7EC705CE193FEF9EA7BEC96E463FEF4034B145C3C83FEEC28409A9A9A9"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F7F800B3F7E00AB3F7B835F3F780AA53F7399F53F6E35BF3F67E3683F60A9403F588E823F4F9B473F45D8833F3B4FF63F300C293F24185F3F17808A3F0A51403EF92F633EDCC32B3EBF7A423EA171EF3E82C8373E4737843E0817733D90DEAA3C07ECEBBD5DE8D8BDEE778ABE368622BE751A09BE995C75BEB79295BED51133BEF1BAD1BF06B964BF140EB1BF20CFFDBF2CF085BF38642BBF431F7DBF4D17BFBF5642FBBF5E9806BF660E8BBF6C9F15BF724313BF76F4E3BF7AAFD2BF7D7026BF7F331FBF7FF6FBBF7FBAF4BF7E7F48BF7C4532BF790EECBF74DFACBF6FBBA0BF69A7EDBF62AAA5BF5ACAC6BF52102EBF488397BF3E2E8DBF331B65BF275530BF1AE7B4BF0DDF5DBF004933BEE46594BEC75470BEA97C08BE8AFA32BE57DADBBE18E989BDB2BEB3BCCBDE963D1A04B73DCCAF613E25C7E43E64925D3E913C2C3EAF9DF83ECD50363EEA35353F0318093F10926A3F1D7C453F29C8B13F356B623F4058B73F4A85C33F53E85B3F5C771B3F6429773F6AF7BD3F70DB1E3F75CDB83F79CA993F7CCDC53F7ED4373F7FDBEB3F7FE3D83F7EEBF63F7CF53E3F7A01A63F761420"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEFF0015549F4D301623FEFC015527D5BD301633FEF706BDF9ECE1C"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FEFC015527D5BD3016103666F6F3FEFF0015549F4D30162036261723FEF01549F7DEEA1016203666F6F3FEF706BDF9ECE1C0163036261723FEDC6B7EB995912016303666F6F3FEE733EA0193D40"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FEE733EA0193D40016103626172016A3FEDC6B7EB995912016103626172016B3FECFC6CFA52AD9F016103626172016C3FEC1528065B7D50016103666F6F01693FEFF0015549F4D3016103666F6F016A3FEFC015527D5BD3016103666F6F016B3FEF706BDF9ECE1C016103666F6F016C3FEF01549F7DEEA101620362617201693FE6018526F563DF016203626172016A3FE4830BD7D4CEB3016203626172016B3FE2F011326420E4016203626172016C3FE14A280FB5068C016203666F6F01693FEB11D04162A4C6016203666F6F016A3FE9F368ED912F85016203666F6F016B3FE8BB105A5DC900016203666F6F016C3FE769FEC655211F01630362617201693FD05906DEC537DA016303626172016A3FC8E6F075A987D6016303626172016B3FC102EE507FF5F0016303626172016C3FB21BD54FC5F9A7016303666F6F01693FDF25EC6B852FC2016303666F6F016A3FDB9865639D0596016303666F6F016B3FD7EF4842F0BCCD016303666F6F016C3FD42E3DD88BD952"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F7399F5016103626172016A3F6E35BF016103626172016B3F67E368016103626172016C3F60A940016103666F6F01693F7F800B016103666F6F016A3F7E00AB016103666F6F016B3F7B835F016103666F6F016C3F780AA501620362617201693F300C29016203626172016A3F24185F016203626172016B3F17808A016203626172016C3F0A5140016203666F6F01693F588E82016203666F6F016A3F4F9B47016203666F6F016B3F45D883016203666F6F016C3F3B4FF601630362617201693E82C837016303626172016A3E473784016303626172016B3E081773016303626172016C3D90DEAA016303666F6F01693EF92F63016303666F6F016A3EDCC32B016303666F6F016B3EBF7A42016303666F6F016C3EA171EF"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FEC1528065B7D503FEB11D04162A4C63FE9F368ED912F853FE8BB105A5DC9003FE769FEC655211F3FE6018526F563DF3FE4830BD7D4CEB33FC8E6F075A987D63FC102EE507FF5F03FB21BD54FC5F9A73F80FD9D5C093DF5BFABBD1AFE4369EFBFBDCEF1441CB33CBFC6D0C449D3E98ABFE419FF91B9BA6DBFE59E10A28E82EDBFE70C856FDD6B67BFE863EFA361DC25BFE9A2F7EF858B7DBFEAC85F6691793EBFEBD300B98112C303666F6F3FEFF0015549F4D33FEFC015527D5BD33FEF706BDF9ECE1C3FEF01549F7DEEA13FEE733EA0193D403FEDC6B7EB9959123FECFC6CFA52AD9F3FE2F011326420E43FE14A280FB5068C3FDF25EC6B852FC23FDB9865639D05963FD7EF4842F0BCCD3FD42E3DD88BD9523FD05906DEC537DABFCEA34113FA728FBFD32B8E9548FCE1BFD6F252AAE8625BBFDAA22657537205BFDE375A15821AB9BFE0D72C7F114E12BFE281D62E1A3938"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEFF0015549F4D33FEE733EA0193D403FEB11D04162A4C63FE6018526F563DF3FDF25EC6B852FC20161016A3FEFC015527D5BD33FEDC6B7EB9959123FE9F368ED912F853FE4830BD7D4CEB33FDB9865639D05960161016B3FEF706BDF9ECE1C3FECFC6CFA52AD9F3FE8BB105A5DC9003FE2F011326420E43FD7EF4842F0BCCD0161016C3FEF01549F7DEEA13FEC1528065B7D503FE769FEC655211F3FE14A280FB5068C3FD42E3DD88BD952016201693FD05906DEC537DA3F80FD9D5C093DF5BFCEA34113FA728FBFDE375A15821AB9BFE59E10A28E82ED0162016A3FC8E6F075A987D6BFABBD1AFE4369EFBFD32B8E9548FCE1BFE0D72C7F114E12BFE70C856FDD6B670162016B3FC102EE507FF5F0BFBDCEF1441CB33CBFD6F252AAE8625BBFE281D62E1A3938BFE863EFA361DC250162016C3FB21BD54FC5F9A7BFC6D0C449D3E98ABFDAA22657537205BFE419FF91B9BA6DBFE9A2F7EF858B7D01630169BFEAC85F6691793EBFEE486261109C75BFEFE663E586EF52BFEF88A6496C3517BFED34FD9ADE76220163016ABFEBD300B98112C3BFEEDE9C50B7E58FBFEFFEDF51141634BFEF21DD83591FF9BFEC5554A36151120163016BBFECC1D15D38C71CBFEF55FA36858A40BFEFF75E87CC04E0BFEE9BF577D4599DBFEB5958B39E5D690163016CBFED93E294FAED14BFEFAE04BE85E5D2BFEFCFE909D7F7F8BFEDF77403C11A5FBFEA4205B28667F7"}}
-{"expression":"map(a,f(a)(cos(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F7F800B3F7399F53F588E823F300C293EF92F630161016A3F7E00AB3F6E35BF3F4F9B473F24185F3EDCC32B0161016B3F7B835F3F67E3683F45D8833F17808A3EBF7A420161016C3F780AA53F60A9403F3B4FF63F0A51403EA171EF016201693E82C8373C07ECEBBE751A09BEF1BAD1BF2CF0850162016A3E473784BD5DE8D8BE995C75BF06B964BF38642B0162016B3E081773BDEE778ABEB79295BF140EB1BF431F7D0162016C3D90DEAABE368622BED51133BF20CFFDBF4D17BF01630169BF5642FBBF724313BF7F331FBF7C4532BF69A7ED0163016ABF5E9806BF76F4E3BF7FF6FBBF790EECBF62AAA50163016BBF660E8BBF7AAFD2BF7FBAF4BF74DFACBF5ACAC60163016CBF6C9F15BF7D7026BF7E7F48BF6FBBA0BF52102E"}}
-{"expression":"sin(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFFAAAEEED4EDB"}}
-{"expression":"sin(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B5"}}
-{"expression":"sin(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FE9CB6A9BBCE64B"}}
-{"expression":"sin(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FE9CB6A9BBCE64B3FEAED548F090CEE3FEBF4536C24BB853FECDF604A1CADCE3FEDAD902FA8AC873FEE5E14FE11418C3FEEF03E3F3D42A23FEF6379D619369D3FEFB75490A83C2C3FEFEB7A9B2C6D8B3FEFFFB7D3F3A2533FEFF3F7FF74C9A73FEFC846DC89C3AF3FEF7CD018B182463FEF11DF24662DAD3FEE87DEE7B2F3933FEDDF595754E4443FED18F6EAD1B4463FEC357DF40E40243FEB35D1D90D2DD63FEA1AF2309BDCA63FE8E5F9C2D0E3A93FE7981D6E5B8B113FE632AAF3BED93B3FE4B707A7ACDECD3FE326AF0DCFCAB13FE183315D65DF2A3FDF9C63E25718C73FDC12CB48474A243FD86D2239C183FB3FD4AF0E1208CD6D3FD0DC4C957085213FC9F16067CFB7383FC210386DB6D55B3FB43A0378FADB653F90FD770A03E5AABFA77F0DEE42925CBFBBB2AD2464A48CBFC5C51179A9D633BFCD9B09200454F7BFD2A9B41A5FED1FBFD6733B7EBA621FBFDA26518675C600BFDDBF436A743C91BFE09D3C42C705C2BFE24A3AF6750621BFE3E4F0F54F24AABFE56BC3AB8F386FBFE6DD2C670F7AA7BFE837B9DDDC1EAEBFE97A119F5E80B1BFEAA2F16EB0DE8EBFEBB13084C06416BFECA3C0B8FB8370BFED79AF8F640408BFEE32272AF6CC72BFEECC6F237713B1BFEF47ED3DC74080BFEFA42606172D14BFEFE0BD4B4DADF3BFEFFD767B31FCA1BFEFFA34DEF8E460BFEFD6FBB7F928EABFEF93EE3C6A751BBFEF314F7432125FBFEEAF81F5E09933BFEE0F0784239781BFED50808C0DB2ECBFEC74AB84B6F427BFEB7C6430D58DA3BFEA68A2C30D7500BFE93A7AE5D26D43BFE7F31AA7D48B36BFE693C94E0AB057BFE51DE60C88D8D5BFE392E6A7694AEEBFE1F455FD27A14CBFE043D27BE3362FBFDD06190627183ABFD967896699BA40BFD5AF945B89D004BFD1E1F18AB0A2C0BFCC04DC8B7DB26ABFC429D37AB7C0E8BFB87544891F6C54BFA0FCDDC3F512BC3F9E0391FB79D87D3FB778B79B464BD93FC3AC89FA5E11293FCB890D40C6CB3C3FD1A504E2A377CE"}}
-{"expression":"sin(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FD5573DFF55773E3EE0813E7D57773E9D68953EBB88133ED8EC183EF577443F0886863F15C8EF3F22759C3F2E7FE13F39DBB43F447DBB3F4E5B553F576AA43F5FA29B3F66FB023F6D6C813F72F0A83F7781F23F7B1BCF3F7DBAA53F7F5BD53F7FFDBF3F7F9FC03F7E42373F7BE6813F788EF93F743EF73F6EFACB3F68C7B73F61ABF03F59AE8F3F50D7923F472FCE3F3CC0EB3F3195583F25B83D3F1935783F0C198B3EFCE31F3EE0965A3EC369123EA578713E86E2653E4F8B033E1081C33DA1D01C3C87EBB8BD3BF86FBDDD9569BE2E288CBE6CD849BE954DA1BEB399DCBED1328CBEEDFA1BBF04E9E2BF1251D8BF1F2788BF2B5E1DBF36E963BF41BDCFBF4BD08DBF55178BBF5D8984BF651E06BF6BCD7CBF719139BF766379BF7A3F6ABF7D2130BF7F05EABF7FEBB4BF7FD1A7BF7EB7DEBF7C9F72BF798A7CBF757C10BF70783CBF6A8404BF63A55CBF5BE322BF534516BF49D3D7BF3F98D5BF349E4ABF28EF30BF1C9735BF0FA2B0BF021E94BEE830C8BECB3C4BBEAD7CA3BE8F0F8CBE6026E4BE214E9CBDC3AA24BD07E6EE3CF01C903DBBC5BD3E1D64503E5C486A3E8D2827"}}
-{"expression":"sin(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFFAAAEEED4EDB01623FBFEAAEEE86EE3601633FC7DC102FBAF2B5"}}
-{"expression":"sin(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFEAAEEE86EE36016103666F6F3FAFFAAAEEED4EDB0162036261723FCFAAEED4F31577016203666F6F3FC7DC102FBAF2B50163036261723FD7710255764214016303666F6F3FD3AD129769D3D8"}}
-{"expression":"sin(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD3AD129769D3D8016103626172016A3FD7710255764214016103626172016B3FDB1D8305321617016103626172016C3FDEAEE8744B05F0016103666F6F01693FAFFAAAEEED4EDB016103666F6F016A3FBFEAAEEE86EE36016103666F6F016B3FC7DC102FBAF2B5016103666F6F016C3FCFAAEED4F3157701620362617201693FE73B7680DEA578016203626172016A3FE88FB7640B8DA2016203626172016B3FE9CB6A9BBCE64B016203626172016C3FEAED548F090CEE016203666F6F01693FE110D0C4B69C3B016203666F6F016A3FE2B91DEA88421E016203666F6F016B3FE44EB381CF386B016203666F6F016C3FE5CFFC16BF8F0D01630362617201693FEEF03E3F3D42A2016303626172016A3FEF6379D619369D016303626172016B3FEFB75490A83C2C016303626172016C3FEFEB7A9B2C6D8B016303666F6F01693FEBF4536C24BB85016303666F6F016A3FECDF604A1CADCE016303666F6F016B3FEDAD902FA8AC87016303666F6F016C3FEE5E14FE11418C"}}
-{"expression":"sin(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9D6895016103626172016A3EBB8813016103626172016B3ED8EC18016103626172016C3EF57744016103666F6F01693D7FD557016103666F6F016A3DFF5577016103666F6F016B3E3EE081016103666F6F016C3E7D577701620362617201693F39DBB4016203626172016A3F447DBB016203626172016B3F4E5B55016203626172016C3F576AA4016203666F6F01693F088686016203666F6F016A3F15C8EF016203666F6F016B3F22759C016203666F6F016C3F2E7FE101630362617201693F7781F2016303626172016A3F7B1BCF016303626172016B3F7DBAA5016303626172016C3F7F5BD5016303666F6F01693F5FA29B016303666F6F016A3F66FB02016303666F6F016B3F6D6C81016303666F6F016C3F72F0A8"}}
-{"expression":"sin(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FEF6379D619369D3FEFB75490A83C2C3FEFEB7A9B2C6D8B3FEFFFB7D3F3A2533FEFF3F7FF74C9A73FEFC846DC89C3AF3FEF7CD018B182463FE8E5F9C2D0E3A93FE7981D6E5B8B113FE632AAF3BED93B3FE4B707A7ACDECD3FE326AF0DCFCAB13FE183315D65DF2A3FDF9C63E25718C703666F6F3FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FE9CB6A9BBCE64B3FEAED548F090CEE3FEBF4536C24BB853FECDF604A1CADCE3FEDAD902FA8AC873FEE5E14FE11418C3FEEF03E3F3D42A23FEF11DF24662DAD3FEE87DEE7B2F3933FEDDF595754E4443FED18F6EAD1B4463FEC357DF40E40243FEB35D1D90D2DD63FEA1AF2309BDCA6"}}
-{"expression":"sin(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFFAAAEEED4EDB3FD3AD129769D3D83FE110D0C4B69C3B3FE73B7680DEA5783FEBF4536C24BB850161016A3FBFEAAEEE86EE363FD77102557642143FE2B91DEA88421E3FE88FB7640B8DA23FECDF604A1CADCE0161016B3FC7DC102FBAF2B53FDB1D83053216173FE44EB381CF386B3FE9CB6A9BBCE64B3FEDAD902FA8AC870161016C3FCFAAEED4F315773FDEAEE8744B05F03FE5CFFC16BF8F0D3FEAED548F090CEE3FEE5E14FE11418C016201693FEEF03E3F3D42A23FEFFFB7D3F3A2533FEF11DF24662DAD3FEC357DF40E40243FE7981D6E5B8B110162016A3FEF6379D619369D3FEFF3F7FF74C9A73FEE87DEE7B2F3933FEB35D1D90D2DD63FE632AAF3BED93B0162016B3FEFB75490A83C2C3FEFC846DC89C3AF3FEDDF595754E4443FEA1AF2309BDCA63FE4B707A7ACDECD0162016C3FEFEB7A9B2C6D8B3FEF7CD018B182463FED18F6EAD1B4463FE8E5F9C2D0E3A93FE326AF0DCFCAB1016301693FE183315D65DF2A3FD4AF0E1208CD6D3FB43A0378FADB65BFC5C51179A9D633BFDA26518675C6000163016A3FDF9C63E25718C73FD0DC4C957085213F90FD770A03E5AABFCD9B09200454F7BFDDBF436A743C910163016B3FDC12CB48474A243FC9F16067CFB738BFA77F0DEE42925CBFD2A9B41A5FED1FBFE09D3C42C705C20163016C3FD86D2239C183FB3FC210386DB6D55BBFBBB2AD2464A48CBFD6733B7EBA621FBFE24A3AF6750621"}}
-{"expression":"sin(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FD5573E9D68953F0886863F39DBB43F5FA29B0161016A3DFF55773EBB88133F15C8EF3F447DBB3F66FB020161016B3E3EE0813ED8EC183F22759C3F4E5B553F6D6C810161016C3E7D57773EF577443F2E7FE13F576AA43F72F0A8016201693F7781F23F7FFDBF3F788EF93F61ABF03F3CC0EB0162016A3F7B1BCF3F7F9FC03F743EF73F59AE8F3F3195580162016B3F7DBAA53F7E42373F6EFACB3F50D7923F25B83D0162016C3F7F5BD53F7BE6813F68C7B73F472FCE3F193578016301693F0C198B3EA578713DA1D01CBE2E288CBED1328C0163016A3EFCE31F3E86E2653C87EBB8BE6CD849BEEDFA1B0163016B3EE0965A3E4F8B03BD3BF86FBE954DA1BF04E9E20163016C3EC369123E1081C3BDDD9569BEB399DCBF1251D8"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFFAAAEEED4EDB"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B5"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FE9CB6A9BBCE64B"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FE9CB6A9BBCE64B3FEAED548F090CEE3FEBF4536C24BB853FECDF604A1CADCE3FEDAD902FA8AC873FEE5E14FE11418C3FEEF03E3F3D42A23FEF6379D619369D3FEFB75490A83C2C3FEFEB7A9B2C6D8B3FEFFFB7D3F3A2533FEFF3F7FF74C9A73FEFC846DC89C3AF3FEF7CD018B182463FEF11DF24662DAD3FEE87DEE7B2F3933FEDDF595754E4443FED18F6EAD1B4463FEC357DF40E40243FEB35D1D90D2DD63FEA1AF2309BDCA63FE8E5F9C2D0E3A93FE7981D6E5B8B113FE632AAF3BED93B3FE4B707A7ACDECD3FE326AF0DCFCAB13FE183315D65DF2A3FDF9C63E25718C73FDC12CB48474A243FD86D2239C183FB3FD4AF0E1208CD6D3FD0DC4C957085213FC9F16067CFB7383FC210386DB6D55B3FB43A0378FADB653F90FD770A03E5AABFA77F0DEE42925CBFBBB2AD2464A48CBFC5C51179A9D633BFCD9B09200454F7BFD2A9B41A5FED1FBFD6733B7EBA621FBFDA26518675C600BFDDBF436A743C91BFE09D3C42C705C2BFE24A3AF6750621BFE3E4F0F54F24AABFE56BC3AB8F386FBFE6DD2C670F7AA7BFE837B9DDDC1EAEBFE97A119F5E80B1BFEAA2F16EB0DE8EBFEBB13084C06416BFECA3C0B8FB8370BFED79AF8F640408BFEE32272AF6CC72BFEECC6F237713B1BFEF47ED3DC74080BFEFA42606172D14BFEFE0BD4B4DADF3BFEFFD767B31FCA1BFEFFA34DEF8E460BFEFD6FBB7F928EABFEF93EE3C6A751BBFEF314F7432125FBFEEAF81F5E09933BFEE0F0784239781BFED50808C0DB2ECBFEC74AB84B6F427BFEB7C6430D58DA3BFEA68A2C30D7500BFE93A7AE5D26D43BFE7F31AA7D48B36BFE693C94E0AB057BFE51DE60C88D8D5BFE392E6A7694AEEBFE1F455FD27A14CBFE043D27BE3362FBFDD06190627183ABFD967896699BA40BFD5AF945B89D004BFD1E1F18AB0A2C0BFCC04DC8B7DB26ABFC429D37AB7C0E8BFB87544891F6C54BFA0FCDDC3F512BC3F9E0391FB79D87D3FB778B79B464BD93FC3AC89FA5E11293FCB890D40C6CB3C3FD1A504E2A377CE"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FD5573DFF55773E3EE0813E7D57773E9D68953EBB88133ED8EC183EF577443F0886863F15C8EF3F22759C3F2E7FE13F39DBB43F447DBB3F4E5B553F576AA43F5FA29B3F66FB023F6D6C813F72F0A83F7781F23F7B1BCF3F7DBAA53F7F5BD53F7FFDBF3F7F9FC03F7E42373F7BE6813F788EF93F743EF73F6EFACB3F68C7B73F61ABF03F59AE8F3F50D7923F472FCE3F3CC0EB3F3195583F25B83D3F1935783F0C198B3EFCE31F3EE0965A3EC369123EA578713E86E2653E4F8B033E1081C33DA1D01C3C87EBB8BD3BF86FBDDD9569BE2E288CBE6CD849BE954DA1BEB399DCBED1328CBEEDFA1BBF04E9E2BF1251D8BF1F2788BF2B5E1DBF36E963BF41BDCFBF4BD08DBF55178BBF5D8984BF651E06BF6BCD7CBF719139BF766379BF7A3F6ABF7D2130BF7F05EABF7FEBB4BF7FD1A7BF7EB7DEBF7C9F72BF798A7CBF757C10BF70783CBF6A8404BF63A55CBF5BE322BF534516BF49D3D7BF3F98D5BF349E4ABF28EF30BF1C9735BF0FA2B0BF021E94BEE830C8BECB3C4BBEAD7CA3BE8F0F8CBE6026E4BE214E9CBDC3AA24BD07E6EE3CF01C903DBBC5BD3E1D64503E5C486A3E8D2827"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFFAAAEEED4EDB01623FBFEAAEEE86EE3601633FC7DC102FBAF2B5"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFEAAEEE86EE36016103666F6F3FAFFAAAEEED4EDB0162036261723FCFAAEED4F31577016203666F6F3FC7DC102FBAF2B50163036261723FD7710255764214016303666F6F3FD3AD129769D3D8"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD3AD129769D3D8016103626172016A3FD7710255764214016103626172016B3FDB1D8305321617016103626172016C3FDEAEE8744B05F0016103666F6F01693FAFFAAAEEED4EDB016103666F6F016A3FBFEAAEEE86EE36016103666F6F016B3FC7DC102FBAF2B5016103666F6F016C3FCFAAEED4F3157701620362617201693FE73B7680DEA578016203626172016A3FE88FB7640B8DA2016203626172016B3FE9CB6A9BBCE64B016203626172016C3FEAED548F090CEE016203666F6F01693FE110D0C4B69C3B016203666F6F016A3FE2B91DEA88421E016203666F6F016B3FE44EB381CF386B016203666F6F016C3FE5CFFC16BF8F0D01630362617201693FEEF03E3F3D42A2016303626172016A3FEF6379D619369D016303626172016B3FEFB75490A83C2C016303626172016C3FEFEB7A9B2C6D8B016303666F6F01693FEBF4536C24BB85016303666F6F016A3FECDF604A1CADCE016303666F6F016B3FEDAD902FA8AC87016303666F6F016C3FEE5E14FE11418C"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9D6895016103626172016A3EBB8813016103626172016B3ED8EC18016103626172016C3EF57744016103666F6F01693D7FD557016103666F6F016A3DFF5577016103666F6F016B3E3EE081016103666F6F016C3E7D577701620362617201693F39DBB4016203626172016A3F447DBB016203626172016B3F4E5B55016203626172016C3F576AA4016203666F6F01693F088686016203666F6F016A3F15C8EF016203666F6F016B3F22759C016203666F6F016C3F2E7FE101630362617201693F7781F2016303626172016A3F7B1BCF016303626172016B3F7DBAA5016303626172016C3F7F5BD5016303666F6F01693F5FA29B016303666F6F016A3F66FB02016303666F6F016B3F6D6C81016303666F6F016C3F72F0A8"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDEAEE8744B05F03FE110D0C4B69C3B3FE2B91DEA88421E3FE44EB381CF386B3FE5CFFC16BF8F0D3FE73B7680DEA5783FE88FB7640B8DA23FEF6379D619369D3FEFB75490A83C2C3FEFEB7A9B2C6D8B3FEFFFB7D3F3A2533FEFF3F7FF74C9A73FEFC846DC89C3AF3FEF7CD018B182463FE8E5F9C2D0E3A93FE7981D6E5B8B113FE632AAF3BED93B3FE4B707A7ACDECD3FE326AF0DCFCAB13FE183315D65DF2A3FDF9C63E25718C703666F6F3FAFFAAAEEED4EDB3FBFEAAEEE86EE363FC7DC102FBAF2B53FCFAAEED4F315773FD3AD129769D3D83FD77102557642143FDB1D83053216173FE9CB6A9BBCE64B3FEAED548F090CEE3FEBF4536C24BB853FECDF604A1CADCE3FEDAD902FA8AC873FEE5E14FE11418C3FEEF03E3F3D42A23FEF11DF24662DAD3FEE87DEE7B2F3933FEDDF595754E4443FED18F6EAD1B4463FEC357DF40E40243FEB35D1D90D2DD63FEA1AF2309BDCA6"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFFAAAEEED4EDB3FD3AD129769D3D83FE110D0C4B69C3B3FE73B7680DEA5783FEBF4536C24BB850161016A3FBFEAAEEE86EE363FD77102557642143FE2B91DEA88421E3FE88FB7640B8DA23FECDF604A1CADCE0161016B3FC7DC102FBAF2B53FDB1D83053216173FE44EB381CF386B3FE9CB6A9BBCE64B3FEDAD902FA8AC870161016C3FCFAAEED4F315773FDEAEE8744B05F03FE5CFFC16BF8F0D3FEAED548F090CEE3FEE5E14FE11418C016201693FEEF03E3F3D42A23FEFFFB7D3F3A2533FEF11DF24662DAD3FEC357DF40E40243FE7981D6E5B8B110162016A3FEF6379D619369D3FEFF3F7FF74C9A73FEE87DEE7B2F3933FEB35D1D90D2DD63FE632AAF3BED93B0162016B3FEFB75490A83C2C3FEFC846DC89C3AF3FEDDF595754E4443FEA1AF2309BDCA63FE4B707A7ACDECD0162016C3FEFEB7A9B2C6D8B3FEF7CD018B182463FED18F6EAD1B4463FE8E5F9C2D0E3A93FE326AF0DCFCAB1016301693FE183315D65DF2A3FD4AF0E1208CD6D3FB43A0378FADB65BFC5C51179A9D633BFDA26518675C6000163016A3FDF9C63E25718C73FD0DC4C957085213F90FD770A03E5AABFCD9B09200454F7BFDDBF436A743C910163016B3FDC12CB48474A243FC9F16067CFB738BFA77F0DEE42925CBFD2A9B41A5FED1FBFE09D3C42C705C20163016C3FD86D2239C183FB3FC210386DB6D55BBFBBB2AD2464A48CBFD6733B7EBA621FBFE24A3AF6750621"}}
-{"expression":"map(a,f(a)(sin(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FD5573E9D68953F0886863F39DBB43F5FA29B0161016A3DFF55773EBB88133F15C8EF3F447DBB3F66FB020161016B3E3EE0813ED8EC183F22759C3F4E5B553F6D6C810161016C3E7D57773EF577443F2E7FE13F576AA43F72F0A8016201693F7781F23F7FFDBF3F788EF93F61ABF03F3CC0EB0162016A3F7B1BCF3F7F9FC03F743EF73F59AE8F3F3195580162016B3F7DBAA53F7E42373F6EFACB3F50D7923F25B83D0162016C3F7F5BD53F7BE6813F68C7B73F472FCE3F193578016301693F0C198B3EA578713DA1D01CBE2E288CBED1328C0163016A3EFCE31F3E86E2653C87EBB8BE6CD849BEEDFA1B0163016B3EE0965A3E4F8B03BD3BF86FBE954DA1BF04E9E20163016C3EC369123E1081C3BDDD9569BEB399DCBF1251D8"}}
-{"expression":"tan(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB005577854DF01"}}
-{"expression":"tan(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB005577854DF013FC01577AF1511A53FC84906F1132568"}}
-{"expression":"tan(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E3FF5CB0BFC155800"}}
-{"expression":"tan(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E3FF5CB0BFC1558003FF8EB245CBEE3A63FFCB80AC81FE6124000BD9602648A364003D6DC956EAC7D4008139943E231A8400E47C2171B112F40142AEBD53F29E4401DD494676F5DE5402C33ED50B88777405E221492E1D037C0326E4D05A17116C0210F3E89743E64C01614DE7972B0BBC01039C49AF46BAAC0097B5E8AE9A21CC004D447FA59C62FC0017AF62E0950F8BFFDDFCE116F57D6BFF9DA268DC2B78ABFF6919ACAC2CE03BFF3D16B30F9ADCFBFF1768CA5B5D45ABFEED18AF0B0BA81BFEB2D89A938294DBFE7E79B4E00BB15BFE4EC85CE990E65BFE22D6F57473123BFDF3D3D32863EF3BFDA6D3F2D2FBDDFBFD5DB528F41917CBFD17A5C176D8C58BFCA7E234DE0A4F4BFC23EF71254B86FBFB44A40761A778BBF90FE105579A5AF3FA78565F743DAF03FBBDC8BF445936C3FC61776AA407A433FCE6E46F812C2CF3FD382C98851ECD93FD7F9360C8212A73FDCA67B832312D33FE0CC62B7B1011F3FE3708B193E47D63FE64A2502B0CA3B3FE96640D9C118B63FECD596116A9ACB3FF057024229C0393FF2866F9BE4DE133FF50D44313164823FF8082D137499253FFBA16375ABCA7040000CEBBF628F314002ED79A93FB5024006CE0DBC2BBBD5400C5DABB45BAC1A40128CA0C62BF595401A7C7BF053BFB74026D3F0B68A96FB404415C6B92FB3C1C03A934E58D7CC85C023E9399D7179C4C01861A2306F0447C01177C493149363C00B0B4B739BBB07C005E89676221B0AC00246964CCCCFCEBFFF1A7B3EDFBDD6BFFAD65436D2B404BFF761AE36E41E8BBFF4814840BD0DEEBFF20E3C35AE57B4BFEFDBD31615B07ABFEC1AE0FB48E205BFE8BE108A4D2566BFE5B0B6340CDE46BFE2E2F32D88343EBFE048525BC11821BFDBADAD53CCF0A6BFD70CA41938429CBFD29FD86EBB95BEBFCCB724D6BE97F4BFC46B1664AF4326BFB8920A614F6F8BBFA0FF43123A338E3F9E06DF74530A4A3FB792220E870BEC3FC3E91B7F5723613FCC320B15C520E83FD25B22CF12B730"}}
-{"expression":"tan(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D802ABC3E00ABBD3E4248383E82BC2D3EA56B8F3EC9896C3EEF7A4F3F0BDA7B3F21645D3F38B3343F5236593F6E7D1B3F8722153F99451D3FAE58603FC759233FE5C0564005ECB0401EB6E540409CCA40723E1140A1575F40EEA4A341619F6B42F110A5C1937268C10879F4C0B0A6F4C081CE25C04BDAF4C026A240C00BD7B1BFEEFE71BFCED134BFB48CD6BF9E8B5ABF8BB465BF768C58BF596C4DBF3F3CDABF27642EBF116B7BBEF9E9EABED369F9BEAEDA94BE8BD2E1BE53F11ABE11F7B9BDA25204BC87F0833D3C2B303DDEE4603E30BBB53E7372383E9C164C3EBFC9B03EE533DC3F0663163F1B84593F3251283F4B32073F66ACB13F82B8123F94337D3FA86A223FC041693FDD0B1C4000675E40176BCD4036706E4062ED5E4094650640D3E3E041369F864220AE36C1D49A73C11F49CDC0C30D12C08BBE25C0585A5CC02F44B4C01234B2BFF8D3DABFD6B2A2BFBB0D72BFA40A42BF9071E2BF7EDE99BF60D708BF45F084BF2D85B2BF171799BF024293BEDD6D6BBEB86521BE94FEC3BE65B927BE2358B3BDC49053BD07FA193CF036FC3DBC91103E1F48DC3E6190593E92D916"}}
-{"expression":"tan(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB005577854DF0101623FC01577AF1511A501633FC84906F1132568"}}
-{"expression":"tan(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC01577AF1511A5016103666F6F3FB005577854DF010162036261723FD05785A43C4C56016203666F6F3FC84906F11325680163036261723FD9312D859BF8B0016303666F6F3FD4AD71ED51CE39"}}
-{"expression":"tan(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD4AD71ED51CE39016103626172016A3FD9312D859BF8B0016103626172016B3FDDEF49EAAB37A1016103626172016C3FE17B4F5BF3474A016103666F6F01693FB005577854DF01016103666F6F016A3FC01577AF1511A5016103666F6F016B3FC84906F1132568016103666F6F016C3FD05785A43C4C5601620362617201693FF0E442AA4C1EA0016203626172016A3FF328A395115A5E016203626172016B3FF5CB0BFC155800016203626172016C3FF8EB245CBEE3A6016203666F6F01693FE42C8BA0E9537A016203666F6F016A3FE7166689D41EF0016203666F6F016B3FEA46CB2BE6A0B2016203666F6F016C3FEDCFA36110EEEC0163036261720169400E47C2171B112F016303626172016A40142AEBD53F29E4016303626172016B401DD494676F5DE5016303626172016C402C33ED50B88777016303666F6F01693FFCB80AC81FE612016303666F6F016A4000BD9602648A36016303666F6F016B4003D6DC956EAC7D016303666F6F016C4008139943E231A8"}}
-{"expression":"tan(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA56B8F016103626172016A3EC9896C016103626172016B3EEF7A4F016103626172016C3F0BDA7B016103666F6F01693D802ABC016103666F6F016A3E00ABBD016103666F6F016B3E424838016103666F6F016C3E82BC2D01620362617201693F872215016203626172016A3F99451D016203626172016B3FAE5860016203626172016C3FC75923016203666F6F01693F21645D016203666F6F016A3F38B334016203666F6F016B3F523659016203666F6F016C3F6E7D1B016303626172016940723E11016303626172016A40A1575F016303626172016B40EEA4A3016303626172016C41619F6B016303666F6F01693FE5C056016303666F6F016A4005ECB0016303666F6F016B401EB6E5016303666F6F016C40409CCA"}}
-{"expression":"tan(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E40142AEBD53F29E4401DD494676F5DE5402C33ED50B88777405E221492E1D037C0326E4D05A17116C0210F3E89743E64C01614DE7972B0BBBFF3D16B30F9ADCFBFF1768CA5B5D45ABFEED18AF0B0BA81BFEB2D89A938294DBFE7E79B4E00BB15BFE4EC85CE990E65BFE22D6F5747312303666F6F3FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FF5CB0BFC1558003FF8EB245CBEE3A63FFCB80AC81FE6124000BD9602648A364003D6DC956EAC7D4008139943E231A8400E47C2171B112FC01039C49AF46BAAC0097B5E8AE9A21CC004D447FA59C62FC0017AF62E0950F8BFFDDFCE116F57D6BFF9DA268DC2B78ABFF6919ACAC2CE03"}}
-{"expression":"tan(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB005577854DF013FD4AD71ED51CE393FE42C8BA0E9537A3FF0E442AA4C1EA03FFCB80AC81FE6120161016A3FC01577AF1511A53FD9312D859BF8B03FE7166689D41EF03FF328A395115A5E4000BD9602648A360161016B3FC84906F11325683FDDEF49EAAB37A13FEA46CB2BE6A0B23FF5CB0BFC1558004003D6DC956EAC7D0161016C3FD05785A43C4C563FE17B4F5BF3474A3FEDCFA36110EEEC3FF8EB245CBEE3A64008139943E231A801620169400E47C2171B112F405E221492E1D037C01039C49AF46BAABFFDDFCE116F57D6BFF1768CA5B5D45A0162016A40142AEBD53F29E4C0326E4D05A17116C0097B5E8AE9A21CBFF9DA268DC2B78ABFEED18AF0B0BA810162016B401DD494676F5DE5C0210F3E89743E64C004D447FA59C62FBFF6919ACAC2CE03BFEB2D89A938294D0162016C402C33ED50B88777C01614DE7972B0BBC0017AF62E0950F8BFF3D16B30F9ADCFBFE7E79B4E00BB1501630169BFE4EC85CE990E65BFD5DB528F41917CBFB44A40761A778B3FC61776AA407A433FDCA67B832312D30163016ABFE22D6F57473123BFD17A5C176D8C58BF90FE105579A5AF3FCE6E46F812C2CF3FE0CC62B7B1011F0163016BBFDF3D3D32863EF3BFCA7E234DE0A4F43FA78565F743DAF03FD382C98851ECD93FE3708B193E47D60163016CBFDA6D3F2D2FBDDFBFC23EF71254B86F3FBBDC8BF445936C3FD7F9360C8212A73FE64A2502B0CA3B"}}
-{"expression":"tan(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D802ABC3EA56B8F3F21645D3F8722153FE5C0560161016A3E00ABBD3EC9896C3F38B3343F99451D4005ECB00161016B3E4248383EEF7A4F3F5236593FAE5860401EB6E50161016C3E82BC2D3F0BDA7B3F6E7D1B3FC7592340409CCA0162016940723E1142F110A5C081CE25BFEEFE71BF8BB4650162016A40A1575FC1937268C04BDAF4BFCED134BF768C580162016B40EEA4A3C10879F4C026A240BFB48CD6BF596C4D0162016C41619F6BC0B0A6F4C00BD7B1BF9E8B5ABF3F3CDA01630169BF27642EBEAEDA94BDA252043E30BBB53EE533DC0163016ABF116B7BBE8BD2E1BC87F0833E7372383F0663160163016BBEF9E9EABE53F11A3D3C2B303E9C164C3F1B84590163016CBED369F9BE11F7B93DDEE4603EBFC9B03F325128"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB005577854DF01"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB005577854DF013FC01577AF1511A53FC84906F1132568"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E3FF5CB0BFC155800"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E3FF5CB0BFC1558003FF8EB245CBEE3A63FFCB80AC81FE6124000BD9602648A364003D6DC956EAC7D4008139943E231A8400E47C2171B112F40142AEBD53F29E4401DD494676F5DE5402C33ED50B88777405E221492E1D037C0326E4D05A17116C0210F3E89743E64C01614DE7972B0BBC01039C49AF46BAAC0097B5E8AE9A21CC004D447FA59C62FC0017AF62E0950F8BFFDDFCE116F57D6BFF9DA268DC2B78ABFF6919ACAC2CE03BFF3D16B30F9ADCFBFF1768CA5B5D45ABFEED18AF0B0BA81BFEB2D89A938294DBFE7E79B4E00BB15BFE4EC85CE990E65BFE22D6F57473123BFDF3D3D32863EF3BFDA6D3F2D2FBDDFBFD5DB528F41917CBFD17A5C176D8C58BFCA7E234DE0A4F4BFC23EF71254B86FBFB44A40761A778BBF90FE105579A5AF3FA78565F743DAF03FBBDC8BF445936C3FC61776AA407A433FCE6E46F812C2CF3FD382C98851ECD93FD7F9360C8212A73FDCA67B832312D33FE0CC62B7B1011F3FE3708B193E47D63FE64A2502B0CA3B3FE96640D9C118B63FECD596116A9ACB3FF057024229C0393FF2866F9BE4DE133FF50D44313164823FF8082D137499253FFBA16375ABCA7040000CEBBF628F314002ED79A93FB5024006CE0DBC2BBBD5400C5DABB45BAC1A40128CA0C62BF595401A7C7BF053BFB74026D3F0B68A96FB404415C6B92FB3C1C03A934E58D7CC85C023E9399D7179C4C01861A2306F0447C01177C493149363C00B0B4B739BBB07C005E89676221B0AC00246964CCCCFCEBFFF1A7B3EDFBDD6BFFAD65436D2B404BFF761AE36E41E8BBFF4814840BD0DEEBFF20E3C35AE57B4BFEFDBD31615B07ABFEC1AE0FB48E205BFE8BE108A4D2566BFE5B0B6340CDE46BFE2E2F32D88343EBFE048525BC11821BFDBADAD53CCF0A6BFD70CA41938429CBFD29FD86EBB95BEBFCCB724D6BE97F4BFC46B1664AF4326BFB8920A614F6F8BBFA0FF43123A338E3F9E06DF74530A4A3FB792220E870BEC3FC3E91B7F5723613FCC320B15C520E83FD25B22CF12B730"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D802ABC3E00ABBD3E4248383E82BC2D3EA56B8F3EC9896C3EEF7A4F3F0BDA7B3F21645D3F38B3343F5236593F6E7D1B3F8722153F99451D3FAE58603FC759233FE5C0564005ECB0401EB6E540409CCA40723E1140A1575F40EEA4A341619F6B42F110A5C1937268C10879F4C0B0A6F4C081CE25C04BDAF4C026A240C00BD7B1BFEEFE71BFCED134BFB48CD6BF9E8B5ABF8BB465BF768C58BF596C4DBF3F3CDABF27642EBF116B7BBEF9E9EABED369F9BEAEDA94BE8BD2E1BE53F11ABE11F7B9BDA25204BC87F0833D3C2B303DDEE4603E30BBB53E7372383E9C164C3EBFC9B03EE533DC3F0663163F1B84593F3251283F4B32073F66ACB13F82B8123F94337D3FA86A223FC041693FDD0B1C4000675E40176BCD4036706E4062ED5E4094650640D3E3E041369F864220AE36C1D49A73C11F49CDC0C30D12C08BBE25C0585A5CC02F44B4C01234B2BFF8D3DABFD6B2A2BFBB0D72BFA40A42BF9071E2BF7EDE99BF60D708BF45F084BF2D85B2BF171799BF024293BEDD6D6BBEB86521BE94FEC3BE65B927BE2358B3BDC49053BD07FA193CF036FC3DBC91103E1F48DC3E6190593E92D916"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB005577854DF0101623FC01577AF1511A501633FC84906F1132568"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC01577AF1511A5016103666F6F3FB005577854DF010162036261723FD05785A43C4C56016203666F6F3FC84906F11325680163036261723FD9312D859BF8B0016303666F6F3FD4AD71ED51CE39"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD4AD71ED51CE39016103626172016A3FD9312D859BF8B0016103626172016B3FDDEF49EAAB37A1016103626172016C3FE17B4F5BF3474A016103666F6F01693FB005577854DF01016103666F6F016A3FC01577AF1511A5016103666F6F016B3FC84906F1132568016103666F6F016C3FD05785A43C4C5601620362617201693FF0E442AA4C1EA0016203626172016A3FF328A395115A5E016203626172016B3FF5CB0BFC155800016203626172016C3FF8EB245CBEE3A6016203666F6F01693FE42C8BA0E9537A016203666F6F016A3FE7166689D41EF0016203666F6F016B3FEA46CB2BE6A0B2016203666F6F016C3FEDCFA36110EEEC0163036261720169400E47C2171B112F016303626172016A40142AEBD53F29E4016303626172016B401DD494676F5DE5016303626172016C402C33ED50B88777016303666F6F01693FFCB80AC81FE612016303666F6F016A4000BD9602648A36016303666F6F016B4003D6DC956EAC7D016303666F6F016C4008139943E231A8"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA56B8F016103626172016A3EC9896C016103626172016B3EEF7A4F016103626172016C3F0BDA7B016103666F6F01693D802ABC016103666F6F016A3E00ABBD016103666F6F016B3E424838016103666F6F016C3E82BC2D01620362617201693F872215016203626172016A3F99451D016203626172016B3FAE5860016203626172016C3FC75923016203666F6F01693F21645D016203666F6F016A3F38B334016203666F6F016B3F523659016203666F6F016C3F6E7D1B016303626172016940723E11016303626172016A40A1575F016303626172016B40EEA4A3016303626172016C41619F6B016303666F6F01693FE5C056016303666F6F016A4005ECB0016303666F6F016B401EB6E5016303666F6F016C40409CCA"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE17B4F5BF3474A3FE42C8BA0E9537A3FE7166689D41EF03FEA46CB2BE6A0B23FEDCFA36110EEEC3FF0E442AA4C1EA03FF328A395115A5E40142AEBD53F29E4401DD494676F5DE5402C33ED50B88777405E221492E1D037C0326E4D05A17116C0210F3E89743E64C01614DE7972B0BBBFF3D16B30F9ADCFBFF1768CA5B5D45ABFEED18AF0B0BA81BFEB2D89A938294DBFE7E79B4E00BB15BFE4EC85CE990E65BFE22D6F5747312303666F6F3FB005577854DF013FC01577AF1511A53FC84906F11325683FD05785A43C4C563FD4AD71ED51CE393FD9312D859BF8B03FDDEF49EAAB37A13FF5CB0BFC1558003FF8EB245CBEE3A63FFCB80AC81FE6124000BD9602648A364003D6DC956EAC7D4008139943E231A8400E47C2171B112FC01039C49AF46BAAC0097B5E8AE9A21CC004D447FA59C62FC0017AF62E0950F8BFFDDFCE116F57D6BFF9DA268DC2B78ABFF6919ACAC2CE03"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB005577854DF013FD4AD71ED51CE393FE42C8BA0E9537A3FF0E442AA4C1EA03FFCB80AC81FE6120161016A3FC01577AF1511A53FD9312D859BF8B03FE7166689D41EF03FF328A395115A5E4000BD9602648A360161016B3FC84906F11325683FDDEF49EAAB37A13FEA46CB2BE6A0B23FF5CB0BFC1558004003D6DC956EAC7D0161016C3FD05785A43C4C563FE17B4F5BF3474A3FEDCFA36110EEEC3FF8EB245CBEE3A64008139943E231A801620169400E47C2171B112F405E221492E1D037C01039C49AF46BAABFFDDFCE116F57D6BFF1768CA5B5D45A0162016A40142AEBD53F29E4C0326E4D05A17116C0097B5E8AE9A21CBFF9DA268DC2B78ABFEED18AF0B0BA810162016B401DD494676F5DE5C0210F3E89743E64C004D447FA59C62FBFF6919ACAC2CE03BFEB2D89A938294D0162016C402C33ED50B88777C01614DE7972B0BBC0017AF62E0950F8BFF3D16B30F9ADCFBFE7E79B4E00BB1501630169BFE4EC85CE990E65BFD5DB528F41917CBFB44A40761A778B3FC61776AA407A433FDCA67B832312D30163016ABFE22D6F57473123BFD17A5C176D8C58BF90FE105579A5AF3FCE6E46F812C2CF3FE0CC62B7B1011F0163016BBFDF3D3D32863EF3BFCA7E234DE0A4F43FA78565F743DAF03FD382C98851ECD93FE3708B193E47D60163016CBFDA6D3F2D2FBDDFBFC23EF71254B86F3FBBDC8BF445936C3FD7F9360C8212A73FE64A2502B0CA3B"}}
-{"expression":"map(a,f(a)(tan(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D802ABC3EA56B8F3F21645D3F8722153FE5C0560161016A3E00ABBD3EC9896C3F38B3343F99451D4005ECB00161016B3E4248383EEF7A4F3F5236593FAE5860401EB6E50161016C3E82BC2D3F0BDA7B3F6E7D1B3FC7592340409CCA0162016940723E1142F110A5C081CE25BFEEFE71BF8BB4650162016A40A1575FC1937268C04BDAF4BFCED134BF768C580162016B40EEA4A3C10879F4C026A240BFB48CD6BF596C4D0162016C41619F6BC0B0A6F4C00BD7B1BF9E8B5ABF3F3CDA01630169BF27642EBEAEDA94BDA252043E30BBB53EE533DC0163016ABF116B7BBE8BD2E1BC87F0833E7372383F0663160163016BBEF9E9EABE53F11A3D3C2B303E9C164C3F1B84590163016CBED369F9BE11F7B93DDEE4603EBFC9B03F325128"}}
-{"expression":"cosh(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF00800AAB05B20"}}
-{"expression":"cosh(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA"}}
-{"expression":"cosh(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D13FF78FC270CA6067"}}
-{"expression":"cosh(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D13FF78FC270CA60673FF8B07551D9F5503FF9E9DAB70164893FFB3D2C1FC47CCC3FFCABBCF9D3BB3E3FFE36FBF49645FA3FFFE0746FF7E2D84000D4E803F4EB7F4001CA6C1F11287A4002D1BC21E220224003EBDF725CB441400519F04B55197140065D1CD6D130FB4007B6A85C4BBDC3400927EC8416D084400AB25AB120E8EA400C577D7276AD4F400E18FA0DF2D9BC400FF89225A736FD4010FC12BCD212E740120CD9E3F055A240132FAF66118731401465B630F50D1D4015B024653C8DA5401710448CA66A4D40188776E4B30AA3401A1732BEFFB81E401BC107F8B78338401D86A08A91C20B401F69C232EE483D4020B6281DDCCBF94021C826AEEF8AE74022EBEEE2166D43402422A497D6185E40256D7E9FC9A2AC4026CDC7EF8C1654402844E0EDC9A1A24029D440D2C3A213402B7D771FA82B6B402D422D2E3481AE402F2427DA3249AD403092A4A33C887B4031A3C95F9CAA214032C6935DB9BBDC4033FC257FCE2961403545B571C910C94036A48CDF1400D740381A0ABC59DC704039A7A4A698C57C403B4EE858DE3E80403D117D3A235E29403EF12604D7121F404077E144DF0F63404187A8C7F5F0AE4042A8F969D9FAB04043DCF49349ECB2404524CE591A551F404681CEB06413584047F552B694C5EA404980CE0EA950EC404B25CC54EFD428404CE5F2AAC4F210404EC3015BD8459A40505F6ACF4EB76640516DB5B8D5261740528D6FCBEFF3AA4053BFB8DAAD33CB405505C347A2941D405660D538697AF34057D249DBDFCF6B40595B92C573C6E2405AFE395ED62077405CBBE071849FB1405E9645C9B6718B406047A1FA26C59E4061546A0CC58C9A40627287FB30ED344063A319FB2FF2254064E750B824F30A4066407083D25B354067AFD29AC773CD406936E67DB9B919406AD73361243111406C9259B49C8130406E6A14C36539344070301E37EF03F040713B6385C6B76D407257E5A6CE134F407386C134DC6C0B4074C92524BD9DDC40762053F540188A"}}
-{"expression":"cosh(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F8040053F8100553F8241B13F8405583F864D103F891B203F8C72573F90560C3F94CA233F99D3113F9F75DE3FA5B82F3FACA0453FB4350A3FBC7E143FC583AB3FCF4ED63FD9E9613FE55DE83FF1B7E03FFF03A34006A740400E536140168DE1401F5EFC4028CF824032E8E7403DB54340493F64405592D64062BBEC4070C7D0407FC4914087E096409066CF40997D7B40A32DB240AD812340B8822440C43BB740D0B99640DE084040EC350440FB4E124105B141410E413541175F7741211525412B6BF541366E3F41422707414EA207415BEBB9416A11694179213F41849525418D1E4B4196349B419FE12C41AA2DAC41B5246741C0D05641CD3D2541DA774341E88BEA41F789304203BF0A420C3D46421547CB421EE7A54229267342340E76423FAA96424C067042592E6342672F954276180B4282FB56428B6DAE42946B7E429DFDC742A82E1A42B306AA42BE924F42CADC9642D7F1CB42E5DF0442F4B22E43023D10430AA35043139440431D18D043273A8643320384433D7E954349B7344356B99B436492CE437350A6438180F24389DB1C4392BF2D439C360A43A6492943B102A0"}}
-{"expression":"cosh(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF00800AAB05B2001623FF0200AAC16DB6F01633FF048361035CDFA"}}
-{"expression":"cosh(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF0200AAC16DB6F016103666F6F3FF00800AAB05B200162036261723FF080AB05CA6146016203666F6F3FF048361035CDFA0163036261723FF123640F685B59016303666F6F3FF0C9A2067EBBDA"}}
-{"expression":"cosh(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0C9A2067EBBDA016103626172016A3FF123640F685B59016103626172016B3FF18E4AEA0B3F4A016103626172016C3FF20AC1862AE8D0016103666F6F01693FF00800AAB05B20016103666F6F016A3FF0200AAC16DB6F016103666F6F016B3FF048361035CDFA016103666F6F016C3FF080AB05CA614601620362617201693FF59408A2DFB8DA016203626172016A3FF686A148E1E0D1016203626172016B3FF78FC270CA6067016203626172016C3FF8B07551D9F550016203666F6F01693FF2994464C307C6016203666F6F016A3FF33A621492D6DA016203666F6F016B3FF3EEBBC0B7BC6C016203666F6F016C3FF4B705D1E5D6A801630362617201693FFFE0746FF7E2D8016303626172016A4000D4E803F4EB7F016303626172016B4001CA6C1F11287A016303626172016C4002D1BC21E22022016303666F6F01693FF9E9DAB7016489016303666F6F016A3FFB3D2C1FC47CCC016303666F6F016B3FFCABBCF9D3BB3E016303666F6F016C3FFE36FBF49645FA"}}
-{"expression":"cosh(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F864D10016103626172016A3F891B20016103626172016B3F8C7257016103626172016C3F90560C016103666F6F01693F804005016103666F6F016A3F810055016103666F6F016B3F8241B1016103666F6F016C3F84055801620362617201693FACA045016203626172016A3FB4350A016203626172016B3FBC7E14016203626172016C3FC583AB016203666F6F01693F94CA23016203666F6F016A3F99D311016203666F6F016B3F9F75DE016203666F6F016C3FA5B82F01630362617201693FFF03A3016303626172016A4006A740016303626172016B400E5361016303626172016C40168DE1016303666F6F01693FCF4ED6016303666F6F016A3FD9E961016303666F6F016B3FE55DE8016303666F6F016C3FF1B7E0"}}
-{"expression":"cosh(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D14000D4E803F4EB7F4001CA6C1F11287A4002D1BC21E220224003EBDF725CB441400519F04B55197140065D1CD6D130FB4007B6A85C4BBDC340132FAF66118731401465B630F50D1D4015B024653C8DA5401710448CA66A4D40188776E4B30AA3401A1732BEFFB81E401BC107F8B7833803666F6F3FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF78FC270CA60673FF8B07551D9F5503FF9E9DAB70164893FFB3D2C1FC47CCC3FFCABBCF9D3BB3E3FFE36FBF49645FA3FFFE0746FF7E2D8400927EC8416D084400AB25AB120E8EA400C577D7276AD4F400E18FA0DF2D9BC400FF89225A736FD4010FC12BCD212E740120CD9E3F055A2"}}
-{"expression":"cosh(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00800AAB05B203FF0C9A2067EBBDA3FF2994464C307C63FF59408A2DFB8DA3FF9E9DAB70164890161016A3FF0200AAC16DB6F3FF123640F685B593FF33A621492D6DA3FF686A148E1E0D13FFB3D2C1FC47CCC0161016B3FF048361035CDFA3FF18E4AEA0B3F4A3FF3EEBBC0B7BC6C3FF78FC270CA60673FFCABBCF9D3BB3E0161016C3FF080AB05CA61463FF20AC1862AE8D03FF4B705D1E5D6A83FF8B07551D9F5503FFE36FBF49645FA016201693FFFE0746FF7E2D84003EBDF725CB441400927EC8416D084400FF89225A736FD401465B630F50D1D0162016A4000D4E803F4EB7F400519F04B551971400AB25AB120E8EA4010FC12BCD212E74015B024653C8DA50162016B4001CA6C1F11287A40065D1CD6D130FB400C577D7276AD4F40120CD9E3F055A2401710448CA66A4D0162016C4002D1BC21E220224007B6A85C4BBDC3400E18FA0DF2D9BC40132FAF6611873140188776E4B30AA301630169401A1732BEFFB81E4020B6281DDCCBF940256D7E9FC9A2AC402B7D771FA82B6B4031A3C95F9CAA210163016A401BC107F8B783384021C826AEEF8AE74026CDC7EF8C1654402D422D2E3481AE4032C6935DB9BBDC0163016B401D86A08A91C20B4022EBEEE2166D43402844E0EDC9A1A2402F2427DA3249AD4033FC257FCE29610163016C401F69C232EE483D402422A497D6185E4029D440D2C3A213403092A4A33C887B403545B571C910C9"}}
-{"expression":"cosh(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8040053F864D103F94CA233FACA0453FCF4ED60161016A3F8100553F891B203F99D3113FB4350A3FD9E9610161016B3F8241B13F8C72573F9F75DE3FBC7E143FE55DE80161016C3F8405583F90560C3FA5B82F3FC583AB3FF1B7E0016201693FFF03A3401F5EFC40493F64407FC49140A32DB20162016A4006A7404028CF82405592D64087E09640AD81230162016B400E53614032E8E74062BBEC409066CF40B882240162016C40168DE1403DB5434070C7D040997D7B40C43BB70163016940D0B9964105B141412B6BF5415BEBB9418D1E4B0163016A40DE0840410E413541366E3F416A11694196349B0163016B40EC350441175F77414227074179213F419FE12C0163016C40FB4E1241211525414EA2074184952541AA2DAC"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF00800AAB05B20"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D13FF78FC270CA6067"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D13FF78FC270CA60673FF8B07551D9F5503FF9E9DAB70164893FFB3D2C1FC47CCC3FFCABBCF9D3BB3E3FFE36FBF49645FA3FFFE0746FF7E2D84000D4E803F4EB7F4001CA6C1F11287A4002D1BC21E220224003EBDF725CB441400519F04B55197140065D1CD6D130FB4007B6A85C4BBDC3400927EC8416D084400AB25AB120E8EA400C577D7276AD4F400E18FA0DF2D9BC400FF89225A736FD4010FC12BCD212E740120CD9E3F055A240132FAF66118731401465B630F50D1D4015B024653C8DA5401710448CA66A4D40188776E4B30AA3401A1732BEFFB81E401BC107F8B78338401D86A08A91C20B401F69C232EE483D4020B6281DDCCBF94021C826AEEF8AE74022EBEEE2166D43402422A497D6185E40256D7E9FC9A2AC4026CDC7EF8C1654402844E0EDC9A1A24029D440D2C3A213402B7D771FA82B6B402D422D2E3481AE402F2427DA3249AD403092A4A33C887B4031A3C95F9CAA214032C6935DB9BBDC4033FC257FCE2961403545B571C910C94036A48CDF1400D740381A0ABC59DC704039A7A4A698C57C403B4EE858DE3E80403D117D3A235E29403EF12604D7121F404077E144DF0F63404187A8C7F5F0AE4042A8F969D9FAB04043DCF49349ECB2404524CE591A551F404681CEB06413584047F552B694C5EA404980CE0EA950EC404B25CC54EFD428404CE5F2AAC4F210404EC3015BD8459A40505F6ACF4EB76640516DB5B8D5261740528D6FCBEFF3AA4053BFB8DAAD33CB405505C347A2941D405660D538697AF34057D249DBDFCF6B40595B92C573C6E2405AFE395ED62077405CBBE071849FB1405E9645C9B6718B406047A1FA26C59E4061546A0CC58C9A40627287FB30ED344063A319FB2FF2254064E750B824F30A4066407083D25B354067AFD29AC773CD406936E67DB9B919406AD73361243111406C9259B49C8130406E6A14C36539344070301E37EF03F040713B6385C6B76D407257E5A6CE134F407386C134DC6C0B4074C92524BD9DDC40762053F540188A"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F8040053F8100553F8241B13F8405583F864D103F891B203F8C72573F90560C3F94CA233F99D3113F9F75DE3FA5B82F3FACA0453FB4350A3FBC7E143FC583AB3FCF4ED63FD9E9613FE55DE83FF1B7E03FFF03A34006A740400E536140168DE1401F5EFC4028CF824032E8E7403DB54340493F64405592D64062BBEC4070C7D0407FC4914087E096409066CF40997D7B40A32DB240AD812340B8822440C43BB740D0B99640DE084040EC350440FB4E124105B141410E413541175F7741211525412B6BF541366E3F41422707414EA207415BEBB9416A11694179213F41849525418D1E4B4196349B419FE12C41AA2DAC41B5246741C0D05641CD3D2541DA774341E88BEA41F789304203BF0A420C3D46421547CB421EE7A54229267342340E76423FAA96424C067042592E6342672F954276180B4282FB56428B6DAE42946B7E429DFDC742A82E1A42B306AA42BE924F42CADC9642D7F1CB42E5DF0442F4B22E43023D10430AA35043139440431D18D043273A8643320384433D7E954349B7344356B99B436492CE437350A6438180F24389DB1C4392BF2D439C360A43A6492943B102A0"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF00800AAB05B2001623FF0200AAC16DB6F01633FF048361035CDFA"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF0200AAC16DB6F016103666F6F3FF00800AAB05B200162036261723FF080AB05CA6146016203666F6F3FF048361035CDFA0163036261723FF123640F685B59016303666F6F3FF0C9A2067EBBDA"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0C9A2067EBBDA016103626172016A3FF123640F685B59016103626172016B3FF18E4AEA0B3F4A016103626172016C3FF20AC1862AE8D0016103666F6F01693FF00800AAB05B20016103666F6F016A3FF0200AAC16DB6F016103666F6F016B3FF048361035CDFA016103666F6F016C3FF080AB05CA614601620362617201693FF59408A2DFB8DA016203626172016A3FF686A148E1E0D1016203626172016B3FF78FC270CA6067016203626172016C3FF8B07551D9F550016203666F6F01693FF2994464C307C6016203666F6F016A3FF33A621492D6DA016203666F6F016B3FF3EEBBC0B7BC6C016203666F6F016C3FF4B705D1E5D6A801630362617201693FFFE0746FF7E2D8016303626172016A4000D4E803F4EB7F016303626172016B4001CA6C1F11287A016303626172016C4002D1BC21E22022016303666F6F01693FF9E9DAB7016489016303666F6F016A3FFB3D2C1FC47CCC016303666F6F016B3FFCABBCF9D3BB3E016303666F6F016C3FFE36FBF49645FA"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F864D10016103626172016A3F891B20016103626172016B3F8C7257016103626172016C3F90560C016103666F6F01693F804005016103666F6F016A3F810055016103666F6F016B3F8241B1016103666F6F016C3F84055801620362617201693FACA045016203626172016A3FB4350A016203626172016B3FBC7E14016203626172016C3FC583AB016203666F6F01693F94CA23016203666F6F016A3F99D311016203666F6F016B3F9F75DE016203666F6F016C3FA5B82F01630362617201693FFF03A3016303626172016A4006A740016303626172016B400E5361016303626172016C40168DE1016303666F6F01693FCF4ED6016303666F6F016A3FD9E961016303666F6F016B3FE55DE8016303666F6F016C3FF1B7E0"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF20AC1862AE8D03FF2994464C307C63FF33A621492D6DA3FF3EEBBC0B7BC6C3FF4B705D1E5D6A83FF59408A2DFB8DA3FF686A148E1E0D14000D4E803F4EB7F4001CA6C1F11287A4002D1BC21E220224003EBDF725CB441400519F04B55197140065D1CD6D130FB4007B6A85C4BBDC340132FAF66118731401465B630F50D1D4015B024653C8DA5401710448CA66A4D40188776E4B30AA3401A1732BEFFB81E401BC107F8B7833803666F6F3FF00800AAB05B203FF0200AAC16DB6F3FF048361035CDFA3FF080AB05CA61463FF0C9A2067EBBDA3FF123640F685B593FF18E4AEA0B3F4A3FF78FC270CA60673FF8B07551D9F5503FF9E9DAB70164893FFB3D2C1FC47CCC3FFCABBCF9D3BB3E3FFE36FBF49645FA3FFFE0746FF7E2D8400927EC8416D084400AB25AB120E8EA400C577D7276AD4F400E18FA0DF2D9BC400FF89225A736FD4010FC12BCD212E740120CD9E3F055A2"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00800AAB05B203FF0C9A2067EBBDA3FF2994464C307C63FF59408A2DFB8DA3FF9E9DAB70164890161016A3FF0200AAC16DB6F3FF123640F685B593FF33A621492D6DA3FF686A148E1E0D13FFB3D2C1FC47CCC0161016B3FF048361035CDFA3FF18E4AEA0B3F4A3FF3EEBBC0B7BC6C3FF78FC270CA60673FFCABBCF9D3BB3E0161016C3FF080AB05CA61463FF20AC1862AE8D03FF4B705D1E5D6A83FF8B07551D9F5503FFE36FBF49645FA016201693FFFE0746FF7E2D84003EBDF725CB441400927EC8416D084400FF89225A736FD401465B630F50D1D0162016A4000D4E803F4EB7F400519F04B551971400AB25AB120E8EA4010FC12BCD212E74015B024653C8DA50162016B4001CA6C1F11287A40065D1CD6D130FB400C577D7276AD4F40120CD9E3F055A2401710448CA66A4D0162016C4002D1BC21E220224007B6A85C4BBDC3400E18FA0DF2D9BC40132FAF6611873140188776E4B30AA301630169401A1732BEFFB81E4020B6281DDCCBF940256D7E9FC9A2AC402B7D771FA82B6B4031A3C95F9CAA210163016A401BC107F8B783384021C826AEEF8AE74026CDC7EF8C1654402D422D2E3481AE4032C6935DB9BBDC0163016B401D86A08A91C20B4022EBEEE2166D43402844E0EDC9A1A2402F2427DA3249AD4033FC257FCE29610163016C401F69C232EE483D402422A497D6185E4029D440D2C3A213403092A4A33C887B403545B571C910C9"}}
-{"expression":"map(a,f(a)(cosh(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8040053F864D103F94CA233FACA0453FCF4ED60161016A3F8100553F891B203F99D3113FB4350A3FD9E9610161016B3F8241B13F8C72573F9F75DE3FBC7E143FE55DE80161016C3F8405583F90560C3FA5B82F3FC583AB3FF1B7E0016201693FFF03A3401F5EFC40493F64407FC49140A32DB20162016A4006A7404028CF82405592D64087E09640AD81230162016B400E53614032E8E74062BBEC409066CF40B882240162016C40168DE1403DB5434070C7D040997D7B40C43BB70163016940D0B9964105B141412B6BF5415BEBB9418D1E4B0163016A40DE0840410E413541366E3F416A11694196349B0163016B40EC350441175F77414227074179213F419FE12C0163016C40FB4E1241211525414EA2074184952541AA2DAC"}}
-{"expression":"sinh(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB002AACCCD9CDD"}}
-{"expression":"sinh(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD"}}
-{"expression":"sinh(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FF14BBE2DD2460A"}}
-{"expression":"sinh(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FF14BBE2DD2460A3FF2CD9FC44EB9823FF462508BBF80A93FF60B6556A692043FF7CA875D3C69323FF9A175E6CBAFE63FFB9208091DCFC63FFD9E2E7FB7FEF43FFFC7F59CC02B95400108C3AABD6A6040023E96B6373D25400386A9DDAB7A8B4004E2454F996E14400652C4C46B9BBA4007D998DA4D257C4009784885E6AF4C400B307299739D43400D03CF63B6E1A0400EF432686E7235401081C619FEFEA9401199F6261257EA4012C3C19FD775D1401400526B99E613401550E53487B2914016B6CAA976F3DE40183368CDB0B6D34019C83C5F121C3C401B76DA52E9F182401D40F16B0FBFB3401F284BE4C989BD40209768A197A1BD4021AB441B6B45A14022D0CC52573D2D40240926E70949AE4025558C4E1E87B44026B74908B216D040282FBEF0F9EB004029C0669C3E8083402B6AD0D38F8723402D30A824AE5917402F13B28CBF496140308AE99F364F3B40319C8642A0C10D4032BFC0E41034CD4033F5BCD66BCBD340353FB02F7BBD0540369EE4FE18F513403814BA945771844039A2A6E6F59C8A403B4A3803703630403D0D159E30FDFF403EED02BA666CF1404075EFB6963D63404185D55EE4DE8C4042A7425270A2A24043DB58164C4CDE4045234AD9E90F0140468062AB5FA9FC4047F3FCBF99DE2440497F8CCFA46FA0404B249E8C872E52404CE4D72B16F828404EC1F7094DA8E640505EEDB766B93240516D403528230B40528D0166F073744053BF5125ED038940550561DB644EEF40566079B338C3F34057D1F3E22FD53340595B420143AF17405AFDED7F5AFFC3405CBB992AD8A81F405E9602D48D06614060478286D5F7384061544C8142B58E4062726C39EE144C4063A2FFE86984574064E73839C5FD9C40664059815A74974067AFBCFD32392B406936D22F67C805406AD7204DC5865B406C9247C91C272C406E6A03EDD63132407030164FB4ADD640713B5C1830AC2D407257DEAC6E1E64407386BAA6B7989C4074C91EFC453B364076204E2C4B2AEA"}}
-{"expression":"sinh(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D8015563E0055663E4120823E8156673EA29DEE3EC488213EE736EC3F0566803F17B6FD3F2A9F3D3F3E322A3F5283593F67A71E3F7DB29C3F8A5DF13F966CFE3FA312843FB05B2B3FBE543B3FCD0BAF3FDC90403FECF1743FFE3FAD4008461D4011F4B6401C354F4027122A40329626403ECCC7404BC2444059839540681E7B4077A19340840E31408CCFB140961E0D40A0029340AA872A40B5B65540C19B4640CE41E340DBB6D340EA078B40F9425F4104BB45410D5A214116866341204937412AAC624135BA4841417DF8414E0335415B56874169854141789D944184574D418CE4324195FE07419FADE741A9FD8141B4F72841C0A5D541CD153741DA51C041E868AD41F768164203AF7E420C2EAB42153A13421EDAC142291A5742340315423F9FE6424BFC66425924F4426726B942760FB84282F76E428B6A024294680B429DFA8942A82B0F42B303CE42BE8F9F42CADA1042D7EF6C42E5DCC942F4B01743023C14430AA26443139362431D17FF432739C2433202CC433D7DE84349B6914356B9024364923E4373501F438180B24389DAE14392BEF5439C35D543A648F843B10271"}}
-{"expression":"sinh(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB002AACCCD9CDD01623FC00AACCD00D2F101633FC8241036AC51DD"}}
-{"expression":"sinh(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC00AACCD00D2F1016103666F6F3FB002AACCCD9CDD0162036261723FD02ACCD9D08102016203666F6F3FC8241036AC51DD0163036261723FD8910411CE5046016303666F6F3FD453BDBE16906C"}}
-{"expression":"sinh(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD453BDBE16906C016103626172016A3FD8910411CE5046016103626172016B3FDCE6DD75BF0317016103626172016C3FE0ACD00FE63B97016103666F6F01693FB002AACCCD9CDD016103666F6F016A3FC00AACCD00D2F1016103666F6F016B3FC8241036AC51DD016103666F6F016C3FD02ACCD9D0810201620362617201693FECF4E3B6AFE2AD016203626172016A3FEFB6538D14EAFC016203626172016B3FF14BBE2DD2460A016203626172016C3FF2CD9FC44EB982016203666F6F01693FE2F6DF98C4B900016203666F6F016A3FE553E795DC19CC016203666F6F016B3FE7C645419678B8016203666F6F016C3FEA506B2DD3C69001630362617201693FFB9208091DCFC6016303626172016A3FFD9E2E7FB7FEF4016303626172016B3FFFC7F59CC02B95016303626172016C400108C3AABD6A60016303666F6F01693FF462508BBF80A9016303666F6F016A3FF60B6556A69204016303666F6F016B3FF7CA875D3C6932016303666F6F016C3FF9A175E6CBAFE6"}}
-{"expression":"sinh(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA29DEE016103626172016A3EC48821016103626172016B3EE736EC016103626172016C3F056680016103666F6F01693D801556016103666F6F016A3E005566016103666F6F016B3E412082016103666F6F016C3E81566701620362617201693F67A71E016203626172016A3F7DB29C016203626172016B3F8A5DF1016203626172016C3F966CFE016203666F6F01693F17B6FD016203666F6F016A3F2A9F3D016203666F6F016B3F3E322A016203666F6F016C3F52835901630362617201693FDC9040016303626172016A3FECF174016303626172016B3FFE3FAD016303626172016C4008461D016303666F6F01693FA31284016303666F6F016A3FB05B2B016303666F6F016B3FBE543B016303666F6F016C3FCD0BAF"}}
-{"expression":"sinh(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FFD9E2E7FB7FEF43FFFC7F59CC02B95400108C3AABD6A6040023E96B6373D25400386A9DDAB7A8B4004E2454F996E14400652C4C46B9BBA4012C3C19FD775D1401400526B99E613401550E53487B2914016B6CAA976F3DE40183368CDB0B6D34019C83C5F121C3C401B76DA52E9F18203666F6F3FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FF14BBE2DD2460A3FF2CD9FC44EB9823FF462508BBF80A93FF60B6556A692043FF7CA875D3C69323FF9A175E6CBAFE63FFB9208091DCFC64007D998DA4D257C4009784885E6AF4C400B307299739D43400D03CF63B6E1A0400EF432686E7235401081C619FEFEA9401199F6261257EA"}}
-{"expression":"sinh(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB002AACCCD9CDD3FD453BDBE16906C3FE2F6DF98C4B9003FECF4E3B6AFE2AD3FF462508BBF80A90161016A3FC00AACCD00D2F13FD8910411CE50463FE553E795DC19CC3FEFB6538D14EAFC3FF60B6556A692040161016B3FC8241036AC51DD3FDCE6DD75BF03173FE7C645419678B83FF14BBE2DD2460A3FF7CA875D3C69320161016C3FD02ACCD9D081023FE0ACD00FE63B973FEA506B2DD3C6903FF2CD9FC44EB9823FF9A175E6CBAFE6016201693FFB9208091DCFC640023E96B6373D254007D998DA4D257C400EF432686E7235401400526B99E6130162016A3FFD9E2E7FB7FEF4400386A9DDAB7A8B4009784885E6AF4C401081C619FEFEA9401550E53487B2910162016B3FFFC7F59CC02B954004E2454F996E14400B307299739D43401199F6261257EA4016B6CAA976F3DE0162016C400108C3AABD6A60400652C4C46B9BBA400D03CF63B6E1A04012C3C19FD775D140183368CDB0B6D3016301694019C83C5F121C3C40209768A197A1BD4025558C4E1E87B4402B6AD0D38F872340319C8642A0C10D0163016A401B76DA52E9F1824021AB441B6B45A14026B74908B216D0402D30A824AE59174032BFC0E41034CD0163016B401D40F16B0FBFB34022D0CC52573D2D40282FBEF0F9EB00402F13B28CBF49614033F5BCD66BCBD30163016C401F284BE4C989BD40240926E70949AE4029C0669C3E808340308AE99F364F3B40353FB02F7BBD05"}}
-{"expression":"sinh(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D8015563EA29DEE3F17B6FD3F67A71E3FA312840161016A3E0055663EC488213F2A9F3D3F7DB29C3FB05B2B0161016B3E4120823EE736EC3F3E322A3F8A5DF13FBE543B0161016C3E8156673F0566803F5283593F966CFE3FCD0BAF016201693FDC90404011F4B6403ECCC74077A19340A002930162016A3FECF174401C354F404BC24440840E3140AA872A0162016B3FFE3FAD4027122A40598395408CCFB140B5B6550162016C4008461D4032962640681E7B40961E0D40C19B460163016940CE41E34104BB45412AAC62415B5687418CE4320163016A40DBB6D3410D5A214135BA48416985414195FE070163016B40EA078B4116866341417DF841789D94419FADE70163016C40F9425F41204937414E03354184574D41A9FD81"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB002AACCCD9CDD"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FF14BBE2DD2460A"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FF14BBE2DD2460A3FF2CD9FC44EB9823FF462508BBF80A93FF60B6556A692043FF7CA875D3C69323FF9A175E6CBAFE63FFB9208091DCFC63FFD9E2E7FB7FEF43FFFC7F59CC02B95400108C3AABD6A6040023E96B6373D25400386A9DDAB7A8B4004E2454F996E14400652C4C46B9BBA4007D998DA4D257C4009784885E6AF4C400B307299739D43400D03CF63B6E1A0400EF432686E7235401081C619FEFEA9401199F6261257EA4012C3C19FD775D1401400526B99E613401550E53487B2914016B6CAA976F3DE40183368CDB0B6D34019C83C5F121C3C401B76DA52E9F182401D40F16B0FBFB3401F284BE4C989BD40209768A197A1BD4021AB441B6B45A14022D0CC52573D2D40240926E70949AE4025558C4E1E87B44026B74908B216D040282FBEF0F9EB004029C0669C3E8083402B6AD0D38F8723402D30A824AE5917402F13B28CBF496140308AE99F364F3B40319C8642A0C10D4032BFC0E41034CD4033F5BCD66BCBD340353FB02F7BBD0540369EE4FE18F513403814BA945771844039A2A6E6F59C8A403B4A3803703630403D0D159E30FDFF403EED02BA666CF1404075EFB6963D63404185D55EE4DE8C4042A7425270A2A24043DB58164C4CDE4045234AD9E90F0140468062AB5FA9FC4047F3FCBF99DE2440497F8CCFA46FA0404B249E8C872E52404CE4D72B16F828404EC1F7094DA8E640505EEDB766B93240516D403528230B40528D0166F073744053BF5125ED038940550561DB644EEF40566079B338C3F34057D1F3E22FD53340595B420143AF17405AFDED7F5AFFC3405CBB992AD8A81F405E9602D48D06614060478286D5F7384061544C8142B58E4062726C39EE144C4063A2FFE86984574064E73839C5FD9C40664059815A74974067AFBCFD32392B406936D22F67C805406AD7204DC5865B406C9247C91C272C406E6A03EDD63132407030164FB4ADD640713B5C1830AC2D407257DEAC6E1E64407386BAA6B7989C4074C91EFC453B364076204E2C4B2AEA"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D8015563E0055663E4120823E8156673EA29DEE3EC488213EE736EC3F0566803F17B6FD3F2A9F3D3F3E322A3F5283593F67A71E3F7DB29C3F8A5DF13F966CFE3FA312843FB05B2B3FBE543B3FCD0BAF3FDC90403FECF1743FFE3FAD4008461D4011F4B6401C354F4027122A40329626403ECCC7404BC2444059839540681E7B4077A19340840E31408CCFB140961E0D40A0029340AA872A40B5B65540C19B4640CE41E340DBB6D340EA078B40F9425F4104BB45410D5A214116866341204937412AAC624135BA4841417DF8414E0335415B56874169854141789D944184574D418CE4324195FE07419FADE741A9FD8141B4F72841C0A5D541CD153741DA51C041E868AD41F768164203AF7E420C2EAB42153A13421EDAC142291A5742340315423F9FE6424BFC66425924F4426726B942760FB84282F76E428B6A024294680B429DFA8942A82B0F42B303CE42BE8F9F42CADA1042D7EF6C42E5DCC942F4B01743023C14430AA26443139362431D17FF432739C2433202CC433D7DE84349B6914356B9024364923E4373501F438180B24389DAE14392BEF5439C35D543A648F843B10271"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB002AACCCD9CDD01623FC00AACCD00D2F101633FC8241036AC51DD"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC00AACCD00D2F1016103666F6F3FB002AACCCD9CDD0162036261723FD02ACCD9D08102016203666F6F3FC8241036AC51DD0163036261723FD8910411CE5046016303666F6F3FD453BDBE16906C"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD453BDBE16906C016103626172016A3FD8910411CE5046016103626172016B3FDCE6DD75BF0317016103626172016C3FE0ACD00FE63B97016103666F6F01693FB002AACCCD9CDD016103666F6F016A3FC00AACCD00D2F1016103666F6F016B3FC8241036AC51DD016103666F6F016C3FD02ACCD9D0810201620362617201693FECF4E3B6AFE2AD016203626172016A3FEFB6538D14EAFC016203626172016B3FF14BBE2DD2460A016203626172016C3FF2CD9FC44EB982016203666F6F01693FE2F6DF98C4B900016203666F6F016A3FE553E795DC19CC016203666F6F016B3FE7C645419678B8016203666F6F016C3FEA506B2DD3C69001630362617201693FFB9208091DCFC6016303626172016A3FFD9E2E7FB7FEF4016303626172016B3FFFC7F59CC02B95016303626172016C400108C3AABD6A60016303666F6F01693FF462508BBF80A9016303666F6F016A3FF60B6556A69204016303666F6F016B3FF7CA875D3C6932016303666F6F016C3FF9A175E6CBAFE6"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA29DEE016103626172016A3EC48821016103626172016B3EE736EC016103626172016C3F056680016103666F6F01693D801556016103666F6F016A3E005566016103666F6F016B3E412082016103666F6F016C3E81566701620362617201693F67A71E016203626172016A3F7DB29C016203626172016B3F8A5DF1016203626172016C3F966CFE016203666F6F01693F17B6FD016203666F6F016A3F2A9F3D016203666F6F016B3F3E322A016203666F6F016C3F52835901630362617201693FDC9040016303626172016A3FECF174016303626172016B3FFE3FAD016303626172016C4008461D016303666F6F01693FA31284016303666F6F016A3FB05B2B016303666F6F016B3FBE543B016303666F6F016C3FCD0BAF"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE0ACD00FE63B973FE2F6DF98C4B9003FE553E795DC19CC3FE7C645419678B83FEA506B2DD3C6903FECF4E3B6AFE2AD3FEFB6538D14EAFC3FFD9E2E7FB7FEF43FFFC7F59CC02B95400108C3AABD6A6040023E96B6373D25400386A9DDAB7A8B4004E2454F996E14400652C4C46B9BBA4012C3C19FD775D1401400526B99E613401550E53487B2914016B6CAA976F3DE40183368CDB0B6D34019C83C5F121C3C401B76DA52E9F18203666F6F3FB002AACCCD9CDD3FC00AACCD00D2F13FC8241036AC51DD3FD02ACCD9D081023FD453BDBE16906C3FD8910411CE50463FDCE6DD75BF03173FF14BBE2DD2460A3FF2CD9FC44EB9823FF462508BBF80A93FF60B6556A692043FF7CA875D3C69323FF9A175E6CBAFE63FFB9208091DCFC64007D998DA4D257C4009784885E6AF4C400B307299739D43400D03CF63B6E1A0400EF432686E7235401081C619FEFEA9401199F6261257EA"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB002AACCCD9CDD3FD453BDBE16906C3FE2F6DF98C4B9003FECF4E3B6AFE2AD3FF462508BBF80A90161016A3FC00AACCD00D2F13FD8910411CE50463FE553E795DC19CC3FEFB6538D14EAFC3FF60B6556A692040161016B3FC8241036AC51DD3FDCE6DD75BF03173FE7C645419678B83FF14BBE2DD2460A3FF7CA875D3C69320161016C3FD02ACCD9D081023FE0ACD00FE63B973FEA506B2DD3C6903FF2CD9FC44EB9823FF9A175E6CBAFE6016201693FFB9208091DCFC640023E96B6373D254007D998DA4D257C400EF432686E7235401400526B99E6130162016A3FFD9E2E7FB7FEF4400386A9DDAB7A8B4009784885E6AF4C401081C619FEFEA9401550E53487B2910162016B3FFFC7F59CC02B954004E2454F996E14400B307299739D43401199F6261257EA4016B6CAA976F3DE0162016C400108C3AABD6A60400652C4C46B9BBA400D03CF63B6E1A04012C3C19FD775D140183368CDB0B6D3016301694019C83C5F121C3C40209768A197A1BD4025558C4E1E87B4402B6AD0D38F872340319C8642A0C10D0163016A401B76DA52E9F1824021AB441B6B45A14026B74908B216D0402D30A824AE59174032BFC0E41034CD0163016B401D40F16B0FBFB34022D0CC52573D2D40282FBEF0F9EB00402F13B28CBF49614033F5BCD66BCBD30163016C401F284BE4C989BD40240926E70949AE4029C0669C3E808340308AE99F364F3B40353FB02F7BBD05"}}
-{"expression":"map(a,f(a)(sinh(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D8015563EA29DEE3F17B6FD3F67A71E3FA312840161016A3E0055663EC488213F2A9F3D3F7DB29C3FB05B2B0161016B3E4120823EE736EC3F3E322A3F8A5DF13FBE543B0161016C3E8156673F0566803F5283593F966CFE3FCD0BAF016201693FDC90404011F4B6403ECCC74077A19340A002930162016A3FECF174401C354F404BC24440840E3140AA872A0162016B3FFE3FAD4027122A40598395408CCFB140B5B6550162016C4008461D4032962640681E7B40961E0D40C19B460163016940CE41E34104BB45412AAC62415B5687418CE4320163016A40DBB6D3410D5A214135BA48416985414195FE070163016B40EA078B4116866341417DF841789D94419FADE70163016C40F9425F41204937414E03354184574D41A9FD81"}}
-{"expression":"tanh(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFF55997E030D7"}}
-{"expression":"tanh(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF775"}}
-{"expression":"tanh(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FE77D838E34057D"}}
-{"expression":"tanh(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FE77D838E34057D3FE85EFAB514F3943FE92BFB370D9B723FE9E5CB5BA44D693FEA8DBCBC31897A3FEB2523BB6B2DEE3FEBAD50A4A68BC23FEC278A52A4E4783FEC950A3340C8C03FECF6F9786DF5773FED4E6F464286B13FED9C6FAFE61C783FEDE1EB5937518F3FEE1FBF97E335273FEE56B6F3EFABFD3FEE8789ECEC0DDA3FEEB2DFEDD5EC933FEED9505E1BC3D43FEEFB63C1F339983FEF1994DF724FC83FEF3451E0899E213FEF4BFD6C2DFD1E3FEF60EFB2C128493FEF73776B2AA2DB3FEF83DABF23E1773FEF9258260A71C23FEF9F272E24FE6C3FEFAA7934B75EBD3FEFB47A0D8F6D243FEFBD509AE7AE3E3FEFC51F569C07DB3FEFCC04CDBCDC4C3FEFD21C0F91C6583FEFD77D111A0B003FEFDC3D06100D203FEFE06EB06882123FEFE422A737407E3FEFE76795D353A03FEFEA4A74034D753FEFECD6B7EA31283FEFEF16825D225B3FEFF112C63A90773FEFF2D36B4D02D93FEFF45F6D36133B3FEFF5BCF6D192443FEFF6F17A7547723FEFF801C76733AF3FEFF8F21CDAAA633FEFF9C63ABBE9F43FEFFA81708A0B423FEFFB26AA7817A33FEFFBB87D07C5DF3FEFFC392F4AB8D53FEFFCAAC3F20E663FEFFD0F014F8C4D3FEFFD677867B57F3FEFFDB58B3080623FEFFDFA721539833FEFFE3740D54C9A3FEFFE6CEAD12CDD3FEFFE9C46D65D833FEFFEC61279A3A43FEFFEEAF50CAC563FEFFF0B823AE6E63FEFFF283C57F53E3FEFFF419668DF113FEFFF57F5F022B63FEFFF6BB483CC793FEFFF7D2133E7443FEFFF8C81C6DC343FEFFF9A13D0AFAE3FEFFFA60DA976AA3FEFFFB09F46DC8D3FEFFFB9F2FC1E913FEFFFC22E237BFF3FEFFFC971B3C0753FEFFFCFDAC43E313FEFFFD5830148253FEFFFDA8112FDB43FEFFFDEE8F803513FEFFFE2CC5593093FEFFFE63ABE253C3FEFFFE941EFCC6C3FEFFFEBEE0B3DA03FEFFFEE49C461A13FEFFFF05E8D31923FEFFFF234BB8A593FEFFFF3D3AA8E643FEFFFF541D81B583FEFFFF684FEC9B93FEFFFF7A22CDE86"}}
-{"expression":"tanh(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FAACD3DFEACC93E3DC7FD3E7ACBF53E9AFCC53EB77A9F3ED2B94F3EEC9A9F3F0284383F0DFA3F3F18ABF03F22991F3F2BC4803F3433283F3BEC1C3F42F7D63F495FDA3F4F2E5B3F546DE63F59291E3F5D6A853F613C533F64A8523F67B7CC3F6A737A3F6CE37D3F6F0F5B3F70FDFD3F72B5B83F743C4F3F7596FF3F76CA833F77DB1E3F78CCA73F79A28F3F7A5FEB3F7B077E3F7B9BBB3F7C1ED63F7C92C13F7CF9393F7D53CA3F7DA3D03F7DEA853F7E28FB3F7E60263F7E90E03F7EBBE93F7EE1E83F7F03763F7F21153F7F3B3D3F7F52543F7F66B63F7F78B43F7F88963F7F969B3F7FA2FB3F7FADE83F7FB78C3F7FC00E3F7FC7913F7FCE323F7FD40C3F7FD9353F7FDDC43F7FE1C93F7FE5563F7FE8783F7FEB3C3F7FEDAC3F7FEFD43F7FF1BA3F7FF3673F7FF4E23F7FF6313F7FF7583F7FF85C3F7FF9423F7FFA0D3F7FFAC03F7FFB5E3F7FFBE93F7FFC643F7FFCD13F7FFD303F7FFD853F7FFDD03F7FFE113F7FFE4C3F7FFE7F3F7FFEAC3F7FFED43F7FFEF73F7FFF163F7FFF323F7FFF4A3F7FFF5F3F7FFF723F7FFF833F7FFF923F7FFF9F3F7FFFAA3F7FFFB43F7FFFBD"}}
-{"expression":"tanh(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFF55997E030D701623FBFD5992BC4B83401633FC7B8FF903BF775"}}
-{"expression":"tanh(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFD5992BC4B834016103666F6F3FAFF55997E030D70162036261723FCF597EA69A1C86016203666F6F3FC7B8FF903BF7750163036261723FD6EF53DE8C8FB0016303666F6F3FD35F98A0EA650E"}}
-{"expression":"tanh(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD35F98A0EA650E016103626172016A3FD6EF53DE8C8FB0016103626172016B3FDA5729EE488036016103626172016C3FDD9353D7568AF3016103666F6F01693FAFF55997E030D7016103666F6F016A3FBFD5992BC4B834016103666F6F016B3FC7B8FF903BF775016103666F6F016C3FCF597EA69A1C8601620362617201693FE5788FF10D2999016203626172016A3FE686650B8C2016016203626172016B3FE77D838E34057D016203626172016C3FE85EFAB514F394016203666F6F01693FE05086F2F6D4B7016203666F6F016A3FE1BF47EABB8F95016203666F6F016B3FE3157DFE9F715B016203666F6F016C3FE45323E552F22801630362617201693FEBAD50A4A68BC2016303626172016A3FEC278A52A4E478016303626172016B3FEC950A3340C8C0016303626172016C3FECF6F9786DF577016303666F6F01693FE92BFB370D9B72016303666F6F016A3FE9E5CB5BA44D69016303666F6F016B3FEA8DBCBC31897A016303666F6F016C3FEB2523BB6B2DEE"}}
-{"expression":"tanh(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9AFCC5016103626172016A3EB77A9F016103626172016B3ED2B94F016103626172016C3EEC9A9F016103666F6F01693D7FAACD016103666F6F016A3DFEACC9016103666F6F016B3E3DC7FD016103666F6F016C3E7ACBF501620362617201693F2BC480016203626172016A3F343328016203626172016B3F3BEC1C016203626172016C3F42F7D6016203666F6F01693F028438016203666F6F016A3F0DFA3F016203666F6F016B3F18ABF0016203666F6F016C3F22991F01630362617201693F5D6A85016303626172016A3F613C53016303626172016B3F64A852016303626172016C3F67B7CC016303666F6F01693F495FDA016303666F6F016A3F4F2E5B016303666F6F016B3F546DE6016303666F6F016C3F59291E"}}
-{"expression":"tanh(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FEC278A52A4E4783FEC950A3340C8C03FECF6F9786DF5773FED4E6F464286B13FED9C6FAFE61C783FEDE1EB5937518F3FEE1FBF97E335273FEF4BFD6C2DFD1E3FEF60EFB2C128493FEF73776B2AA2DB3FEF83DABF23E1773FEF9258260A71C23FEF9F272E24FE6C3FEFAA7934B75EBD03666F6F3FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FE77D838E34057D3FE85EFAB514F3943FE92BFB370D9B723FE9E5CB5BA44D693FEA8DBCBC31897A3FEB2523BB6B2DEE3FEBAD50A4A68BC23FEE56B6F3EFABFD3FEE8789ECEC0DDA3FEEB2DFEDD5EC933FEED9505E1BC3D43FEEFB63C1F339983FEF1994DF724FC83FEF3451E0899E21"}}
-{"expression":"tanh(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFF55997E030D73FD35F98A0EA650E3FE05086F2F6D4B73FE5788FF10D29993FE92BFB370D9B720161016A3FBFD5992BC4B8343FD6EF53DE8C8FB03FE1BF47EABB8F953FE686650B8C20163FE9E5CB5BA44D690161016B3FC7B8FF903BF7753FDA5729EE4880363FE3157DFE9F715B3FE77D838E34057D3FEA8DBCBC31897A0161016C3FCF597EA69A1C863FDD9353D7568AF33FE45323E552F2283FE85EFAB514F3943FEB2523BB6B2DEE016201693FEBAD50A4A68BC23FED4E6F464286B13FEE56B6F3EFABFD3FEEFB63C1F339983FEF60EFB2C128490162016A3FEC278A52A4E4783FED9C6FAFE61C783FEE8789ECEC0DDA3FEF1994DF724FC83FEF73776B2AA2DB0162016B3FEC950A3340C8C03FEDE1EB5937518F3FEEB2DFEDD5EC933FEF3451E0899E213FEF83DABF23E1770162016C3FECF6F9786DF5773FEE1FBF97E335273FEED9505E1BC3D43FEF4BFD6C2DFD1E3FEF9258260A71C2016301693FEF9F272E24FE6C3FEFC51F569C07DB3FEFDC3D06100D203FEFEA4A74034D753FEFF2D36B4D02D90163016A3FEFAA7934B75EBD3FEFCC04CDBCDC4C3FEFE06EB06882123FEFECD6B7EA31283FEFF45F6D36133B0163016B3FEFB47A0D8F6D243FEFD21C0F91C6583FEFE422A737407E3FEFEF16825D225B3FEFF5BCF6D192440163016C3FEFBD509AE7AE3E3FEFD77D111A0B003FEFE76795D353A03FEFF112C63A90773FEFF6F17A754772"}}
-{"expression":"tanh(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FAACD3E9AFCC53F0284383F2BC4803F495FDA0161016A3DFEACC93EB77A9F3F0DFA3F3F3433283F4F2E5B0161016B3E3DC7FD3ED2B94F3F18ABF03F3BEC1C3F546DE60161016C3E7ACBF53EEC9A9F3F22991F3F42F7D63F59291E016201693F5D6A853F6A737A3F72B5B83F77DB1E3F7B077E0162016A3F613C533F6CE37D3F743C4F3F78CCA73F7B9BBB0162016B3F64A8523F6F0F5B3F7596FF3F79A28F3F7C1ED60162016C3F67B7CC3F70FDFD3F76CA833F7A5FEB3F7C92C1016301693F7CF9393F7E28FB3F7EE1E83F7F52543F7F969B0163016A3F7D53CA3F7E60263F7F03763F7F66B63F7FA2FB0163016B3F7DA3D03F7E90E03F7F21153F7F78B43F7FADE80163016C3F7DEA853F7EBBE93F7F3B3D3F7F88963F7FB78C"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFF55997E030D7"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF775"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FE77D838E34057D"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FE77D838E34057D3FE85EFAB514F3943FE92BFB370D9B723FE9E5CB5BA44D693FEA8DBCBC31897A3FEB2523BB6B2DEE3FEBAD50A4A68BC23FEC278A52A4E4783FEC950A3340C8C03FECF6F9786DF5773FED4E6F464286B13FED9C6FAFE61C783FEDE1EB5937518F3FEE1FBF97E335273FEE56B6F3EFABFD3FEE8789ECEC0DDA3FEEB2DFEDD5EC933FEED9505E1BC3D43FEEFB63C1F339983FEF1994DF724FC83FEF3451E0899E213FEF4BFD6C2DFD1E3FEF60EFB2C128493FEF73776B2AA2DB3FEF83DABF23E1773FEF9258260A71C23FEF9F272E24FE6C3FEFAA7934B75EBD3FEFB47A0D8F6D243FEFBD509AE7AE3E3FEFC51F569C07DB3FEFCC04CDBCDC4C3FEFD21C0F91C6583FEFD77D111A0B003FEFDC3D06100D203FEFE06EB06882123FEFE422A737407E3FEFE76795D353A03FEFEA4A74034D753FEFECD6B7EA31283FEFEF16825D225B3FEFF112C63A90773FEFF2D36B4D02D93FEFF45F6D36133B3FEFF5BCF6D192443FEFF6F17A7547723FEFF801C76733AF3FEFF8F21CDAAA633FEFF9C63ABBE9F43FEFFA81708A0B423FEFFB26AA7817A33FEFFBB87D07C5DF3FEFFC392F4AB8D53FEFFCAAC3F20E663FEFFD0F014F8C4D3FEFFD677867B57F3FEFFDB58B3080623FEFFDFA721539833FEFFE3740D54C9A3FEFFE6CEAD12CDD3FEFFE9C46D65D833FEFFEC61279A3A43FEFFEEAF50CAC563FEFFF0B823AE6E63FEFFF283C57F53E3FEFFF419668DF113FEFFF57F5F022B63FEFFF6BB483CC793FEFFF7D2133E7443FEFFF8C81C6DC343FEFFF9A13D0AFAE3FEFFFA60DA976AA3FEFFFB09F46DC8D3FEFFFB9F2FC1E913FEFFFC22E237BFF3FEFFFC971B3C0753FEFFFCFDAC43E313FEFFFD5830148253FEFFFDA8112FDB43FEFFFDEE8F803513FEFFFE2CC5593093FEFFFE63ABE253C3FEFFFE941EFCC6C3FEFFFEBEE0B3DA03FEFFFEE49C461A13FEFFFF05E8D31923FEFFFF234BB8A593FEFFFF3D3AA8E643FEFFFF541D81B583FEFFFF684FEC9B93FEFFFF7A22CDE86"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FAACD3DFEACC93E3DC7FD3E7ACBF53E9AFCC53EB77A9F3ED2B94F3EEC9A9F3F0284383F0DFA3F3F18ABF03F22991F3F2BC4803F3433283F3BEC1C3F42F7D63F495FDA3F4F2E5B3F546DE63F59291E3F5D6A853F613C533F64A8523F67B7CC3F6A737A3F6CE37D3F6F0F5B3F70FDFD3F72B5B83F743C4F3F7596FF3F76CA833F77DB1E3F78CCA73F79A28F3F7A5FEB3F7B077E3F7B9BBB3F7C1ED63F7C92C13F7CF9393F7D53CA3F7DA3D03F7DEA853F7E28FB3F7E60263F7E90E03F7EBBE93F7EE1E83F7F03763F7F21153F7F3B3D3F7F52543F7F66B63F7F78B43F7F88963F7F969B3F7FA2FB3F7FADE83F7FB78C3F7FC00E3F7FC7913F7FCE323F7FD40C3F7FD9353F7FDDC43F7FE1C93F7FE5563F7FE8783F7FEB3C3F7FEDAC3F7FEFD43F7FF1BA3F7FF3673F7FF4E23F7FF6313F7FF7583F7FF85C3F7FF9423F7FFA0D3F7FFAC03F7FFB5E3F7FFBE93F7FFC643F7FFCD13F7FFD303F7FFD853F7FFDD03F7FFE113F7FFE4C3F7FFE7F3F7FFEAC3F7FFED43F7FFEF73F7FFF163F7FFF323F7FFF4A3F7FFF5F3F7FFF723F7FFF833F7FFF923F7FFF9F3F7FFFAA3F7FFFB43F7FFFBD"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFF55997E030D701623FBFD5992BC4B83401633FC7B8FF903BF775"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFD5992BC4B834016103666F6F3FAFF55997E030D70162036261723FCF597EA69A1C86016203666F6F3FC7B8FF903BF7750163036261723FD6EF53DE8C8FB0016303666F6F3FD35F98A0EA650E"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD35F98A0EA650E016103626172016A3FD6EF53DE8C8FB0016103626172016B3FDA5729EE488036016103626172016C3FDD9353D7568AF3016103666F6F01693FAFF55997E030D7016103666F6F016A3FBFD5992BC4B834016103666F6F016B3FC7B8FF903BF775016103666F6F016C3FCF597EA69A1C8601620362617201693FE5788FF10D2999016203626172016A3FE686650B8C2016016203626172016B3FE77D838E34057D016203626172016C3FE85EFAB514F394016203666F6F01693FE05086F2F6D4B7016203666F6F016A3FE1BF47EABB8F95016203666F6F016B3FE3157DFE9F715B016203666F6F016C3FE45323E552F22801630362617201693FEBAD50A4A68BC2016303626172016A3FEC278A52A4E478016303626172016B3FEC950A3340C8C0016303626172016C3FECF6F9786DF577016303666F6F01693FE92BFB370D9B72016303666F6F016A3FE9E5CB5BA44D69016303666F6F016B3FEA8DBCBC31897A016303666F6F016C3FEB2523BB6B2DEE"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9AFCC5016103626172016A3EB77A9F016103626172016B3ED2B94F016103626172016C3EEC9A9F016103666F6F01693D7FAACD016103666F6F016A3DFEACC9016103666F6F016B3E3DC7FD016103666F6F016C3E7ACBF501620362617201693F2BC480016203626172016A3F343328016203626172016B3F3BEC1C016203626172016C3F42F7D6016203666F6F01693F028438016203666F6F016A3F0DFA3F016203666F6F016B3F18ABF0016203666F6F016C3F22991F01630362617201693F5D6A85016303626172016A3F613C53016303626172016B3F64A852016303626172016C3F67B7CC016303666F6F01693F495FDA016303666F6F016A3F4F2E5B016303666F6F016B3F546DE6016303666F6F016C3F59291E"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDD9353D7568AF33FE05086F2F6D4B73FE1BF47EABB8F953FE3157DFE9F715B3FE45323E552F2283FE5788FF10D29993FE686650B8C20163FEC278A52A4E4783FEC950A3340C8C03FECF6F9786DF5773FED4E6F464286B13FED9C6FAFE61C783FEDE1EB5937518F3FEE1FBF97E335273FEF4BFD6C2DFD1E3FEF60EFB2C128493FEF73776B2AA2DB3FEF83DABF23E1773FEF9258260A71C23FEF9F272E24FE6C3FEFAA7934B75EBD03666F6F3FAFF55997E030D73FBFD5992BC4B8343FC7B8FF903BF7753FCF597EA69A1C863FD35F98A0EA650E3FD6EF53DE8C8FB03FDA5729EE4880363FE77D838E34057D3FE85EFAB514F3943FE92BFB370D9B723FE9E5CB5BA44D693FEA8DBCBC31897A3FEB2523BB6B2DEE3FEBAD50A4A68BC23FEE56B6F3EFABFD3FEE8789ECEC0DDA3FEEB2DFEDD5EC933FEED9505E1BC3D43FEEFB63C1F339983FEF1994DF724FC83FEF3451E0899E21"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFF55997E030D73FD35F98A0EA650E3FE05086F2F6D4B73FE5788FF10D29993FE92BFB370D9B720161016A3FBFD5992BC4B8343FD6EF53DE8C8FB03FE1BF47EABB8F953FE686650B8C20163FE9E5CB5BA44D690161016B3FC7B8FF903BF7753FDA5729EE4880363FE3157DFE9F715B3FE77D838E34057D3FEA8DBCBC31897A0161016C3FCF597EA69A1C863FDD9353D7568AF33FE45323E552F2283FE85EFAB514F3943FEB2523BB6B2DEE016201693FEBAD50A4A68BC23FED4E6F464286B13FEE56B6F3EFABFD3FEEFB63C1F339983FEF60EFB2C128490162016A3FEC278A52A4E4783FED9C6FAFE61C783FEE8789ECEC0DDA3FEF1994DF724FC83FEF73776B2AA2DB0162016B3FEC950A3340C8C03FEDE1EB5937518F3FEEB2DFEDD5EC933FEF3451E0899E213FEF83DABF23E1770162016C3FECF6F9786DF5773FEE1FBF97E335273FEED9505E1BC3D43FEF4BFD6C2DFD1E3FEF9258260A71C2016301693FEF9F272E24FE6C3FEFC51F569C07DB3FEFDC3D06100D203FEFEA4A74034D753FEFF2D36B4D02D90163016A3FEFAA7934B75EBD3FEFCC04CDBCDC4C3FEFE06EB06882123FEFECD6B7EA31283FEFF45F6D36133B0163016B3FEFB47A0D8F6D243FEFD21C0F91C6583FEFE422A737407E3FEFEF16825D225B3FEFF5BCF6D192440163016C3FEFBD509AE7AE3E3FEFD77D111A0B003FEFE76795D353A03FEFF112C63A90773FEFF6F17A754772"}}
-{"expression":"map(a,f(a)(tanh(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FAACD3E9AFCC53F0284383F2BC4803F495FDA0161016A3DFEACC93EB77A9F3F0DFA3F3F3433283F4F2E5B0161016B3E3DC7FD3ED2B94F3F18ABF03F3BEC1C3F546DE60161016C3E7ACBF53EEC9A9F3F22991F3F42F7D63F59291E016201693F5D6A853F6A737A3F72B5B83F77DB1E3F7B077E0162016A3F613C533F6CE37D3F743C4F3F78CCA73F7B9BBB0162016B3F64A8523F6F0F5B3F7596FF3F79A28F3F7C1ED60162016C3F67B7CC3F70FDFD3F76CA833F7A5FEB3F7C92C1016301693F7CF9393F7E28FB3F7EE1E83F7F52543F7F969B0163016A3F7D53CA3F7E60263F7F03763F7F66B63F7FA2FB0163016B3F7DA3D03F7E90E03F7F21153F7F78B43F7FADE80163016C3F7DEA853F7EBBE93F7F3B3D3F7F88963F7FB78C"}}
-{"expression":"acos(a)","inputs":{"a":"0x02003FE07FF560000000"},"result":{"expect":"0x02003FF0770D2E39D866"}}
-{"expression":"acos(a)","inputs":{"a":"0x02010178033FE07FF5600000003FE0FFAAC00000003FE17EE100000000"},"result":{"expect":"0x02010178033FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D0"}}
-{"expression":"acos(a)","inputs":{"a":"0x02020178030179053FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A0000000"},"result":{"expect":"0x02020178030179053FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE89BCA4C25AB4D"}}
-{"expression":"acos(a)","inputs":{"a":"0x0203017803017905017A073FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A400000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A8600000003FEDF60C000000003FEE13C5200000003FEE2FE7400000003FEE4A85200000003FEE63B1000000003FEE7B7CC00000003FEE91F9600000003FEEA737A00000003FEEBB47600000003FEECE37E00000003FEEE017E00000003FEEF0F5A00000003FEF00DEA00000003FEF0FDFC00000003FEF1E05800000003FEF2B5B800000003FEF37ED200000003FEF43C5000000003FEF4EED600000003FEF5970000000003FEF6356000000003FEF6CA8200000003FEF756EE00000003FEF7DB1E00000003FEF8578C00000003FEF8CCA600000003FEF93ADC00000003FEF9A29000000003FEFA042000000003FEFA5FEC00000003FEFAB64400000003FEFB077E00000003FEFB53E200000003FEFB9BBC00000003FEFBDF4C00000003FEFC1ED600000003FEFC5A9400000003FEFC92C200000003FEFCC79200000003FEFCF93A00000003FEFD27E800000003FEFD53CA00000003FEFD7D0A00000003FEFDA3D000000003FEFDC84200000003FEFDEA8400000003FEFE0AB800000003FEFE28FA00000003FEFE456C00000003FEFE602600000003FEFE794600000003FEFE90E000000003FEFEA71000000003FEFEBBE800000003FEFECF8000000003FEFEE1E800000003FEFEF33400000003FEFF037600000003FEFF12BC00000003FEFF211600000003FEFF2E9200000003FEFF3B3C00000003FEFF47240000000"},"result":{"expect":"0x0203017803017905017A073FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE89BCA4C25AB4D3FE8079226F2A4A13FE774C415B470C73FE6E381BDEB896C3FE653EB0FC3031A3FE5C61D15D03BCB3FE53A32D43D8D6A3FE4B04498A69D9C3FE4286874A3812A3FE3A2B1E87FDA4B3FE31F32D557E5553FE29DF9D621C37D3FE21F148BF8F9D13FE1A28D7C2EB40D3FE1286E03E6D6203FE0B0BD170137253FE03B801F7ACC8E3FDF91766FDBAFC03FDEB0E0B8909A4F3FDDD5404E485F613FDCFE943F0E92CC3FDC2CD996EB66993FDB600927F03DA93FDA981B2BC392543FD9D50673A834E63FD916BE2A3CCF5E3FD85D35F40557E63FD7A85E8161AFA73FD6F828A933916E3FD64C833AD32C493FD5A55B74820A113FD5029F2311B3483FD4643B29B929213FD3CA1A9A3879EF3FD33429E2DDA3943FD2A252BDB691E63FD214805B10C9F03FD18A9DDD7CF9863FD10495801E910C3FD0825091AACCC63FD003B9770DB3933FCF1175E08EA98A3FCE227C4B74859C3FCD3A5DF3D7885B3FCC58EDDA134CA33FCB7E032B3EE0D83FCAA972FB3383BB3FC9DB12BFD4766C3FC912BB488591DB3FC850444E5036DA3FC79381DFC4615C3FC6DC5238513BFB3FC62A8B642BCCBB3FC57E0C37F8D6823FC4D6A874857ECD3FC43440CA4BB98F3FC396B4DD466C8F3FC2FDD93D3E89BF3FC269955AA037BC3FC1D9BF501638753FC14E3E7E55C3983FC0C6EC37653D253FC043B1564854463FBF88D0FEA925AF3FBE91F2FD73DC543FBDA28379819F0B3FBCBA5B43B2EB9D3FBBD936180C4FA73FBAFEE76D579BB93FBA2B37AAD474D43FB95DF7125EF2BE3FB896F51D54BC433FB7D600D6D055173FB71AE946A351983FB6657DEE9F16053FB5B5A6F8A750323FB50B20853231F13FB465D877D98CB73FB3C58F5421F2213FB32A3C38002AA03FB29399FF4EA0543FB2019DE5287BF83FB1740C0467A2D03FB0EAD9B0B380483FB065D82033EE143FAFC9BE574ABBD23FAECFBEEDC9EA703FADDD66A20AE9C43FACF27D72A973683FAC0EE297A5079C3FAB321FC1B733E8"}}
-{"expression":"acos(a)","inputs":{"a":"0x060103017803017905017A073F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B223F7D83BF3F7DA9F13F7DCDDE3F7DEFA63F7E0F6B3F7E2D4A3F7E49613F7E63C93F7E7C9D3F7E93F43F7EA9E53F7EBE853F7ED1E83F7EE4213F7EF5423F7F055C3F7F147D3F7F22B63F7F30133F7F3CA33F7F48703F7F53883F7F5DF43F7F67C03F7F70F43F7F799A3F7F81BB3F7F895E3F7F908B3F7F97493F7F9D9E3F7FA392"},"result":{"expect":"0x060103017803017905017A073F83B8693F8160E13F7E09853F7949B83F7483FC3F6FB9ED3F6AED2C3F661F4F3F6151EA3F5C86863F57BEA33F52FBB53F4E3F213F498A3E3F44DE523F403C913F3BA6213F371C0E3F329F583F2E30E93F29D1973F2582253F2143443F1D158F3F18F9973F14EFCF3F10F8A43F0D146C3F0943703F0585E93F01DC013EFC8BB33EF587063EEEAA023EE7F4A23EE166CD3EDB00493ED4C0D93ECEA8343EC8B5F13EC2E9B03EBD42F43EB7C1453EB2641A3EAD2ADC3EA814F93EA321D93E9E50D53E99A14F3E9512963E90A4033E8C54EF3E8824AC3E8412853E801DCC3E788BAF3E7113E23E69D2F03E62C76F3E5BF0193E554B983E4ED8963E4895DA3E4282223E3C9C0F3E36E2923E31545B3E2BF0623E26B5443E21A2063E1CB5A73E17EECA3E134CAB3E0ECDFB3E0A71F43E0637623E021D8B3DFC46883DF48F983DED141C3DE5D2DA3DDEC9B13DD7F73B3DD159BD3DCAEFB93DC4B7A93DBEB0073DB8D74A3DB32BEF3DADAD383DA859043DA32EC43D9E2C7B3D9951E23D949CD03D900CEF3D8BA0603D8756CE3D832EC13D7E4DF33D767DF73D6EEB353D6793EC3D6077153D5990FE"}}
-{"expression":"acos(a)","inputs":{"a":"0x010101780301613FE07FF56000000001623FE0FFAAC000000001633FE17EE100000000"},"result":{"expect":"0x010101780301613FF0770D2E39D86601623FF02C1C1DB279AA01633FEFC130910699D0"}}
-{"expression":"acos(a)","inputs":{"a":"0x010201780179060161036261723FE0FFAAC0000000016103666F6F3FE07FF5600000000162036261723FE1FD59A0000000016203666F6F3FE17EE1000000000163036261723FE2F72000000000016303666F6F3FE27AD780000000"},"result":{"expect":"0x010201780179060161036261723FF02C1C1DB279AA016103666F6F3FF0770D2E39D8660162036261723FEF2936F9155E81016203666F6F3FEFC130910699D00163036261723FEDF73DA75B8C67016303666F6F3FEE907F87E9CD33"}}
-{"expression":"acos(a)","inputs":{"a":"0x010301780179017A1801610362617201693FE27AD780000000016103626172016A3FE2F72000000000016103626172016B3FE371FA00000000016103626172016C3FE3EB2FE0000000016103666F6F01693FE07FF560000000016103666F6F016A3FE0FFAAC0000000016103666F6F016B3FE17EE100000000016103666F6F016C3FE1FD59A000000001620362617201693FE62A1F80000000016203626172016A3FE695CA80000000016203626172016B3FE6FEB9A0000000016203626172016C3FE764D500000000016203666F6F01693FE4628E60000000016203666F6F016A3FE4D7E620000000016203666F6F016B3FE54B0B20000000016203666F6F016C3FE5BBD50000000001630362617201693FE936BB80000000016303626172016A3FE98ABF00000000016303626172016B3FE9DBAFC0000000016303626172016C3FEA299200000000016303666F6F01693FE7C80840000000016303666F6F016A3FE8284380000000016303666F6F016B3FE8857A40000000016303666F6F016C3FE8DFA400000000"},"result":{"expect":"0x010301780179017A1801610362617201693FEE907F87E9CD33016103626172016A3FEDF73DA75B8C67016103626172016B3FED5DA5869287BA016103626172016C3FECC3E9D18B46CB016103666F6F01693FF0770D2E39D866016103666F6F016A3FF02C1C1DB279AA016103666F6F016B3FEFC130910699D0016103666F6F016C3FEF2936F9155E8101620362617201693FE9C7E42E684019016203626172016A3FE93147BBCF7AA6016203626172016B3FE89BCA4C25AB4D016203626172016C3FE8079226F2A4A1016203666F6F01693FEC2A3D3E9A3807016203666F6F016A3FEB90D0C67C7CE9016203666F6F016B3FEAF7D4591D34FB016203666F6F016C3FEA5F76989F704101630362617201693FE53A32D43D8D6A016303626172016A3FE4B04498A69D9C016303626172016B3FE4286874A3812A016303626172016C3FE3A2B1E87FDA4B016303666F6F01693FE774C415B470C7016303666F6F016A3FE6E381BDEB896C016303666F6F016B3FE653EB0FC3031A016303666F6F016C3FE5C61D15D03BCB"}}
-{"expression":"acos(a)","inputs":{"a":"0x05010301780179017A1801610362617201693F13D6BC016103626172016A3F17B900016103626172016B3F1B8FD0016103626172016C3F1F597F016103666F6F01693F03FFAB016103666F6F016A3F07FD56016103666F6F016B3F0BF708016103666F6F016C3F0FEACD01620362617201693F3150FC016203626172016A3F34AE54016203626172016B3F37F5CD016203626172016C3F3B26A8016203666F6F01693F231473016203666F6F016A3F26BF31016203666F6F016B3F2A5859016203666F6F016C3F2DDEA801630362617201693F49B5DC016303626172016A3F4C55F8016303626172016B3F4EDD7E016303626172016C3F514C90016303666F6F01693F3E4042016303666F6F016A3F41421C016303666F6F016B3F442BD2016303666F6F016C3F46FD20"},"result":{"expect":"0x05010301780179017A1801610362617201693F7483FC016103626172016A3F6FB9ED016103626172016B3F6AED2C016103626172016C3F661F4F016103666F6F01693F83B869016103666F6F016A3F8160E1016103666F6F016B3F7E0985016103666F6F016C3F7949B801620362617201693F4E3F21016203626172016A3F498A3E016203626172016B3F44DE52016203626172016C3F403C91016203666F6F01693F6151EA016203666F6F016A3F5C8686016203666F6F016B3F57BEA3016203666F6F016C3F52FBB501630362617201693F29D197016303626172016A3F258225016303626172016B3F214344016303626172016C3F1D158F016303666F6F01693F3BA621016303666F6F016A3F371C0E016303666F6F016B3F329F58016303666F6F016C3F2E30E9"}}
-{"expression":"acos(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A86000000003666F6F3FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A40000000"},"result":{"expect":"0x0301017902017803017A0702036261723FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE4B04498A69D9C3FE4286874A3812A3FE3A2B1E87FDA4B3FE31F32D557E5553FE29DF9D621C37D3FE21F148BF8F9D13FE1A28D7C2EB40D3FDC2CD996EB66993FDB600927F03DA93FDA981B2BC392543FD9D50673A834E63FD916BE2A3CCF5E3FD85D35F40557E63FD7A85E8161AFA703666F6F3FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FE89BCA4C25AB4D3FE8079226F2A4A13FE774C415B470C73FE6E381BDEB896C3FE653EB0FC3031A3FE5C61D15D03BCB3FE53A32D43D8D6A3FE1286E03E6D6203FE0B0BD170137253FE03B801F7ACC8E3FDF91766FDBAFC03FDEB0E0B8909A4F3FDDD5404E485F613FDCFE943F0E92CC"}}
-{"expression":"acos(a)","inputs":{"a":"0x03020178017A010179050C016101693FE07FF5600000003FE27AD7800000003FE4628E600000003FE62A1F800000003FE7C808400000000161016A3FE0FFAAC00000003FE2F720000000003FE4D7E6200000003FE695CA800000003FE82843800000000161016B3FE17EE1000000003FE371FA000000003FE54B0B200000003FE6FEB9A00000003FE8857A400000000161016C3FE1FD59A00000003FE3EB2FE00000003FE5BBD5000000003FE764D5000000003FE8DFA400000000016201693FE936BB800000003FEA746C400000003FEB825D800000003FEC63FAE00000003FED1DF5400000000162016A3FE98ABF000000003FEABC48000000003FEBBEC1C00000003FEC95FDA00000003FED46DE600000000162016B3FE9DBAFC00000003FEB0130400000003FEBF870E00000003FECC59A400000003FED6DB6200000000162016C3FEA2992000000003FEB4332800000003FEC2F7D600000003FECF2E5A00000003FED9291E0000000016301693FEDB586600000003FEE2FE7400000003FEE91F9600000003FEEE017E00000003FEF1E05800000000163016A3FEDD6A8600000003FEE4A85200000003FEEA737A00000003FEEF0F5A00000003FEF2B5B800000000163016B3FEDF60C000000003FEE63B1000000003FEEBB47600000003FEF00DEA00000003FEF37ED200000000163016C3FEE13C5200000003FEE7B7CC00000003FEECE37E00000003FEF0FDFC00000003FEF43C500000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0770D2E39D8663FEE907F87E9CD333FEC2A3D3E9A38073FE9C7E42E6840193FE774C415B470C70161016A3FF02C1C1DB279AA3FEDF73DA75B8C673FEB90D0C67C7CE93FE93147BBCF7AA63FE6E381BDEB896C0161016B3FEFC130910699D03FED5DA5869287BA3FEAF7D4591D34FB3FE89BCA4C25AB4D3FE653EB0FC3031A0161016C3FEF2936F9155E813FECC3E9D18B46CB3FEA5F76989F70413FE8079226F2A4A13FE5C61D15D03BCB016201693FE53A32D43D8D6A3FE31F32D557E5553FE1286E03E6D6203FDEB0E0B8909A4F3FDB600927F03DA90162016A3FE4B04498A69D9C3FE29DF9D621C37D3FE0B0BD170137253FDDD5404E485F613FDA981B2BC392540162016B3FE4286874A3812A3FE21F148BF8F9D13FE03B801F7ACC8E3FDCFE943F0E92CC3FD9D50673A834E60162016C3FE3A2B1E87FDA4B3FE1A28D7C2EB40D3FDF91766FDBAFC03FDC2CD996EB66993FD916BE2A3CCF5E016301693FD85D35F40557E63FD5A55B74820A113FD33429E2DDA3943FD10495801E910C3FCE227C4B74859C0163016A3FD7A85E8161AFA73FD5029F2311B3483FD2A252BDB691E63FD0825091AACCC63FCD3A5DF3D7885B0163016B3FD6F828A933916E3FD4643B29B929213FD214805B10C9F03FD003B9770DB3933FCC58EDDA134CA30163016C3FD64C833AD32C493FD3CA1A9A3879EF3FD18A9DDD7CF9863FCF1175E08EA98A3FCB7E032B3EE0D8"}}
-{"expression":"acos(a)","inputs":{"a":"0x0701020178017A010179050C016101693F03FFAB3F13D6BC3F2314733F3150FC3F3E40420161016A3F07FD563F17B9003F26BF313F34AE543F41421C0161016B3F0BF7083F1B8FD03F2A58593F37F5CD3F442BD20161016C3F0FEACD3F1F597F3F2DDEA83F3B26A83F46FD20016201693F49B5DC3F53A3623F5C12EC3F631FD73F68EFAA0162016A3F4C55F83F55E2403F5DF60E3F64AFED3F6A36F30162016B3F4EDD7E3F5809823F5FC3873F662CD23F6B6DB10162016C3F514C903F5A19943F617BEB3F67972D3F6C948F016301693F6DAC333F717F3A3F748FCB3F7700BF3F78F02C0163016A3F6EB5433F7254293F7539BD3F7787AD3F795ADC0163016B3F6FB0603F731D883F75DA3B3F7806F53F79BF690163016C3F709E293F73DBE63F7671BF3F787EFE3F7A1E28"},"result":{"expect":"0x0701020178017A010179050C016101693F83B8693F7483FC3F6151EA3F4E3F213F3BA6210161016A3F8160E13F6FB9ED3F5C86863F498A3E3F371C0E0161016B3F7E09853F6AED2C3F57BEA33F44DE523F329F580161016C3F7949B83F661F4F3F52FBB53F403C913F2E30E9016201693F29D1973F18F9973F0943703EF587063EDB00490162016A3F2582253F14EFCF3F0585E93EEEAA023ED4C0D90162016B3F2143443F10F8A43F01DC013EE7F4A23ECEA8340162016C3F1D158F3F0D146C3EFC8BB33EE166CD3EC8B5F1016301693EC2E9B03EAD2ADC3E99A14F3E8824AC3E7113E20163016A3EBD42F43EA814F93E9512963E8412853E69D2F00163016B3EB7C1453EA321D93E90A4033E801DCC3E62C76F0163016C3EB2641A3E9E50D53E8C54EF3E788BAF3E5BF019"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x02003FE07FF560000000"},"result":{"expect":"0x02003FF0770D2E39D866"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x02010178033FE07FF5600000003FE0FFAAC00000003FE17EE100000000"},"result":{"expect":"0x02010178033FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D0"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x02020178030179053FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A0000000"},"result":{"expect":"0x02020178030179053FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE89BCA4C25AB4D"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x0203017803017905017A073FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A400000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A8600000003FEDF60C000000003FEE13C5200000003FEE2FE7400000003FEE4A85200000003FEE63B1000000003FEE7B7CC00000003FEE91F9600000003FEEA737A00000003FEEBB47600000003FEECE37E00000003FEEE017E00000003FEEF0F5A00000003FEF00DEA00000003FEF0FDFC00000003FEF1E05800000003FEF2B5B800000003FEF37ED200000003FEF43C5000000003FEF4EED600000003FEF5970000000003FEF6356000000003FEF6CA8200000003FEF756EE00000003FEF7DB1E00000003FEF8578C00000003FEF8CCA600000003FEF93ADC00000003FEF9A29000000003FEFA042000000003FEFA5FEC00000003FEFAB64400000003FEFB077E00000003FEFB53E200000003FEFB9BBC00000003FEFBDF4C00000003FEFC1ED600000003FEFC5A9400000003FEFC92C200000003FEFCC79200000003FEFCF93A00000003FEFD27E800000003FEFD53CA00000003FEFD7D0A00000003FEFDA3D000000003FEFDC84200000003FEFDEA8400000003FEFE0AB800000003FEFE28FA00000003FEFE456C00000003FEFE602600000003FEFE794600000003FEFE90E000000003FEFEA71000000003FEFEBBE800000003FEFECF8000000003FEFEE1E800000003FEFEF33400000003FEFF037600000003FEFF12BC00000003FEFF211600000003FEFF2E9200000003FEFF3B3C00000003FEFF47240000000"},"result":{"expect":"0x0203017803017905017A073FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE89BCA4C25AB4D3FE8079226F2A4A13FE774C415B470C73FE6E381BDEB896C3FE653EB0FC3031A3FE5C61D15D03BCB3FE53A32D43D8D6A3FE4B04498A69D9C3FE4286874A3812A3FE3A2B1E87FDA4B3FE31F32D557E5553FE29DF9D621C37D3FE21F148BF8F9D13FE1A28D7C2EB40D3FE1286E03E6D6203FE0B0BD170137253FE03B801F7ACC8E3FDF91766FDBAFC03FDEB0E0B8909A4F3FDDD5404E485F613FDCFE943F0E92CC3FDC2CD996EB66993FDB600927F03DA93FDA981B2BC392543FD9D50673A834E63FD916BE2A3CCF5E3FD85D35F40557E63FD7A85E8161AFA73FD6F828A933916E3FD64C833AD32C493FD5A55B74820A113FD5029F2311B3483FD4643B29B929213FD3CA1A9A3879EF3FD33429E2DDA3943FD2A252BDB691E63FD214805B10C9F03FD18A9DDD7CF9863FD10495801E910C3FD0825091AACCC63FD003B9770DB3933FCF1175E08EA98A3FCE227C4B74859C3FCD3A5DF3D7885B3FCC58EDDA134CA33FCB7E032B3EE0D83FCAA972FB3383BB3FC9DB12BFD4766C3FC912BB488591DB3FC850444E5036DA3FC79381DFC4615C3FC6DC5238513BFB3FC62A8B642BCCBB3FC57E0C37F8D6823FC4D6A874857ECD3FC43440CA4BB98F3FC396B4DD466C8F3FC2FDD93D3E89BF3FC269955AA037BC3FC1D9BF501638753FC14E3E7E55C3983FC0C6EC37653D253FC043B1564854463FBF88D0FEA925AF3FBE91F2FD73DC543FBDA28379819F0B3FBCBA5B43B2EB9D3FBBD936180C4FA73FBAFEE76D579BB93FBA2B37AAD474D43FB95DF7125EF2BE3FB896F51D54BC433FB7D600D6D055173FB71AE946A351983FB6657DEE9F16053FB5B5A6F8A750323FB50B20853231F13FB465D877D98CB73FB3C58F5421F2213FB32A3C38002AA03FB29399FF4EA0543FB2019DE5287BF83FB1740C0467A2D03FB0EAD9B0B380483FB065D82033EE143FAFC9BE574ABBD23FAECFBEEDC9EA703FADDD66A20AE9C43FACF27D72A973683FAC0EE297A5079C3FAB321FC1B733E8"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x060103017803017905017A073F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B223F7D83BF3F7DA9F13F7DCDDE3F7DEFA63F7E0F6B3F7E2D4A3F7E49613F7E63C93F7E7C9D3F7E93F43F7EA9E53F7EBE853F7ED1E83F7EE4213F7EF5423F7F055C3F7F147D3F7F22B63F7F30133F7F3CA33F7F48703F7F53883F7F5DF43F7F67C03F7F70F43F7F799A3F7F81BB3F7F895E3F7F908B3F7F97493F7F9D9E3F7FA392"},"result":{"expect":"0x060103017803017905017A073F83B8693F8160E13F7E09853F7949B83F7483FC3F6FB9ED3F6AED2C3F661F4F3F6151EA3F5C86863F57BEA33F52FBB53F4E3F213F498A3E3F44DE523F403C913F3BA6213F371C0E3F329F583F2E30E93F29D1973F2582253F2143443F1D158F3F18F9973F14EFCF3F10F8A43F0D146C3F0943703F0585E93F01DC013EFC8BB33EF587063EEEAA023EE7F4A23EE166CD3EDB00493ED4C0D93ECEA8343EC8B5F13EC2E9B03EBD42F43EB7C1453EB2641A3EAD2ADC3EA814F93EA321D93E9E50D53E99A14F3E9512963E90A4033E8C54EF3E8824AC3E8412853E801DCC3E788BAF3E7113E23E69D2F03E62C76F3E5BF0193E554B983E4ED8963E4895DA3E4282223E3C9C0F3E36E2923E31545B3E2BF0623E26B5443E21A2063E1CB5A73E17EECA3E134CAB3E0ECDFB3E0A71F43E0637623E021D8B3DFC46883DF48F983DED141C3DE5D2DA3DDEC9B13DD7F73B3DD159BD3DCAEFB93DC4B7A93DBEB0073DB8D74A3DB32BEF3DADAD383DA859043DA32EC43D9E2C7B3D9951E23D949CD03D900CEF3D8BA0603D8756CE3D832EC13D7E4DF33D767DF73D6EEB353D6793EC3D6077153D5990FE"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x010101780301613FE07FF56000000001623FE0FFAAC000000001633FE17EE100000000"},"result":{"expect":"0x010101780301613FF0770D2E39D86601623FF02C1C1DB279AA01633FEFC130910699D0"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x010201780179060161036261723FE0FFAAC0000000016103666F6F3FE07FF5600000000162036261723FE1FD59A0000000016203666F6F3FE17EE1000000000163036261723FE2F72000000000016303666F6F3FE27AD780000000"},"result":{"expect":"0x010201780179060161036261723FF02C1C1DB279AA016103666F6F3FF0770D2E39D8660162036261723FEF2936F9155E81016203666F6F3FEFC130910699D00163036261723FEDF73DA75B8C67016303666F6F3FEE907F87E9CD33"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FE27AD780000000016103626172016A3FE2F72000000000016103626172016B3FE371FA00000000016103626172016C3FE3EB2FE0000000016103666F6F01693FE07FF560000000016103666F6F016A3FE0FFAAC0000000016103666F6F016B3FE17EE100000000016103666F6F016C3FE1FD59A000000001620362617201693FE62A1F80000000016203626172016A3FE695CA80000000016203626172016B3FE6FEB9A0000000016203626172016C3FE764D500000000016203666F6F01693FE4628E60000000016203666F6F016A3FE4D7E620000000016203666F6F016B3FE54B0B20000000016203666F6F016C3FE5BBD50000000001630362617201693FE936BB80000000016303626172016A3FE98ABF00000000016303626172016B3FE9DBAFC0000000016303626172016C3FEA299200000000016303666F6F01693FE7C80840000000016303666F6F016A3FE8284380000000016303666F6F016B3FE8857A40000000016303666F6F016C3FE8DFA400000000"},"result":{"expect":"0x010301780179017A1801610362617201693FEE907F87E9CD33016103626172016A3FEDF73DA75B8C67016103626172016B3FED5DA5869287BA016103626172016C3FECC3E9D18B46CB016103666F6F01693FF0770D2E39D866016103666F6F016A3FF02C1C1DB279AA016103666F6F016B3FEFC130910699D0016103666F6F016C3FEF2936F9155E8101620362617201693FE9C7E42E684019016203626172016A3FE93147BBCF7AA6016203626172016B3FE89BCA4C25AB4D016203626172016C3FE8079226F2A4A1016203666F6F01693FEC2A3D3E9A3807016203666F6F016A3FEB90D0C67C7CE9016203666F6F016B3FEAF7D4591D34FB016203666F6F016C3FEA5F76989F704101630362617201693FE53A32D43D8D6A016303626172016A3FE4B04498A69D9C016303626172016B3FE4286874A3812A016303626172016C3FE3A2B1E87FDA4B016303666F6F01693FE774C415B470C7016303666F6F016A3FE6E381BDEB896C016303666F6F016B3FE653EB0FC3031A016303666F6F016C3FE5C61D15D03BCB"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693F13D6BC016103626172016A3F17B900016103626172016B3F1B8FD0016103626172016C3F1F597F016103666F6F01693F03FFAB016103666F6F016A3F07FD56016103666F6F016B3F0BF708016103666F6F016C3F0FEACD01620362617201693F3150FC016203626172016A3F34AE54016203626172016B3F37F5CD016203626172016C3F3B26A8016203666F6F01693F231473016203666F6F016A3F26BF31016203666F6F016B3F2A5859016203666F6F016C3F2DDEA801630362617201693F49B5DC016303626172016A3F4C55F8016303626172016B3F4EDD7E016303626172016C3F514C90016303666F6F01693F3E4042016303666F6F016A3F41421C016303666F6F016B3F442BD2016303666F6F016C3F46FD20"},"result":{"expect":"0x05010301780179017A1801610362617201693F7483FC016103626172016A3F6FB9ED016103626172016B3F6AED2C016103626172016C3F661F4F016103666F6F01693F83B869016103666F6F016A3F8160E1016103666F6F016B3F7E0985016103666F6F016C3F7949B801620362617201693F4E3F21016203626172016A3F498A3E016203626172016B3F44DE52016203626172016C3F403C91016203666F6F01693F6151EA016203666F6F016A3F5C8686016203666F6F016B3F57BEA3016203666F6F016C3F52FBB501630362617201693F29D197016303626172016A3F258225016303626172016B3F214344016303626172016C3F1D158F016303666F6F01693F3BA621016303666F6F016A3F371C0E016303666F6F016B3F329F58016303666F6F016C3F2E30E9"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A86000000003666F6F3FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A40000000"},"result":{"expect":"0x0301017902017803017A0702036261723FECC3E9D18B46CB3FEC2A3D3E9A38073FEB90D0C67C7CE93FEAF7D4591D34FB3FEA5F76989F70413FE9C7E42E6840193FE93147BBCF7AA63FE4B04498A69D9C3FE4286874A3812A3FE3A2B1E87FDA4B3FE31F32D557E5553FE29DF9D621C37D3FE21F148BF8F9D13FE1A28D7C2EB40D3FDC2CD996EB66993FDB600927F03DA93FDA981B2BC392543FD9D50673A834E63FD916BE2A3CCF5E3FD85D35F40557E63FD7A85E8161AFA703666F6F3FF0770D2E39D8663FF02C1C1DB279AA3FEFC130910699D03FEF2936F9155E813FEE907F87E9CD333FEDF73DA75B8C673FED5DA5869287BA3FE89BCA4C25AB4D3FE8079226F2A4A13FE774C415B470C73FE6E381BDEB896C3FE653EB0FC3031A3FE5C61D15D03BCB3FE53A32D43D8D6A3FE1286E03E6D6203FE0B0BD170137253FE03B801F7ACC8E3FDF91766FDBAFC03FDEB0E0B8909A4F3FDDD5404E485F613FDCFE943F0E92CC"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x03020178017A010179050C016101693FE07FF5600000003FE27AD7800000003FE4628E600000003FE62A1F800000003FE7C808400000000161016A3FE0FFAAC00000003FE2F720000000003FE4D7E6200000003FE695CA800000003FE82843800000000161016B3FE17EE1000000003FE371FA000000003FE54B0B200000003FE6FEB9A00000003FE8857A400000000161016C3FE1FD59A00000003FE3EB2FE00000003FE5BBD5000000003FE764D5000000003FE8DFA400000000016201693FE936BB800000003FEA746C400000003FEB825D800000003FEC63FAE00000003FED1DF5400000000162016A3FE98ABF000000003FEABC48000000003FEBBEC1C00000003FEC95FDA00000003FED46DE600000000162016B3FE9DBAFC00000003FEB0130400000003FEBF870E00000003FECC59A400000003FED6DB6200000000162016C3FEA2992000000003FEB4332800000003FEC2F7D600000003FECF2E5A00000003FED9291E0000000016301693FEDB586600000003FEE2FE7400000003FEE91F9600000003FEEE017E00000003FEF1E05800000000163016A3FEDD6A8600000003FEE4A85200000003FEEA737A00000003FEEF0F5A00000003FEF2B5B800000000163016B3FEDF60C000000003FEE63B1000000003FEEBB47600000003FEF00DEA00000003FEF37ED200000000163016C3FEE13C5200000003FEE7B7CC00000003FEECE37E00000003FEF0FDFC00000003FEF43C500000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0770D2E39D8663FEE907F87E9CD333FEC2A3D3E9A38073FE9C7E42E6840193FE774C415B470C70161016A3FF02C1C1DB279AA3FEDF73DA75B8C673FEB90D0C67C7CE93FE93147BBCF7AA63FE6E381BDEB896C0161016B3FEFC130910699D03FED5DA5869287BA3FEAF7D4591D34FB3FE89BCA4C25AB4D3FE653EB0FC3031A0161016C3FEF2936F9155E813FECC3E9D18B46CB3FEA5F76989F70413FE8079226F2A4A13FE5C61D15D03BCB016201693FE53A32D43D8D6A3FE31F32D557E5553FE1286E03E6D6203FDEB0E0B8909A4F3FDB600927F03DA90162016A3FE4B04498A69D9C3FE29DF9D621C37D3FE0B0BD170137253FDDD5404E485F613FDA981B2BC392540162016B3FE4286874A3812A3FE21F148BF8F9D13FE03B801F7ACC8E3FDCFE943F0E92CC3FD9D50673A834E60162016C3FE3A2B1E87FDA4B3FE1A28D7C2EB40D3FDF91766FDBAFC03FDC2CD996EB66993FD916BE2A3CCF5E016301693FD85D35F40557E63FD5A55B74820A113FD33429E2DDA3943FD10495801E910C3FCE227C4B74859C0163016A3FD7A85E8161AFA73FD5029F2311B3483FD2A252BDB691E63FD0825091AACCC63FCD3A5DF3D7885B0163016B3FD6F828A933916E3FD4643B29B929213FD214805B10C9F03FD003B9770DB3933FCC58EDDA134CA30163016C3FD64C833AD32C493FD3CA1A9A3879EF3FD18A9DDD7CF9863FCF1175E08EA98A3FCB7E032B3EE0D8"}}
-{"expression":"map(a,f(a)(acos(a)))","inputs":{"a":"0x0701020178017A010179050C016101693F03FFAB3F13D6BC3F2314733F3150FC3F3E40420161016A3F07FD563F17B9003F26BF313F34AE543F41421C0161016B3F0BF7083F1B8FD03F2A58593F37F5CD3F442BD20161016C3F0FEACD3F1F597F3F2DDEA83F3B26A83F46FD20016201693F49B5DC3F53A3623F5C12EC3F631FD73F68EFAA0162016A3F4C55F83F55E2403F5DF60E3F64AFED3F6A36F30162016B3F4EDD7E3F5809823F5FC3873F662CD23F6B6DB10162016C3F514C903F5A19943F617BEB3F67972D3F6C948F016301693F6DAC333F717F3A3F748FCB3F7700BF3F78F02C0163016A3F6EB5433F7254293F7539BD3F7787AD3F795ADC0163016B3F6FB0603F731D883F75DA3B3F7806F53F79BF690163016C3F709E293F73DBE63F7671BF3F787EFE3F7A1E28"},"result":{"expect":"0x0701020178017A010179050C016101693F83B8693F7483FC3F6151EA3F4E3F213F3BA6210161016A3F8160E13F6FB9ED3F5C86863F498A3E3F371C0E0161016B3F7E09853F6AED2C3F57BEA33F44DE523F329F580161016C3F7949B83F661F4F3F52FBB53F403C913F2E30E9016201693F29D1973F18F9973F0943703EF587063EDB00490162016A3F2582253F14EFCF3F0585E93EEEAA023ED4C0D90162016B3F2143443F10F8A43F01DC013EE7F4A23ECEA8340162016C3F1D158F3F0D146C3EFC8BB33EE166CD3EC8B5F1016301693EC2E9B03EAD2ADC3E99A14F3E8824AC3E7113E20163016A3EBD42F43EA814F93E9512963E8412853E69D2F00163016B3EB7C1453EA321D93E90A4033E801DCC3E62C76F0163016C3EB2641A3E9E50D53E8C54EF3E788BAF3E5BF019"}}
-{"expression":"asin(a)","inputs":{"a":"0x02003FE07FF560000000"},"result":{"expect":"0x02003FE155DC4C14A964"}}
-{"expression":"asin(a)","inputs":{"a":"0x02010178033FE07FF5600000003FE0FFAAC00000003FE17EE100000000"},"result":{"expect":"0x02010178033FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C061"}}
-{"expression":"asin(a)","inputs":{"a":"0x02020178030179053FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A0000000"},"result":{"expect":"0x02020178030179053FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FE9A82C5C62AEE4"}}
-{"expression":"asin(a)","inputs":{"a":"0x0203017803017905017A073FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A400000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A8600000003FEDF60C000000003FEE13C5200000003FEE2FE7400000003FEE4A85200000003FEE63B1000000003FEE7B7CC00000003FEE91F9600000003FEEA737A00000003FEEBB47600000003FEECE37E00000003FEEE017E00000003FEEF0F5A00000003FEF00DEA00000003FEF0FDFC00000003FEF1E05800000003FEF2B5B800000003FEF37ED200000003FEF43C5000000003FEF4EED600000003FEF5970000000003FEF6356000000003FEF6CA8200000003FEF756EE00000003FEF7DB1E00000003FEF8578C00000003FEF8CCA600000003FEF93ADC00000003FEF9A29000000003FEFA042000000003FEFA5FEC00000003FEFAB64400000003FEFB077E00000003FEFB53E200000003FEFB9BBC00000003FEFBDF4C00000003FEFC1ED600000003FEFC5A9400000003FEFC92C200000003FEFCC79200000003FEFCF93A00000003FEFD27E800000003FEFD53CA00000003FEFD7D0A00000003FEFDA3D000000003FEFDC84200000003FEFDEA8400000003FEFE0AB800000003FEFE28FA00000003FEFE456C00000003FEFE602600000003FEFE794600000003FEFE90E000000003FEFEA71000000003FEFEBBE800000003FEFECF8000000003FEFEE1E800000003FEFEF33400000003FEFF037600000003FEFF12BC00000003FEFF211600000003FEFF2E9200000003FEFF3B3C00000003FEFF47240000000"},"result":{"expect":"0x0203017803017905017A073FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FE9A82C5C62AEE43FEA3C648195B58F3FEACF3292D3E9693FEB6074EA9CD0C53FEBF00B98C557173FEC7DD992B81E653FED09C3D44ACCC73FED93B20FE1BC943FEE1B8E33E4D9073FEEA144C0087FE53FEF24C3D33074DC3FEFA5FCD26696B33FF012710E47B0303FF050B4962CD3123FF08DC45250C2083FF0C99CC8C391863FF1043B4486C6D23FF13D9DB84D41283FF175C3262006853FF1ACAB40B215403FF1E256448088653FF216C4EE8953723FF249F90A481DAE3FF27BF4895348833FF2ACB9B75A1FDF3FF2DC4BC9B4F9413FF30AADD742D71F3FF337E3B3EBC12F3FF363F129F748BD3FF38EDA858F62063FF3B8A47723AA943FF3E1538B7FC0463FF408EC89D5E2D03FF42F74ADB60E9C3FF454F0DB8CC4333FF47966A4D6889F3FF49CDB3D7FFA9C3FF4BF53DCE4EEB73FF4E0D5F43C88D53FF501672FD979E73FF5210CF680C0343FF53FCC983257E73FF55DABCAD59C653FF57AAF95C93C0D3FF596DD9901C3843FF5B23AEEDC50FD3FF5CCCCF4DDBCA13FF5E698FC499E4B3FF5FFA3EB337ADD3FF617F2CA7A263D3FF62F8B184BA0ED3FF646710D3A05993FF65CA9E7BEB3813FF67239CD4512483FF6872645B37D3F3FF69B733AFAB5E63FF6AF24B89B5F863FF6C2402C9C5BE03FF6D4C8A8F026213FF6E6C36A41660A3FF6F833847974A53FF7091DCD5785743FF71985297B22903FF7296E44599ABD3FF738DC246CEF533FF747D31CAC13283FF75655A008FE5E3FF76467F2C3681E3FF7720CDD6EB35D3FF77F47D996E5CB3FF78C1BE31E3DEC3FF7988C026EE1543FF7A49B46D727C73FF7B04CBFD9F7FF3FF7BBA3755A3BB83FF7C6A0E4B9B8153FF7D1494BF109F93FF7DB9DCCC6944D3FF7E5A25F020DF63FF7EF5790C42A6E3FF7F8C1B44F43133FF801E175F1A5593FF80ABA93FDB2EB3FF8134DB938F5143FF81B9DD240EE373FF823AD6189D73A3FF82B7D5CD5DDC53FF833101F33D5CA3FF83A6768AEE17D3FF841843F8704DB3FF8486A56367379"}}
-{"expression":"asin(a)","inputs":{"a":"0x060103017803017905017A073F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B223F7D83BF3F7DA9F13F7DCDDE3F7DEFA63F7E0F6B3F7E2D4A3F7E49613F7E63C93F7E7C9D3F7E93F43F7EA9E53F7EBE853F7ED1E83F7EE4213F7EF5423F7F055C3F7F147D3F7F22B63F7F30133F7F3CA33F7F48703F7F53883F7F5DF43F7F67C03F7F70F43F7F799A3F7F81BB3F7F895E3F7F908B3F7F97493F7F9D9E3F7FA392"},"result":{"expect":"0x060103017803017905017A073F0AAEE23F0F5DF33F1416313F18D5FD3F1D9BB93F2265C83F2732893F2C00673F30CDCB3F35992F3F3A61123F3F24003F43E0943F4895773F4D41633F51E3243F5679953F5B03A73F5F805D3F63EECD3F684E1F3F6C9D903F70DC723F750A263F79261F3F7D2FE73F8093883F8285A53F846E233F864CE63F8821DA3F89ECEE3F8BAE193F8D655A3F8F12B23F90B6273F924FC83F93DFA43F9565CE3F96E25E3F98556F3F99BF1E3F9B1F893F9C76D43F9DC5243F9F0A9C3FA047643FA17BA53FA2A7873FA3CB353FA4E6DA3FA5FA9F3FA706B03FA80B393FA908683FA9FE653FAAED5E3FABD57D3FACB6ED3FAD91D73FAE66683FAF34C83FAFFD1F3FB0BF963FB17C593FB233883FB2E54F3FB391CE3FB439323FB4DB9A3FB579263FB612013FB6A6453FB7361B3FB7C19C3FB848EE3FB8CC293FB94B723FB9C6E13FBA3E993FBAB2AD3FBB23403FBB90673FBBFA3F3FBC60DF3FBCC4603FBD24DA3FBD82663FBDDD1C3FBE35073FBE8A4A3FBEDCEE3FBF2D133FBF7ABD3FBFC60E3FC00F0C3FC055D53FC09A6E3FC0DCEF3FC11D6B3FC15BEB3FC198813FC1D33B3FC20C223FC24353"}}
-{"expression":"asin(a)","inputs":{"a":"0x010101780301613FE07FF56000000001623FE0FFAAC000000001633FE17EE100000000"},"result":{"expect":"0x010101780301613FE155DC4C14A96401623FE1EBBE6D2366DE01633FE282C61781C061"}}
-{"expression":"asin(a)","inputs":{"a":"0x010201780179060161036261723FE0FFAAC0000000016103666F6F3FE07FF5600000000162036261723FE1FD59A0000000016203666F6F3FE17EE1000000000163036261723FE2F72000000000016303666F6F3FE27AD780000000"},"result":{"expect":"0x010201780179060161036261723FE1EBBE6D2366DE016103666F6F3FE155DC4C14A9640162036261723FE31ABFAF72FBB0016203666F6F3FE282C61781C0610163036261723FE44CB9012CCDCA016303666F6F3FE3B377209E8CFE"}}
-{"expression":"asin(a)","inputs":{"a":"0x010301780179017A1801610362617201693FE27AD780000000016103626172016A3FE2F72000000000016103626172016B3FE371FA00000000016103626172016C3FE3EB2FE0000000016103666F6F01693FE07FF560000000016103666F6F016A3FE0FFAAC0000000016103666F6F016B3FE17EE100000000016103666F6F016C3FE1FD59A000000001620362617201693FE62A1F80000000016203626172016A3FE695CA80000000016203626172016B3FE6FEB9A0000000016203626172016C3FE764D500000000016203666F6F01693FE4628E60000000016203666F6F016A3FE4D7E620000000016203666F6F016B3FE54B0B20000000016203666F6F016C3FE5BBD50000000001630362617201693FE936BB80000000016303626172016A3FE98ABF00000000016303626172016B3FE9DBAFC0000000016303626172016C3FEA299200000000016303666F6F01693FE7C80840000000016303666F6F016A3FE8284380000000016303666F6F016B3FE8857A40000000016303666F6F016C3FE8DFA400000000"},"result":{"expect":"0x010301780179017A1801610362617201693FE3B377209E8CFE016103626172016A3FE44CB9012CCDCA016103626172016B3FE4E65121F5D276016103626172016C3FE5800CD6FD1365016103666F6F01693FE155DC4C14A964016103666F6F016A3FE1EBBE6D2366DE016103666F6F016B3FE282C61781C061016103666F6F016C3FE31ABFAF72FBB001620362617201693FE87C127A201A17016203626172016A3FE912AEECB8DF8A016203626172016B3FE9A82C5C62AEE4016203626172016C3FEA3C648195B58F016203666F6F01693FE619B969EE2229016203666F6F016A3FE6B325E20BDD47016203666F6F016B3FE74C224F6B2535016203666F6F016C3FE7E4800FE8E9F001630362617201693FED09C3D44ACCC7016303626172016A3FED93B20FE1BC94016303626172016B3FEE1B8E33E4D907016303626172016C3FEEA144C0087FE5016303666F6F01693FEACF3292D3E969016303666F6F016A3FEB6074EA9CD0C5016303666F6F016B3FEBF00B98C55717016303666F6F016C3FEC7DD992B81E65"}}
-{"expression":"asin(a)","inputs":{"a":"0x05010301780179017A1801610362617201693F13D6BC016103626172016A3F17B900016103626172016B3F1B8FD0016103626172016C3F1F597F016103666F6F01693F03FFAB016103666F6F016A3F07FD56016103666F6F016B3F0BF708016103666F6F016C3F0FEACD01620362617201693F3150FC016203626172016A3F34AE54016203626172016B3F37F5CD016203626172016C3F3B26A8016203666F6F01693F231473016203666F6F016A3F26BF31016203666F6F016B3F2A5859016203666F6F016C3F2DDEA801630362617201693F49B5DC016303626172016A3F4C55F8016303626172016B3F4EDD7E016303626172016C3F514C90016303666F6F01693F3E4042016303666F6F016A3F41421C016303666F6F016B3F442BD2016303666F6F016C3F46FD20"},"result":{"expect":"0x05010301780179017A1801610362617201693F1D9BB9016103626172016A3F2265C8016103626172016B3F273289016103626172016C3F2C0067016103666F6F01693F0AAEE2016103666F6F016A3F0F5DF3016103666F6F016B3F141631016103666F6F016C3F18D5FD01620362617201693F43E094016203626172016A3F489577016203626172016B3F4D4163016203626172016C3F51E324016203666F6F01693F30CDCB016203666F6F016A3F35992F016203666F6F016B3F3A6112016203666F6F016C3F3F240001630362617201693F684E1F016303626172016A3F6C9D90016303626172016B3F70DC72016303626172016C3F750A26016303666F6F01693F567995016303666F6F016A3F5B03A7016303666F6F016B3F5F805D016303666F6F016C3F63EECD"}}
-{"expression":"asin(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A86000000003666F6F3FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A40000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FED93B20FE1BC943FEE1B8E33E4D9073FEEA144C0087FE53FEF24C3D33074DC3FEFA5FCD26696B33FF012710E47B0303FF050B4962CD3123FF216C4EE8953723FF249F90A481DAE3FF27BF4895348833FF2ACB9B75A1FDF3FF2DC4BC9B4F9413FF30AADD742D71F3FF337E3B3EBC12F03666F6F3FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE9A82C5C62AEE43FEA3C648195B58F3FEACF3292D3E9693FEB6074EA9CD0C53FEBF00B98C557173FEC7DD992B81E653FED09C3D44ACCC73FF08DC45250C2083FF0C99CC8C391863FF1043B4486C6D23FF13D9DB84D41283FF175C3262006853FF1ACAB40B215403FF1E25644808865"}}
-{"expression":"asin(a)","inputs":{"a":"0x03020178017A010179050C016101693FE07FF5600000003FE27AD7800000003FE4628E600000003FE62A1F800000003FE7C808400000000161016A3FE0FFAAC00000003FE2F720000000003FE4D7E6200000003FE695CA800000003FE82843800000000161016B3FE17EE1000000003FE371FA000000003FE54B0B200000003FE6FEB9A00000003FE8857A400000000161016C3FE1FD59A00000003FE3EB2FE00000003FE5BBD5000000003FE764D5000000003FE8DFA400000000016201693FE936BB800000003FEA746C400000003FEB825D800000003FEC63FAE00000003FED1DF5400000000162016A3FE98ABF000000003FEABC48000000003FEBBEC1C00000003FEC95FDA00000003FED46DE600000000162016B3FE9DBAFC00000003FEB0130400000003FEBF870E00000003FECC59A400000003FED6DB6200000000162016C3FEA2992000000003FEB4332800000003FEC2F7D600000003FECF2E5A00000003FED9291E0000000016301693FEDB586600000003FEE2FE7400000003FEE91F9600000003FEEE017E00000003FEF1E05800000000163016A3FEDD6A8600000003FEE4A85200000003FEEA737A00000003FEEF0F5A00000003FEF2B5B800000000163016B3FEDF60C000000003FEE63B1000000003FEEBB47600000003FEF00DEA00000003FEF37ED200000000163016C3FEE13C5200000003FEE7B7CC00000003FEECE37E00000003FEF0FDFC00000003FEF43C500000000"},"result":{"expect":"0x03020178017A010179050C016101693FE155DC4C14A9643FE3B377209E8CFE3FE619B969EE22293FE87C127A201A173FEACF3292D3E9690161016A3FE1EBBE6D2366DE3FE44CB9012CCDCA3FE6B325E20BDD473FE912AEECB8DF8A3FEB6074EA9CD0C50161016B3FE282C61781C0613FE4E65121F5D2763FE74C224F6B25353FE9A82C5C62AEE43FEBF00B98C557170161016C3FE31ABFAF72FBB03FE5800CD6FD13653FE7E4800FE8E9F03FEA3C648195B58F3FEC7DD992B81E65016201693FED09C3D44ACCC73FEF24C3D33074DC3FF08DC45250C2083FF175C3262006853FF249F90A481DAE0162016A3FED93B20FE1BC943FEFA5FCD26696B33FF0C99CC8C391863FF1ACAB40B215403FF27BF4895348830162016B3FEE1B8E33E4D9073FF012710E47B0303FF1043B4486C6D23FF1E256448088653FF2ACB9B75A1FDF0162016C3FEEA144C0087FE53FF050B4962CD3123FF13D9DB84D41283FF216C4EE8953723FF2DC4BC9B4F941016301693FF30AADD742D71F3FF3B8A47723AA943FF454F0DB8CC4333FF4E0D5F43C88D53FF55DABCAD59C650163016A3FF337E3B3EBC12F3FF3E1538B7FC0463FF47966A4D6889F3FF501672FD979E73FF57AAF95C93C0D0163016B3FF363F129F748BD3FF408EC89D5E2D03FF49CDB3D7FFA9C3FF5210CF680C0343FF596DD9901C3840163016C3FF38EDA858F62063FF42F74ADB60E9C3FF4BF53DCE4EEB73FF53FCC983257E73FF5B23AEEDC50FD"}}
-{"expression":"asin(a)","inputs":{"a":"0x0701020178017A010179050C016101693F03FFAB3F13D6BC3F2314733F3150FC3F3E40420161016A3F07FD563F17B9003F26BF313F34AE543F41421C0161016B3F0BF7083F1B8FD03F2A58593F37F5CD3F442BD20161016C3F0FEACD3F1F597F3F2DDEA83F3B26A83F46FD20016201693F49B5DC3F53A3623F5C12EC3F631FD73F68EFAA0162016A3F4C55F83F55E2403F5DF60E3F64AFED3F6A36F30162016B3F4EDD7E3F5809823F5FC3873F662CD23F6B6DB10162016C3F514C903F5A19943F617BEB3F67972D3F6C948F016301693F6DAC333F717F3A3F748FCB3F7700BF3F78F02C0163016A3F6EB5433F7254293F7539BD3F7787AD3F795ADC0163016B3F6FB0603F731D883F75DA3B3F7806F53F79BF690163016C3F709E293F73DBE63F7671BF3F787EFE3F7A1E28"},"result":{"expect":"0x0701020178017A010179050C016101693F0AAEE23F1D9BB93F30CDCB3F43E0943F5679950161016A3F0F5DF33F2265C83F35992F3F4895773F5B03A70161016B3F1416313F2732893F3A61123F4D41633F5F805D0161016C3F18D5FD3F2C00673F3F24003F51E3243F63EECD016201693F684E1F3F79261F3F846E233F8BAE193F924FC80162016A3F6C9D903F7D2FE73F864CE63F8D655A3F93DFA40162016B3F70DC723F8093883F8821DA3F8F12B23F9565CE0162016C3F750A263F8285A53F89ECEE3F90B6273F96E25E016301693F98556F3F9DC5243FA2A7873FA706B03FAAED5E0163016A3F99BF1E3F9F0A9C3FA3CB353FA80B393FABD57D0163016B3F9B1F893FA047643FA4E6DA3FA908683FACB6ED0163016C3F9C76D43FA17BA53FA5FA9F3FA9FE653FAD91D7"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x02003FE07FF560000000"},"result":{"expect":"0x02003FE155DC4C14A964"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x02010178033FE07FF5600000003FE0FFAAC00000003FE17EE100000000"},"result":{"expect":"0x02010178033FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C061"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x02020178030179053FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A0000000"},"result":{"expect":"0x02020178030179053FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FE9A82C5C62AEE4"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x0203017803017905017A073FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A400000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A8600000003FEDF60C000000003FEE13C5200000003FEE2FE7400000003FEE4A85200000003FEE63B1000000003FEE7B7CC00000003FEE91F9600000003FEEA737A00000003FEEBB47600000003FEECE37E00000003FEEE017E00000003FEEF0F5A00000003FEF00DEA00000003FEF0FDFC00000003FEF1E05800000003FEF2B5B800000003FEF37ED200000003FEF43C5000000003FEF4EED600000003FEF5970000000003FEF6356000000003FEF6CA8200000003FEF756EE00000003FEF7DB1E00000003FEF8578C00000003FEF8CCA600000003FEF93ADC00000003FEF9A29000000003FEFA042000000003FEFA5FEC00000003FEFAB64400000003FEFB077E00000003FEFB53E200000003FEFB9BBC00000003FEFBDF4C00000003FEFC1ED600000003FEFC5A9400000003FEFC92C200000003FEFCC79200000003FEFCF93A00000003FEFD27E800000003FEFD53CA00000003FEFD7D0A00000003FEFDA3D000000003FEFDC84200000003FEFDEA8400000003FEFE0AB800000003FEFE28FA00000003FEFE456C00000003FEFE602600000003FEFE794600000003FEFE90E000000003FEFEA71000000003FEFEBBE800000003FEFECF8000000003FEFEE1E800000003FEFEF33400000003FEFF037600000003FEFF12BC00000003FEFF211600000003FEFF2E9200000003FEFF3B3C00000003FEFF47240000000"},"result":{"expect":"0x0203017803017905017A073FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FE9A82C5C62AEE43FEA3C648195B58F3FEACF3292D3E9693FEB6074EA9CD0C53FEBF00B98C557173FEC7DD992B81E653FED09C3D44ACCC73FED93B20FE1BC943FEE1B8E33E4D9073FEEA144C0087FE53FEF24C3D33074DC3FEFA5FCD26696B33FF012710E47B0303FF050B4962CD3123FF08DC45250C2083FF0C99CC8C391863FF1043B4486C6D23FF13D9DB84D41283FF175C3262006853FF1ACAB40B215403FF1E256448088653FF216C4EE8953723FF249F90A481DAE3FF27BF4895348833FF2ACB9B75A1FDF3FF2DC4BC9B4F9413FF30AADD742D71F3FF337E3B3EBC12F3FF363F129F748BD3FF38EDA858F62063FF3B8A47723AA943FF3E1538B7FC0463FF408EC89D5E2D03FF42F74ADB60E9C3FF454F0DB8CC4333FF47966A4D6889F3FF49CDB3D7FFA9C3FF4BF53DCE4EEB73FF4E0D5F43C88D53FF501672FD979E73FF5210CF680C0343FF53FCC983257E73FF55DABCAD59C653FF57AAF95C93C0D3FF596DD9901C3843FF5B23AEEDC50FD3FF5CCCCF4DDBCA13FF5E698FC499E4B3FF5FFA3EB337ADD3FF617F2CA7A263D3FF62F8B184BA0ED3FF646710D3A05993FF65CA9E7BEB3813FF67239CD4512483FF6872645B37D3F3FF69B733AFAB5E63FF6AF24B89B5F863FF6C2402C9C5BE03FF6D4C8A8F026213FF6E6C36A41660A3FF6F833847974A53FF7091DCD5785743FF71985297B22903FF7296E44599ABD3FF738DC246CEF533FF747D31CAC13283FF75655A008FE5E3FF76467F2C3681E3FF7720CDD6EB35D3FF77F47D996E5CB3FF78C1BE31E3DEC3FF7988C026EE1543FF7A49B46D727C73FF7B04CBFD9F7FF3FF7BBA3755A3BB83FF7C6A0E4B9B8153FF7D1494BF109F93FF7DB9DCCC6944D3FF7E5A25F020DF63FF7EF5790C42A6E3FF7F8C1B44F43133FF801E175F1A5593FF80ABA93FDB2EB3FF8134DB938F5143FF81B9DD240EE373FF823AD6189D73A3FF82B7D5CD5DDC53FF833101F33D5CA3FF83A6768AEE17D3FF841843F8704DB3FF8486A56367379"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x060103017803017905017A073F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B223F7D83BF3F7DA9F13F7DCDDE3F7DEFA63F7E0F6B3F7E2D4A3F7E49613F7E63C93F7E7C9D3F7E93F43F7EA9E53F7EBE853F7ED1E83F7EE4213F7EF5423F7F055C3F7F147D3F7F22B63F7F30133F7F3CA33F7F48703F7F53883F7F5DF43F7F67C03F7F70F43F7F799A3F7F81BB3F7F895E3F7F908B3F7F97493F7F9D9E3F7FA392"},"result":{"expect":"0x060103017803017905017A073F0AAEE23F0F5DF33F1416313F18D5FD3F1D9BB93F2265C83F2732893F2C00673F30CDCB3F35992F3F3A61123F3F24003F43E0943F4895773F4D41633F51E3243F5679953F5B03A73F5F805D3F63EECD3F684E1F3F6C9D903F70DC723F750A263F79261F3F7D2FE73F8093883F8285A53F846E233F864CE63F8821DA3F89ECEE3F8BAE193F8D655A3F8F12B23F90B6273F924FC83F93DFA43F9565CE3F96E25E3F98556F3F99BF1E3F9B1F893F9C76D43F9DC5243F9F0A9C3FA047643FA17BA53FA2A7873FA3CB353FA4E6DA3FA5FA9F3FA706B03FA80B393FA908683FA9FE653FAAED5E3FABD57D3FACB6ED3FAD91D73FAE66683FAF34C83FAFFD1F3FB0BF963FB17C593FB233883FB2E54F3FB391CE3FB439323FB4DB9A3FB579263FB612013FB6A6453FB7361B3FB7C19C3FB848EE3FB8CC293FB94B723FB9C6E13FBA3E993FBAB2AD3FBB23403FBB90673FBBFA3F3FBC60DF3FBCC4603FBD24DA3FBD82663FBDDD1C3FBE35073FBE8A4A3FBEDCEE3FBF2D133FBF7ABD3FBFC60E3FC00F0C3FC055D53FC09A6E3FC0DCEF3FC11D6B3FC15BEB3FC198813FC1D33B3FC20C223FC24353"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x010101780301613FE07FF56000000001623FE0FFAAC000000001633FE17EE100000000"},"result":{"expect":"0x010101780301613FE155DC4C14A96401623FE1EBBE6D2366DE01633FE282C61781C061"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x010201780179060161036261723FE0FFAAC0000000016103666F6F3FE07FF5600000000162036261723FE1FD59A0000000016203666F6F3FE17EE1000000000163036261723FE2F72000000000016303666F6F3FE27AD780000000"},"result":{"expect":"0x010201780179060161036261723FE1EBBE6D2366DE016103666F6F3FE155DC4C14A9640162036261723FE31ABFAF72FBB0016203666F6F3FE282C61781C0610163036261723FE44CB9012CCDCA016303666F6F3FE3B377209E8CFE"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FE27AD780000000016103626172016A3FE2F72000000000016103626172016B3FE371FA00000000016103626172016C3FE3EB2FE0000000016103666F6F01693FE07FF560000000016103666F6F016A3FE0FFAAC0000000016103666F6F016B3FE17EE100000000016103666F6F016C3FE1FD59A000000001620362617201693FE62A1F80000000016203626172016A3FE695CA80000000016203626172016B3FE6FEB9A0000000016203626172016C3FE764D500000000016203666F6F01693FE4628E60000000016203666F6F016A3FE4D7E620000000016203666F6F016B3FE54B0B20000000016203666F6F016C3FE5BBD50000000001630362617201693FE936BB80000000016303626172016A3FE98ABF00000000016303626172016B3FE9DBAFC0000000016303626172016C3FEA299200000000016303666F6F01693FE7C80840000000016303666F6F016A3FE8284380000000016303666F6F016B3FE8857A40000000016303666F6F016C3FE8DFA400000000"},"result":{"expect":"0x010301780179017A1801610362617201693FE3B377209E8CFE016103626172016A3FE44CB9012CCDCA016103626172016B3FE4E65121F5D276016103626172016C3FE5800CD6FD1365016103666F6F01693FE155DC4C14A964016103666F6F016A3FE1EBBE6D2366DE016103666F6F016B3FE282C61781C061016103666F6F016C3FE31ABFAF72FBB001620362617201693FE87C127A201A17016203626172016A3FE912AEECB8DF8A016203626172016B3FE9A82C5C62AEE4016203626172016C3FEA3C648195B58F016203666F6F01693FE619B969EE2229016203666F6F016A3FE6B325E20BDD47016203666F6F016B3FE74C224F6B2535016203666F6F016C3FE7E4800FE8E9F001630362617201693FED09C3D44ACCC7016303626172016A3FED93B20FE1BC94016303626172016B3FEE1B8E33E4D907016303626172016C3FEEA144C0087FE5016303666F6F01693FEACF3292D3E969016303666F6F016A3FEB6074EA9CD0C5016303666F6F016B3FEBF00B98C55717016303666F6F016C3FEC7DD992B81E65"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693F13D6BC016103626172016A3F17B900016103626172016B3F1B8FD0016103626172016C3F1F597F016103666F6F01693F03FFAB016103666F6F016A3F07FD56016103666F6F016B3F0BF708016103666F6F016C3F0FEACD01620362617201693F3150FC016203626172016A3F34AE54016203626172016B3F37F5CD016203626172016C3F3B26A8016203666F6F01693F231473016203666F6F016A3F26BF31016203666F6F016B3F2A5859016203666F6F016C3F2DDEA801630362617201693F49B5DC016303626172016A3F4C55F8016303626172016B3F4EDD7E016303626172016C3F514C90016303666F6F01693F3E4042016303666F6F016A3F41421C016303666F6F016B3F442BD2016303666F6F016C3F46FD20"},"result":{"expect":"0x05010301780179017A1801610362617201693F1D9BB9016103626172016A3F2265C8016103626172016B3F273289016103626172016C3F2C0067016103666F6F01693F0AAEE2016103666F6F016A3F0F5DF3016103666F6F016B3F141631016103666F6F016C3F18D5FD01620362617201693F43E094016203626172016A3F489577016203626172016B3F4D4163016203626172016C3F51E324016203666F6F01693F30CDCB016203666F6F016A3F35992F016203666F6F016B3F3A6112016203666F6F016C3F3F240001630362617201693F684E1F016303626172016A3F6C9D90016303626172016B3F70DC72016303626172016C3F750A26016303666F6F01693F567995016303666F6F016A3F5B03A7016303666F6F016B3F5F805D016303666F6F016C3F63EECD"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE3EB2FE00000003FE4628E600000003FE4D7E6200000003FE54B0B200000003FE5BBD5000000003FE62A1F800000003FE695CA800000003FE98ABF000000003FE9DBAFC00000003FEA2992000000003FEA746C400000003FEABC48000000003FEB0130400000003FEB4332800000003FECF2E5A00000003FED1DF5400000003FED46DE600000003FED6DB6200000003FED9291E00000003FEDB586600000003FEDD6A86000000003666F6F3FE07FF5600000003FE0FFAAC00000003FE17EE1000000003FE1FD59A00000003FE27AD7800000003FE2F720000000003FE371FA000000003FE6FEB9A00000003FE764D5000000003FE7C808400000003FE82843800000003FE8857A400000003FE8DFA4000000003FE936BB800000003FEB825D800000003FEBBEC1C00000003FEBF870E00000003FEC2F7D600000003FEC63FAE00000003FEC95FDA00000003FECC59A40000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE5800CD6FD13653FE619B969EE22293FE6B325E20BDD473FE74C224F6B25353FE7E4800FE8E9F03FE87C127A201A173FE912AEECB8DF8A3FED93B20FE1BC943FEE1B8E33E4D9073FEEA144C0087FE53FEF24C3D33074DC3FEFA5FCD26696B33FF012710E47B0303FF050B4962CD3123FF216C4EE8953723FF249F90A481DAE3FF27BF4895348833FF2ACB9B75A1FDF3FF2DC4BC9B4F9413FF30AADD742D71F3FF337E3B3EBC12F03666F6F3FE155DC4C14A9643FE1EBBE6D2366DE3FE282C61781C0613FE31ABFAF72FBB03FE3B377209E8CFE3FE44CB9012CCDCA3FE4E65121F5D2763FE9A82C5C62AEE43FEA3C648195B58F3FEACF3292D3E9693FEB6074EA9CD0C53FEBF00B98C557173FEC7DD992B81E653FED09C3D44ACCC73FF08DC45250C2083FF0C99CC8C391863FF1043B4486C6D23FF13D9DB84D41283FF175C3262006853FF1ACAB40B215403FF1E25644808865"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x03020178017A010179050C016101693FE07FF5600000003FE27AD7800000003FE4628E600000003FE62A1F800000003FE7C808400000000161016A3FE0FFAAC00000003FE2F720000000003FE4D7E6200000003FE695CA800000003FE82843800000000161016B3FE17EE1000000003FE371FA000000003FE54B0B200000003FE6FEB9A00000003FE8857A400000000161016C3FE1FD59A00000003FE3EB2FE00000003FE5BBD5000000003FE764D5000000003FE8DFA400000000016201693FE936BB800000003FEA746C400000003FEB825D800000003FEC63FAE00000003FED1DF5400000000162016A3FE98ABF000000003FEABC48000000003FEBBEC1C00000003FEC95FDA00000003FED46DE600000000162016B3FE9DBAFC00000003FEB0130400000003FEBF870E00000003FECC59A400000003FED6DB6200000000162016C3FEA2992000000003FEB4332800000003FEC2F7D600000003FECF2E5A00000003FED9291E0000000016301693FEDB586600000003FEE2FE7400000003FEE91F9600000003FEEE017E00000003FEF1E05800000000163016A3FEDD6A8600000003FEE4A85200000003FEEA737A00000003FEEF0F5A00000003FEF2B5B800000000163016B3FEDF60C000000003FEE63B1000000003FEEBB47600000003FEF00DEA00000003FEF37ED200000000163016C3FEE13C5200000003FEE7B7CC00000003FEECE37E00000003FEF0FDFC00000003FEF43C500000000"},"result":{"expect":"0x03020178017A010179050C016101693FE155DC4C14A9643FE3B377209E8CFE3FE619B969EE22293FE87C127A201A173FEACF3292D3E9690161016A3FE1EBBE6D2366DE3FE44CB9012CCDCA3FE6B325E20BDD473FE912AEECB8DF8A3FEB6074EA9CD0C50161016B3FE282C61781C0613FE4E65121F5D2763FE74C224F6B25353FE9A82C5C62AEE43FEBF00B98C557170161016C3FE31ABFAF72FBB03FE5800CD6FD13653FE7E4800FE8E9F03FEA3C648195B58F3FEC7DD992B81E65016201693FED09C3D44ACCC73FEF24C3D33074DC3FF08DC45250C2083FF175C3262006853FF249F90A481DAE0162016A3FED93B20FE1BC943FEFA5FCD26696B33FF0C99CC8C391863FF1ACAB40B215403FF27BF4895348830162016B3FEE1B8E33E4D9073FF012710E47B0303FF1043B4486C6D23FF1E256448088653FF2ACB9B75A1FDF0162016C3FEEA144C0087FE53FF050B4962CD3123FF13D9DB84D41283FF216C4EE8953723FF2DC4BC9B4F941016301693FF30AADD742D71F3FF3B8A47723AA943FF454F0DB8CC4333FF4E0D5F43C88D53FF55DABCAD59C650163016A3FF337E3B3EBC12F3FF3E1538B7FC0463FF47966A4D6889F3FF501672FD979E73FF57AAF95C93C0D0163016B3FF363F129F748BD3FF408EC89D5E2D03FF49CDB3D7FFA9C3FF5210CF680C0343FF596DD9901C3840163016C3FF38EDA858F62063FF42F74ADB60E9C3FF4BF53DCE4EEB73FF53FCC983257E73FF5B23AEEDC50FD"}}
-{"expression":"map(a,f(a)(asin(a)))","inputs":{"a":"0x0701020178017A010179050C016101693F03FFAB3F13D6BC3F2314733F3150FC3F3E40420161016A3F07FD563F17B9003F26BF313F34AE543F41421C0161016B3F0BF7083F1B8FD03F2A58593F37F5CD3F442BD20161016C3F0FEACD3F1F597F3F2DDEA83F3B26A83F46FD20016201693F49B5DC3F53A3623F5C12EC3F631FD73F68EFAA0162016A3F4C55F83F55E2403F5DF60E3F64AFED3F6A36F30162016B3F4EDD7E3F5809823F5FC3873F662CD23F6B6DB10162016C3F514C903F5A19943F617BEB3F67972D3F6C948F016301693F6DAC333F717F3A3F748FCB3F7700BF3F78F02C0163016A3F6EB5433F7254293F7539BD3F7787AD3F795ADC0163016B3F6FB0603F731D883F75DA3B3F7806F53F79BF690163016C3F709E293F73DBE63F7671BF3F787EFE3F7A1E28"},"result":{"expect":"0x0701020178017A010179050C016101693F0AAEE23F1D9BB93F30CDCB3F43E0943F5679950161016A3F0F5DF33F2265C83F35992F3F4895773F5B03A70161016B3F1416313F2732893F3A61123F4D41633F5F805D0161016C3F18D5FD3F2C00673F3F24003F51E3243F63EECD016201693F684E1F3F79261F3F846E233F8BAE193F924FC80162016A3F6C9D903F7D2FE73F864CE63F8D655A3F93DFA40162016B3F70DC723F8093883F8821DA3F8F12B23F9565CE0162016C3F750A263F8285A53F89ECEE3F90B6273F96E25E016301693F98556F3F9DC5243FA2A7873FA706B03FAAED5E0163016A3F99BF1E3F9F0A9C3FA3CB353FA80B393FABD57D0163016B3F9B1F893FA047643FA4E6DA3FA908683FACB6ED0163016C3F9C76D43FA17BA53FA5FA9F3FA9FE653FAD91D7"}}
-{"expression":"atan(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFF55BB72CFDEA"}}
-{"expression":"atan(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B02"}}
-{"expression":"atan(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FE819D0B7158A4D"}}
-{"expression":"atan(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FE819D0B7158A4D3FE921FB54442D183FEA1A25F2C825063FEB034F38649C883FEBDE70ED439FE73FECAC7C57846F9E3FED6E57CF4F0ACA3FEE24DD44C855D13FEED0D97C9041C93FEF730BD281F69B3FF006132E34D6173FF04E67277A01D73FF092CE471853CC3FF0D38F2C5BA09F3FF110EB007F39F73FF14B1DD5F90CE13FF1825F074030D93FF1B6E192EBBE443FF1E8D473C5D5CA3FF21862F3FADE363FF245B4FAF231113FF270EF55A53A253FF29A33F97BDBEA3FF2C1A241D66DC33FF2E75728833A543FF30B6D796A4DA83FF32DFE01C11C213FF34F1FBB19EB093FF36EE7F2A246443FF38D6A6CE133533FF3AAB98641F26B3FF3C6E650B380473FF3E200AEA00D993FF3FC176B7A85603FF41538521B2F983FF42D70411F9EC13FF444CB3D7D780C3FF45B54837351A03FF4711695FEDDE23FF4861B4CFBE7103FF49A6BE20C3A523FF4AE10FC6589A53FF4C112BB9F7C633FF4D378C1999A0D3FF4E54A3B8E6CF83FF4F68DEA6726173FF5074A2A612AC33FF51784FA1544BA3FF5274400EEA72B3FF5368C951E9CFD3FF54563C118794C3FF553CE48A047653FF561D0AD75B8533FF56F6F33A3E6A73FF57CADE57DBA513FF58990974DFC9B3FF5961AEAC184B33FF5A25052114E603FF5AE3412F1C4673FF5B9C9494C0D733FF5C512E9C5BB9F3FF5D013C41ADABD3FF5DACE854DFF1C3FF5E545B9B1A4C83FF5EF7BCECDE57A3FF5F973152548573FF6032DC1DB31F63FF60CADF03E444D3FF615F5A338CC043FF61F06C6A92B893FF627E330A40AE93FF6308CA2A1EE293FF63904CA99B1923FF6414D44094C7C3FF6496798EE1EC53FF6515542ADF35B3FF65917AAF1CAA23FF660B02C736A063FF6682013BE9A643FF66F689FE6ECD73FF6768B0332CD223FF67D8863BC99BD3FF68461DC0A6BC73FF68B187B9D2C613FF691AD477789583FF698213A9D50533FF69E75468BADCD3FF6A4AA53AAC4493FF6AAC141B907913FF6B0BAE830C0703FF6B69816A8160F"}}
-{"expression":"atan(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FAADE3DFEADD53E3DCBDA3E7ADBB03E9B13BA3EB7B0CA3ED327763EED63383F032BF53F0F005D3F1A2F813F24BC7D3F2EAC4C3F38053E3F40CE863F490FDB3F50D1303F581A7A3F5EF3873F6563E33F6B72BE3F7126EA3F7686CC3F7B985F3F8030993F8273393F8496723F869C793F8887583F8A58EF3F8C12F83F8DB70D3F8F46A43F90C3183F922DA83F93877B3F94D1A03F960D123F973AB93F985B6C3F996FF03F9A78FE3F9B77403F9C6B533F9D55CC3F9E37333F9F10053F9FE0BB3FA0A9C33FA16B823FA2265A3FA2DAA43FA388B53FA430DA3FA4D35F3FA570883FA608963FA69BC63FA72A523FA7B46F3FA83A513FA8BC283FA93A203FA9B4653FAA2B1E3FAA9E723FAB0E853FAB7B7A3FABE56F3FAC4C853FACB0D73FAD12833FAD71A13FADCE4A3FAE28973FAE809E3FAED6743FAF2A2E3FAF7BDE3FAFCB993FB0196E3FB065703FB0AFAD3FB0F8363FB13F1A3FB184653FB1C8263FB20A6A3FB24B3D3FB28AAA3FB2C8BD3FB305813FB341013FB37B453FB3B4583FB3EC433FB4230F3FB458C43FB48D6A3FB4C10A3FB4F3AA3FB525533FB5560A3FB585D73FB5B4C1"}}
-{"expression":"atan(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFF55BB72CFDEA01623FBFD5BA9AAC2F6E01633FC7B97B4BCE5B02"}}
-{"expression":"atan(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFD5BA9AAC2F6E016103666F6F3FAFF55BB72CFDEA0162036261723FCF5B75F92C80DD016203666F6F3FC7B97B4BCE5B020163036261723FD6F61941E4DEF1016303666F6F3FD362773707EBCC"}}
-{"expression":"atan(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD362773707EBCC016103626172016A3FD6F61941E4DEF1016103626172016B3FDA64EEC3CC23FD016103626172016C3FDDAC670561BB4F016103666F6F01693FAFF55BB72CFDEA016103666F6F016A3FBFD5BA9AAC2F6E016103666F6F016B3FC7B97B4BCE5B02016103666F6F016C3FCF5B75F92C80DD01620362617201693FE5D58987169B18016203626172016A3FE700A7C5784634016203626172016B3FE819D0B7158A4D016203626172016C3FE921FB54442D18016203666F6F01693FE0657E94DB30D0016203666F6F016A3FE1E00BABDEFEB4016203666F6F016B3FE345F01CCE37BB016203666F6F016C3FE4978FA3269EE101630362617201693FED6E57CF4F0ACA016303626172016A3FEE24DD44C855D1016303626172016B3FEED0D97C9041C9016303626172016C3FEF730BD281F69B016303666F6F01693FEA1A25F2C82506016303666F6F016A3FEB034F38649C88016303666F6F016B3FEBDE70ED439FE7016303666F6F016C3FECAC7C57846F9E"}}
-{"expression":"atan(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9B13BA016103626172016A3EB7B0CA016103626172016B3ED32776016103626172016C3EED6338016103666F6F01693D7FAADE016103666F6F016A3DFEADD5016103666F6F016B3E3DCBDA016103666F6F016C3E7ADBB001620362617201693F2EAC4C016203626172016A3F38053E016203626172016B3F40CE86016203626172016C3F490FDB016203666F6F01693F032BF5016203666F6F016A3F0F005D016203666F6F016B3F1A2F81016203666F6F016C3F24BC7D01630362617201693F6B72BE016303626172016A3F7126EA016303626172016B3F7686CC016303626172016C3F7B985F016303666F6F01693F50D130016303666F6F016A3F581A7A016303666F6F016B3F5EF387016303666F6F016C3F6563E3"}}
-{"expression":"atan(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FEE24DD44C855D13FEED0D97C9041C93FEF730BD281F69B3FF006132E34D6173FF04E67277A01D73FF092CE471853CC3FF0D38F2C5BA09F3FF270EF55A53A253FF29A33F97BDBEA3FF2C1A241D66DC33FF2E75728833A543FF30B6D796A4DA83FF32DFE01C11C213FF34F1FBB19EB0903666F6F3FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FE819D0B7158A4D3FE921FB54442D183FEA1A25F2C825063FEB034F38649C883FEBDE70ED439FE73FECAC7C57846F9E3FED6E57CF4F0ACA3FF110EB007F39F73FF14B1DD5F90CE13FF1825F074030D93FF1B6E192EBBE443FF1E8D473C5D5CA3FF21862F3FADE363FF245B4FAF23111"}}
-{"expression":"atan(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFF55BB72CFDEA3FD362773707EBCC3FE0657E94DB30D03FE5D58987169B183FEA1A25F2C825060161016A3FBFD5BA9AAC2F6E3FD6F61941E4DEF13FE1E00BABDEFEB43FE700A7C57846343FEB034F38649C880161016B3FC7B97B4BCE5B023FDA64EEC3CC23FD3FE345F01CCE37BB3FE819D0B7158A4D3FEBDE70ED439FE70161016C3FCF5B75F92C80DD3FDDAC670561BB4F3FE4978FA3269EE13FE921FB54442D183FECAC7C57846F9E016201693FED6E57CF4F0ACA3FF006132E34D6173FF110EB007F39F73FF1E8D473C5D5CA3FF29A33F97BDBEA0162016A3FEE24DD44C855D13FF04E67277A01D73FF14B1DD5F90CE13FF21862F3FADE363FF2C1A241D66DC30162016B3FEED0D97C9041C93FF092CE471853CC3FF1825F074030D93FF245B4FAF231113FF2E75728833A540162016C3FEF730BD281F69B3FF0D38F2C5BA09F3FF1B6E192EBBE443FF270EF55A53A253FF30B6D796A4DA8016301693FF32DFE01C11C213FF3AAB98641F26B3FF41538521B2F983FF4711695FEDDE23FF4C112BB9F7C630163016A3FF34F1FBB19EB093FF3C6E650B380473FF42D70411F9EC13FF4861B4CFBE7103FF4D378C1999A0D0163016B3FF36EE7F2A246443FF3E200AEA00D993FF444CB3D7D780C3FF49A6BE20C3A523FF4E54A3B8E6CF80163016C3FF38D6A6CE133533FF3FC176B7A85603FF45B54837351A03FF4AE10FC6589A53FF4F68DEA672617"}}
-{"expression":"atan(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FAADE3E9B13BA3F032BF53F2EAC4C3F50D1300161016A3DFEADD53EB7B0CA3F0F005D3F38053E3F581A7A0161016B3E3DCBDA3ED327763F1A2F813F40CE863F5EF3870161016C3E7ADBB03EED63383F24BC7D3F490FDB3F6563E3016201693F6B72BE3F8030993F8887583F8F46A43F94D1A00162016A3F7126EA3F8273393F8A58EF3F90C3183F960D120162016B3F7686CC3F8496723F8C12F83F922DA83F973AB90162016C3F7B985F3F869C793F8DB70D3F93877B3F985B6C016301693F996FF03F9D55CC3FA0A9C33FA388B53FA608960163016A3F9A78FE3F9E37333FA16B823FA430DA3FA69BC60163016B3F9B77403F9F10053FA2265A3FA4D35F3FA72A520163016C3F9C6B533F9FE0BB3FA2DAA43FA570883FA7B46F"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FAFF55BB72CFDEA"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B02"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FE819D0B7158A4D"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FE819D0B7158A4D3FE921FB54442D183FEA1A25F2C825063FEB034F38649C883FEBDE70ED439FE73FECAC7C57846F9E3FED6E57CF4F0ACA3FEE24DD44C855D13FEED0D97C9041C93FEF730BD281F69B3FF006132E34D6173FF04E67277A01D73FF092CE471853CC3FF0D38F2C5BA09F3FF110EB007F39F73FF14B1DD5F90CE13FF1825F074030D93FF1B6E192EBBE443FF1E8D473C5D5CA3FF21862F3FADE363FF245B4FAF231113FF270EF55A53A253FF29A33F97BDBEA3FF2C1A241D66DC33FF2E75728833A543FF30B6D796A4DA83FF32DFE01C11C213FF34F1FBB19EB093FF36EE7F2A246443FF38D6A6CE133533FF3AAB98641F26B3FF3C6E650B380473FF3E200AEA00D993FF3FC176B7A85603FF41538521B2F983FF42D70411F9EC13FF444CB3D7D780C3FF45B54837351A03FF4711695FEDDE23FF4861B4CFBE7103FF49A6BE20C3A523FF4AE10FC6589A53FF4C112BB9F7C633FF4D378C1999A0D3FF4E54A3B8E6CF83FF4F68DEA6726173FF5074A2A612AC33FF51784FA1544BA3FF5274400EEA72B3FF5368C951E9CFD3FF54563C118794C3FF553CE48A047653FF561D0AD75B8533FF56F6F33A3E6A73FF57CADE57DBA513FF58990974DFC9B3FF5961AEAC184B33FF5A25052114E603FF5AE3412F1C4673FF5B9C9494C0D733FF5C512E9C5BB9F3FF5D013C41ADABD3FF5DACE854DFF1C3FF5E545B9B1A4C83FF5EF7BCECDE57A3FF5F973152548573FF6032DC1DB31F63FF60CADF03E444D3FF615F5A338CC043FF61F06C6A92B893FF627E330A40AE93FF6308CA2A1EE293FF63904CA99B1923FF6414D44094C7C3FF6496798EE1EC53FF6515542ADF35B3FF65917AAF1CAA23FF660B02C736A063FF6682013BE9A643FF66F689FE6ECD73FF6768B0332CD223FF67D8863BC99BD3FF68461DC0A6BC73FF68B187B9D2C613FF691AD477789583FF698213A9D50533FF69E75468BADCD3FF6A4AA53AAC4493FF6AAC141B907913FF6B0BAE830C0703FF6B69816A8160F"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D7FAADE3DFEADD53E3DCBDA3E7ADBB03E9B13BA3EB7B0CA3ED327763EED63383F032BF53F0F005D3F1A2F813F24BC7D3F2EAC4C3F38053E3F40CE863F490FDB3F50D1303F581A7A3F5EF3873F6563E33F6B72BE3F7126EA3F7686CC3F7B985F3F8030993F8273393F8496723F869C793F8887583F8A58EF3F8C12F83F8DB70D3F8F46A43F90C3183F922DA83F93877B3F94D1A03F960D123F973AB93F985B6C3F996FF03F9A78FE3F9B77403F9C6B533F9D55CC3F9E37333F9F10053F9FE0BB3FA0A9C33FA16B823FA2265A3FA2DAA43FA388B53FA430DA3FA4D35F3FA570883FA608963FA69BC63FA72A523FA7B46F3FA83A513FA8BC283FA93A203FA9B4653FAA2B1E3FAA9E723FAB0E853FAB7B7A3FABE56F3FAC4C853FACB0D73FAD12833FAD71A13FADCE4A3FAE28973FAE809E3FAED6743FAF2A2E3FAF7BDE3FAFCB993FB0196E3FB065703FB0AFAD3FB0F8363FB13F1A3FB184653FB1C8263FB20A6A3FB24B3D3FB28AAA3FB2C8BD3FB305813FB341013FB37B453FB3B4583FB3EC433FB4230F3FB458C43FB48D6A3FB4C10A3FB4F3AA3FB525533FB5560A3FB585D73FB5B4C1"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FAFF55BB72CFDEA01623FBFD5BA9AAC2F6E01633FC7B97B4BCE5B02"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FBFD5BA9AAC2F6E016103666F6F3FAFF55BB72CFDEA0162036261723FCF5B75F92C80DD016203666F6F3FC7B97B4BCE5B020163036261723FD6F61941E4DEF1016303666F6F3FD362773707EBCC"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD362773707EBCC016103626172016A3FD6F61941E4DEF1016103626172016B3FDA64EEC3CC23FD016103626172016C3FDDAC670561BB4F016103666F6F01693FAFF55BB72CFDEA016103666F6F016A3FBFD5BA9AAC2F6E016103666F6F016B3FC7B97B4BCE5B02016103666F6F016C3FCF5B75F92C80DD01620362617201693FE5D58987169B18016203626172016A3FE700A7C5784634016203626172016B3FE819D0B7158A4D016203626172016C3FE921FB54442D18016203666F6F01693FE0657E94DB30D0016203666F6F016A3FE1E00BABDEFEB4016203666F6F016B3FE345F01CCE37BB016203666F6F016C3FE4978FA3269EE101630362617201693FED6E57CF4F0ACA016303626172016A3FEE24DD44C855D1016303626172016B3FEED0D97C9041C9016303626172016C3FEF730BD281F69B016303666F6F01693FEA1A25F2C82506016303666F6F016A3FEB034F38649C88016303666F6F016B3FEBDE70ED439FE7016303666F6F016C3FECAC7C57846F9E"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693E9B13BA016103626172016A3EB7B0CA016103626172016B3ED32776016103626172016C3EED6338016103666F6F01693D7FAADE016103666F6F016A3DFEADD5016103666F6F016B3E3DCBDA016103666F6F016C3E7ADBB001620362617201693F2EAC4C016203626172016A3F38053E016203626172016B3F40CE86016203626172016C3F490FDB016203666F6F01693F032BF5016203666F6F016A3F0F005D016203666F6F016B3F1A2F81016203666F6F016C3F24BC7D01630362617201693F6B72BE016303626172016A3F7126EA016303626172016B3F7686CC016303626172016C3F7B985F016303666F6F01693F50D130016303666F6F016A3F581A7A016303666F6F016B3F5EF387016303666F6F016C3F6563E3"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FDDAC670561BB4F3FE0657E94DB30D03FE1E00BABDEFEB43FE345F01CCE37BB3FE4978FA3269EE13FE5D58987169B183FE700A7C57846343FEE24DD44C855D13FEED0D97C9041C93FEF730BD281F69B3FF006132E34D6173FF04E67277A01D73FF092CE471853CC3FF0D38F2C5BA09F3FF270EF55A53A253FF29A33F97BDBEA3FF2C1A241D66DC33FF2E75728833A543FF30B6D796A4DA83FF32DFE01C11C213FF34F1FBB19EB0903666F6F3FAFF55BB72CFDEA3FBFD5BA9AAC2F6E3FC7B97B4BCE5B023FCF5B75F92C80DD3FD362773707EBCC3FD6F61941E4DEF13FDA64EEC3CC23FD3FE819D0B7158A4D3FE921FB54442D183FEA1A25F2C825063FEB034F38649C883FEBDE70ED439FE73FECAC7C57846F9E3FED6E57CF4F0ACA3FF110EB007F39F73FF14B1DD5F90CE13FF1825F074030D93FF1B6E192EBBE443FF1E8D473C5D5CA3FF21862F3FADE363FF245B4FAF23111"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FAFF55BB72CFDEA3FD362773707EBCC3FE0657E94DB30D03FE5D58987169B183FEA1A25F2C825060161016A3FBFD5BA9AAC2F6E3FD6F61941E4DEF13FE1E00BABDEFEB43FE700A7C57846343FEB034F38649C880161016B3FC7B97B4BCE5B023FDA64EEC3CC23FD3FE345F01CCE37BB3FE819D0B7158A4D3FEBDE70ED439FE70161016C3FCF5B75F92C80DD3FDDAC670561BB4F3FE4978FA3269EE13FE921FB54442D183FECAC7C57846F9E016201693FED6E57CF4F0ACA3FF006132E34D6173FF110EB007F39F73FF1E8D473C5D5CA3FF29A33F97BDBEA0162016A3FEE24DD44C855D13FF04E67277A01D73FF14B1DD5F90CE13FF21862F3FADE363FF2C1A241D66DC30162016B3FEED0D97C9041C93FF092CE471853CC3FF1825F074030D93FF245B4FAF231113FF2E75728833A540162016C3FEF730BD281F69B3FF0D38F2C5BA09F3FF1B6E192EBBE443FF270EF55A53A253FF30B6D796A4DA8016301693FF32DFE01C11C213FF3AAB98641F26B3FF41538521B2F983FF4711695FEDDE23FF4C112BB9F7C630163016A3FF34F1FBB19EB093FF3C6E650B380473FF42D70411F9EC13FF4861B4CFBE7103FF4D378C1999A0D0163016B3FF36EE7F2A246443FF3E200AEA00D993FF444CB3D7D780C3FF49A6BE20C3A523FF4E54A3B8E6CF80163016C3FF38D6A6CE133533FF3FC176B7A85603FF45B54837351A03FF4AE10FC6589A53FF4F68DEA672617"}}
-{"expression":"map(a,f(a)(atan(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D7FAADE3E9B13BA3F032BF53F2EAC4C3F50D1300161016A3DFEADD53EB7B0CA3F0F005D3F38053E3F581A7A0161016B3E3DCBDA3ED327763F1A2F813F40CE863F5EF3870161016C3E7ADBB03EED63383F24BC7D3F490FDB3F6563E3016201693F6B72BE3F8030993F8887583F8F46A43F94D1A00162016A3F7126EA3F8273393F8A58EF3F90C3183F960D120162016B3F7686CC3F8496723F8C12F83F922DA83F973AB90162016C3F7B985F3F869C793F8DB70D3F93877B3F985B6C016301693F996FF03F9D55CC3FA0A9C33FA388B53FA608960163016A3F9A78FE3F9E37333FA16B823FA430DA3FA69BC60163016B3F9B77403F9F10053FA2265A3FA4D35F3FA72A520163016C3F9C6B533F9FE0BB3FA2DAA43FA570883FA7B46F"}}
-{"expression":"exp(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF1082B577D34ED"}}
-{"expression":"exp(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B5835"}}
-{"expression":"exp(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B00103FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B2840046DC04F4E5338"}}
-{"expression":"exp(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B00103FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B2840046DC04F4E53384005BF0A8B14576940072615A16072994008A448BB358768400A3B222B881238400BEC38EDB0FAF0400DB93E3C8AD94F400FA3FF43D0EAF94010D73376B89F224011ED3FE64FC5414013153B1449F8B34014504D148049FE40159FB113354F87401704B6905BACBF401880C2AF31FB00401A15519B83CC1B401BC3F805F52549401D8E64B8D4DDAE401F7662470AD4994020BEEC6B6888C84021D368050156C64022F9B882F47E81402433044E47799840258084CCE2201B4026E3879B0EAF1540285D6FD931E0BB4029EFB78F08EA2D402B9BF125D0BA5D402D63C8FAD0C0DF402F49070BDBE8FD4030A6C85FBA36DB4031B9B5652D68444032DE5D9A36D538403415E5BF6FB1064035618576F415304036C2887C1F169240383A4FEF61C6514039CA53B781114B403B7423F99BD947403D396AA9716D63403F1BED3378C98740408EC721396BDB4041A027D11EB5974042C32A20E4F8554043F8F12B1CFA9A404542B2D0A266E74046A1B8EE967AF540481762A858A6FA4049A525C6C73103404B4C902E273A58404D0F496C2A2E14404EEF145F9EBF88405076E87DBAA663405186BF136D679D4052A81DDE254EA94053DC2654CB1CC84055240C9981B21040568118ADE1DEAA4057F4A7BB1752074059802D6F26E046405B253570BB813D405CE564EAEDF51C405EC27C3292F74040605F2C435AB84C40616D7AF6FEA49140628D389970338F4063BF85004D1BAA4065059291837186406660A775D11F734067D21EDF07D24F40695B6A635BBAFD406AFE136F18901D406CBBBCCE2EA3E8406E96244F21BBF640704792407E5E6B4071545B470421144072727A1A8F80C04073A30CF1CCBB3E4074E74478F5785340764065029667E64077AFC7CBFCD67C407936DC5690C08F407AD729D774DBB6407C9250BEDC542E407E6A0C589DB5334080301A43D1D8E340813B5FCEFBB1CD408257E2299E18D9408386BDEDCA02534084C92210816C894086205110C5A1BA"}}
-{"expression":"exp(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F88415B3F910B023F9A65C13FA45AF23FAEF48C3FBA3D293FC640123FD3094C3FE0A5A23FEF22AF3FFE8EF340077CEE401039EA4019872C40236E02402DF854403930AD404522464051D911405F61C7406DC9F2407D1FFA4086B99C408F69FF4098A9D940A2826940ACFD8940B825B540C4061540D0AA8D40DE1FC040EC732640FBB3124105F763410E9B404117CDC441219822412C042641371C3D4142EB7F414F7DBC415CDF89416B1E48417A483841853643418DCDAB4196F2ED41A0AF2E41AB0C2C41B6144441C1D27F41CE529E41DBA12041E9CB5541F8DF6A42047639420D013F42161951421FC789422A159742350DC74240BB15424D292E425A648142687A4B427778A34283B744428C35F9429540EF429EE13342A9206542B408C542BFA53E42CC016B42D929AC42E72B2742F613E24302F962430B6BD8431469C5431DFC2843282C954333053C433E90F7434ADB534357F09B4365DDE64374B12243823C92438AA2DA439393D1439D186843A73A2443B2032843BD7E3E43C9B6E343D6B94F43E4928643F35063440180D24409DAFE4412BF11441C35EF4426491144310289"}}
-{"expression":"exp(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF1082B577D34ED01623FF2216045B6F5CD01633FF34CB8170B5835"}}
-{"expression":"exp(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF2216045B6F5CD016103666F6F3FF1082B577D34ED0162036261723FF48B5E3C3E8186016203666F6F3FF34CB8170B58350163036261723FF747A513DBEF6A016303666F6F3FF5DE9176045FF5"}}
-{"expression":"exp(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF5DE9176045FF5016103626172016A3FF747A513DBEF6A016103626172016B3FF8C802477B0010016103626172016C3FFA61298E1E069C016103666F6F01693FF1082B577D34ED016103666F6F016A3FF2216045B6F5CD016103666F6F016B3FF34CB8170B5835016103666F6F016C3FF48B5E3C3E818601620362617201694002073D3F1BD518016203626172016A400330E587B62B28016203626172016B40046DC04F4E5338016203626172016C4005BF0A8B145769016203666F6F01693FFC14B431256446016203666F6F016A3FFDE455DF80E3C0016203666F6F016B3FFFD1DE6182F8C9016203666F6F016C4000EF9DB467DCF80163036261720169400DB93E3C8AD94F016303626172016A400FA3FF43D0EAF9016303626172016B4010D73376B89F22016303626172016C4011ED3FE64FC541016303666F6F016940072615A1607299016303666F6F016A4008A448BB358768016303666F6F016B400A3B222B881238016303666F6F016C400BEC38EDB0FAF0"}}
-{"expression":"exp(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693FAEF48C016103626172016A3FBA3D29016103626172016B3FC64012016103626172016C3FD3094C016103666F6F01693F88415B016103666F6F016A3F910B02016103666F6F016B3F9A65C1016103666F6F016C3FA45AF20162036261720169401039EA016203626172016A4019872C016203626172016B40236E02016203626172016C402DF854016203666F6F01693FE0A5A2016203666F6F016A3FEF22AF016203666F6F016B3FFE8EF3016203666F6F016C40077CEE0163036261720169406DC9F2016303626172016A407D1FFA016303626172016B4086B99C016303626172016C408F69FF016303666F6F0169403930AD016303666F6F016A40452246016303666F6F016B4051D911016303666F6F016C405F61C7"}}
-{"expression":"exp(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B28400FA3FF43D0EAF94010D73376B89F224011ED3FE64FC5414013153B1449F8B34014504D148049FE40159FB113354F87401704B6905BACBF4022F9B882F47E81402433044E47799840258084CCE2201B4026E3879B0EAF1540285D6FD931E0BB4029EFB78F08EA2D402B9BF125D0BA5D03666F6F3FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B001040046DC04F4E53384005BF0A8B14576940072615A16072994008A448BB358768400A3B222B881238400BEC38EDB0FAF0400DB93E3C8AD94F401880C2AF31FB00401A15519B83CC1B401BC3F805F52549401D8E64B8D4DDAE401F7662470AD4994020BEEC6B6888C84021D368050156C6"}}
-{"expression":"exp(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF1082B577D34ED3FF5DE9176045FF53FFC14B4312564464002073D3F1BD51840072615A16072990161016A3FF2216045B6F5CD3FF747A513DBEF6A3FFDE455DF80E3C0400330E587B62B284008A448BB3587680161016B3FF34CB8170B58353FF8C802477B00103FFFD1DE6182F8C940046DC04F4E5338400A3B222B8812380161016C3FF48B5E3C3E81863FFA61298E1E069C4000EF9DB467DCF84005BF0A8B145769400BEC38EDB0FAF001620169400DB93E3C8AD94F4013153B1449F8B3401880C2AF31FB00401F7662470AD499402433044E4779980162016A400FA3FF43D0EAF94014504D148049FE401A15519B83CC1B4020BEEC6B6888C840258084CCE2201B0162016B4010D73376B89F2240159FB113354F87401BC3F805F525494021D368050156C64026E3879B0EAF150162016C4011ED3FE64FC541401704B6905BACBF401D8E64B8D4DDAE4022F9B882F47E8140285D6FD931E0BB016301694029EFB78F08EA2D4030A6C85FBA36DB4035618576F41530403B7423F99BD9474041A027D11EB5970163016A402B9BF125D0BA5D4031B9B5652D68444036C2887C1F1692403D396AA9716D634042C32A20E4F8550163016B402D63C8FAD0C0DF4032DE5D9A36D53840383A4FEF61C651403F1BED3378C9874043F8F12B1CFA9A0163016C402F49070BDBE8FD403415E5BF6FB1064039CA53B781114B40408EC721396BDB404542B2D0A266E7"}}
-{"expression":"exp(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F88415B3FAEF48C3FE0A5A2401039EA403930AD0161016A3F910B023FBA3D293FEF22AF4019872C404522460161016B3F9A65C13FC640123FFE8EF340236E024051D9110161016C3FA45AF23FD3094C40077CEE402DF854405F61C701620169406DC9F24098A9D940C4061540FBB312412198220162016A407D1FFA40A2826940D0AA8D4105F763412C04260162016B4086B99C40ACFD8940DE1FC0410E9B4041371C3D0162016C408F69FF40B825B540EC73264117CDC44142EB7F01630169414F7DBC4185364341AB0C2C41DBA120420D013F0163016A415CDF89418DCDAB41B6144441E9CB55421619510163016B416B1E484196F2ED41C1D27F41F8DF6A421FC7890163016C417A483841A0AF2E41CE529E42047639422A1597"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF1082B577D34ED"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B5835"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B00103FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B2840046DC04F4E5338"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B00103FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B2840046DC04F4E53384005BF0A8B14576940072615A16072994008A448BB358768400A3B222B881238400BEC38EDB0FAF0400DB93E3C8AD94F400FA3FF43D0EAF94010D73376B89F224011ED3FE64FC5414013153B1449F8B34014504D148049FE40159FB113354F87401704B6905BACBF401880C2AF31FB00401A15519B83CC1B401BC3F805F52549401D8E64B8D4DDAE401F7662470AD4994020BEEC6B6888C84021D368050156C64022F9B882F47E81402433044E47799840258084CCE2201B4026E3879B0EAF1540285D6FD931E0BB4029EFB78F08EA2D402B9BF125D0BA5D402D63C8FAD0C0DF402F49070BDBE8FD4030A6C85FBA36DB4031B9B5652D68444032DE5D9A36D538403415E5BF6FB1064035618576F415304036C2887C1F169240383A4FEF61C6514039CA53B781114B403B7423F99BD947403D396AA9716D63403F1BED3378C98740408EC721396BDB4041A027D11EB5974042C32A20E4F8554043F8F12B1CFA9A404542B2D0A266E74046A1B8EE967AF540481762A858A6FA4049A525C6C73103404B4C902E273A58404D0F496C2A2E14404EEF145F9EBF88405076E87DBAA663405186BF136D679D4052A81DDE254EA94053DC2654CB1CC84055240C9981B21040568118ADE1DEAA4057F4A7BB1752074059802D6F26E046405B253570BB813D405CE564EAEDF51C405EC27C3292F74040605F2C435AB84C40616D7AF6FEA49140628D389970338F4063BF85004D1BAA4065059291837186406660A775D11F734067D21EDF07D24F40695B6A635BBAFD406AFE136F18901D406CBBBCCE2EA3E8406E96244F21BBF640704792407E5E6B4071545B470421144072727A1A8F80C04073A30CF1CCBB3E4074E74478F5785340764065029667E64077AFC7CBFCD67C407936DC5690C08F407AD729D774DBB6407C9250BEDC542E407E6A0C589DB5334080301A43D1D8E340813B5FCEFBB1CD408257E2299E18D9408386BDEDCA02534084C92210816C894086205110C5A1BA"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F88415B3F910B023F9A65C13FA45AF23FAEF48C3FBA3D293FC640123FD3094C3FE0A5A23FEF22AF3FFE8EF340077CEE401039EA4019872C40236E02402DF854403930AD404522464051D911405F61C7406DC9F2407D1FFA4086B99C408F69FF4098A9D940A2826940ACFD8940B825B540C4061540D0AA8D40DE1FC040EC732640FBB3124105F763410E9B404117CDC441219822412C042641371C3D4142EB7F414F7DBC415CDF89416B1E48417A483841853643418DCDAB4196F2ED41A0AF2E41AB0C2C41B6144441C1D27F41CE529E41DBA12041E9CB5541F8DF6A42047639420D013F42161951421FC789422A159742350DC74240BB15424D292E425A648142687A4B427778A34283B744428C35F9429540EF429EE13342A9206542B408C542BFA53E42CC016B42D929AC42E72B2742F613E24302F962430B6BD8431469C5431DFC2843282C954333053C433E90F7434ADB534357F09B4365DDE64374B12243823C92438AA2DA439393D1439D186843A73A2443B2032843BD7E3E43C9B6E343D6B94F43E4928643F35063440180D24409DAFE4412BF11441C35EF4426491144310289"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF1082B577D34ED01623FF2216045B6F5CD01633FF34CB8170B5835"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF2216045B6F5CD016103666F6F3FF1082B577D34ED0162036261723FF48B5E3C3E8186016203666F6F3FF34CB8170B58350163036261723FF747A513DBEF6A016303666F6F3FF5DE9176045FF5"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF5DE9176045FF5016103626172016A3FF747A513DBEF6A016103626172016B3FF8C802477B0010016103626172016C3FFA61298E1E069C016103666F6F01693FF1082B577D34ED016103666F6F016A3FF2216045B6F5CD016103666F6F016B3FF34CB8170B5835016103666F6F016C3FF48B5E3C3E818601620362617201694002073D3F1BD518016203626172016A400330E587B62B28016203626172016B40046DC04F4E5338016203626172016C4005BF0A8B145769016203666F6F01693FFC14B431256446016203666F6F016A3FFDE455DF80E3C0016203666F6F016B3FFFD1DE6182F8C9016203666F6F016C4000EF9DB467DCF80163036261720169400DB93E3C8AD94F016303626172016A400FA3FF43D0EAF9016303626172016B4010D73376B89F22016303626172016C4011ED3FE64FC541016303666F6F016940072615A1607299016303666F6F016A4008A448BB358768016303666F6F016B400A3B222B881238016303666F6F016C400BEC38EDB0FAF0"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693FAEF48C016103626172016A3FBA3D29016103626172016B3FC64012016103626172016C3FD3094C016103666F6F01693F88415B016103666F6F016A3F910B02016103666F6F016B3F9A65C1016103666F6F016C3FA45AF20162036261720169401039EA016203626172016A4019872C016203626172016B40236E02016203626172016C402DF854016203666F6F01693FE0A5A2016203666F6F016A3FEF22AF016203666F6F016B3FFE8EF3016203666F6F016C40077CEE0163036261720169406DC9F2016303626172016A407D1FFA016303626172016B4086B99C016303626172016C408F69FF016303666F6F0169403930AD016303666F6F016A40452246016303666F6F016B4051D911016303666F6F016C405F61C7"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FFA61298E1E069C3FFC14B4312564463FFDE455DF80E3C03FFFD1DE6182F8C94000EF9DB467DCF84002073D3F1BD518400330E587B62B28400FA3FF43D0EAF94010D73376B89F224011ED3FE64FC5414013153B1449F8B34014504D148049FE40159FB113354F87401704B6905BACBF4022F9B882F47E81402433044E47799840258084CCE2201B4026E3879B0EAF1540285D6FD931E0BB4029EFB78F08EA2D402B9BF125D0BA5D03666F6F3FF1082B577D34ED3FF2216045B6F5CD3FF34CB8170B58353FF48B5E3C3E81863FF5DE9176045FF53FF747A513DBEF6A3FF8C802477B001040046DC04F4E53384005BF0A8B14576940072615A16072994008A448BB358768400A3B222B881238400BEC38EDB0FAF0400DB93E3C8AD94F401880C2AF31FB00401A15519B83CC1B401BC3F805F52549401D8E64B8D4DDAE401F7662470AD4994020BEEC6B6888C84021D368050156C6"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF1082B577D34ED3FF5DE9176045FF53FFC14B4312564464002073D3F1BD51840072615A16072990161016A3FF2216045B6F5CD3FF747A513DBEF6A3FFDE455DF80E3C0400330E587B62B284008A448BB3587680161016B3FF34CB8170B58353FF8C802477B00103FFFD1DE6182F8C940046DC04F4E5338400A3B222B8812380161016C3FF48B5E3C3E81863FFA61298E1E069C4000EF9DB467DCF84005BF0A8B145769400BEC38EDB0FAF001620169400DB93E3C8AD94F4013153B1449F8B3401880C2AF31FB00401F7662470AD499402433044E4779980162016A400FA3FF43D0EAF94014504D148049FE401A15519B83CC1B4020BEEC6B6888C840258084CCE2201B0162016B4010D73376B89F2240159FB113354F87401BC3F805F525494021D368050156C64026E3879B0EAF150162016C4011ED3FE64FC541401704B6905BACBF401D8E64B8D4DDAE4022F9B882F47E8140285D6FD931E0BB016301694029EFB78F08EA2D4030A6C85FBA36DB4035618576F41530403B7423F99BD9474041A027D11EB5970163016A402B9BF125D0BA5D4031B9B5652D68444036C2887C1F1692403D396AA9716D634042C32A20E4F8550163016B402D63C8FAD0C0DF4032DE5D9A36D53840383A4FEF61C651403F1BED3378C9874043F8F12B1CFA9A0163016C402F49070BDBE8FD403415E5BF6FB1064039CA53B781114B40408EC721396BDB404542B2D0A266E7"}}
-{"expression":"map(a,f(a)(exp(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F88415B3FAEF48C3FE0A5A2401039EA403930AD0161016A3F910B023FBA3D293FEF22AF4019872C404522460161016B3F9A65C13FC640123FFE8EF340236E024051D9110161016C3FA45AF23FD3094C40077CEE402DF854405F61C701620169406DC9F24098A9D940C4061540FBB312412198220162016A407D1FFA40A2826940D0AA8D4105F763412C04260162016B4086B99C40ACFD8940DE1FC0410E9B4041371C3D0162016C408F69FF40B825B540EC73264117CDC44142EB7F01630169414F7DBC4185364341AB0C2C41DBA120420D013F0163016A415CDF89418DCDAB41B6144441E9CB55421619510163016B416B1E484196F2ED41C1D27F41F8DF6A421FC7890163016C417A483841A0AF2E41CE529E42047639422A1597"}}
-{"expression":"log10(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x0200BFF34413509F79FF"}}
-{"expression":"log10(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FF"}}
-{"expression":"log10(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF4BF9CB38FCCD8BFDC"}}
-{"expression":"log10(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A07BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF4BF9CB38FCCD8BFDC00000000000000003F9AF5F92B00E60F3FAA30A9D609EFEA3FB31B3055C471183FB8CF183886480D3FBE3BC1AB0E19FE3FC1B3E71EC94F7A3FC42C7E7FE3FC023FC68A288B60B7FC3FC8CF183886480D3FCAFD3E3A23B6803FCD165300E333F73FCF1BDEEB6549003FD087A0832FA7AC3FD178DA53D1EE013FD2622B0EE3B79D3FD34413509F79FF3FD41F07D51503BB3FD4F372E34F88603FD5C1B583D436843FD68A288B60B7FC3FD74D1D811B9A043FD80ADF661096453FD8C3B362C2373E3FD977D95EC10C023FDA278C858A49653FDAD303BB63007E3FDB7A720472DBDA3FDC1E06E00421BC3FDCBDEE998249FF3FDD5A52909178003FDDF3597965027B3FDE8927964FD5FD3FDF1BDEEB6549013FDFAB9F6CE29E063FE01C43947FF22F3FE0615936D8AAA03FE0A51DF56800893FE0E79E688889FD3FE128E67712D9E03FE1690163290F403FE1A7F9D5E079223FE1E5D9E9E790D63FE222AB3542EDDE3FE25E76D238B4003FE29945677F43E13FE2D31F2FC198CE3FE30C0C0089AE3E3FE34413509F79FF3FE37B3C3DE973A13FE3B18D92DA3EDD3FE3E70DCB75D65E3FE41BC319F7812F3FE44FB36B20E9FF3FE482E46A39D8413FE4B55B84C74CA83FE4E71DEE0018FE3FE51830A20474CA3FE5489868DD8A023FE57859D9497D023FE5A7795B5808223FE5D5FB2ADB631E3FE603E359B0D89E3FE63135D1E41EDF3FE65DF657B043013FE68A288B60B7FC3FE6B5CFEB14E1B23FE6E0EFD46841B43FE70B8B86013D3F3FE735A621084A313FE75F42AA892AED3FE788640CBFBED53FE7B10D1851CDDE3FE7D9408577194E3FE80100F510E1FF3FE82850F1B1FCE03FE84F32F09879003FE875A95299C6CD3FE89BB665023E3D3FE8C15C6268D1243FE8E69D7377A7FE3FE90B7BAFAA599F3FE92FF91E0261803FE95417B5B26CDC3FE977D95EC10C023FE99B3FF2A34B6E3FE9BE4D3CCFAF2E3FE9E102FB4A02BC3FEA0362DF28679F3FEA256E8D120640"}}
-{"expression":"log10(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A07BF9A209BBF6730E8BF3A1C97BF1A209BBF015182BEDA1893BEB7D1B9BE9A209BBE7FDFE1BE5104D4BE26A1FCBDFFDFE1BDB8AE86BD6D88F7BCE59C7E000000003CD7AFC93D51854F3D98D9833DC678C23DF1DE0D3E0D9F393E2163F43E3451443E4678C23E57E9F23E68B2983E78DEF73E843D043E8BC6D33E9311583E9A209B3EA0F83F3EA79B973EAE0DAC3EB451443EBA68EC3EC056FB3EC61D9B3ECBBECB3ED13C643ED6981E3EDBD3903EE0F0373EE5EF753EEAD2953EEF9ACC3EF4493D3EF8DEF73EFD5CFB3F00E21D3F030ACA3F0528F03F073CF33F0947343F0B480B3F0D3FCF3F0F2ECF3F11155A3F12F3B73F14CA2B3F1698F93F1860603F1A209B3F1BD9E23F1D8C6D3F1F386E3F20DE193F227D9B3F2417233F25AADC3F2738EF3F28C1853F2A44C33F2BC2CF3F2D3BCB3F2EAFD93F301F1B3F3189AF3F32EFB33F3451443F35AE7F3F37077F3F385C5C3F39AD313F3AFA153F3C43203F3D88693F3ECA043F4008083F4142883F4279983F43AD4B3F44DDB33F460AE33F4734EC3F485BDD3F497FC93F4AA0BE3F4BBECB3F4CDA003F4DF26A3F4F08183F501B173F512B74"}}
-{"expression":"log10(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x01010178030161BFF34413509F79FF0162BFECE61CF8EF36FE0163BFE74392D61708FF"}}
-{"expression":"log10(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x01020178017906016103626172BFECE61CF8EF36FE016103666F6FBFF34413509F79FF016203626172BFE34413509F79FF016203666F6FBFE74392D61708FF016303626172BFDB43125B8E9800016303666F6FBFE02A30498EB0FE"}}
-{"expression":"log10(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFE02A30498EB0FE016103626172016ABFDB43125B8E9800016103626172016BBFD6FA372B8C4F7E016103626172016CBFD34413509F79FF016103666F6F0169BFF34413509F79FF016103666F6F016ABFECE61CF8EF36FE016103666F6F016BBFE74392D61708FF016103666F6F016CBFE34413509F79FF0162036261720169BFB715D0CE367AFB016203626172016ABFADB11ED766ABF4016203626172016BBF9CB38FCCD8BFDC016203626172016C0000000000000000016203666F6F0169BFCFFBFC2BBC7802016203666F6F016ABFCA209A84FBCFF8016203666F6F016BBFC4D43F8275A483016203666F6F016CBFBFFBFC2BBC780201630362617201693FBE3BC1AB0E19FE016303626172016A3FC1B3E71EC94F7A016303626172016B3FC42C7E7FE3FC02016303626172016C3FC68A288B60B7FC016303666F6F01693F9AF5F92B00E60F016303666F6F016A3FAA30A9D609EFEA016303666F6F016B3FB31B3055C47118016303666F6F016C3FB8CF183886480D"}}
-{"expression":"log10(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A180161036261720169BF015182016103626172016ABEDA1893016103626172016BBEB7D1B9016103626172016CBE9A209B016103666F6F0169BF9A209B016103666F6F016ABF6730E8016103666F6F016BBF3A1C97016103666F6F016CBF1A209B0162036261720169BDB8AE86016203626172016ABD6D88F7016203626172016BBCE59C7E016203626172016C00000000016203666F6F0169BE7FDFE1016203666F6F016ABE5104D4016203666F6F016BBE26A1FC016203666F6F016CBDFFDFE101630362617201693DF1DE0D016303626172016A3E0D9F39016303626172016B3E2163F4016303626172016C3E345144016303666F6F01693CD7AFC9016303666F6F016A3D51854F016303666F6F016B3D98D983016303666F6F016C3DC678C2"}}
-{"expression":"log10(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF43FC1B3E71EC94F7A3FC42C7E7FE3FC023FC68A288B60B7FC3FC8CF183886480D3FCAFD3E3A23B6803FCD165300E333F73FCF1BDEEB6549003FD68A288B60B7FC3FD74D1D811B9A043FD80ADF661096453FD8C3B362C2373E3FD977D95EC10C023FDA278C858A49653FDAD303BB63007E03666F6FBFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBF9CB38FCCD8BFDC00000000000000003F9AF5F92B00E60F3FAA30A9D609EFEA3FB31B3055C471183FB8CF183886480D3FBE3BC1AB0E19FE3FD087A0832FA7AC3FD178DA53D1EE013FD2622B0EE3B79D3FD34413509F79FF3FD41F07D51503BB3FD4F372E34F88603FD5C1B583D43684"}}
-{"expression":"log10(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C01610169BFF34413509F79FFBFE02A30498EB0FEBFCFFBFC2BBC7802BFB715D0CE367AFB3F9AF5F92B00E60F0161016ABFECE61CF8EF36FEBFDB43125B8E9800BFCA209A84FBCFF8BFADB11ED766ABF43FAA30A9D609EFEA0161016BBFE74392D61708FFBFD6FA372B8C4F7EBFC4D43F8275A483BF9CB38FCCD8BFDC3FB31B3055C471180161016CBFE34413509F79FFBFD34413509F79FFBFBFFBFC2BBC780200000000000000003FB8CF183886480D016201693FBE3BC1AB0E19FE3FC8CF183886480D3FD087A0832FA7AC3FD41F07D51503BB3FD74D1D811B9A040162016A3FC1B3E71EC94F7A3FCAFD3E3A23B6803FD178DA53D1EE013FD4F372E34F88603FD80ADF661096450162016B3FC42C7E7FE3FC023FCD165300E333F73FD2622B0EE3B79D3FD5C1B583D436843FD8C3B362C2373E0162016C3FC68A288B60B7FC3FCF1BDEEB6549003FD34413509F79FF3FD68A288B60B7FC3FD977D95EC10C02016301693FDA278C858A49653FDCBDEE998249FF3FDF1BDEEB6549013FE0A51DF56800893FE1A7F9D5E079220163016A3FDAD303BB63007E3FDD5A52909178003FDFAB9F6CE29E063FE0E79E688889FD3FE1E5D9E9E790D60163016B3FDB7A720472DBDA3FDDF3597965027B3FE01C43947FF22F3FE128E67712D9E03FE222AB3542EDDE0163016C3FDC1E06E00421BC3FDE8927964FD5FD3FE0615936D8AAA03FE1690163290F403FE25E76D238B400"}}
-{"expression":"log10(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169BF9A209BBF015182BE7FDFE1BDB8AE863CD7AFC90161016ABF6730E8BEDA1893BE5104D4BD6D88F73D51854F0161016BBF3A1C97BEB7D1B9BE26A1FCBCE59C7E3D98D9830161016CBF1A209BBE9A209BBDFFDFE1000000003DC678C2016201693DF1DE0D3E4678C23E843D043EA0F83F3EBA68EC0162016A3E0D9F393E57E9F23E8BC6D33EA79B973EC056FB0162016B3E2163F43E68B2983E9311583EAE0DAC3EC61D9B0162016C3E3451443E78DEF73E9A209B3EB451443ECBBECB016301693ED13C643EE5EF753EF8DEF73F0528F03F0D3FCF0163016A3ED6981E3EEAD2953EFD5CFB3F073CF33F0F2ECF0163016B3EDBD3903EEF9ACC3F00E21D3F0947343F11155A0163016C3EE0F0373EF4493D3F030ACA3F0B480B3F12F3B7"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x0200BFF34413509F79FF"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FF"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF4BF9CB38FCCD8BFDC"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A07BFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF4BF9CB38FCCD8BFDC00000000000000003F9AF5F92B00E60F3FAA30A9D609EFEA3FB31B3055C471183FB8CF183886480D3FBE3BC1AB0E19FE3FC1B3E71EC94F7A3FC42C7E7FE3FC023FC68A288B60B7FC3FC8CF183886480D3FCAFD3E3A23B6803FCD165300E333F73FCF1BDEEB6549003FD087A0832FA7AC3FD178DA53D1EE013FD2622B0EE3B79D3FD34413509F79FF3FD41F07D51503BB3FD4F372E34F88603FD5C1B583D436843FD68A288B60B7FC3FD74D1D811B9A043FD80ADF661096453FD8C3B362C2373E3FD977D95EC10C023FDA278C858A49653FDAD303BB63007E3FDB7A720472DBDA3FDC1E06E00421BC3FDCBDEE998249FF3FDD5A52909178003FDDF3597965027B3FDE8927964FD5FD3FDF1BDEEB6549013FDFAB9F6CE29E063FE01C43947FF22F3FE0615936D8AAA03FE0A51DF56800893FE0E79E688889FD3FE128E67712D9E03FE1690163290F403FE1A7F9D5E079223FE1E5D9E9E790D63FE222AB3542EDDE3FE25E76D238B4003FE29945677F43E13FE2D31F2FC198CE3FE30C0C0089AE3E3FE34413509F79FF3FE37B3C3DE973A13FE3B18D92DA3EDD3FE3E70DCB75D65E3FE41BC319F7812F3FE44FB36B20E9FF3FE482E46A39D8413FE4B55B84C74CA83FE4E71DEE0018FE3FE51830A20474CA3FE5489868DD8A023FE57859D9497D023FE5A7795B5808223FE5D5FB2ADB631E3FE603E359B0D89E3FE63135D1E41EDF3FE65DF657B043013FE68A288B60B7FC3FE6B5CFEB14E1B23FE6E0EFD46841B43FE70B8B86013D3F3FE735A621084A313FE75F42AA892AED3FE788640CBFBED53FE7B10D1851CDDE3FE7D9408577194E3FE80100F510E1FF3FE82850F1B1FCE03FE84F32F09879003FE875A95299C6CD3FE89BB665023E3D3FE8C15C6268D1243FE8E69D7377A7FE3FE90B7BAFAA599F3FE92FF91E0261803FE95417B5B26CDC3FE977D95EC10C023FE99B3FF2A34B6E3FE9BE4D3CCFAF2E3FE9E102FB4A02BC3FEA0362DF28679F3FEA256E8D120640"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A07BF9A209BBF6730E8BF3A1C97BF1A209BBF015182BEDA1893BEB7D1B9BE9A209BBE7FDFE1BE5104D4BE26A1FCBDFFDFE1BDB8AE86BD6D88F7BCE59C7E000000003CD7AFC93D51854F3D98D9833DC678C23DF1DE0D3E0D9F393E2163F43E3451443E4678C23E57E9F23E68B2983E78DEF73E843D043E8BC6D33E9311583E9A209B3EA0F83F3EA79B973EAE0DAC3EB451443EBA68EC3EC056FB3EC61D9B3ECBBECB3ED13C643ED6981E3EDBD3903EE0F0373EE5EF753EEAD2953EEF9ACC3EF4493D3EF8DEF73EFD5CFB3F00E21D3F030ACA3F0528F03F073CF33F0947343F0B480B3F0D3FCF3F0F2ECF3F11155A3F12F3B73F14CA2B3F1698F93F1860603F1A209B3F1BD9E23F1D8C6D3F1F386E3F20DE193F227D9B3F2417233F25AADC3F2738EF3F28C1853F2A44C33F2BC2CF3F2D3BCB3F2EAFD93F301F1B3F3189AF3F32EFB33F3451443F35AE7F3F37077F3F385C5C3F39AD313F3AFA153F3C43203F3D88693F3ECA043F4008083F4142883F4279983F43AD4B3F44DDB33F460AE33F4734EC3F485BDD3F497FC93F4AA0BE3F4BBECB3F4CDA003F4DF26A3F4F08183F501B173F512B74"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x01010178030161BFF34413509F79FF0162BFECE61CF8EF36FE0163BFE74392D61708FF"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x01020178017906016103626172BFECE61CF8EF36FE016103666F6FBFF34413509F79FF016203626172BFE34413509F79FF016203666F6FBFE74392D61708FF016303626172BFDB43125B8E9800016303666F6FBFE02A30498EB0FE"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFE02A30498EB0FE016103626172016ABFDB43125B8E9800016103626172016BBFD6FA372B8C4F7E016103626172016CBFD34413509F79FF016103666F6F0169BFF34413509F79FF016103666F6F016ABFECE61CF8EF36FE016103666F6F016BBFE74392D61708FF016103666F6F016CBFE34413509F79FF0162036261720169BFB715D0CE367AFB016203626172016ABFADB11ED766ABF4016203626172016BBF9CB38FCCD8BFDC016203626172016C0000000000000000016203666F6F0169BFCFFBFC2BBC7802016203666F6F016ABFCA209A84FBCFF8016203666F6F016BBFC4D43F8275A483016203666F6F016CBFBFFBFC2BBC780201630362617201693FBE3BC1AB0E19FE016303626172016A3FC1B3E71EC94F7A016303626172016B3FC42C7E7FE3FC02016303626172016C3FC68A288B60B7FC016303666F6F01693F9AF5F92B00E60F016303666F6F016A3FAA30A9D609EFEA016303666F6F016B3FB31B3055C47118016303666F6F016C3FB8CF183886480D"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A180161036261720169BF015182016103626172016ABEDA1893016103626172016BBEB7D1B9016103626172016CBE9A209B016103666F6F0169BF9A209B016103666F6F016ABF6730E8016103666F6F016BBF3A1C97016103666F6F016CBF1A209B0162036261720169BDB8AE86016203626172016ABD6D88F7016203626172016BBCE59C7E016203626172016C00000000016203666F6F0169BE7FDFE1016203666F6F016ABE5104D4016203666F6F016BBE26A1FC016203666F6F016CBDFFDFE101630362617201693DF1DE0D016303626172016A3E0D9F39016303626172016B3E2163F4016303626172016C3E345144016303666F6F01693CD7AFC9016303666F6F016A3D51854F016303666F6F016B3D98D983016303666F6F016C3DC678C2"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFD34413509F79FFBFCFFBFC2BBC7802BFCA209A84FBCFF8BFC4D43F8275A483BFBFFBFC2BBC7802BFB715D0CE367AFBBFADB11ED766ABF43FC1B3E71EC94F7A3FC42C7E7FE3FC023FC68A288B60B7FC3FC8CF183886480D3FCAFD3E3A23B6803FCD165300E333F73FCF1BDEEB6549003FD68A288B60B7FC3FD74D1D811B9A043FD80ADF661096453FD8C3B362C2373E3FD977D95EC10C023FDA278C858A49653FDAD303BB63007E03666F6FBFF34413509F79FFBFECE61CF8EF36FEBFE74392D61708FFBFE34413509F79FFBFE02A30498EB0FEBFDB43125B8E9800BFD6FA372B8C4F7EBF9CB38FCCD8BFDC00000000000000003F9AF5F92B00E60F3FAA30A9D609EFEA3FB31B3055C471183FB8CF183886480D3FBE3BC1AB0E19FE3FD087A0832FA7AC3FD178DA53D1EE013FD2622B0EE3B79D3FD34413509F79FF3FD41F07D51503BB3FD4F372E34F88603FD5C1B583D43684"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C01610169BFF34413509F79FFBFE02A30498EB0FEBFCFFBFC2BBC7802BFB715D0CE367AFB3F9AF5F92B00E60F0161016ABFECE61CF8EF36FEBFDB43125B8E9800BFCA209A84FBCFF8BFADB11ED766ABF43FAA30A9D609EFEA0161016BBFE74392D61708FFBFD6FA372B8C4F7EBFC4D43F8275A483BF9CB38FCCD8BFDC3FB31B3055C471180161016CBFE34413509F79FFBFD34413509F79FFBFBFFBFC2BBC780200000000000000003FB8CF183886480D016201693FBE3BC1AB0E19FE3FC8CF183886480D3FD087A0832FA7AC3FD41F07D51503BB3FD74D1D811B9A040162016A3FC1B3E71EC94F7A3FCAFD3E3A23B6803FD178DA53D1EE013FD4F372E34F88603FD80ADF661096450162016B3FC42C7E7FE3FC023FCD165300E333F73FD2622B0EE3B79D3FD5C1B583D436843FD8C3B362C2373E0162016C3FC68A288B60B7FC3FCF1BDEEB6549003FD34413509F79FF3FD68A288B60B7FC3FD977D95EC10C02016301693FDA278C858A49653FDCBDEE998249FF3FDF1BDEEB6549013FE0A51DF56800893FE1A7F9D5E079220163016A3FDAD303BB63007E3FDD5A52909178003FDFAB9F6CE29E063FE0E79E688889FD3FE1E5D9E9E790D60163016B3FDB7A720472DBDA3FDDF3597965027B3FE01C43947FF22F3FE128E67712D9E03FE222AB3542EDDE0163016C3FDC1E06E00421BC3FDE8927964FD5FD3FE0615936D8AAA03FE1690163290F403FE25E76D238B400"}}
-{"expression":"map(a,f(a)(log10(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169BF9A209BBF015182BE7FDFE1BDB8AE863CD7AFC90161016ABF6730E8BEDA1893BE5104D4BD6D88F73D51854F0161016BBF3A1C97BEB7D1B9BE26A1FCBCE59C7E3D98D9830161016CBF1A209BBE9A209BBDFFDFE1000000003DC678C2016201693DF1DE0D3E4678C23E843D043EA0F83F3EBA68EC0162016A3E0D9F393E57E9F23E8BC6D33EA79B973EC056FB0162016B3E2163F43E68B2983E9311583EAE0DAC3EC61D9B0162016C3E3451443E78DEF73E9A209B3EB451443ECBBECB016301693ED13C643EE5EF753EF8DEF73F0528F03F0D3FCF0163016A3ED6981E3EEAD2953EFD5CFB3F073CF33F0F2ECF0163016B3EDBD3903EEF9ACC3F00E21D3F0947343F11155A0163016C3EE0F0373EF4493D3F030ACA3F0B480B3F12F3B7"}}
-{"expression":"log(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x0200C0062E42FEFA39EF"}}
-{"expression":"log(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4"}}
-{"expression":"log(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47CBFB08598B59E3A07"}}
-{"expression":"log(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A07C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47CBFB08598B59E3A0700000000000000003FAF0A30C01162A63FBE27076E2AF2E63FC5FF3070A793D43FCC8FF7C79A9A223FD1675CABABA60E3FD4618BC21C5EC23FD739D7F6BBD0073FD9F323ECBF984C3FDC8FF7C79A9A223FDF128F5FAF06ED3FE0BE72E4252A833FE1E85F5E7040D03FE307D7334F10BE3FE41D8FE84672AE3FE52A2D265BC5AB3FE62E42FEFA39EF3FE72A57D76DFB873FE81EE60AFB501A3FE90C5D5056E7593FE9F323ECBF984C3FEAD397BD0237383FEBAE0F1B241EE43FEC82D9A6374F9C3FED5240F0E0E0783FEE1C891A51C97A3FEEE1F154D00CF63FEFA2B45C6AC8883FF02F84700434A83FF08B90EF531F6A3FF0E5977D2C10F93FF13DAE612D6D8E3FF193EA7AAD030B3FF1E85F5E7040D03FF23B1F7163C3803FF28C3C00AD8E203FF2DBC55768DEB33FF329CAD25005773FF3765AF18FB2393FF3C18368F787EC3FF40B512EB53D603FF453D088C1F5853FF49B0D1924A5573FF4E111E92832043FF525E973A0564F3FF5699DAE553C553FF5AC3812AAFFCD3FF5EDC1A597EC8E3FF62E42FEFA39EF3FF66DC4505C31F73FF6AC4D6B341ABB3FF6E9E5C6ABD0D73FF7269484FAC5043FF76260785BF70C3FF79D5027A890A43FF7D769D29EE7453FF810B375DCE91E3FF84932CE944BBA3FF880ED5DFE38943FF8B7E86C93A9933FF8EE290D0F2C6A3FF923B41F3C55103FF9588E5298C4C63FF98CBC28CA51EE3FF9C041F7ED8D333FF9F323ECBF984C3FFA25660CA601B53FFA570C37971E283FFA881A29E523733FFAB8937DEE18493FFAE87BADB2813B3FFB17D614548B6A3FFB46A5EF8151A03FFB74EE60C5B7FA3FFBA2B26ED03C623FFBCFF506A0FF1B3FFBFCB8FCA92DF13FFC29010DDAE5E03FFC54CFE0AA8A863FFC802806027FAE3FFCAB0BFA2A20023FFCD57E25A0BC023FFCFF80DDED5DC83FFD2916666400CE3FFD5240F0E0E0783FFD7B029E7A74E53FFDA35D802AAB173FFDCB53976FDBD13FFDF2E6D6E5FBAA3FFE1A1922D876B7"}}
-{"expression":"log(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A07C0317218C0051592BFD644DCBFB17218BF94E220BF7B17A0BF53A135BF317218BF134B11BEF0A451BEBFD7D2BE934B11BE549F6ABE08BC74BD842CC6000000003D7851863DF1383B3E2FF9843E647FBE3E8B3AE53EA30C5E3EB9CEC03ECF991F3EE47FBE3EF8947B3F05F3973F0F42FB3F183EBA3F20EC7F3F2951693F3172183F3952BF3F40F7303F4862EB3F4F991F3F569CBE3F5D70793F6416CD3F6A92083F70E4493F770F8B3F7D15A33F817C243F845C873F872CBC3F89ED733F8C9F543F8F42FB3F91D8FC3F9461E03F96DE2B3F994E573F9BB2D83F9E0C1B3FA05A893FA29E843FA4D8693FA7088F3FA92F4C3FAB4CED3FAD61C13FAF6E0D3FB172183FB36E233FB5626B3FB74F2E3FB934A43FBB13043FBCEA813FBEBB4F3FC0859C3FC249963FC4076B3FC5BF433FC771483FC91DA13FCAC4733FCC65E13FCE02103FCF991F3FD12B303FD2B8623FD440D13FD5C49C3FD743DD3FD8BEB13FDA352F3FDBA7733FDD15933FDE7FA83FDFE5C83FE148083FE2A67F3FE401403FE558603FE6ABF13FE7FC073FE948B33FEA92083FEBD8153FED1AEC3FEE5A9D3FEF97373FF0D0C9"}}
-{"expression":"log(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x01010178030161C0062E42FEFA39EF0162C000A2B23F3BAB730163BFFAC89B834770D4"}}
-{"expression":"log(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x01020178017906016103626172C000A2B23F3BAB73016103666F6FC0062E42FEFA39EF016203626172BFF62E42FEFA39EF016203666F6FBFFAC89B834770D4016303626172BFEF62F40794A7B8016303666F6FBFF29C440606E6AB"}}
-{"expression":"log(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFF29C440606E6AB016103626172016ABFEF62F40794A7B8016103626172016BBFEA74269F84330E016103626172016CBFE62E42FEFA39EF016103666F6F0169C0062E42FEFA39EF016103666F6F016AC000A2B23F3BAB73016103666F6F016BBFFAC89B834770D4016103666F6F016CBFF62E42FEFA39EF0162036261720169BFCA93ED3C8AD9E3016203626172016ABFC1178E8227E47C016203626172016BBFB08598B59E3A07016203626172016C0000000000000000016203666F6F0169BFE269621134DB92016203666F6F016ABFDE148A1A2726CE016203666F6F016BBFD7FAFA3BD8151C016203666F6F016CBFD269621134DB9201630362617201693FD1675CABABA60E016303626172016A3FD4618BC21C5EC2016303626172016B3FD739D7F6BBD007016303626172016C3FD9F323ECBF984C016303666F6F01693FAF0A30C01162A6016303666F6F016A3FBE27076E2AF2E6016303666F6F016B3FC5FF3070A793D4016303666F6F016C3FCC8FF7C79A9A22"}}
-{"expression":"log(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A180161036261720169BF94E220016103626172016ABF7B17A0016103626172016BBF53A135016103626172016CBF317218016103666F6F0169C0317218016103666F6F016AC0051592016103666F6F016BBFD644DC016103666F6F016CBFB172180162036261720169BE549F6A016203626172016ABE08BC74016203626172016BBD842CC6016203626172016C00000000016203666F6F0169BF134B11016203666F6F016ABEF0A451016203666F6F016BBEBFD7D2016203666F6F016CBE934B1101630362617201693E8B3AE5016303626172016A3EA30C5E016303626172016B3EB9CEC0016303626172016C3ECF991F016303666F6F01693D785186016303666F6F016A3DF1383B016303666F6F016B3E2FF984016303666F6F016C3E647FBE"}}
-{"expression":"log(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47C3FD4618BC21C5EC23FD739D7F6BBD0073FD9F323ECBF984C3FDC8FF7C79A9A223FDF128F5FAF06ED3FE0BE72E4252A833FE1E85F5E7040D03FE9F323ECBF984C3FEAD397BD0237383FEBAE0F1B241EE43FEC82D9A6374F9C3FED5240F0E0E0783FEE1C891A51C97A3FEEE1F154D00CF603666F6FC0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFB08598B59E3A0700000000000000003FAF0A30C01162A63FBE27076E2AF2E63FC5FF3070A793D43FCC8FF7C79A9A223FD1675CABABA60E3FE307D7334F10BE3FE41D8FE84672AE3FE52A2D265BC5AB3FE62E42FEFA39EF3FE72A57D76DFB873FE81EE60AFB501A3FE90C5D5056E759"}}
-{"expression":"log(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C01610169C0062E42FEFA39EFBFF29C440606E6ABBFE269621134DB92BFCA93ED3C8AD9E33FAF0A30C01162A60161016AC000A2B23F3BAB73BFEF62F40794A7B8BFDE148A1A2726CEBFC1178E8227E47C3FBE27076E2AF2E60161016BBFFAC89B834770D4BFEA74269F84330EBFD7FAFA3BD8151CBFB08598B59E3A073FC5FF3070A793D40161016CBFF62E42FEFA39EFBFE62E42FEFA39EFBFD269621134DB9200000000000000003FCC8FF7C79A9A22016201693FD1675CABABA60E3FDC8FF7C79A9A223FE307D7334F10BE3FE72A57D76DFB873FEAD397BD0237380162016A3FD4618BC21C5EC23FDF128F5FAF06ED3FE41D8FE84672AE3FE81EE60AFB501A3FEBAE0F1B241EE40162016B3FD739D7F6BBD0073FE0BE72E4252A833FE52A2D265BC5AB3FE90C5D5056E7593FEC82D9A6374F9C0162016C3FD9F323ECBF984C3FE1E85F5E7040D03FE62E42FEFA39EF3FE9F323ECBF984C3FED5240F0E0E078016301693FEE1C891A51C97A3FF08B90EF531F6A3FF1E85F5E7040D03FF329CAD25005773FF453D088C1F5850163016A3FEEE1F154D00CF63FF0E5977D2C10F93FF23B1F7163C3803FF3765AF18FB2393FF49B0D1924A5570163016B3FEFA2B45C6AC8883FF13DAE612D6D8E3FF28C3C00AD8E203FF3C18368F787EC3FF4E111E92832040163016C3FF02F84700434A83FF193EA7AAD030B3FF2DBC55768DEB33FF40B512EB53D603FF525E973A0564F"}}
-{"expression":"log(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169C0317218BF94E220BF134B11BE549F6A3D7851860161016AC0051592BF7B17A0BEF0A451BE08BC743DF1383B0161016BBFD644DCBF53A135BEBFD7D2BD842CC63E2FF9840161016CBFB17218BF317218BE934B11000000003E647FBE016201693E8B3AE53EE47FBE3F183EBA3F3952BF3F569CBE0162016A3EA30C5E3EF8947B3F20EC7F3F40F7303F5D70790162016B3EB9CEC03F05F3973F2951693F4862EB3F6416CD0162016C3ECF991F3F0F42FB3F3172183F4F991F3F6A9208016301693F70E4493F845C873F8F42FB3F994E573FA29E840163016A3F770F8B3F872CBC3F91D8FC3F9BB2D83FA4D8690163016B3F7D15A33F89ED733F9461E03F9E0C1B3FA7088F0163016C3F817C243F8C9F543F96DE2B3FA05A893FA92F4C"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x0200C0062E42FEFA39EF"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47CBFB08598B59E3A07"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A07C0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47CBFB08598B59E3A0700000000000000003FAF0A30C01162A63FBE27076E2AF2E63FC5FF3070A793D43FCC8FF7C79A9A223FD1675CABABA60E3FD4618BC21C5EC23FD739D7F6BBD0073FD9F323ECBF984C3FDC8FF7C79A9A223FDF128F5FAF06ED3FE0BE72E4252A833FE1E85F5E7040D03FE307D7334F10BE3FE41D8FE84672AE3FE52A2D265BC5AB3FE62E42FEFA39EF3FE72A57D76DFB873FE81EE60AFB501A3FE90C5D5056E7593FE9F323ECBF984C3FEAD397BD0237383FEBAE0F1B241EE43FEC82D9A6374F9C3FED5240F0E0E0783FEE1C891A51C97A3FEEE1F154D00CF63FEFA2B45C6AC8883FF02F84700434A83FF08B90EF531F6A3FF0E5977D2C10F93FF13DAE612D6D8E3FF193EA7AAD030B3FF1E85F5E7040D03FF23B1F7163C3803FF28C3C00AD8E203FF2DBC55768DEB33FF329CAD25005773FF3765AF18FB2393FF3C18368F787EC3FF40B512EB53D603FF453D088C1F5853FF49B0D1924A5573FF4E111E92832043FF525E973A0564F3FF5699DAE553C553FF5AC3812AAFFCD3FF5EDC1A597EC8E3FF62E42FEFA39EF3FF66DC4505C31F73FF6AC4D6B341ABB3FF6E9E5C6ABD0D73FF7269484FAC5043FF76260785BF70C3FF79D5027A890A43FF7D769D29EE7453FF810B375DCE91E3FF84932CE944BBA3FF880ED5DFE38943FF8B7E86C93A9933FF8EE290D0F2C6A3FF923B41F3C55103FF9588E5298C4C63FF98CBC28CA51EE3FF9C041F7ED8D333FF9F323ECBF984C3FFA25660CA601B53FFA570C37971E283FFA881A29E523733FFAB8937DEE18493FFAE87BADB2813B3FFB17D614548B6A3FFB46A5EF8151A03FFB74EE60C5B7FA3FFBA2B26ED03C623FFBCFF506A0FF1B3FFBFCB8FCA92DF13FFC29010DDAE5E03FFC54CFE0AA8A863FFC802806027FAE3FFCAB0BFA2A20023FFCD57E25A0BC023FFCFF80DDED5DC83FFD2916666400CE3FFD5240F0E0E0783FFD7B029E7A74E53FFDA35D802AAB173FFDCB53976FDBD13FFDF2E6D6E5FBAA3FFE1A1922D876B7"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A07C0317218C0051592BFD644DCBFB17218BF94E220BF7B17A0BF53A135BF317218BF134B11BEF0A451BEBFD7D2BE934B11BE549F6ABE08BC74BD842CC6000000003D7851863DF1383B3E2FF9843E647FBE3E8B3AE53EA30C5E3EB9CEC03ECF991F3EE47FBE3EF8947B3F05F3973F0F42FB3F183EBA3F20EC7F3F2951693F3172183F3952BF3F40F7303F4862EB3F4F991F3F569CBE3F5D70793F6416CD3F6A92083F70E4493F770F8B3F7D15A33F817C243F845C873F872CBC3F89ED733F8C9F543F8F42FB3F91D8FC3F9461E03F96DE2B3F994E573F9BB2D83F9E0C1B3FA05A893FA29E843FA4D8693FA7088F3FA92F4C3FAB4CED3FAD61C13FAF6E0D3FB172183FB36E233FB5626B3FB74F2E3FB934A43FBB13043FBCEA813FBEBB4F3FC0859C3FC249963FC4076B3FC5BF433FC771483FC91DA13FCAC4733FCC65E13FCE02103FCF991F3FD12B303FD2B8623FD440D13FD5C49C3FD743DD3FD8BEB13FDA352F3FDBA7733FDD15933FDE7FA83FDFE5C83FE148083FE2A67F3FE401403FE558603FE6ABF13FE7FC073FE948B33FEA92083FEBD8153FED1AEC3FEE5A9D3FEF97373FF0D0C9"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x01010178030161C0062E42FEFA39EF0162C000A2B23F3BAB730163BFFAC89B834770D4"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x01020178017906016103626172C000A2B23F3BAB73016103666F6FC0062E42FEFA39EF016203626172BFF62E42FEFA39EF016203666F6FBFFAC89B834770D4016303626172BFEF62F40794A7B8016303666F6FBFF29C440606E6AB"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFF29C440606E6AB016103626172016ABFEF62F40794A7B8016103626172016BBFEA74269F84330E016103626172016CBFE62E42FEFA39EF016103666F6F0169C0062E42FEFA39EF016103666F6F016AC000A2B23F3BAB73016103666F6F016BBFFAC89B834770D4016103666F6F016CBFF62E42FEFA39EF0162036261720169BFCA93ED3C8AD9E3016203626172016ABFC1178E8227E47C016203626172016BBFB08598B59E3A07016203626172016C0000000000000000016203666F6F0169BFE269621134DB92016203666F6F016ABFDE148A1A2726CE016203666F6F016BBFD7FAFA3BD8151C016203666F6F016CBFD269621134DB9201630362617201693FD1675CABABA60E016303626172016A3FD4618BC21C5EC2016303626172016B3FD739D7F6BBD007016303626172016C3FD9F323ECBF984C016303666F6F01693FAF0A30C01162A6016303666F6F016A3FBE27076E2AF2E6016303666F6F016B3FC5FF3070A793D4016303666F6F016C3FCC8FF7C79A9A22"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A180161036261720169BF94E220016103626172016ABF7B17A0016103626172016BBF53A135016103626172016CBF317218016103666F6F0169C0317218016103666F6F016AC0051592016103666F6F016BBFD644DC016103666F6F016CBFB172180162036261720169BE549F6A016203626172016ABE08BC74016203626172016BBD842CC6016203626172016C00000000016203666F6F0169BF134B11016203666F6F016ABEF0A451016203666F6F016BBEBFD7D2016203666F6F016CBE934B1101630362617201693E8B3AE5016303626172016A3EA30C5E016303626172016B3EB9CEC0016303626172016C3ECF991F016303666F6F01693D785186016303666F6F016A3DF1383B016303666F6F016B3E2FF984016303666F6F016C3E647FBE"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFE62E42FEFA39EFBFE269621134DB92BFDE148A1A2726CEBFD7FAFA3BD8151CBFD269621134DB92BFCA93ED3C8AD9E3BFC1178E8227E47C3FD4618BC21C5EC23FD739D7F6BBD0073FD9F323ECBF984C3FDC8FF7C79A9A223FDF128F5FAF06ED3FE0BE72E4252A833FE1E85F5E7040D03FE9F323ECBF984C3FEAD397BD0237383FEBAE0F1B241EE43FEC82D9A6374F9C3FED5240F0E0E0783FEE1C891A51C97A3FEEE1F154D00CF603666F6FC0062E42FEFA39EFC000A2B23F3BAB73BFFAC89B834770D4BFF62E42FEFA39EFBFF29C440606E6ABBFEF62F40794A7B8BFEA74269F84330EBFB08598B59E3A0700000000000000003FAF0A30C01162A63FBE27076E2AF2E63FC5FF3070A793D43FCC8FF7C79A9A223FD1675CABABA60E3FE307D7334F10BE3FE41D8FE84672AE3FE52A2D265BC5AB3FE62E42FEFA39EF3FE72A57D76DFB873FE81EE60AFB501A3FE90C5D5056E759"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C01610169C0062E42FEFA39EFBFF29C440606E6ABBFE269621134DB92BFCA93ED3C8AD9E33FAF0A30C01162A60161016AC000A2B23F3BAB73BFEF62F40794A7B8BFDE148A1A2726CEBFC1178E8227E47C3FBE27076E2AF2E60161016BBFFAC89B834770D4BFEA74269F84330EBFD7FAFA3BD8151CBFB08598B59E3A073FC5FF3070A793D40161016CBFF62E42FEFA39EFBFE62E42FEFA39EFBFD269621134DB9200000000000000003FCC8FF7C79A9A22016201693FD1675CABABA60E3FDC8FF7C79A9A223FE307D7334F10BE3FE72A57D76DFB873FEAD397BD0237380162016A3FD4618BC21C5EC23FDF128F5FAF06ED3FE41D8FE84672AE3FE81EE60AFB501A3FEBAE0F1B241EE40162016B3FD739D7F6BBD0073FE0BE72E4252A833FE52A2D265BC5AB3FE90C5D5056E7593FEC82D9A6374F9C0162016C3FD9F323ECBF984C3FE1E85F5E7040D03FE62E42FEFA39EF3FE9F323ECBF984C3FED5240F0E0E078016301693FEE1C891A51C97A3FF08B90EF531F6A3FF1E85F5E7040D03FF329CAD25005773FF453D088C1F5850163016A3FEEE1F154D00CF63FF0E5977D2C10F93FF23B1F7163C3803FF3765AF18FB2393FF49B0D1924A5570163016B3FEFA2B45C6AC8883FF13DAE612D6D8E3FF28C3C00AD8E203FF3C18368F787EC3FF4E111E92832040163016C3FF02F84700434A83FF193EA7AAD030B3FF2DBC55768DEB33FF40B512EB53D603FF525E973A0564F"}}
-{"expression":"map(a,f(a)(log(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169C0317218BF94E220BF134B11BE549F6A3D7851860161016AC0051592BF7B17A0BEF0A451BE08BC743DF1383B0161016BBFD644DCBF53A135BEBFD7D2BD842CC63E2FF9840161016CBFB17218BF317218BE934B11000000003E647FBE016201693E8B3AE53EE47FBE3F183EBA3F3952BF3F569CBE0162016A3EA30C5E3EF8947B3F20EC7F3F40F7303F5D70790162016B3EB9CEC03F05F3973F2951693F4862EB3F6416CD0162016C3ECF991F3F0F42FB3F3172183F4F991F3F6A9208016301693F70E4493F845C873F8F42FB3F994E573FA29E840163016A3F770F8B3F872CBC3F91D8FC3F9BB2D83FA4D8690163016B3F7D15A33F89ED733F9461E03F9E0C1B3FA7088F0163016C3F817C243F8C9F543F96DE2B3FA05A893FA92F4C"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FD0000000000000"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FEEFBDEB14F4EDA"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FEEFBDEB14F4EDA3FF00000000000003FF07E0F66AFED073FF0F876CCDF6CD93FF16F8334644DF93FF1E3779B97F4A83FF2548EB9151E853FF2C2FC595456A73FF32EEE757704163FF3988E1409212E3FF40000000000003FF465655F122FF63FF4C8DC2E4239803FF52A7FA9D2F8EA3FF58A68A4A8D9F33FF5E8ADD236A58F3FF645640568C1C33FF6A09E667F3BCD3FF6FA6EA162D0F03FF752E50DB3A3A23FF7AA10D193C22D3FF80000000000003FF854BFB363DC393FF8A85C24F706593FF8FAE0C15AD38A3FF94C583ADA5B533FF99CCC999FFF003FF9EC474A2612643FFA3AD12A1DA1603FFA887293FD6F343FFAD5336963EEFC3FFB211B1C70D0233FFB6C30B83593E63FFBB67AE8584CAA3FFC0000000000003FFC48C6001F0AC03FFC90D29D2D43CE3FFCD82B446159F33FFD1ED52076FBE93FFD64D51E0DB1C63FFDAA2FEFAAE1D83FFDEEEA11683F493FFE3307CC56CF5C3FFE768D399DC4703FFEB97E455B9EDB3FFEFBDEB14F4EDA3FFF3DB2174E74683FFF7EFBEB8D4F123FFFBFBF7EBC755F400000000000000040001FE03F61BAD040003F81F636B80C40005EE68EFAD48B40007E0F66AFED0740009CFDCD8ED0094000BBB307ACAFDB4000DA304D95FB064000F876CCDF6CD940011687A8AE14A340013463FA37014E4001520CD1372FEB40016F8334644DF940018CC821D6D3E34001A9DC8F6DF1044001C6C16B2DB8704001E3779B97F4A8400200000000000040021C5B70D9F8244002388AC0059C284002548EB9151E854002706821902E9A40028C17B93378344002A79E3A2CD2E64002C2FC595456A74002DE32C66287414002F9422C23C47E4003142B30A929AB40032EEE757704164003498C97B10540400364063044530640037E5BD40F95A14003988E1409212E4003B29D7D6356624003CC8A99AF54534003E655EEFE13674004000000000000400419894C2329F0400432F24FB01C7A40044C3B83E57153400465655F122FF640047E7054AF0989"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073E8000003EB504F33EDDB3D73F0000003F0F1BBD3F1CC4713F2953FD3F3504F33F4000003F4A62C23F5443953F5DB3D73F66C15A3F6F77513F77DEF63F8000003F83F07B3F87C3B63F8B7C1A3F8F1BBD3F92A4763F9617E33F9977743F9CC4713FA000003FA32B2B3FA646E13FA953FD3FAC53453FAF456F3FB22B203FB504F33FB7D3753FBA97283FBD50873FC000003FC2A5FE3FC542E13FC7D7063FCA62C23FCCE6653FCF623A3FD1D6893FD443953FD6A99B3FD908D93FDB61863FDDB3D73FE000003FE246303FE486953FE6C15A3FE8F6A93FEB26A93FED517F3FEF77513FF1983E3FF3B46A3FF5CBF23FF7DEF63FF9ED913FFBF7DF3FFDFDFC400000004000FF024001FC104002F7344003F07B4004E7EE4005DD984006D1824007C3B64008B43D4009A320400A9067400B7C1A400C6641400D4EE4400E360B400F1BBD401000004010E2DC4011C4564012A47640138341401460BE40153CF2401617E34016F1964017CA114018A15A40197774401A4C65401B2032401BF2DF401CC471401D94EC401E6455401F32AF402000004020CC4A40219792402261DC40232B2B4023F383"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FD000000000000001623FD6A09E667F3BCD01633FDBB67AE8584CAA"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FD6A09E667F3BCD016103666F6F3FD00000000000000162036261723FE0000000000000016203666F6F3FDBB67AE8584CAA0163036261723FE3988E1409212E016303666F6F3FE1E3779B97F4A8"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FE1E3779B97F4A8016103626172016A3FE3988E1409212E016103626172016B3FE52A7FA9D2F8EA016103626172016C3FE6A09E667F3BCD016103666F6F01693FD0000000000000016103666F6F016A3FD6A09E667F3BCD016103666F6F016B3FDBB67AE8584CAA016103666F6F016C3FE000000000000001620362617201693FECD82B446159F3016203626172016A3FEDEEEA11683F49016203626172016B3FEEFBDEB14F4EDA016203626172016C3FF0000000000000016203666F6F01693FE8000000000000016203666F6F016A3FE94C583ADA5B53016203666F6F016B3FEA887293FD6F34016203666F6F016C3FEBB67AE8584CAA01630362617201693FF2548EB9151E85016303626172016A3FF2C2FC595456A7016303626172016B3FF32EEE75770416016303626172016C3FF3988E1409212E016303666F6F01693FF07E0F66AFED07016303666F6F016A3FF0F876CCDF6CD9016303666F6F016B3FF16F8334644DF9016303666F6F016C3FF1E3779B97F4A8"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F0F1BBD016103626172016A3F1CC471016103626172016B3F2953FD016103626172016C3F3504F3016103666F6F01693E800000016103666F6F016A3EB504F3016103666F6F016B3EDDB3D7016103666F6F016C3F00000001620362617201693F66C15A016203626172016A3F6F7751016203626172016B3F77DEF6016203626172016C3F800000016203666F6F01693F400000016203666F6F016A3F4A62C2016203666F6F016B3F544395016203666F6F016C3F5DB3D701630362617201693F92A476016303626172016A3F9617E3016303626172016B3F997774016303626172016C3F9CC471016303666F6F01693F83F07B016303666F6F016A3F87C3B6016303666F6F016B3F8B7C1A016303666F6F016C3F8F1BBD"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FF2C2FC595456A73FF32EEE757704163FF3988E1409212E3FF40000000000003FF465655F122FF63FF4C8DC2E4239803FF52A7FA9D2F8EA3FF80000000000003FF854BFB363DC393FF8A85C24F706593FF8FAE0C15AD38A3FF94C583ADA5B533FF99CCC999FFF003FF9EC474A26126403666F6F3FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FEEFBDEB14F4EDA3FF00000000000003FF07E0F66AFED073FF0F876CCDF6CD93FF16F8334644DF93FF1E3779B97F4A83FF2548EB9151E853FF58A68A4A8D9F33FF5E8ADD236A58F3FF645640568C1C33FF6A09E667F3BCD3FF6FA6EA162D0F03FF752E50DB3A3A23FF7AA10D193C22D"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FD00000000000003FE1E3779B97F4A83FE80000000000003FECD82B446159F33FF07E0F66AFED070161016A3FD6A09E667F3BCD3FE3988E1409212E3FE94C583ADA5B533FEDEEEA11683F493FF0F876CCDF6CD90161016B3FDBB67AE8584CAA3FE52A7FA9D2F8EA3FEA887293FD6F343FEEFBDEB14F4EDA3FF16F8334644DF90161016C3FE00000000000003FE6A09E667F3BCD3FEBB67AE8584CAA3FF00000000000003FF1E3779B97F4A8016201693FF2548EB9151E853FF40000000000003FF58A68A4A8D9F33FF6FA6EA162D0F03FF854BFB363DC390162016A3FF2C2FC595456A73FF465655F122FF63FF5E8ADD236A58F3FF752E50DB3A3A23FF8A85C24F706590162016B3FF32EEE757704163FF4C8DC2E4239803FF645640568C1C33FF7AA10D193C22D3FF8FAE0C15AD38A0162016C3FF3988E1409212E3FF52A7FA9D2F8EA3FF6A09E667F3BCD3FF80000000000003FF94C583ADA5B53016301693FF99CCC999FFF003FFAD5336963EEFC3FFC0000000000003FFD1ED52076FBE93FFE3307CC56CF5C0163016A3FF9EC474A2612643FFB211B1C70D0233FFC48C6001F0AC03FFD64D51E0DB1C63FFE768D399DC4700163016B3FFA3AD12A1DA1603FFB6C30B83593E63FFC90D29D2D43CE3FFDAA2FEFAAE1D83FFEB97E455B9EDB0163016C3FFA887293FD6F343FFBB67AE8584CAA3FFCD82B446159F33FFDEEEA11683F493FFEFBDEB14F4EDA"}}
-{"expression":"sqrt(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693E8000003F0F1BBD3F4000003F66C15A3F83F07B0161016A3EB504F33F1CC4713F4A62C23F6F77513F87C3B60161016B3EDDB3D73F2953FD3F5443953F77DEF63F8B7C1A0161016C3F0000003F3504F33F5DB3D73F8000003F8F1BBD016201693F92A4763FA000003FAC53453FB7D3753FC2A5FE0162016A3F9617E33FA32B2B3FAF456F3FBA97283FC542E10162016B3F9977743FA646E13FB22B203FBD50873FC7D7060162016C3F9CC4713FA953FD3FB504F33FC000003FCA62C2016301693FCCE6653FD6A99B3FE000003FE8F6A93FF1983E0163016A3FCF623A3FD908D93FE246303FEB26A93FF3B46A0163016B3FD1D6893FDB61863FE486953FED517F3FF5CBF20163016C3FD443953FDDB3D73FE6C15A3FEF77513FF7DEF6"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FD0000000000000"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FEEFBDEB14F4EDA"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FEEFBDEB14F4EDA3FF00000000000003FF07E0F66AFED073FF0F876CCDF6CD93FF16F8334644DF93FF1E3779B97F4A83FF2548EB9151E853FF2C2FC595456A73FF32EEE757704163FF3988E1409212E3FF40000000000003FF465655F122FF63FF4C8DC2E4239803FF52A7FA9D2F8EA3FF58A68A4A8D9F33FF5E8ADD236A58F3FF645640568C1C33FF6A09E667F3BCD3FF6FA6EA162D0F03FF752E50DB3A3A23FF7AA10D193C22D3FF80000000000003FF854BFB363DC393FF8A85C24F706593FF8FAE0C15AD38A3FF94C583ADA5B533FF99CCC999FFF003FF9EC474A2612643FFA3AD12A1DA1603FFA887293FD6F343FFAD5336963EEFC3FFB211B1C70D0233FFB6C30B83593E63FFBB67AE8584CAA3FFC0000000000003FFC48C6001F0AC03FFC90D29D2D43CE3FFCD82B446159F33FFD1ED52076FBE93FFD64D51E0DB1C63FFDAA2FEFAAE1D83FFDEEEA11683F493FFE3307CC56CF5C3FFE768D399DC4703FFEB97E455B9EDB3FFEFBDEB14F4EDA3FFF3DB2174E74683FFF7EFBEB8D4F123FFFBFBF7EBC755F400000000000000040001FE03F61BAD040003F81F636B80C40005EE68EFAD48B40007E0F66AFED0740009CFDCD8ED0094000BBB307ACAFDB4000DA304D95FB064000F876CCDF6CD940011687A8AE14A340013463FA37014E4001520CD1372FEB40016F8334644DF940018CC821D6D3E34001A9DC8F6DF1044001C6C16B2DB8704001E3779B97F4A8400200000000000040021C5B70D9F8244002388AC0059C284002548EB9151E854002706821902E9A40028C17B93378344002A79E3A2CD2E64002C2FC595456A74002DE32C66287414002F9422C23C47E4003142B30A929AB40032EEE757704164003498C97B10540400364063044530640037E5BD40F95A14003988E1409212E4003B29D7D6356624003CC8A99AF54534003E655EEFE13674004000000000000400419894C2329F0400432F24FB01C7A40044C3B83E57153400465655F122FF640047E7054AF0989"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073E8000003EB504F33EDDB3D73F0000003F0F1BBD3F1CC4713F2953FD3F3504F33F4000003F4A62C23F5443953F5DB3D73F66C15A3F6F77513F77DEF63F8000003F83F07B3F87C3B63F8B7C1A3F8F1BBD3F92A4763F9617E33F9977743F9CC4713FA000003FA32B2B3FA646E13FA953FD3FAC53453FAF456F3FB22B203FB504F33FB7D3753FBA97283FBD50873FC000003FC2A5FE3FC542E13FC7D7063FCA62C23FCCE6653FCF623A3FD1D6893FD443953FD6A99B3FD908D93FDB61863FDDB3D73FE000003FE246303FE486953FE6C15A3FE8F6A93FEB26A93FED517F3FEF77513FF1983E3FF3B46A3FF5CBF23FF7DEF63FF9ED913FFBF7DF3FFDFDFC400000004000FF024001FC104002F7344003F07B4004E7EE4005DD984006D1824007C3B64008B43D4009A320400A9067400B7C1A400C6641400D4EE4400E360B400F1BBD401000004010E2DC4011C4564012A47640138341401460BE40153CF2401617E34016F1964017CA114018A15A40197774401A4C65401B2032401BF2DF401CC471401D94EC401E6455401F32AF402000004020CC4A40219792402261DC40232B2B4023F383"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FD000000000000001623FD6A09E667F3BCD01633FDBB67AE8584CAA"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FD6A09E667F3BCD016103666F6F3FD00000000000000162036261723FE0000000000000016203666F6F3FDBB67AE8584CAA0163036261723FE3988E1409212E016303666F6F3FE1E3779B97F4A8"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FE1E3779B97F4A8016103626172016A3FE3988E1409212E016103626172016B3FE52A7FA9D2F8EA016103626172016C3FE6A09E667F3BCD016103666F6F01693FD0000000000000016103666F6F016A3FD6A09E667F3BCD016103666F6F016B3FDBB67AE8584CAA016103666F6F016C3FE000000000000001620362617201693FECD82B446159F3016203626172016A3FEDEEEA11683F49016203626172016B3FEEFBDEB14F4EDA016203626172016C3FF0000000000000016203666F6F01693FE8000000000000016203666F6F016A3FE94C583ADA5B53016203666F6F016B3FEA887293FD6F34016203666F6F016C3FEBB67AE8584CAA01630362617201693FF2548EB9151E85016303626172016A3FF2C2FC595456A7016303626172016B3FF32EEE75770416016303626172016C3FF3988E1409212E016303666F6F01693FF07E0F66AFED07016303666F6F016A3FF0F876CCDF6CD9016303666F6F016B3FF16F8334644DF9016303666F6F016C3FF1E3779B97F4A8"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F0F1BBD016103626172016A3F1CC471016103626172016B3F2953FD016103626172016C3F3504F3016103666F6F01693E800000016103666F6F016A3EB504F3016103666F6F016B3EDDB3D7016103666F6F016C3F00000001620362617201693F66C15A016203626172016A3F6F7751016203626172016B3F77DEF6016203626172016C3F800000016203666F6F01693F400000016203666F6F016A3F4A62C2016203666F6F016B3F544395016203666F6F016C3F5DB3D701630362617201693F92A476016303626172016A3F9617E3016303626172016B3F997774016303626172016C3F9CC471016303666F6F01693F83F07B016303666F6F016A3F87C3B6016303666F6F016B3F8B7C1A016303666F6F016C3F8F1BBD"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE6A09E667F3BCD3FE80000000000003FE94C583ADA5B533FEA887293FD6F343FEBB67AE8584CAA3FECD82B446159F33FEDEEEA11683F493FF2C2FC595456A73FF32EEE757704163FF3988E1409212E3FF40000000000003FF465655F122FF63FF4C8DC2E4239803FF52A7FA9D2F8EA3FF80000000000003FF854BFB363DC393FF8A85C24F706593FF8FAE0C15AD38A3FF94C583ADA5B533FF99CCC999FFF003FF9EC474A26126403666F6F3FD00000000000003FD6A09E667F3BCD3FDBB67AE8584CAA3FE00000000000003FE1E3779B97F4A83FE3988E1409212E3FE52A7FA9D2F8EA3FEEFBDEB14F4EDA3FF00000000000003FF07E0F66AFED073FF0F876CCDF6CD93FF16F8334644DF93FF1E3779B97F4A83FF2548EB9151E853FF58A68A4A8D9F33FF5E8ADD236A58F3FF645640568C1C33FF6A09E667F3BCD3FF6FA6EA162D0F03FF752E50DB3A3A23FF7AA10D193C22D"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FD00000000000003FE1E3779B97F4A83FE80000000000003FECD82B446159F33FF07E0F66AFED070161016A3FD6A09E667F3BCD3FE3988E1409212E3FE94C583ADA5B533FEDEEEA11683F493FF0F876CCDF6CD90161016B3FDBB67AE8584CAA3FE52A7FA9D2F8EA3FEA887293FD6F343FEEFBDEB14F4EDA3FF16F8334644DF90161016C3FE00000000000003FE6A09E667F3BCD3FEBB67AE8584CAA3FF00000000000003FF1E3779B97F4A8016201693FF2548EB9151E853FF40000000000003FF58A68A4A8D9F33FF6FA6EA162D0F03FF854BFB363DC390162016A3FF2C2FC595456A73FF465655F122FF63FF5E8ADD236A58F3FF752E50DB3A3A23FF8A85C24F706590162016B3FF32EEE757704163FF4C8DC2E4239803FF645640568C1C33FF7AA10D193C22D3FF8FAE0C15AD38A0162016C3FF3988E1409212E3FF52A7FA9D2F8EA3FF6A09E667F3BCD3FF80000000000003FF94C583ADA5B53016301693FF99CCC999FFF003FFAD5336963EEFC3FFC0000000000003FFD1ED52076FBE93FFE3307CC56CF5C0163016A3FF9EC474A2612643FFB211B1C70D0233FFC48C6001F0AC03FFD64D51E0DB1C63FFE768D399DC4700163016B3FFA3AD12A1DA1603FFB6C30B83593E63FFC90D29D2D43CE3FFDAA2FEFAAE1D83FFEB97E455B9EDB0163016C3FFA887293FD6F343FFBB67AE8584CAA3FFCD82B446159F33FFDEEEA11683F493FFEFBDEB14F4EDA"}}
-{"expression":"map(a,f(a)(sqrt(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693E8000003F0F1BBD3F4000003F66C15A3F83F07B0161016A3EB504F33F1CC4713F4A62C23F6F77513F87C3B60161016B3EDDB3D73F2953FD3F5443953F77DEF63F8B7C1A0161016C3F0000003F3504F33F5DB3D73F8000003F8F1BBD016201693F92A4763FA000003FAC53453FB7D3753FC2A5FE0162016A3F9617E33FA32B2B3FAF456F3FBA97283FC542E10162016B3F9977743FA646E13FB22B203FBD50873FC7D7060162016C3F9CC4713FA953FD3FB504F33FC000003FCA62C2016301693FCCE6653FD6A99B3FE000003FE8F6A93FF1983E0163016A3FCF623A3FD908D93FE246303FEB26A93FF3B46A0163016B3FD1D6893FDB61863FE486953FED517F3FF5CBF20163016C3FD443953FDDB3D73FE6C15A3FEF77513FF7DEF6"}}
-{"expression":"ceil(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E00000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201694000000000000000016303626172016A4000000000000000016303626172016B4000000000000000016303626172016C4000000000000000016303666F6F01694000000000000000016303666F6F016A4000000000000000016303666F6F016B4000000000000000016303666F6F016C4000000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F01693F800000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F80000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C3F800000016303626172016940000000016303626172016A40000000016303626172016B40000000016303626172016C40000000016303666F6F016940000000016303666F6F016A40000000016303666F6F016B40000000016303666F6F016C40000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000003666F6F3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000001620169400000000000000040000000000000004000000000000000400800000000000040080000000000000162016A400000000000000040000000000000004000000000000000400800000000000040080000000000000162016B400000000000000040000000000000004000000000000000400800000000000040080000000000000162016C4000000000000000400000000000000040000000000000004008000000000000400800000000000001630169400800000000000040080000000000004010000000000000401000000000000040100000000000000163016A400800000000000040080000000000004010000000000000401000000000000040100000000000000163016B400800000000000040080000000000004010000000000000401000000000000040100000000000000163016C40080000000000004008000000000000401000000000000040100000000000004010000000000000"}}
-{"expression":"ceil(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F8000003F8000003F800000400000000161016A3F8000003F8000003F8000003F800000400000000161016B3F8000003F8000003F8000003F800000400000000161016C3F8000003F8000003F8000003F800000400000000162016940000000400000004000000040400000404000000162016A40000000400000004000000040400000404000000162016B40000000400000004000000040400000404000000162016C40000000400000004000000040400000404000000163016940400000404000004080000040800000408000000163016A40400000404000004080000040800000408000000163016B40400000404000004080000040800000408000000163016C4040000040400000408000004080000040800000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000401C000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E0000040E00000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201694000000000000000016303626172016A4000000000000000016303626172016B4000000000000000016303626172016C4000000000000000016303666F6F01694000000000000000016303666F6F016A4000000000000000016303666F6F016B4000000000000000016303666F6F016C4000000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F01693F800000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F80000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C3F800000016303626172016940000000016303626172016A40000000016303626172016B40000000016303626172016C40000000016303666F6F016940000000016303666F6F016A40000000016303666F6F016B40000000016303666F6F016C40000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000003666F6F3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000001620169400000000000000040000000000000004000000000000000400800000000000040080000000000000162016A400000000000000040000000000000004000000000000000400800000000000040080000000000000162016B400000000000000040000000000000004000000000000000400800000000000040080000000000000162016C4000000000000000400000000000000040000000000000004008000000000000400800000000000001630169400800000000000040080000000000004010000000000000401000000000000040100000000000000163016A400800000000000040080000000000004010000000000000401000000000000040100000000000000163016B400800000000000040080000000000004010000000000000401000000000000040100000000000000163016C40080000000000004008000000000000401000000000000040100000000000004010000000000000"}}
-{"expression":"map(a,f(a)(ceil(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F8000003F8000003F800000400000000161016A3F8000003F8000003F8000003F800000400000000161016B3F8000003F8000003F8000003F800000400000000161016C3F8000003F8000003F8000003F800000400000000162016940000000400000004000000040400000404000000162016A40000000400000004000000040400000404000000162016B40000000400000004000000040400000404000000162016C40000000400000004000000040400000404000000163016940400000404000004080000040800000408000000163016A40400000404000004080000040800000408000000163016B40400000404000004080000040800000408000000163016C4040000040400000408000004080000040800000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"}}
-{"expression":"fabs(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"}}
-{"expression":"map(a,f(a)(fabs(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"}}
-{"expression":"floor(a)","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803000000000000000000000000000000000000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C00000"}}
-{"expression":"floor(a)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C0000000001630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"}}
-{"expression":"floor(a)","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000003666F6F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000004000000000000000400000000000000040000000000000004000000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016B00000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016A3FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016B3FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016C3FF00000000000003FF000000000000040000000000000004000000000000000400000000000000001630169400000000000000040000000000000004008000000000000400800000000000040080000000000000163016A400000000000000040000000000000004008000000000000400800000000000040080000000000000163016B400000000000000040000000000000004008000000000000400800000000000040080000000000000163016C40000000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"floor(a)","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169000000000000000000000000000000003F8000000161016A000000000000000000000000000000003F8000000161016B000000000000000000000000000000003F8000000161016C0000000000000000000000003F8000003F800000016201693F8000003F8000003F80000040000000400000000162016A3F8000003F8000003F80000040000000400000000162016B3F8000003F8000003F80000040000000400000000162016C3F8000003F8000004000000040000000400000000163016940000000400000004040000040400000404000000163016A40000000400000004040000040400000404000000163016B40000000400000004040000040400000404000000163016C4000000040400000404000004040000040400000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000400800000000000040080000000000004008000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040100000000000004010000000000000401000000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004014000000000000401400000000000040140000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000401800000000000040180000000000004018000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000400000004000000040000000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004040000040400000404000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040800000408000004080000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040A0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C0000040C00000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201693FF0000000000000016303626172016A3FF0000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B3FF0000000000000016303666F6F016C3FF0000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C0000000001630362617201693F800000016303626172016A3F800000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B3F800000016303666F6F016C3F800000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000004000000000000000400000000000000040000000000000004000000000000000400000000000000003666F6F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000004000000000000000400000000000000040000000000000004000000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016B00000000000000000000000000000000000000000000000000000000000000003FF00000000000000161016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016A3FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016B3FF00000000000003FF00000000000003FF0000000000000400000000000000040000000000000000162016C3FF00000000000003FF000000000000040000000000000004000000000000000400000000000000001630169400000000000000040000000000000004008000000000000400800000000000040080000000000000163016A400000000000000040000000000000004008000000000000400800000000000040080000000000000163016B400000000000000040000000000000004008000000000000400800000000000040080000000000000163016C40000000000000004008000000000000400800000000000040080000000000004008000000000000"}}
-{"expression":"map(a,f(a)(floor(a)))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C01610169000000000000000000000000000000003F8000000161016A000000000000000000000000000000003F8000000161016B000000000000000000000000000000003F8000000161016C0000000000000000000000003F8000003F800000016201693F8000003F8000003F80000040000000400000000162016A3F8000003F8000003F80000040000000400000000162016B3F8000003F8000003F80000040000000400000000162016C3F8000003F8000004000000040000000400000000163016940000000400000004040000040400000404000000163016A40000000400000004040000040400000404000000163016B40000000400000004040000040400000404000000163016C4000000040400000404000004040000040400000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x02007FF8000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x02010178037FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x02020178030179057FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02020178030179053FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x0203017803017905017A077FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A073FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x060103017803017905017A077FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F800000"},"result":{"expect":"0x060103017803017905017A073F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F8000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x010101780301617FF800000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x010201780179060161036261723FF0000000000000016103666F6F7FF80000000000000162036261727FF8000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B7FF8000000000000016103626172016C3FF0000000000000016103666F6F01697FF8000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C7FF800000000000001620362617201697FF8000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C7FF8000000000000016203666F6F01693FF0000000000000016203666F6F016A7FF8000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201693FF0000000000000016303626172016A7FF8000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B7FF8000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A3FF0000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B3FF0000000000000016303666F6F016C0000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B7FC00000016103626172016C3F800000016103666F6F01697FC00000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C7FC0000001620362617201697FC00000016203626172016A3F800000016203626172016B3F800000016203626172016C7FC00000016203666F6F01693F800000016203666F6F016A7FC00000016203666F6F016B3F800000016203666F6F016C3F80000001630362617201693F800000016303626172016A7FC00000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B7FC00000016303666F6F016C3F800000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C3F80000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A3F800000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B3F800000016303666F6F016C00000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF000000000000003666F6F7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF0000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x03020178017A010179050C016101697FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000161016A3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000161016B3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000161016C7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF0000000000000016201693FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000162016A7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000162016B3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000162016C3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF8000000000000016301693FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000163016A3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000163016B7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000163016C3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016B00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016C3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016C00000000000000003FF0000000000000000000000000000000000000000000003FF000000000000001630169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"isNan(a)","inputs":{"a":"0x0701020178017A010179050C016101697FC000003F8000003F8000007FC000003F8000000161016A3F8000003F8000007FC000003F8000003F8000000161016B3F8000007FC000003F8000003F8000007FC000000161016C7FC000003F8000003F8000007FC000003F800000016201693F8000007FC000003F8000003F8000007FC000000162016A7FC000003F8000003F8000007FC000003F8000000162016B3F8000003F8000007FC000003F8000003F8000000162016C3F8000007FC000003F8000003F8000007FC00000016301693F8000003F8000007FC000003F8000003F8000000163016A3F8000007FC000003F8000003F8000007FC000000163016B7FC000003F8000003F8000007FC000003F8000000163016C3F8000003F8000007FC000003F8000003F800000"},"result":{"expect":"0x0701020178017A010179050C016101693F80000000000000000000003F800000000000000161016A00000000000000003F80000000000000000000000161016B000000003F80000000000000000000003F8000000161016C3F80000000000000000000003F8000000000000001620169000000003F80000000000000000000003F8000000162016A3F80000000000000000000003F800000000000000162016B00000000000000003F80000000000000000000000162016C000000003F80000000000000000000003F8000000163016900000000000000003F80000000000000000000000163016A000000003F80000000000000000000003F8000000163016B3F80000000000000000000003F800000000000000163016C00000000000000003F8000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x02007FF8000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x02010178037FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x02020178030179057FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x02020178030179053FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x0203017803017905017A077FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A073FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x060103017803017905017A077FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F8000007FC000003F8000003F800000"},"result":{"expect":"0x060103017803017905017A073F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F80000000000000000000003F8000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x010101780301617FF800000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x010201780179060161036261723FF0000000000000016103666F6F7FF80000000000000162036261727FF8000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B7FF8000000000000016103626172016C3FF0000000000000016103666F6F01697FF8000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C7FF800000000000001620362617201697FF8000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C7FF8000000000000016203666F6F01693FF0000000000000016203666F6F016A7FF8000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF000000000000001630362617201693FF0000000000000016303626172016A7FF8000000000000016303626172016B3FF0000000000000016303626172016C3FF0000000000000016303666F6F01693FF0000000000000016303666F6F016A3FF0000000000000016303666F6F016B7FF8000000000000016303666F6F016C3FF0000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A3FF0000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B3FF0000000000000016303666F6F016C0000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x05010301780179017A1801610362617201693F800000016103626172016A3F800000016103626172016B7FC00000016103626172016C3F800000016103666F6F01697FC00000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C7FC0000001620362617201697FC00000016203626172016A3F800000016203626172016B3F800000016203626172016C7FC00000016203666F6F01693F800000016203666F6F016A7FC00000016203666F6F016B3F800000016203666F6F016C3F80000001630362617201693F800000016303626172016A7FC00000016303626172016B3F800000016303626172016C3F800000016303666F6F01693F800000016303666F6F016A3F800000016303666F6F016B7FC00000016303666F6F016C3F800000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C3F80000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A3F800000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B3F800000016303666F6F016C00000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF000000000000003666F6F7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF0000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x03020178017A010179050C016101697FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000161016A3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000161016B3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000161016C7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF0000000000000016201693FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000162016A7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000162016B3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000162016C3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF8000000000000016301693FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF00000000000000163016A3FF00000000000007FF80000000000003FF00000000000003FF00000000000007FF80000000000000163016B7FF80000000000003FF00000000000003FF00000000000007FF80000000000003FF00000000000000163016C3FF00000000000003FF00000000000007FF80000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016B00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016C3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016C00000000000000003FF0000000000000000000000000000000000000000000003FF000000000000001630169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(isNan(a)))","inputs":{"a":"0x0701020178017A010179050C016101697FC000003F8000003F8000007FC000003F8000000161016A3F8000003F8000007FC000003F8000003F8000000161016B3F8000007FC000003F8000003F8000007FC000000161016C7FC000003F8000003F8000007FC000003F800000016201693F8000007FC000003F8000003F8000007FC000000162016A7FC000003F8000003F8000007FC000003F8000000162016B3F8000003F8000007FC000003F8000003F8000000162016C3F8000007FC000003F8000003F8000007FC00000016301693F8000003F8000007FC000003F8000003F8000000163016A3F8000007FC000003F8000003F8000007FC000000163016B7FC000003F8000003F8000007FC000003F8000000163016C3F8000003F8000007FC000003F8000003F800000"},"result":{"expect":"0x0701020178017A010179050C016101693F80000000000000000000003F800000000000000161016A00000000000000003F80000000000000000000000161016B000000003F80000000000000000000003F8000000161016C3F80000000000000000000003F8000000000000001620169000000003F80000000000000000000003F8000000162016A3F80000000000000000000003F800000000000000162016B00000000000000003F80000000000000000000000162016C000000003F80000000000000000000003F8000000163016900000000000000003F80000000000000000000000163016A000000003F80000000000000000000003F8000000163016B3F80000000000000000000003F800000000000000163016C00000000000000003F8000000000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x0201017803000000000000000000000000000000000000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x0202017803017905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"}}
-{"expression":"relu(a)","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A0000000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B0000000000000000016303666F6F016C0000000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A00000000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B00000000016303666F6F016C00000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201690000000000000000000000000000000000000000000000003FB00000000000003FD40000000000000162016A0000000000000000000000000000000000000000000000003FC00000000000003FD80000000000000162016B0000000000000000000000000000000000000000000000003FC80000000000003FDC0000000000000162016C0000000000000000000000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"}}
-{"expression":"relu(a)","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201690000000000000000000000003D8000003EA000000162016A0000000000000000000000003E0000003EC000000162016B0000000000000000000000003E4000003EE000000162016C0000000000000000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x0201017803000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x0202017803017905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F0000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A0000000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B0000000000000000016303666F6F016C0000000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A18016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A00000000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B00000000016303666F6F016C00000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201690000000000000000000000000000000000000000000000003FB00000000000003FD40000000000000162016A0000000000000000000000000000000000000000000000003FC00000000000003FD80000000000000162016B0000000000000000000000000000000000000000000000003FC80000000000003FDC0000000000000162016C0000000000000000000000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"}}
-{"expression":"map(a,f(a)(relu(a)))","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201690000000000000000000000003D8000003EA000000162016A0000000000000000000000003E0000003EC000000162016B0000000000000000000000003E4000003EE000000162016C0000000000000000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02003FC01E3CB664F724"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x02010178033FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x02020178030179053FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD06FEF72E4DC51"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A073FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD06FEF72E4DC513FD136561454BA863FD2028CAA346D913FD2D46B08DBBFE43FD3ABC0F5A661E43FD4885610B9B8283FD569E9D4F13CFC3FD65033AF8ACD793FD73AE330CA5BDD3FD829A0565978DE3FD91C0BEFA560DB3FDA11C01BF102233FDB0A50E13BDCF83FDC054CDA8768FA3FDD023DFB7009EE3FDE00AA6681FCF33FDF001553336A723FE00000000000003FE07FF556664AC73FE0FFAACCBF01873FE17EE10247FB093FE1FD5992BC4B833FE27AD78F6211853FE2F71FF2077EEE3FE371FA082D4F933FE3EB2FD4D343913FE4628E679AD2113FE4D7E6283A99433FE54B0B158761823FE5BBD4F7A323EC3FE62A1F852CCF0E3FE695CA7B92200E3FE6FEB9AAE5C9373FE764D4F5D5A2BD3FE7C808468D91D73FE82843797B6A5B3FE8857A3F05FB083FE8DFA3F55DC7CA3FE936BB7B9919E43FE98ABEFF4FB8AE3FE9DBAFC5E5BA173FEA2991F2A979143FEA746C4AD8086E3FEABC47F88694CD3FEB01304D573E113FEB433285C6100B3FEB825D8DBFE5C03FEBBEC1C71A02BD3FEBF870D266C2373FEC2F7D5A8A79C93FEC63FAE35C07B53FEC95FD9B86CDB83FECC59A31D048CA3FECF2E5ADD226B53FED1DF54C2AB5CB3FED46DE5E18C4BD3FED6DB62C6D6AC03FED9291DDB596F83FEDB5865F7689163FEDD6A8525345E13FEDF60BF8ED890F3FEE13C52952723C3FEE2FE740C2057C3FEE4A8519A0645F3FEE63B1036038143FEE7B7CBC36FABD3FEE91F96C6D823E3FEEA737A32143583FEEBB47544D1E213FEECE37D7F30E3D3FEEE017EA42BDA43FEEF0F5AC9BA8C73FEF00DEA74C30D43FEF0FDFCBF19A933FEF1E05785F852C3FEF2B5B79F7D5FE3FEF37ED115E693E3FEF43C4F67606ED3FEF4EED5C9627163FEF596FF6EAF6493FEF6355FCF2CC3B3FEF6CA82F0DE1EA3FEF756EDB168D2C3FEF7DB1E0F99CCC3FEF8578B747A5BB3FEF8CCA6FB927E33FEF93ADBBA06A983FEF9A28F044CF103FEFA0420B241D503FEFA5FEB616FE8F3FEFAB644B567290"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A073E00F1E63E0827C73E0FB44E3E1799AF3E1FD9F63E2877013E3172773E3ACDC23E448A073E4EA8203E5928913E640B813E6F50B83E7AF7913E837F7C3E89B2B13E9014653E96A3583E9D5E083EA442B13EAB4F4F3EB2819D3EB9D71A3EC14D033EC8E05F3ED08E013ED852873EE02A673EE811F03EF005533EF800AB3F0000003F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B22"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x010101780301613FC01E3CB664F72401623FC104F8E397F50801633FC1F689C90068FD"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261723FC104F8E397F508016103666F6F3FC01E3CB664F7240162036261723FC2F335E8E7BFD6016203666F6F3FC1F689C90068FD0163036261723FC50EE01DE5ACCF016303666F6F3FC3FB3ECAA307BC"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FC3FB3ECAA307BC016103626172016A3FC50EE01DE5ACCF016103626172016B3FC62E4ED49FDE48016103626172016C3FC759B8355A1BB0016103666F6F01693FC01E3CB664F724016103666F6F016A3FC104F8E397F508016103666F6F016B3FC1F689C90068FD016103666F6F016C3FC2F335E8E7BFD601620362617201693FCDEA1703E813E0016203626172016A3FCF5EF21A125693016203626172016B3FD06FEF72E4DC51016203626172016C3FD136561454BA86016203666F6F01693FC89140E86917A6016203666F6F016A3FC9D50402C11D4A016203666F6F016B3FCB2512119B9871016203666F6F016C3FCC81702A88E0D501630362617201693FD569E9D4F13CFC016303626172016A3FD65033AF8ACD79016303626172016B3FD73AE330CA5BDD016303626172016C3FD829A0565978DE016303666F6F01693FD2028CAA346D91016303666F6F016A3FD2D46B08DBBFE4016303666F6F016B3FD3ABC0F5A661E4016303666F6F016C3FD4885610B9B828"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A1801610362617201693E1FD9F6016103626172016A3E287701016103626172016B3E317277016103626172016C3E3ACDC2016103666F6F01693E00F1E6016103666F6F016A3E0827C7016103666F6F016B3E0FB44E016103666F6F016C3E1799AF01620362617201693E6F50B8016203626172016A3E7AF791016203626172016B3E837F7C016203626172016C3E89B2B1016203666F6F01693E448A07016203666F6F016A3E4EA820016203666F6F016B3E592891016203666F6F016C3E640B8101630362617201693EAB4F4F016303626172016A3EB2819D016303626172016B3EB9D71A016303626172016C3EC14D03016303666F6F01693E901465016303666F6F016A3E96A358016303666F6F016B3E9D5E08016303666F6F016C3EA442B1"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD65033AF8ACD793FD73AE330CA5BDD3FD829A0565978DE3FD91C0BEFA560DB3FDA11C01BF102233FDB0A50E13BDCF83FDC054CDA8768FA3FE1FD5992BC4B833FE27AD78F6211853FE2F71FF2077EEE3FE371FA082D4F933FE3EB2FD4D343913FE4628E679AD2113FE4D7E6283A994303666F6F3FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FD06FEF72E4DC513FD136561454BA863FD2028CAA346D913FD2D46B08DBBFE43FD3ABC0F5A661E43FD4885610B9B8283FD569E9D4F13CFC3FDD023DFB7009EE3FDE00AA6681FCF33FDF001553336A723FE00000000000003FE07FF556664AC73FE0FFAACCBF01873FE17EE10247FB09"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC01E3CB664F7243FC3FB3ECAA307BC3FC89140E86917A63FCDEA1703E813E03FD2028CAA346D910161016A3FC104F8E397F5083FC50EE01DE5ACCF3FC9D50402C11D4A3FCF5EF21A1256933FD2D46B08DBBFE40161016B3FC1F689C90068FD3FC62E4ED49FDE483FCB2512119B98713FD06FEF72E4DC513FD3ABC0F5A661E40161016C3FC2F335E8E7BFD63FC759B8355A1BB03FCC81702A88E0D53FD136561454BA863FD4885610B9B828016201693FD569E9D4F13CFC3FD91C0BEFA560DB3FDD023DFB7009EE3FE07FF556664AC73FE27AD78F6211850162016A3FD65033AF8ACD793FDA11C01BF102233FDE00AA6681FCF33FE0FFAACCBF01873FE2F71FF2077EEE0162016B3FD73AE330CA5BDD3FDB0A50E13BDCF83FDF001553336A723FE17EE10247FB093FE371FA082D4F930162016C3FD829A0565978DE3FDC054CDA8768FA3FE00000000000003FE1FD5992BC4B833FE3EB2FD4D34391016301693FE4628E679AD2113FE62A1F852CCF0E3FE7C808468D91D73FE936BB7B9919E43FEA746C4AD8086E0163016A3FE4D7E6283A99433FE695CA7B92200E3FE82843797B6A5B3FE98ABEFF4FB8AE3FEABC47F88694CD0163016B3FE54B0B158761823FE6FEB9AAE5C9373FE8857A3F05FB083FE9DBAFC5E5BA173FEB01304D573E110163016C3FE5BBD4F7A323EC3FE764D4F5D5A2BD3FE8DFA3F55DC7CA3FEA2991F2A979143FEB433285C6100B"}}
-{"expression":"sigmoid(a)","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C016101693E00F1E63E1FD9F63E448A073E6F50B83E9014650161016A3E0827C73E2877013E4EA8203E7AF7913E96A3580161016B3E0FB44E3E3172773E5928913E837F7C3E9D5E080161016C3E1799AF3E3ACDC23E640B813E89B2B13EA442B1016201693EAB4F4F3EC8E05F3EE811F03F03FFAB3F13D6BC0162016A3EB2819D3ED08E013EF005533F07FD563F17B9000162016B3EB9D71A3ED852873EF800AB3F0BF7083F1B8FD00162016C3EC14D033EE02A673F0000003F0FEACD3F1F597F016301693F2314733F3150FC3F3E40423F49B5DC3F53A3620163016A3F26BF313F34AE543F41421C3F4C55F83F55E2400163016B3F2A58593F37F5CD3F442BD23F4EDD7E3F5809820163016C3F2DDEA83F3B26A83F46FD203F514C903F5A1994"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x02003FC01E3CB664F724"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x02010178033FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x02020178030179053FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD06FEF72E4DC51"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A073FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD06FEF72E4DC513FD136561454BA863FD2028CAA346D913FD2D46B08DBBFE43FD3ABC0F5A661E43FD4885610B9B8283FD569E9D4F13CFC3FD65033AF8ACD793FD73AE330CA5BDD3FD829A0565978DE3FD91C0BEFA560DB3FDA11C01BF102233FDB0A50E13BDCF83FDC054CDA8768FA3FDD023DFB7009EE3FDE00AA6681FCF33FDF001553336A723FE00000000000003FE07FF556664AC73FE0FFAACCBF01873FE17EE10247FB093FE1FD5992BC4B833FE27AD78F6211853FE2F71FF2077EEE3FE371FA082D4F933FE3EB2FD4D343913FE4628E679AD2113FE4D7E6283A99433FE54B0B158761823FE5BBD4F7A323EC3FE62A1F852CCF0E3FE695CA7B92200E3FE6FEB9AAE5C9373FE764D4F5D5A2BD3FE7C808468D91D73FE82843797B6A5B3FE8857A3F05FB083FE8DFA3F55DC7CA3FE936BB7B9919E43FE98ABEFF4FB8AE3FE9DBAFC5E5BA173FEA2991F2A979143FEA746C4AD8086E3FEABC47F88694CD3FEB01304D573E113FEB433285C6100B3FEB825D8DBFE5C03FEBBEC1C71A02BD3FEBF870D266C2373FEC2F7D5A8A79C93FEC63FAE35C07B53FEC95FD9B86CDB83FECC59A31D048CA3FECF2E5ADD226B53FED1DF54C2AB5CB3FED46DE5E18C4BD3FED6DB62C6D6AC03FED9291DDB596F83FEDB5865F7689163FEDD6A8525345E13FEDF60BF8ED890F3FEE13C52952723C3FEE2FE740C2057C3FEE4A8519A0645F3FEE63B1036038143FEE7B7CBC36FABD3FEE91F96C6D823E3FEEA737A32143583FEEBB47544D1E213FEECE37D7F30E3D3FEEE017EA42BDA43FEEF0F5AC9BA8C73FEF00DEA74C30D43FEF0FDFCBF19A933FEF1E05785F852C3FEF2B5B79F7D5FE3FEF37ED115E693E3FEF43C4F67606ED3FEF4EED5C9627163FEF596FF6EAF6493FEF6355FCF2CC3B3FEF6CA82F0DE1EA3FEF756EDB168D2C3FEF7DB1E0F99CCC3FEF8578B747A5BB3FEF8CCA6FB927E33FEF93ADBBA06A983FEF9A28F044CF103FEFA0420B241D503FEFA5FEB616FE8F3FEFAB644B567290"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A073E00F1E63E0827C73E0FB44E3E1799AF3E1FD9F63E2877013E3172773E3ACDC23E448A073E4EA8203E5928913E640B813E6F50B83E7AF7913E837F7C3E89B2B13E9014653E96A3583E9D5E083EA442B13EAB4F4F3EB2819D3EB9D71A3EC14D033EC8E05F3ED08E013ED852873EE02A673EE811F03EF005533EF800AB3F0000003F03FFAB3F07FD563F0BF7083F0FEACD3F13D6BC3F17B9003F1B8FD03F1F597F3F2314733F26BF313F2A58593F2DDEA83F3150FC3F34AE543F37F5CD3F3B26A83F3E40423F41421C3F442BD23F46FD203F49B5DC3F4C55F83F4EDD7E3F514C903F53A3623F55E2403F5809823F5A19943F5C12EC3F5DF60E3F5FC3873F617BEB3F631FD73F64AFED3F662CD23F67972D3F68EFAA3F6A36F33F6B6DB13F6C948F3F6DAC333F6EB5433F6FB0603F709E293F717F3A3F7254293F731D883F73DBE63F748FCB3F7539BD3F75DA3B3F7671BF3F7700BF3F7787AD3F7806F53F787EFE3F78F02C3F795ADC3F79BF693F7A1E283F7A776B3F7ACB803F7B1AB03F7B65413F7BAB773F7BED8F3F7C2BC63F7C66533F7C9D6E3F7CD1483F7D02103F7D2FF63F7D5B22"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x010101780301613FC01E3CB664F72401623FC104F8E397F50801633FC1F689C90068FD"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x010201780179060161036261723FC104F8E397F508016103666F6F3FC01E3CB664F7240162036261723FC2F335E8E7BFD6016203666F6F3FC1F689C90068FD0163036261723FC50EE01DE5ACCF016303666F6F3FC3FB3ECAA307BC"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FC3FB3ECAA307BC016103626172016A3FC50EE01DE5ACCF016103626172016B3FC62E4ED49FDE48016103626172016C3FC759B8355A1BB0016103666F6F01693FC01E3CB664F724016103666F6F016A3FC104F8E397F508016103666F6F016B3FC1F689C90068FD016103666F6F016C3FC2F335E8E7BFD601620362617201693FCDEA1703E813E0016203626172016A3FCF5EF21A125693016203626172016B3FD06FEF72E4DC51016203626172016C3FD136561454BA86016203666F6F01693FC89140E86917A6016203666F6F016A3FC9D50402C11D4A016203666F6F016B3FCB2512119B9871016203666F6F016C3FCC81702A88E0D501630362617201693FD569E9D4F13CFC016303626172016A3FD65033AF8ACD79016303626172016B3FD73AE330CA5BDD016303626172016C3FD829A0565978DE016303666F6F01693FD2028CAA346D91016303666F6F016A3FD2D46B08DBBFE4016303666F6F016B3FD3ABC0F5A661E4016303666F6F016C3FD4885610B9B828"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A1801610362617201693E1FD9F6016103626172016A3E287701016103626172016B3E317277016103626172016C3E3ACDC2016103666F6F01693E00F1E6016103666F6F016A3E0827C7016103666F6F016B3E0FB44E016103666F6F016C3E1799AF01620362617201693E6F50B8016203626172016A3E7AF791016203626172016B3E837F7C016203626172016C3E89B2B1016203666F6F01693E448A07016203666F6F016A3E4EA820016203666F6F016B3E592891016203666F6F016C3E640B8101630362617201693EAB4F4F016303626172016A3EB2819D016303626172016B3EB9D71A016303626172016C3EC14D03016303666F6F01693E901465016303666F6F016A3E96A358016303666F6F016B3E9D5E08016303666F6F016C3EA442B1"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC759B8355A1BB03FC89140E86917A63FC9D50402C11D4A3FCB2512119B98713FCC81702A88E0D53FCDEA1703E813E03FCF5EF21A1256933FD65033AF8ACD793FD73AE330CA5BDD3FD829A0565978DE3FD91C0BEFA560DB3FDA11C01BF102233FDB0A50E13BDCF83FDC054CDA8768FA3FE1FD5992BC4B833FE27AD78F6211853FE2F71FF2077EEE3FE371FA082D4F933FE3EB2FD4D343913FE4628E679AD2113FE4D7E6283A994303666F6F3FC01E3CB664F7243FC104F8E397F5083FC1F689C90068FD3FC2F335E8E7BFD63FC3FB3ECAA307BC3FC50EE01DE5ACCF3FC62E4ED49FDE483FD06FEF72E4DC513FD136561454BA863FD2028CAA346D913FD2D46B08DBBFE43FD3ABC0F5A661E43FD4885610B9B8283FD569E9D4F13CFC3FDD023DFB7009EE3FDE00AA6681FCF33FDF001553336A723FE00000000000003FE07FF556664AC73FE0FFAACCBF01873FE17EE10247FB09"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC01E3CB664F7243FC3FB3ECAA307BC3FC89140E86917A63FCDEA1703E813E03FD2028CAA346D910161016A3FC104F8E397F5083FC50EE01DE5ACCF3FC9D50402C11D4A3FCF5EF21A1256933FD2D46B08DBBFE40161016B3FC1F689C90068FD3FC62E4ED49FDE483FCB2512119B98713FD06FEF72E4DC513FD3ABC0F5A661E40161016C3FC2F335E8E7BFD63FC759B8355A1BB03FCC81702A88E0D53FD136561454BA863FD4885610B9B828016201693FD569E9D4F13CFC3FD91C0BEFA560DB3FDD023DFB7009EE3FE07FF556664AC73FE27AD78F6211850162016A3FD65033AF8ACD793FDA11C01BF102233FDE00AA6681FCF33FE0FFAACCBF01873FE2F71FF2077EEE0162016B3FD73AE330CA5BDD3FDB0A50E13BDCF83FDF001553336A723FE17EE10247FB093FE371FA082D4F930162016C3FD829A0565978DE3FDC054CDA8768FA3FE00000000000003FE1FD5992BC4B833FE3EB2FD4D34391016301693FE4628E679AD2113FE62A1F852CCF0E3FE7C808468D91D73FE936BB7B9919E43FEA746C4AD8086E0163016A3FE4D7E6283A99433FE695CA7B92200E3FE82843797B6A5B3FE98ABEFF4FB8AE3FEABC47F88694CD0163016B3FE54B0B158761823FE6FEB9AAE5C9373FE8857A3F05FB083FE9DBAFC5E5BA173FEB01304D573E110163016C3FE5BBD4F7A323EC3FE764D4F5D5A2BD3FE8DFA3F55DC7CA3FEA2991F2A979143FEB433285C6100B"}}
-{"expression":"map(a,f(a)(sigmoid(a)))","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C016101693E00F1E63E1FD9F63E448A073E6F50B83E9014650161016A3E0827C73E2877013E4EA8203E7AF7913E96A3580161016B3E0FB44E3E3172773E5928913E837F7C3E9D5E080161016C3E1799AF3E3ACDC23E640B813E89B2B13EA442B1016201693EAB4F4F3EC8E05F3EE811F03F03FFAB3F13D6BC0162016A3EB2819D3ED08E013EF005533F07FD563F17B9000162016B3EB9D71A3ED852873EF800AB3F0BF7083F1B8FD00162016C3EC14D033EE02A673F0000003F0FEACD3F1F597F016301693F2314733F3150FC3F3E40423F49B5DC3F53A3620163016A3F26BF313F34AE543F41421C3F4C55F83F55E2400163016B3F2A58593F37F5CD3F442BD23F4EDD7E3F5809820163016C3F2DDEA83F3B26A83F46FD203F514C903F5A1994"}}
-{"expression":"elu(a)","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x0200BFEB63D49BF3BFD2"}}
-{"expression":"elu(a)","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x0201017803BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DE"}}
-{"expression":"elu(a)","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x0202017803017905BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFE4F0EBA97C3840"}}
-{"expression":"elu(a)","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A07BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFE4F0EBA97C3840BFE43A54E4E98864BFE377F77A0FCB45BFE2A910FB51295ABFE1CCD270F070FABFE0E25F8A081941BFDFD19B804DFFC0BFDDBE46D96CD830BFDB88AD9E7D52EABFD92E9A0720D3ECBFD6ADB1CD9205EEBFD40373D42CE2E2BFD12D35A41BA104BFCC5041854DF7D4BFC5E25FB4FDE210BFBE14AED893EEF0BFAF0540438FD5C000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"}}
-{"expression":"elu(a)","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A07BF5B1EA5BF58BDBBBF56358BBF53838DBF50A50FBF4D9732BF4A56E8BF46E0F1BF4331D6BF3F45E7BF3B193ABF36A79FBF31ECA6BF2CE393BF27875DBF21D2A7BF1BBFBCBF154888BF0E6694BF0712FCBEFE8CDCBEEDF237BEDC456DBEC974D0BEB56D8EBEA01B9FBE8969ADBE62820CBE2F12FEBDF0A577BD782A02000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"}}
-{"expression":"elu(a)","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x01010178030161BFEB63D49BF3BFD20162BFEB17B75317198B0163BFEAC6B158D953DE"}}
-{"expression":"elu(a)","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x01020178017906016103626172BFEB17B75317198B016103666F6FBFEB63D49BF3BFD2016203626172BFEA7071A07F77E3016203666F6FBFEAC6B158D953DE016303626172BFE9B2E649598467016303666F6FBFEA14A1E320F460"}}
-{"expression":"elu(a)","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFEA14A1E320F460016103626172016ABFE9B2E649598467016103626172016BBFE94ADD0F6A238E016103626172016CBFE8DC1E236D28F9016103666F6F0169BFEB63D49BF3BFD2016103666F6F016ABFEB17B75317198B016103666F6F016BBFEAC6B158D953DE016103666F6F016CBFEA7071A07F77E30162036261720169BFE63D94C6D15BE6016203626172016ABFE59C726DC42A70016203626172016BBFE4F0EBA97C3840016203626172016CBFE43A54E4E98864016203666F6F0169BFE8663ABD3BB540016203666F6F016ABFE7E8BCEF9C4FEA016203666F6F016BBFE76327324BD9DC016203666F6F016CBFE6D4F3E46AD3D80163036261720169BFDFD19B804DFFC0016303626172016ABFDDBE46D96CD830016303626172016BBFDB88AD9E7D52EA016303626172016CBFD92E9A0720D3EC016303666F6F0169BFE377F77A0FCB45016303666F6F016ABFE2A910FB51295A016303666F6F016BBFE1CCD270F070FA016303666F6F016CBFE0E25F8A081941"}}
-{"expression":"elu(a)","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A180161036261720169BF50A50F016103626172016ABF4D9732016103626172016BBF4A56E8016103626172016CBF46E0F1016103666F6F0169BF5B1EA5016103666F6F016ABF58BDBB016103666F6F016BBF56358B016103666F6F016CBF53838D0162036261720169BF31ECA6016203626172016ABF2CE393016203626172016BBF27875D016203626172016CBF21D2A7016203666F6F0169BF4331D6016203666F6F016ABF3F45E7016203666F6F016BBF3B193A016203666F6F016CBF36A79F0163036261720169BEFE8CDC016303626172016ABEEDF237016303626172016BBEDC456D016303626172016CBEC974D0016303666F6F0169BF1BBFBC016303666F6F016ABF154888016303666F6F016BBF0E6694016303666F6F016CBF0712FC"}}
-{"expression":"elu(a)","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFDDBE46D96CD830BFDB88AD9E7D52EABFD92E9A0720D3ECBFD6ADB1CD9205EEBFD40373D42CE2E2BFD12D35A41BA104BFCC5041854DF7D43FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE4F0EBA97C3840BFE43A54E4E98864BFE377F77A0FCB45BFE2A910FB51295ABFE1CCD270F070FABFE0E25F8A081941BFDFD19B804DFFC0BFC5E25FB4FDE210BFBE14AED893EEF0BFAF0540438FD5C000000000000000003FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"elu(a)","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C01610169BFEB63D49BF3BFD2BFEA14A1E320F460BFE8663ABD3BB540BFE63D94C6D15BE6BFE377F77A0FCB450161016ABFEB17B75317198BBFE9B2E649598467BFE7E8BCEF9C4FEABFE59C726DC42A70BFE2A910FB51295A0161016BBFEAC6B158D953DEBFE94ADD0F6A238EBFE76327324BD9DCBFE4F0EBA97C3840BFE1CCD270F070FA0161016CBFEA7071A07F77E3BFE8DC1E236D28F9BFE6D4F3E46AD3D8BFE43A54E4E98864BFE0E25F8A08194101620169BFDFD19B804DFFC0BFD6ADB1CD9205EEBFC5E25FB4FDE2103FB00000000000003FD40000000000000162016ABFDDBE46D96CD830BFD40373D42CE2E2BFBE14AED893EEF03FC00000000000003FD80000000000000162016BBFDB88AD9E7D52EABFD12D35A41BA104BFAF0540438FD5C03FC80000000000003FDC0000000000000162016CBFD92E9A0720D3ECBFCC5041854DF7D400000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"}}
-{"expression":"elu(a)","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C01610169BF5B1EA5BF50A50FBF4331D6BF31ECA6BF1BBFBC0161016ABF58BDBBBF4D9732BF3F45E7BF2CE393BF1548880161016BBF56358BBF4A56E8BF3B193ABF27875DBF0E66940161016CBF53838DBF46E0F1BF36A79FBF21D2A7BF0712FC01620169BEFE8CDCBEB56D8EBE2F12FE3D8000003EA000000162016ABEEDF237BEA01B9FBDF0A5773E0000003EC000000162016BBEDC456DBE8969ADBD782A023E4000003EE000000162016CBEC974D0BE62820C000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0200BFFF000000000000"},"result":{"expect":"0x0200BFEB63D49BF3BFD2"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0201017803BFFF000000000000BFFE000000000000BFFD000000000000"},"result":{"expect":"0x0201017803BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DE"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0202017803017905BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000"},"result":{"expect":"0x0202017803017905BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFE4F0EBA97C3840"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0203017803017905017A07BFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD0000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"},"result":{"expect":"0x0203017803017905017A07BFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFE4F0EBA97C3840BFE43A54E4E98864BFE377F77A0FCB45BFE2A910FB51295ABFE1CCD270F070FABFE0E25F8A081941BFDFD19B804DFFC0BFDDBE46D96CD830BFDB88AD9E7D52EABFD92E9A0720D3ECBFD6ADB1CD9205EEBFD40373D42CE2E2BFD12D35A41BA104BFCC5041854DF7D4BFC5E25FB4FDE210BFBE14AED893EEF0BFAF0540438FD5C000000000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C0000000000040120000000000004012400000000000"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x060103017803017905017A07BFF80000BFF00000BFE80000BFE00000BFD80000BFD00000BFC80000BFC00000BFB80000BFB00000BFA80000BFA00000BF980000BF900000BF880000BF800000BF700000BF600000BF500000BF400000BF300000BF200000BF100000BF000000BEE00000BEC00000BEA00000BE800000BE400000BE000000BD800000000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"},"result":{"expect":"0x060103017803017905017A07BF5B1EA5BF58BDBBBF56358BBF53838DBF50A50FBF4D9732BF4A56E8BF46E0F1BF4331D6BF3F45E7BF3B193ABF36A79FBF31ECA6BF2CE393BF27875DBF21D2A7BF1BBFBCBF154888BF0E6694BF0712FCBEFE8CDCBEEDF237BEDC456DBEC974D0BEB56D8EBEA01B9FBE8969ADBE62820CBE2F12FEBDF0A577BD782A02000000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x01010178030161BFFF0000000000000162BFFE0000000000000163BFFD000000000000"},"result":{"expect":"0x01010178030161BFEB63D49BF3BFD20162BFEB17B75317198B0163BFEAC6B158D953DE"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x01020178017906016103626172BFFE000000000000016103666F6FBFFF000000000000016203626172BFFC000000000000016203666F6FBFFD000000000000016303626172BFFA000000000000016303666F6FBFFB000000000000"},"result":{"expect":"0x01020178017906016103626172BFEB17B75317198B016103666F6FBFEB63D49BF3BFD2016203626172BFEA7071A07F77E3016203666F6FBFEAC6B158D953DE016303626172BFE9B2E649598467016303666F6FBFEA14A1E320F460"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x010301780179017A180161036261720169BFFB000000000000016103626172016ABFFA000000000000016103626172016BBFF9000000000000016103626172016CBFF8000000000000016103666F6F0169BFFF000000000000016103666F6F016ABFFE000000000000016103666F6F016BBFFD000000000000016103666F6F016CBFFC0000000000000162036261720169BFF3000000000000016203626172016ABFF2000000000000016203626172016BBFF1000000000000016203626172016CBFF0000000000000016203666F6F0169BFF7000000000000016203666F6F016ABFF6000000000000016203666F6F016BBFF5000000000000016203666F6F016CBFF40000000000000163036261720169BFE6000000000000016303626172016ABFE4000000000000016303626172016BBFE2000000000000016303626172016CBFE0000000000000016303666F6F0169BFEE000000000000016303666F6F016ABFEC000000000000016303666F6F016BBFEA000000000000016303666F6F016CBFE8000000000000"},"result":{"expect":"0x010301780179017A180161036261720169BFEA14A1E320F460016103626172016ABFE9B2E649598467016103626172016BBFE94ADD0F6A238E016103626172016CBFE8DC1E236D28F9016103666F6F0169BFEB63D49BF3BFD2016103666F6F016ABFEB17B75317198B016103666F6F016BBFEAC6B158D953DE016103666F6F016CBFEA7071A07F77E30162036261720169BFE63D94C6D15BE6016203626172016ABFE59C726DC42A70016203626172016BBFE4F0EBA97C3840016203626172016CBFE43A54E4E98864016203666F6F0169BFE8663ABD3BB540016203666F6F016ABFE7E8BCEF9C4FEA016203666F6F016BBFE76327324BD9DC016203666F6F016CBFE6D4F3E46AD3D80163036261720169BFDFD19B804DFFC0016303626172016ABFDDBE46D96CD830016303626172016BBFDB88AD9E7D52EA016303626172016CBFD92E9A0720D3EC016303666F6F0169BFE377F77A0FCB45016303666F6F016ABFE2A910FB51295A016303666F6F016BBFE1CCD270F070FA016303666F6F016CBFE0E25F8A081941"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x05010301780179017A180161036261720169BFD80000016103626172016ABFD00000016103626172016BBFC80000016103626172016CBFC00000016103666F6F0169BFF80000016103666F6F016ABFF00000016103666F6F016BBFE80000016103666F6F016CBFE000000162036261720169BF980000016203626172016ABF900000016203626172016BBF880000016203626172016CBF800000016203666F6F0169BFB80000016203666F6F016ABFB00000016203666F6F016BBFA80000016203666F6F016CBFA000000163036261720169BF300000016303626172016ABF200000016303626172016BBF100000016303626172016CBF000000016303666F6F0169BF700000016303666F6F016ABF600000016303666F6F016BBF500000016303666F6F016CBF400000"},"result":{"expect":"0x05010301780179017A180161036261720169BF50A50F016103626172016ABF4D9732016103626172016BBF4A56E8016103626172016CBF46E0F1016103666F6F0169BF5B1EA5016103666F6F016ABF58BDBB016103666F6F016BBF56358B016103666F6F016CBF53838D0162036261720169BF31ECA6016203626172016ABF2CE393016203626172016BBF27875D016203626172016CBF21D2A7016203666F6F0169BF4331D6016203666F6F016ABF3F45E7016203666F6F016BBF3B193A016203666F6F016CBF36A79F0163036261720169BEFE8CDC016303626172016ABEEDF237016303626172016BBEDC456D016303626172016CBEC974D0016303666F6F0169BF1BBFBC016303666F6F016ABF154888016303666F6F016BBF0E6694016303666F6F016CBF0712FC"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0301017902017803017A070203626172BFF8000000000000BFF7000000000000BFF6000000000000BFF5000000000000BFF4000000000000BFF3000000000000BFF2000000000000BFE4000000000000BFE2000000000000BFE0000000000000BFDC000000000000BFD8000000000000BFD4000000000000BFD00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFFF000000000000BFFE000000000000BFFD000000000000BFFC000000000000BFFB000000000000BFFA000000000000BFF9000000000000BFF1000000000000BFF0000000000000BFEE000000000000BFEC000000000000BFEA000000000000BFE8000000000000BFE6000000000000BFC8000000000000BFC0000000000000BFB000000000000000000000000000003FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFE8DC1E236D28F9BFE8663ABD3BB540BFE7E8BCEF9C4FEABFE76327324BD9DCBFE6D4F3E46AD3D8BFE63D94C6D15BE6BFE59C726DC42A70BFDDBE46D96CD830BFDB88AD9E7D52EABFD92E9A0720D3ECBFD6ADB1CD9205EEBFD40373D42CE2E2BFD12D35A41BA104BFCC5041854DF7D43FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000003666F6FBFEB63D49BF3BFD2BFEB17B75317198BBFEAC6B158D953DEBFEA7071A07F77E3BFEA14A1E320F460BFE9B2E649598467BFE94ADD0F6A238EBFE4F0EBA97C3840BFE43A54E4E98864BFE377F77A0FCB45BFE2A910FB51295ABFE1CCD270F070FABFE0E25F8A081941BFDFD19B804DFFC0BFC5E25FB4FDE210BFBE14AED893EEF0BFAF0540438FD5C000000000000000003FB00000000000003FC00000000000003FC8000000000000"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x03020178017A010179050C01610169BFFF000000000000BFFB000000000000BFF7000000000000BFF3000000000000BFEE0000000000000161016ABFFE000000000000BFFA000000000000BFF6000000000000BFF2000000000000BFEC0000000000000161016BBFFD000000000000BFF9000000000000BFF5000000000000BFF1000000000000BFEA0000000000000161016CBFFC000000000000BFF8000000000000BFF4000000000000BFF0000000000000BFE800000000000001620169BFE6000000000000BFDC000000000000BFC80000000000003FB00000000000003FD40000000000000162016ABFE4000000000000BFD8000000000000BFC00000000000003FC00000000000003FD80000000000000162016BBFE2000000000000BFD4000000000000BFB00000000000003FC80000000000003FDC0000000000000162016CBFE0000000000000BFD000000000000000000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"},"result":{"expect":"0x03020178017A010179050C01610169BFEB63D49BF3BFD2BFEA14A1E320F460BFE8663ABD3BB540BFE63D94C6D15BE6BFE377F77A0FCB450161016ABFEB17B75317198BBFE9B2E649598467BFE7E8BCEF9C4FEABFE59C726DC42A70BFE2A910FB51295A0161016BBFEAC6B158D953DEBFE94ADD0F6A238EBFE76327324BD9DCBFE4F0EBA97C3840BFE1CCD270F070FA0161016CBFEA7071A07F77E3BFE8DC1E236D28F9BFE6D4F3E46AD3D8BFE43A54E4E98864BFE0E25F8A08194101620169BFDFD19B804DFFC0BFD6ADB1CD9205EEBFC5E25FB4FDE2103FB00000000000003FD40000000000000162016ABFDDBE46D96CD830BFD40373D42CE2E2BFBE14AED893EEF03FC00000000000003FD80000000000000162016BBFDB88AD9E7D52EABFD12D35A41BA104BFAF0540438FD5C03FC80000000000003FDC0000000000000162016CBFD92E9A0720D3ECBFCC5041854DF7D400000000000000003FD00000000000003FE0000000000000016301693FE20000000000003FEA0000000000003FF10000000000003FF50000000000003FF90000000000000163016A3FE40000000000003FEC0000000000003FF20000000000003FF60000000000003FFA0000000000000163016B3FE60000000000003FEE0000000000003FF30000000000003FF70000000000003FFB0000000000000163016C3FE80000000000003FF00000000000003FF40000000000003FF80000000000003FFC000000000000"}}
-{"expression":"map(a,f(a)(elu(a)))","inputs":{"a":"0x0701020178017A010179050C01610169BFF80000BFD80000BFB80000BF980000BF7000000161016ABFF00000BFD00000BFB00000BF900000BF6000000161016BBFE80000BFC80000BFA80000BF880000BF5000000161016CBFE00000BFC00000BFA00000BF800000BF40000001620169BF300000BEE00000BE4000003D8000003EA000000162016ABF200000BEC00000BE0000003E0000003EC000000162016BBF100000BEA00000BD8000003E4000003EE000000162016CBF000000BE800000000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"},"result":{"expect":"0x0701020178017A010179050C01610169BF5B1EA5BF50A50FBF4331D6BF31ECA6BF1BBFBC0161016ABF58BDBBBF4D9732BF3F45E7BF2CE393BF1548880161016BBF56358BBF4A56E8BF3B193ABF27875DBF0E66940161016CBF53838DBF46E0F1BF36A79FBF21D2A7BF0712FC01620169BEFE8CDCBEB56D8EBE2F12FE3D8000003EA000000162016ABEEDF237BEA01B9FBDF0A5773E0000003EC000000162016BBEDC456DBE8969ADBD782A023E4000003EE000000162016CBEC974D0BE62820C000000003E8000003F000000016301693F1000003F5000003F8800003FA800003FC800000163016A3F2000003F6000003F9000003FB000003FD000000163016B3F3000003F7000003F9800003FB800003FD800000163016C3F4000003F8000003FA000003FC000003FE00000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x02003FF0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02020178030179053FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000003F800000000000003F80000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A0000000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B0000000000000000016303666F6F016C0000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F800000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A00000000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B00000000016303666F6F016C00000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000003666F6F3FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B000000000000000000000000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A3FF000000000000000000000000000000000000000000000000000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a in [1,5,7,13,42]","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F800000000000003F800000000000000161016A00000000000000000000000000000000000000000161016B000000003F8000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B00000000000000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A3F800000000000000000000000000000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x02003FF0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000"},"result":{"expect":"0x02010178033FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x02020178030179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E000000000000"},"result":{"expect":"0x02020178030179053FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x0203017803017905017A073FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000403D000000000000403E000000000000403F00000000000040400000000000004040800000000000404100000000000040418000000000004042000000000000404280000000000040430000000000004043800000000000404400000000000040448000000000004045000000000000404580000000000040460000000000004046800000000000404700000000000040478000000000004048000000000000404880000000000040490000000000004049800000000000404A000000000000404A800000000000404B000000000000404B800000000000404C000000000000404C800000000000404D000000000000404D800000000000404E000000000000404E800000000000404F000000000000404F8000000000004050000000000000405040000000000040508000000000004050C000000000004051000000000000405140000000000040518000000000004051C000000000004052000000000000405240000000000040528000000000004052C000000000004053000000000000405340000000000040538000000000004053C000000000004054000000000000405440000000000040548000000000004054C000000000004055000000000000405540000000000040558000000000004055C000000000004056000000000000405640000000000040568000000000004056C000000000004057000000000000405740000000000040578000000000004057C000000000004058000000000000405840000000000040588000000000004058C000000000004059000000000000405940000000000040598000000000004059C00000000000405A000000000000405A400000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x060103017803017905017A073F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C8000041D0000041D8000041E0000041E8000041F0000041F80000420000004204000042080000420C0000421000004214000042180000421C0000422000004224000042280000422C0000423000004234000042380000423C0000424000004244000042480000424C0000425000004254000042580000425C0000426000004264000042680000426C0000427000004274000042780000427C00004280000042820000428400004286000042880000428A0000428C0000428E00004290000042920000429400004296000042980000429A0000429C0000429E000042A0000042A2000042A4000042A6000042A8000042AA000042AC000042AE000042B0000042B2000042B4000042B6000042B8000042BA000042BC000042BE000042C0000042C2000042C4000042C6000042C8000042CA000042CC000042CE000042D0000042D20000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000003F800000000000003F80000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x010101780301613FF00000000000000162400000000000000001634008000000000000"},"result":{"expect":"0x010101780301613FF00000000000000162000000000000000001630000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x010201780179060161036261724000000000000000016103666F6F3FF00000000000000162036261724010000000000000016203666F6F40080000000000000163036261724018000000000000016303666F6F4014000000000000"},"result":{"expect":"0x010201780179060161036261720000000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F00000000000000000163036261720000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x010301780179017A1801610362617201694014000000000000016103626172016A4018000000000000016103626172016B401C000000000000016103626172016C4020000000000000016103666F6F01693FF0000000000000016103666F6F016A4000000000000000016103666F6F016B4008000000000000016103666F6F016C40100000000000000162036261720169402A000000000000016203626172016A402C000000000000016203626172016B402E000000000000016203626172016C4030000000000000016203666F6F01694022000000000000016203666F6F016A4024000000000000016203666F6F016B4026000000000000016203666F6F016C402800000000000001630362617201694035000000000000016303626172016A4036000000000000016303626172016B4037000000000000016303626172016C4038000000000000016303666F6F01694031000000000000016303666F6F016A4032000000000000016303666F6F016B4033000000000000016303666F6F016C4034000000000000"},"result":{"expect":"0x010301780179017A1801610362617201693FF0000000000000016103626172016A0000000000000000016103626172016B3FF0000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C000000000000000001630362617201690000000000000000016303626172016A0000000000000000016303626172016B0000000000000000016303626172016C0000000000000000016303666F6F01690000000000000000016303666F6F016A0000000000000000016303666F6F016B0000000000000000016303666F6F016C0000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x05010301780179017A18016103626172016940A00000016103626172016A40C00000016103626172016B40E00000016103626172016C41000000016103666F6F01693F800000016103666F6F016A40000000016103666F6F016B40400000016103666F6F016C40800000016203626172016941500000016203626172016A41600000016203626172016B41700000016203626172016C41800000016203666F6F016941100000016203666F6F016A41200000016203666F6F016B41300000016203666F6F016C41400000016303626172016941A80000016303626172016A41B00000016303626172016B41B80000016303626172016C41C00000016303666F6F016941880000016303666F6F016A41900000016303666F6F016B41980000016303666F6F016C41A00000"},"result":{"expect":"0x05010301780179017A1801610362617201693F800000016103626172016A00000000016103626172016B3F800000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000016303626172016900000000016303626172016A00000000016303626172016B00000000016303626172016C00000000016303666F6F016900000000016303666F6F016A00000000016303666F6F016B00000000016303666F6F016C00000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x0301017902017803017A07020362617240200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C0000000000004036000000000000403700000000000040380000000000004039000000000000403A000000000000403B000000000000403C000000000000404200000000000040428000000000004043000000000000404380000000000040440000000000004044800000000000404500000000000003666F6F3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402E000000000000403000000000000040310000000000004032000000000000403300000000000040340000000000004035000000000000403D000000000000403E000000000000403F0000000000004040000000000000404080000000000040410000000000004041800000000000"},"result":{"expect":"0x0301017902017803017A070203626172000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000003666F6F3FF00000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x03020178017A010179050C016101693FF000000000000040140000000000004022000000000000402A00000000000040310000000000000161016A400000000000000040180000000000004024000000000000402C00000000000040320000000000000161016B4008000000000000401C0000000000004026000000000000402E00000000000040330000000000000161016C401000000000000040200000000000004028000000000000403000000000000040340000000000000162016940350000000000004039000000000000403D000000000000404080000000000040428000000000000162016A4036000000000000403A000000000000403E000000000000404100000000000040430000000000000162016B4037000000000000403B000000000000403F000000000000404180000000000040438000000000000162016C4038000000000000403C00000000000040400000000000004042000000000000404400000000000001630169404480000000000040468000000000004048800000000000404A800000000000404C8000000000000163016A404500000000000040470000000000004049000000000000404B000000000000404D0000000000000163016B404580000000000040478000000000004049800000000000404B800000000000404D8000000000000163016C40460000000000004048000000000000404A000000000000404C000000000000404E000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B000000000000000000000000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A3FF000000000000000000000000000000000000000000000000000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)(a in [1,5,7,13,42]))","inputs":{"a":"0x0701020178017A010179050C016101693F80000040A000004110000041500000418800000161016A4000000040C000004120000041600000419000000161016B4040000040E000004130000041700000419800000161016C4080000041000000414000004180000041A000000162016941A8000041C8000041E8000042040000421400000162016A41B0000041D0000041F0000042080000421800000162016B41B8000041D8000041F80000420C0000421C00000162016C41C0000041E000004200000042100000422000000163016942240000423400004244000042540000426400000163016A42280000423800004248000042580000426800000163016B422C0000423C0000424C0000425C0000426C00000163016C4230000042400000425000004260000042700000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F800000000000003F800000000000000161016A00000000000000000000000000000000000000000161016B000000003F8000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B00000000000000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A3F800000000000000000000000000000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x02003FB0000000000000"},"result":{"expect":"0x02004001000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x02010178033FB00000000000003FC00000000000003FC8000000000000"},"result":{"expect":"0x0201017803400100000000000040020000000000004003000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000"},"result":{"expect":"0x0202017803017905400100000000000040020000000000004003000000000000400400000000000040050000000000004006000000000000400700000000000040080000000000004009000000000000400A000000000000400B000000000000400C000000000000400D000000000000400E000000000000400F000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040030000000000004003800000000000400400000000000040048000000000004005000000000000400580000000000040060000000000004006800000000000400700000000000040078000000000004008000000000000400880000000000040090000000000004009800000000000400A000000000000400A800000000000400B000000000000400B800000000000400C000000000000400C800000000000400D000000000000400D800000000000400E000000000000400E800000000000400F000000000000400F8000000000004010000000000000401040000000000040108000000000004010C000000000004011000000000000401140000000000040118000000000004011C000000000004012000000000000401240000000000040128000000000004012C000000000004013000000000000401340000000000040138000000000004013C000000000004014000000000000401440000000000040148000000000004014C000000000004015000000000000401540000000000040158000000000004015C000000000004016000000000000401640000000000040168000000000004016C000000000004017000000000000401740000000000040178000000000004017C000000000004018000000000000401840000000000040188000000000004018C000000000004019000000000000401940000000000040198000000000004019C00000000000401A000000000000401A400000000000"},"result":{"expect":"0x0203017803017905017A07400100000000000040020000000000004003000000000000400400000000000040050000000000004006000000000000400700000000000040080000000000004009000000000000400A000000000000400B000000000000400C000000000000400D000000000000400E000000000000400F00000000000040100000000000004010800000000000401100000000000040118000000000004012000000000000401280000000000040130000000000004013800000000000401400000000000040148000000000004015000000000000401580000000000040160000000000004016800000000000401700000000000040178000000000004018000000000000401880000000000040190000000000004019800000000000401A000000000000401A800000000000401B000000000000401B800000000000401C000000000000401C800000000000401D000000000000401D800000000000401E000000000000401E800000000000401F000000000000401F8000000000004020000000000000402040000000000040208000000000004020C000000000004021000000000000402140000000000040218000000000004021C000000000004022000000000000402240000000000040228000000000004022C000000000004023000000000000402340000000000040238000000000004023C000000000004024000000000000402440000000000040248000000000004024C000000000004025000000000000402540000000000040258000000000004025C000000000004026000000000000402640000000000040268000000000004026C000000000004027000000000000402740000000000040278000000000004027C000000000004028000000000000402840000000000040288000000000004028C000000000004029000000000000402940000000000040298000000000004029C00000000000402A000000000000402A400000000000402A800000000000402AC00000000000402B000000000000402B400000000000402B800000000000402BC00000000000402C000000000000402C400000000000402C800000000000402CC00000000000402D000000000000402D400000000000402D800000000000402DC00000000000402E000000000000402E400000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000401000004014000040180000401C0000402000004024000040280000402C0000403000004034000040380000403C0000404000004044000040480000404C0000405000004054000040580000405C0000406000004064000040680000406C0000407000004074000040780000407C00004080000040820000408400004086000040880000408A0000408C0000408E00004090000040920000409400004096000040980000409A0000409C0000409E000040A0000040A2000040A4000040A6000040A8000040AA000040AC000040AE000040B0000040B2000040B4000040B6000040B8000040BA000040BC000040BE000040C0000040C2000040C4000040C6000040C8000040CA000040CC000040CE000040D0000040D20000"},"result":{"expect":"0x060103017803017905017A07400800004010000040180000402000004028000040300000403800004040000040480000405000004058000040600000406800004070000040780000408000004084000040880000408C0000409000004094000040980000409C000040A0000040A4000040A8000040AC000040B0000040B4000040B8000040BC000040C0000040C4000040C8000040CC000040D0000040D4000040D8000040DC000040E0000040E4000040E8000040EC000040F0000040F4000040F8000040FC00004100000041020000410400004106000041080000410A0000410C0000410E00004110000041120000411400004116000041180000411A0000411C0000411E00004120000041220000412400004126000041280000412A0000412C0000412E00004130000041320000413400004136000041380000413A0000413C0000413E00004140000041420000414400004146000041480000414A0000414C0000414E00004150000041520000415400004156000041580000415A0000415C0000415E00004160000041620000416400004166000041680000416A0000416C0000416E00004170000041720000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016140010000000000000162400200000000000001634003000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179060161036261724002000000000000016103666F6F40010000000000000162036261724004000000000000016203666F6F40030000000000000163036261724006000000000000016303666F6F4005000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x010301780179017A1801610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FEA000000000000016203626172016A3FEC000000000000016203626172016B3FEE000000000000016203626172016C3FF0000000000000016203666F6F01693FE2000000000000016203666F6F016A3FE4000000000000016203666F6F016B3FE6000000000000016203666F6F016C3FE800000000000001630362617201693FF5000000000000016303626172016A3FF6000000000000016303626172016B3FF7000000000000016303626172016C3FF8000000000000016303666F6F01693FF1000000000000016303666F6F016A3FF2000000000000016303666F6F016B3FF3000000000000016303666F6F016C3FF4000000000000"},"result":{"expect":"0x010301780179017A1801610362617201694005000000000000016103626172016A4006000000000000016103626172016B4007000000000000016103626172016C4008000000000000016103666F6F01694001000000000000016103666F6F016A4002000000000000016103666F6F016B4003000000000000016103666F6F016C40040000000000000162036261720169400D000000000000016203626172016A400E000000000000016203626172016B400F000000000000016203626172016C4010000000000000016203666F6F01694009000000000000016203666F6F016A400A000000000000016203666F6F016B400B000000000000016203666F6F016C400C00000000000001630362617201694012800000000000016303626172016A4013000000000000016303626172016B4013800000000000016303626172016C4014000000000000016303666F6F01694010800000000000016303666F6F016A4011000000000000016303666F6F016B4011800000000000016303666F6F016C4012000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x05010301780179017A1801610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693F500000016203626172016A3F600000016203626172016B3F700000016203626172016C3F800000016203666F6F01693F100000016203666F6F016A3F200000016203666F6F016B3F300000016203666F6F016C3F40000001630362617201693FA80000016303626172016A3FB00000016303626172016B3FB80000016303626172016C3FC00000016303666F6F01693F880000016303666F6F016A3F900000016303666F6F016B3F980000016303666F6F016C3FA00000"},"result":{"expect":"0x05010301780179017A18016103626172016940280000016103626172016A40300000016103626172016B40380000016103626172016C40400000016103666F6F016940080000016103666F6F016A40100000016103666F6F016B40180000016103666F6F016C40200000016203626172016940680000016203626172016A40700000016203626172016B40780000016203626172016C40800000016203666F6F016940480000016203666F6F016A40500000016203666F6F016B40580000016203666F6F016C40600000016303626172016940940000016303626172016A40980000016303626172016B409C0000016303626172016C40A00000016303666F6F016940840000016303666F6F016A40880000016303666F6F016B408C0000016303666F6F016C40900000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC000000000000400200000000000040028000000000004003000000000000400380000000000040040000000000004004800000000000400500000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0301017902017803017A07020362617240080000000000004009000000000000400A000000000000400B000000000000400C000000000000400D000000000000400E0000000000004013000000000000401380000000000040140000000000004014800000000000401500000000000040158000000000004016000000000000401A000000000000401A800000000000401B000000000000401B800000000000401C000000000000401C800000000000401D00000000000003666F6F4001000000000000400200000000000040030000000000004004000000000000400500000000000040060000000000004007000000000000400F0000000000004010000000000000401080000000000040110000000000004011800000000000401200000000000040128000000000004016800000000000401700000000000040178000000000004018000000000000401880000000000040190000000000004019800000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FF50000000000003FF90000000000003FFD000000000000400080000000000040028000000000000162016A3FF60000000000003FFA0000000000003FFE000000000000400100000000000040030000000000000162016B3FF70000000000003FFB0000000000003FFF000000000000400180000000000040038000000000000162016C3FF80000000000003FFC00000000000040000000000000004002000000000000400400000000000001630169400480000000000040068000000000004008800000000000400A800000000000400C8000000000000163016A400500000000000040070000000000004009000000000000400B000000000000400D0000000000000163016B400580000000000040078000000000004009800000000000400B800000000000400D8000000000000163016C40060000000000004008000000000000400A000000000000400C000000000000400E000000000000"},"result":{"expect":"0x03020178017A010179050C01610169400100000000000040050000000000004009000000000000400D00000000000040108000000000000161016A40020000000000004006000000000000400A000000000000400E00000000000040110000000000000161016B40030000000000004007000000000000400B000000000000400F00000000000040118000000000000161016C40040000000000004008000000000000400C00000000000040100000000000004012000000000000016201694012800000000000401480000000000040168000000000004018800000000000401A8000000000000162016A4013000000000000401500000000000040170000000000004019000000000000401B0000000000000162016B4013800000000000401580000000000040178000000000004019800000000000401B8000000000000162016C401400000000000040160000000000004018000000000000401A000000000000401C00000000000001630169401C800000000000401E8000000000004020400000000000402140000000000040224000000000000163016A401D000000000000401F0000000000004020800000000000402180000000000040228000000000000163016B401D800000000000401F8000000000004020C000000000004021C000000000004022C000000000000163016C401E0000000000004020000000000000402100000000000040220000000000004023000000000000"}}
-{"expression":"map(a,f(a)((a+1)*2))","inputs":{"a":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693FA800003FC800003FE8000040040000401400000162016A3FB000003FD000003FF0000040080000401800000162016B3FB800003FD800003FF80000400C0000401C00000162016C3FC000003FE000004000000040100000402000000163016940240000403400004044000040540000406400000163016A40280000403800004048000040580000406800000163016B402C0000403C0000404C0000405C0000406C00000163016C4030000040400000405000004060000040700000"},"result":{"expect":"0x0701020178017A010179050C0161016940080000402800004048000040680000408400000161016A40100000403000004050000040700000408800000161016B40180000403800004058000040780000408C00000161016C4020000040400000406000004080000040900000016201694094000040A4000040B4000040C4000040D400000162016A4098000040A8000040B8000040C8000040D800000162016B409C000040AC000040BC000040CC000040DC00000162016C40A0000040B0000040C0000040D0000040E000000163016940E4000040F4000041020000410A0000411200000163016A40E8000040F8000041040000410C0000411400000163016B40EC000040FC000041060000410E0000411600000163016C40F0000041000000410800004110000041180000"}}
-{"expression":"a+b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FC0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053E0000003E4000003E8000003EA000003EC00000"}}
-{"expression":"a+b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053E0000003E4000003E8000003EA000003EC00000"}}
-{"expression":"a+b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FC00000000000003FD00000000000003FD80000000000003FE00000000000003FE4000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FC00000000000003FC80000000000003FD00000000000003FC80000000000003FD00000000000003FD40000000000003FD00000000000003FD40000000000003FD80000000000003FD40000000000003FD80000000000003FDC0000000000003FD80000000000003FDC0000000000003FE00000000000003FDC0000000000003FE00000000000003FE2000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073E0000003E4000003E8000003EA000003EC000003EE000003F0000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FD000003FD800003FE000003FE800003FF000003FF800004000000040080000400C0000401000004014000040180000401C0000402000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF80000400000004004000040080000400C00004010000040140000401C0000402000004024000040280000402C000040300000403400003F4000003F5000003F6000003F7000003F8000003F8800003F9000003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FE000003FE800003FF000003FF80000400000004004000040080000401000004014000040180000401C0000402000004024000040280000403000004034000040380000403C0000404000004044000040480000"}}
-{"expression":"a+b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FC000000000000001623FD000000000000001633FD8000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FC000000000000001623FD0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FC800000000000001610362617A3FD0000000000000016103666F6F3FC00000000000000162036261723FD000000000000001620362617A3FD4000000000000016203666F6F3FC80000000000000163036261723FD400000000000001630362617A3FD8000000000000016303666F6F3FD0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FC800000000000001610362617A3FD0000000000000016103666F6F3FC00000000000000162036261723FDC00000000000001620362617A3FE0000000000000016203666F6F3FD80000000000000163036261723FE600000000000001630362617A3FE8000000000000016303666F6F3FE4000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FD0000000000000016103666F6F3FC00000000000000162036261723FE2000000000000016203666F6F3FDC000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EE00000016103626172016A3F000000016103626172016B3F100000016103626172016C3F200000016103666F6F01693E000000016103666F6F016A3E400000016103666F6F016B3E800000016103666F6F016C3EA0000001620362617201693F200000016203626172016A3F300000016203626172016B3F400000016203626172016C3F500000016203666F6F01693EA00000016203666F6F016A3EC00000016203666F6F016B3EE00000016203666F6F016C3F000000"}}
-{"expression":"a+b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF400000000000003666F6F3FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE8000000000000"}}
-{"expression":"a+b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"a+b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"a+b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"a+b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693E0000003EE000003F4000003F8800003FB000000161016A3E4000003F0000003F5000003F9000003FB800000161016B3E8000003F1000003F6000003F9800003FC000000161016C3EA000003F2000003F7000003FA000003FC80000016201693EE000003F4000003F8800003FB000003FD800000162016A3F0000003F5000003F9000003FB800003FE000000162016B3F1000003F6000003F9800003FC000003FE800000162016C3F2000003F7000003FA000003FC800003FF00000016301693F4000003F8800003FB000003FD80000400000000163016A3F5000003F9000003FB800003FE00000400400000163016B3F6000003F9800003FC000003FE80000400800000163016C3F7000003FA000003FC800003FF00000400C0000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053E0000003E4000003E8000003EA000003EC00000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053E0000003E4000003E8000003EA000003EC00000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FC00000000000003FD00000000000003FD80000000000003FE00000000000003FE4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FC00000000000003FC80000000000003FD00000000000003FC80000000000003FD00000000000003FD40000000000003FD00000000000003FD40000000000003FD80000000000003FD40000000000003FD80000000000003FDC0000000000003FD80000000000003FDC0000000000003FE00000000000003FDC0000000000003FE00000000000003FE2000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF000000000000400000000000000040010000000000004001800000000000400200000000000040028000000000004003000000000000400380000000000040040000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000004002000000000000400280000000000040038000000000004004000000000000400480000000000040050000000000004005800000000000400600000000000040068000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040020000000000004002800000000000400300000000000040038000000000004004000000000000400480000000000040050000000000004006000000000000400680000000000040070000000000004007800000000000400800000000000040088000000000004009000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073E0000003E4000003E8000003EA000003EC000003EE000003F0000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FD000003FD800003FE000003FE800003FF000003FF800004000000040080000400C0000401000004014000040180000401C0000402000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF80000400000004004000040080000400C00004010000040140000401C0000402000004024000040280000402C000040300000403400003F4000003F5000003F6000003F7000003F8000003F8800003F9000003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FE000003FE800003FF000003FF80000400000004004000040080000401000004014000040180000401C0000402000004024000040280000403000004034000040380000403C0000404000004044000040480000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FC000000000000001623FD000000000000001633FD8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FC000000000000001623FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FC800000000000001610362617A3FD0000000000000016103666F6F3FC00000000000000162036261723FD000000000000001620362617A3FD4000000000000016203666F6F3FC80000000000000163036261723FD400000000000001630362617A3FD8000000000000016303666F6F3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FC800000000000001610362617A3FD0000000000000016103666F6F3FC00000000000000162036261723FDC00000000000001620362617A3FE0000000000000016203666F6F3FD80000000000000163036261723FE600000000000001630362617A3FE8000000000000016303666F6F3FE4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FD0000000000000016103666F6F3FC00000000000000162036261723FE2000000000000016203666F6F3FDC000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FDC000000000000016103626172016A3FE0000000000000016103626172016B3FE2000000000000016103626172016C3FE4000000000000016103666F6F01693FC0000000000000016103666F6F016A3FC8000000000000016103666F6F016B3FD0000000000000016103666F6F016C3FD400000000000001620362617201693FE4000000000000016203626172016A3FE6000000000000016203626172016B3FE8000000000000016203626172016C3FEA000000000000016203666F6F01693FD4000000000000016203666F6F016A3FD8000000000000016203666F6F016B3FDC000000000000016203666F6F016C3FE0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EE00000016103626172016A3F000000016103626172016B3F100000016103626172016C3F200000016103666F6F01693E000000016103666F6F016A3E400000016103666F6F016B3E800000016103666F6F016C3EA0000001620362617201693F200000016203626172016A3F300000016203626172016B3F400000016203626172016C3F500000016203666F6F01693EA00000016203666F6F016A3EC00000016203666F6F016B3EE00000016203666F6F016C3F000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF400000000000003666F6F3FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FC00000000000003FDC0000000000003FE80000000000003FF10000000000003FF60000000000000161016A3FC80000000000003FE00000000000003FEA0000000000003FF20000000000003FF70000000000000161016B3FD00000000000003FE20000000000003FEC0000000000003FF30000000000003FF80000000000000161016C3FD40000000000003FE40000000000003FEE0000000000003FF40000000000003FF9000000000000016201693FDC0000000000003FE80000000000003FF10000000000003FF60000000000003FFB0000000000000162016A3FE00000000000003FEA0000000000003FF20000000000003FF70000000000003FFC0000000000000162016B3FE20000000000003FEC0000000000003FF30000000000003FF80000000000003FFD0000000000000162016C3FE40000000000003FEE0000000000003FF40000000000003FF90000000000003FFE000000000000016301693FE80000000000003FF10000000000003FF60000000000003FFB00000000000040000000000000000163016A3FEA0000000000003FF20000000000003FF70000000000003FFC00000000000040008000000000000163016B3FEC0000000000003FF30000000000003FF80000000000003FFD00000000000040010000000000000163016C3FEE0000000000003FF40000000000003FF90000000000003FFE0000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(a+b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693E0000003EE000003F4000003F8800003FB000000161016A3E4000003F0000003F5000003F9000003FB800000161016B3E8000003F1000003F6000003F9800003FC000000161016C3EA000003F2000003F7000003FA000003FC80000016201693EE000003F4000003F8800003FB000003FD800000162016A3F0000003F5000003F9000003FB800003FE000000162016B3F1000003F6000003F9800003FC000003FE800000162016C3F2000003F7000003FA000003FC800003FF00000016301693F4000003F8800003FB000003FD80000400000000163016A3F5000003F9000003FB800003FE00000400400000163016B3F6000003F9800003FC000003FE80000400800000163016C3F7000003FA000003FC800003FF00000400C0000"}}
-{"expression":"a-b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FC00000000000003FC80000000000003FD0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x06010101780500000000BD800000BE000000BE400000BE800000"}}
-{"expression":"a-b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003D8000003E0000003E4000003E800000"}}
-{"expression":"a-b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A030000000000000000BFB0000000000000BFC00000000000003FB00000000000000000000000000000BFB00000000000003FC00000000000003FB00000000000000000000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFB0000000000000BFC0000000000000BFC8000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A0700000000BD800000BE000000BE400000BE800000BEA00000BEC00000BEC00000BEE00000BF000000BF100000BF200000BF300000BF400000BF400000BF500000BF600000BF700000BF800000BF880000BF900000BF900000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC00000BFC80000BFD00000BFD80000BFE00000BFE80000BFF000003EA000003E8000003E4000003E0000003D80000000000000BD800000BD800000BE000000BE400000BE800000BEA00000BEC00000BEE00000BEE00000BF000000BF100000BF200000BF300000BF400000BF500000BF500000BF600000BF700000BF800000BF880000BF900000BF980000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC800003F2000003F1000003F0000003EE000003EC000003EA000003E8000003E8000003E4000003E0000003D80000000000000BD800000BE000000BE000000BE400000BE800000BEA00000BEC00000BEE00000BF000000BF000000BF100000BF200000BF300000BF400000BF500000BF600000BF600000BF700000BF800000BF880000BF900000BF980000BFA00000"}}
-{"expression":"a-b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172BFB000000000000001610362617ABFC0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617ABFB0000000000000016203666F6F3FB00000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F3FC0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172BFB000000000000001610362617ABFC0000000000000016103666F6F0000000000000000016203626172BFC800000000000001620362617ABFD0000000000000016203666F6FBFC0000000000000016303626172BFD400000000000001630362617ABFD8000000000000016303666F6FBFD0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A100161036261720169BE400000016103626172016ABE800000016103626172016BBEA00000016103626172016CBEC00000016103666F6F016900000000016103666F6F016ABD800000016103666F6F016BBE000000016103666F6F016CBE400000016203626172016900000000016203626172016ABD800000016203626172016BBE000000016203626172016CBE400000016203666F6F01693E400000016203666F6F016A3E000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"a-b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE000000000000003666F6F0000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"a-b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000BE400000BEC00000BF100000BF4000000161016ABD800000BE800000BEE00000BF200000BF5000000161016BBE000000BEA00000BF000000BF300000BF6000000161016CBE400000BEC00000BF100000BF400000BF700000016201693EA000003E000000BD800000BE800000BEE000000162016A3E8000003D800000BE000000BEA00000BF0000000162016B3E40000000000000BE400000BEC00000BF1000000162016C3E000000BD800000BE800000BEE00000BF200000016301693F2000003EE000003E8000003D800000BE0000000163016A3F1000003EC000003E40000000000000BE4000000163016B3F0000003EA000003E000000BD800000BE8000000163016C3EE000003E8000003D800000BE000000BEA00000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FC00000000000003FC80000000000003FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x06010101780500000000BD800000BE000000BE400000BE800000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003D8000003E0000003E4000003E800000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179050000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A030000000000000000BFB0000000000000BFC00000000000003FB00000000000000000000000000000BFB00000000000003FC00000000000003FB00000000000000000000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFB0000000000000BFC0000000000000BFC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A070000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF2000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF8000000000000BFF9000000000000BFFA000000000000BFFB000000000000BFFC000000000000BFFD000000000000BFFE0000000000003FD40000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEA000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF3000000000000BFF4000000000000BFF5000000000000BFF6000000000000BFF7000000000000BFF8000000000000BFF90000000000003FE40000000000003FE20000000000003FE00000000000003FDC0000000000003FD80000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFEA000000000000BFEC000000000000BFEC000000000000BFEE000000000000BFF0000000000000BFF1000000000000BFF2000000000000BFF3000000000000BFF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A0700000000BD800000BE000000BE400000BE800000BEA00000BEC00000BEC00000BEE00000BF000000BF100000BF200000BF300000BF400000BF400000BF500000BF600000BF700000BF800000BF880000BF900000BF900000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC00000BFC80000BFD00000BFD80000BFE00000BFE80000BFF000003EA000003E8000003E4000003E0000003D80000000000000BD800000BD800000BE000000BE400000BE800000BEA00000BEC00000BEE00000BEE00000BF000000BF100000BF200000BF300000BF400000BF500000BF500000BF600000BF700000BF800000BF880000BF900000BF980000BF980000BFA00000BFA80000BFB00000BFB80000BFC00000BFC800003F2000003F1000003F0000003EE000003EC000003EA000003E8000003E8000003E4000003E0000003D80000000000000BD800000BE000000BE000000BE400000BE800000BEA00000BEC00000BEE00000BF000000BF000000BF100000BF200000BF300000BF400000BF500000BF600000BF600000BF700000BF800000BF880000BF900000BF980000BFA00000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172BFB000000000000001610362617ABFC0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617ABFB0000000000000016203666F6F3FB00000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F3FC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172BFB000000000000001610362617ABFC0000000000000016103666F6F0000000000000000016203626172BFC800000000000001620362617ABFD0000000000000016203666F6FBFC0000000000000016303626172BFD400000000000001630362617ABFD8000000000000016303666F6FBFD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A100161036261720169BFC8000000000000016103626172016ABFD0000000000000016103626172016BBFD4000000000000016103626172016CBFD8000000000000016103666F6F01690000000000000000016103666F6F016ABFB0000000000000016103666F6F016BBFC0000000000000016103666F6F016CBFC800000000000001620362617201690000000000000000016203626172016ABFB0000000000000016203626172016BBFC0000000000000016203626172016CBFC8000000000000016203666F6F01693FC8000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A100161036261720169BE400000016103626172016ABE800000016103626172016BBEA00000016103626172016CBEC00000016103666F6F016900000000016103666F6F016ABD800000016103666F6F016BBE000000016103666F6F016CBE400000016203626172016900000000016203626172016ABD800000016203626172016BBE000000016203626172016CBE400000016203666F6F01693E400000016203666F6F016A3E000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A070203626172BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFE6000000000000BFE8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE0000000000000BFE2000000000000BFE4000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD8000000000000BFDC000000000000BFE000000000000003666F6F0000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD0000000000000BFD4000000000000BFD80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000BFC8000000000000BFD00000000000003FD00000000000003FC80000000000003FC00000000000003FB00000000000000000000000000000BFB0000000000000BFC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101690000000000000000BFC8000000000000BFD8000000000000BFE2000000000000BFE80000000000000161016ABFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000BFEA0000000000000161016BBFC0000000000000BFD4000000000000BFE0000000000000BFE6000000000000BFEC0000000000000161016CBFC8000000000000BFD8000000000000BFE2000000000000BFE8000000000000BFEE000000000000016201693FD40000000000003FC0000000000000BFB0000000000000BFD0000000000000BFDC0000000000000162016A3FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000BFE00000000000000162016B3FC80000000000000000000000000000BFC8000000000000BFD8000000000000BFE20000000000000162016C3FC0000000000000BFB0000000000000BFD0000000000000BFDC000000000000BFE4000000000000016301693FE40000000000003FDC0000000000003FD00000000000003FB0000000000000BFC00000000000000163016A3FE20000000000003FD80000000000003FC80000000000000000000000000000BFC80000000000000163016B3FE00000000000003FD40000000000003FC0000000000000BFB0000000000000BFD00000000000000163016C3FDC0000000000003FD00000000000003FB0000000000000BFC0000000000000BFD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a-b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000BE400000BEC00000BF100000BF4000000161016ABD800000BE800000BEE00000BF200000BF5000000161016BBE000000BEA00000BF000000BF300000BF6000000161016CBE400000BEC00000BF100000BF400000BF700000016201693EA000003E000000BD800000BE800000BEE000000162016A3E8000003D800000BE000000BEA00000BF0000000162016B3E40000000000000BE400000BEC00000BF1000000162016C3E000000BD800000BE800000BEE00000BF200000016301693F2000003EE000003E8000003D800000BE0000000163016A3F1000003EC000003E40000000000000BE4000000163016B3F0000003EA000003E000000BD800000BE8000000163016C3EE000003E8000003D800000BE000000BEA00000"}}
-{"expression":"a*b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003F70000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053F700000000000003F800000000000003F880000000000003F900000000000003F94000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053F700000000000003F800000000000003F880000000000003F900000000000003F94000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053B8000003C0000003C4000003C8000003CA00000"}}
-{"expression":"a*b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053B8000003C0000003C4000003C8000003CA00000"}}
-{"expression":"a*b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053F700000000000003F900000000000003FA20000000000003FB00000000000003FB9000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F800000000000003F900000000000003F980000000000003FA00000000000003FA40000000000003F880000000000003F980000000000003FA20000000000003FA80000000000003FAE0000000000003F900000000000003FA00000000000003FA80000000000003FB00000000000003FB40000000000003F940000000000003FA40000000000003FAE0000000000003FB40000000000003FB9000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003FA80000000000003FAC0000000000003FB00000000000003FB20000000000003FB40000000000003FC08000000000003FC20000000000003FC38000000000003FC50000000000003FC68000000000003FD00000000000003FD10000000000003FD20000000000003FD30000000000003FD40000000000003FDA4000000000003FDB8000000000003FDCC000000000003FDE0000000000003FDF400000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033F700000000000003F800000000000003F880000000000003F800000000000003F900000000000003F980000000000003F880000000000003F980000000000003FA20000000000003F900000000000003F940000000000003F980000000000003FA00000000000003FA40000000000003FA80000000000003FA80000000000003FAE0000000000003FB2000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"a*b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"a*b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"a*b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073B8000003C0000003C4000003C8000003CA000003CC000003CE000003D8000003D9000003DA000003DB000003DC000003DD000003DE000003E3400003E4000003E4C00003E5800003E6400003E7000003E7C00003EB000003EB800003EC000003EC800003ED000003ED800003EE000003F1100003F1600003F1B00003F2000003F2500003F2A00003F2F00003CC000003D4000003D9000003DC000003DF000003E1000003E2800003E6000003E7C00003E8C00003E9A00003EA800003EB600003EC400003EF000003F0000003F0800003F1000003F1800003F2000003F2800003F4600003F4F00003F5800003F6100003F6A00003F7300003F7C00003F9100003F9600003F9B00003FA000003FA500003FAA00003FAF00003D3000003DB000003E0400003E3000003E5C00003E8400003E9A00003EC000003ED800003EF000003F0400003F1000003F1C00003F2800003F4300003F5000003F5D00003F6A00003F7700003F8200003F8880003F9A00003FA100003FA800003FAF00003FB600003FBD00003FC400003FD980003FE100003FE880003FF000003FF780003FFF000040034000"}}
-{"expression":"a*b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613F7000000000000001623F9000000000000001633FA2000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613F7000000000000001623F90000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723F8000000000000001610362617A3F88000000000000016103666F6F3F700000000000000162036261723F9000000000000001620362617A3F98000000000000016203666F6F3F800000000000000163036261723F9800000000000001630362617A3FA2000000000000016303666F6F3F88000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723F8000000000000001610362617A3F88000000000000016103666F6F3F700000000000000162036261723FA400000000000001620362617A3FA8000000000000016203666F6F3FA00000000000000163036261723FB800000000000001630362617A3FBB000000000000016303666F6F3FB5000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723F90000000000000016103666F6F3F700000000000000162036261723FB4000000000000016203666F6F3FA8000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"a*b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693D200000016103626172016A3D400000016103626172016B3D600000016103626172016C3D800000016103666F6F01693B800000016103666F6F016A3C000000016103666F6F016B3C400000016103666F6F016C3C80000001620362617201693DC80000016203626172016A3DF00000016203626172016B3E0C0000016203626172016C3E200000016203666F6F01693C800000016203666F6F016A3D000000016203666F6F016B3D400000016203666F6F016C3D800000"}}
-{"expression":"a*b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC00000000000003FC20000000000003FC40000000000003FC60000000000003FC80000000000003FCA0000000000003FCC0000000000003FC80000000000003FCB0000000000003FCE0000000000003FD08000000000003FD20000000000003FD38000000000003FD500000000000003666F6F3F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003F880000000000003F980000000000003FA20000000000003FA80000000000003FAE0000000000003FB20000000000003FB50000000000003F940000000000003FA40000000000003FAE0000000000003FB40000000000003FB90000000000003FBE0000000000003FC1800000000000"}}
-{"expression":"a*b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"a*b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"a*b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"a*b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693B8000003D2000003DD800003E5000003EAA00000161016A3C0000003D4000003DF000003E6000003EB400000161016B3C4000003D6000003E0400003E7000003EBE00000161016C3C8000003D8000003E1000003E8000003EC80000016201693CC000003E0C00003E9000003EEA00003F2A00000162016A3D4000003E2800003EA000003EFC00003F3400000162016B3D9000003E4400003EB000003F0700003F3E00000162016C3DC000003E6000003EC000003F1000003F480000016301693D3000003E7000003EEA00003F3600003F7F00000163016A3DB000003E9000003F0200003F4400003F8700000163016B3E0400003EA800003F0F00003F5200003F8E80000163016C3E3000003EC000003F1C00003F6000003F960000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003F70000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053F700000000000003F800000000000003F880000000000003F900000000000003F94000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053F700000000000003F800000000000003F880000000000003F900000000000003F94000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053B8000003C0000003C4000003C8000003CA00000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053B8000003C0000003C4000003C8000003CA00000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053F700000000000003F900000000000003FA20000000000003FB00000000000003FB9000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F800000000000003F900000000000003F980000000000003FA00000000000003FA40000000000003F880000000000003F980000000000003FA20000000000003FA80000000000003FAE0000000000003F900000000000003FA00000000000003FA80000000000003FB00000000000003FB40000000000003F940000000000003FA40000000000003FAE0000000000003FB40000000000003FB9000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003FA80000000000003FAC0000000000003FB00000000000003FB20000000000003FB40000000000003FC08000000000003FC20000000000003FC38000000000003FC50000000000003FC68000000000003FD00000000000003FD10000000000003FD20000000000003FD30000000000003FD40000000000003FDA4000000000003FDB8000000000003FDCC000000000003FDE0000000000003FDF400000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033F700000000000003F800000000000003F880000000000003F800000000000003F900000000000003F980000000000003F880000000000003F980000000000003FA20000000000003F900000000000003F940000000000003F980000000000003FA00000000000003FA40000000000003FA80000000000003FA80000000000003FAE0000000000003FB2000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC68000000000003FC80000000000003FC98000000000003FCB0000000000003FCC8000000000003FCE0000000000003FCF8000000000003FD60000000000003FD70000000000003FD80000000000003FD90000000000003FDA0000000000003FDB0000000000003FDC0000000000003FE22000000000003FE2C000000000003FE36000000000003FE40000000000003FE4A000000000003FE54000000000003FE5E000000000003F980000000000003FA80000000000003FB20000000000003FB80000000000003FBE0000000000003FC20000000000003FC50000000000003FCC0000000000003FCF8000000000003FD18000000000003FD34000000000003FD50000000000003FD6C000000000003FD88000000000003FDE0000000000003FE00000000000003FE10000000000003FE20000000000003FE30000000000003FE40000000000003FE50000000000003FE8C000000000003FE9E000000000003FEB0000000000003FEC2000000000003FED4000000000003FEE6000000000003FEF8000000000003FF22000000000003FF2C000000000003FF36000000000003FF40000000000003FF4A000000000003FF54000000000003FF5E000000000003FA60000000000003FB60000000000003FC08000000000003FC60000000000003FCB8000000000003FD08000000000003FD34000000000003FD80000000000003FDB0000000000003FDE0000000000003FE08000000000003FE20000000000003FE38000000000003FE50000000000003FE86000000000003FEA0000000000003FEBA000000000003FED4000000000003FEEE000000000003FF04000000000003FF11000000000003FF34000000000003FF42000000000003FF50000000000003FF5E000000000003FF6C000000000003FF7A000000000003FF88000000000003FFB3000000000003FFC2000000000003FFD1000000000003FFE0000000000003FFEF000000000003FFFE000000000004000680000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073B8000003C0000003C4000003C8000003CA000003CC000003CE000003D8000003D9000003DA000003DB000003DC000003DD000003DE000003E3400003E4000003E4C00003E5800003E6400003E7000003E7C00003EB000003EB800003EC000003EC800003ED000003ED800003EE000003F1100003F1600003F1B00003F2000003F2500003F2A00003F2F00003CC000003D4000003D9000003DC000003DF000003E1000003E2800003E6000003E7C00003E8C00003E9A00003EA800003EB600003EC400003EF000003F0000003F0800003F1000003F1800003F2000003F2800003F4600003F4F00003F5800003F6100003F6A00003F7300003F7C00003F9100003F9600003F9B00003FA000003FA500003FAA00003FAF00003D3000003DB000003E0400003E3000003E5C00003E8400003E9A00003EC000003ED800003EF000003F0400003F1000003F1C00003F2800003F4300003F5000003F5D00003F6A00003F7700003F8200003F8880003F9A00003FA100003FA800003FAF00003FB600003FBD00003FC400003FD980003FE100003FE880003FF000003FF780003FFF000040034000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613F7000000000000001623F9000000000000001633FA2000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613F7000000000000001623F90000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723F8000000000000001610362617A3F88000000000000016103666F6F3F700000000000000162036261723F9000000000000001620362617A3F98000000000000016203666F6F3F800000000000000163036261723F9800000000000001630362617A3FA2000000000000016303666F6F3F88000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723F8000000000000001610362617A3F88000000000000016103666F6F3F700000000000000162036261723FA400000000000001620362617A3FA8000000000000016203666F6F3FA00000000000000163036261723FB800000000000001630362617A3FBB000000000000016303666F6F3FB5000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723F90000000000000016103666F6F3F700000000000000162036261723FB4000000000000016203666F6F3FA8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FA4000000000000016103626172016A3FA8000000000000016103626172016B3FAC000000000000016103626172016C3FB0000000000000016103666F6F01693F70000000000000016103666F6F016A3F80000000000000016103666F6F016B3F88000000000000016103666F6F016C3F9000000000000001620362617201693FB9000000000000016203626172016A3FBE000000000000016203626172016B3FC1800000000000016203626172016C3FC4000000000000016203666F6F01693F90000000000000016203666F6F016A3FA0000000000000016203666F6F016B3FA8000000000000016203666F6F016C3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693D200000016103626172016A3D400000016103626172016B3D600000016103626172016C3D800000016103666F6F01693B800000016103666F6F016A3C000000016103666F6F016B3C400000016103666F6F016C3C80000001620362617201693DC80000016203626172016A3DF00000016203626172016B3E0C0000016203626172016C3E200000016203666F6F01693C800000016203666F6F016A3D000000016203666F6F016B3D400000016203666F6F016C3D800000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FB00000000000003FB20000000000003FB40000000000003FB60000000000003FB80000000000003FBA0000000000003FBC0000000000003FC00000000000003FC20000000000003FC40000000000003FC60000000000003FC80000000000003FCA0000000000003FCC0000000000003FC80000000000003FCB0000000000003FCE0000000000003FD08000000000003FD20000000000003FD38000000000003FD500000000000003666F6F3F700000000000003F800000000000003F880000000000003F900000000000003F940000000000003F980000000000003F9C0000000000003F880000000000003F980000000000003FA20000000000003FA80000000000003FAE0000000000003FB20000000000003FB50000000000003F940000000000003FA40000000000003FAE0000000000003FB40000000000003FB90000000000003FBE0000000000003FC1800000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693F700000000000003FA40000000000003FBB0000000000003FCA0000000000003FD54000000000000161016A3F800000000000003FA80000000000003FBE0000000000003FCC0000000000003FD68000000000000161016B3F880000000000003FAC0000000000003FC08000000000003FCE0000000000003FD7C000000000000161016C3F900000000000003FB00000000000003FC20000000000003FD00000000000003FD9000000000000016201693F980000000000003FC18000000000003FD20000000000003FDD4000000000003FE54000000000000162016A3FA80000000000003FC50000000000003FD40000000000003FDF8000000000003FE68000000000000162016B3FB20000000000003FC88000000000003FD60000000000003FE0E000000000003FE7C000000000000162016C3FB80000000000003FCC0000000000003FD80000000000003FE20000000000003FE9000000000000016301693FA60000000000003FCE0000000000003FDD4000000000003FE6C000000000003FEFE000000000000163016A3FB60000000000003FD20000000000003FE04000000000003FE88000000000003FF0E000000000000163016B3FC08000000000003FD50000000000003FE1E000000000003FEA4000000000003FF1D000000000000163016C3FC60000000000003FD80000000000003FE38000000000003FEC0000000000003FF2C00000000000"}}
-{"expression":"join(a,b,f(a,b)(a*b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693B8000003D2000003DD800003E5000003EAA00000161016A3C0000003D4000003DF000003E6000003EB400000161016B3C4000003D6000003E0400003E7000003EBE00000161016C3C8000003D8000003E1000003E8000003EC80000016201693CC000003E0C00003E9000003EEA00003F2A00000162016A3D4000003E2800003EA000003EFC00003F3400000162016B3D9000003E4400003EB000003F0700003F3E00000162016C3DC000003E6000003EC000003F1000003F480000016301693D3000003E7000003EEA00003F3600003F7F00000163016A3DB000003E9000003F0200003F4400003F8700000163016B3E0400003EA800003F0F00003F5200003F8E80000163016C3E3000003EC000003F1C00003F6000003F960000"}}
-{"expression":"a/b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A"}}
-{"expression":"a/b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F8000003F0000003EAAAAAB3E8000003E4CCCCD"}}
-{"expression":"a/b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000040000000404000004080000040A00000"}}
-{"expression":"a/b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A40000000000000003FF00000000000003FE55555555555553FE00000000000003FD999999999999A40080000000000003FF80000000000003FF00000000000003FE80000000000003FE3333333333333401000000000000040000000000000003FF55555555555553FF00000000000003FE999999999999A401400000000000040040000000000003FFAAAAAAAAAAAAB3FF40000000000003FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FD55555555555553FD24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FD1745D1745D1743FD00000000000003FCD89D89D89D89E3FCB6DB6DB6DB6DB3FC999999999999A3FD00000000000003FCE1E1E1E1E1E1E3FCC71C71C71C71C3FCAF286BCA1AF283FC999999999999A3FCE79E79E79E79E3FCD1745D1745D173FCBD37A6F4DE9BD3FCAAAAAAAAAAAAB3FC999999999999A"}}
-{"expression":"a/b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000003FE00000000000003FD555555555555540000000000000003FF00000000000003FE555555555555540080000000000003FF80000000000003FF00000000000003FD00000000000003FC999999999999A3FC55555555555553FE00000000000003FD999999999999A3FD55555555555553FE80000000000003FE33333333333333FE0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"a/b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"a/b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"a/b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000003F0000003EAAAAAB3E8000003E4CCCCD3E2AAAAB3E1249253E8000003E638E393E4CCCCD3E3A2E8C3E2AAAAB3E1D89D93E1249253E4CCCCD3E4000003E34B4B53E2AAAAB3E21AF283E19999A3E1249253E3A2E8C3E3216433E2AAAAB3E23D70A3E1D89D93E17B4263E1249253E308D3E3E2AAAAB3E25294A3E2000003E1B26CA3E1696973E12492540C0000040400000400000003FC000003F99999A3F8000003F5B6DB73F6000003F471C723F3333333F22E8BA3F1555553F09D89E3F0000003F0888893F0000003EF0F0F13EE38E393ED794363ECCCCCD3EC30C313ED1745D3EC8590B3EC000003EB851EC3EB13B143EAAAAAB3EA492493EB08D3E3EAAAAAB3EA5294A3EA000003E9B26CA3E9696973E9249254130000040B00000406AAAAB40300000400CCCCD3FEAAAAB3FC924923FC000003FAAAAAB3F99999A3F8BA2E93F8000003F6C4EC53F5B6DB73F5DDDDE3F5000003F43C3C43F38E38E3F2F286C3F2666663F1E79E83F22E8BA3F1BD37A3F1555553F0F5C293F09D89E3F04BDA13F0000003F0469EE3F0000003EF7BDEF3EF000003EE8BA2F3EE1E1E23EDB6DB7"}}
-{"expression":"a/b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE000000000000001610362617A3FD5555555555555016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FE5555555555555016203666F6F40000000000000000163036261723FF800000000000001630362617A3FF0000000000000016303666F6F4008000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE000000000000001610362617A3FD5555555555555016103666F6F3FF00000000000000162036261723FD999999999999A01620362617A3FD5555555555555016203666F6F3FE00000000000000163036261723FD800000000000001630362617A3FD5555555555555016303666F6F3FDB6DB6DB6DB6DB"}}
-{"expression":"a/b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF4000000000000016203666F6F3FF5555555555555"}}
-{"expression":"a/b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693ECCCCCD016103626172016A3EAAAAAB016103626172016B3E924925016103626172016C3E800000016103666F6F01693F800000016103666F6F016A3F000000016103666F6F016B3EAAAAAB016103666F6F016C3E80000001620362617201693F800000016203626172016A3F555555016203626172016B3F36DB6E016203626172016C3F200000016203666F6F016940800000016203666F6F016A40000000016203666F6F016B3FAAAAAB016203666F6F016C3F800000"}}
-{"expression":"a/b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FE00000000000003FDC71C71C71C71C3FD999999999999A3FD745D1745D17463FD55555555555553FD3B13B13B13B143FD24924924924923FE80000000000003FE55555555555553FE33333333333333FE1745D1745D1743FE00000000000003FDD89D89D89D89E3FDB6DB6DB6DB6DB03666F6F3FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC249249249249240080000000000003FF80000000000003FF00000000000003FE80000000000003FE33333333333333FE00000000000003FDB6DB6DB6DB6DB401400000000000040040000000000003FFAAAAAAAAAAAAB3FF40000000000003FF00000000000003FEAAAAAAAAAAAAB3FE6DB6DB6DB6DB7"}}
-{"expression":"a/b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"a/b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003ECCCCCD3EAAAAAB3E9D89D93E9696970161016A3F0000003EAAAAAB3E99999A3E9249253E8E38E40161016B3EAAAAAB3E9249253E8BA2E93E8888893E86BCA20161016C3E8000003E8000003E8000003E8000003E8000000162016940C000003FB333333F638E393F313B143F1696970162016A404000003F9555553F4CCCCD3F2492493F0E38E40162016B400000003F8000003F3A2E8C3F19999A3F06BCA20162016C3FC000003F6000003F2AAAAB3F1000003F00000001630169413000004019999A3FB8E38E3F89D89E3F61E1E20163016A40B00000400000003FA666663F8000003F5555550163016B406AAAAB3FDB6DB73F9745D13F6EEEEF3F4A1AF30163016C403000003FC000003F8AAAAB3F6000003F400000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F8000003F0000003EAAAAAB3E8000003E4CCCCD"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000040000000404000004080000040A00000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A40000000000000003FF00000000000003FE55555555555553FE00000000000003FD999999999999A40080000000000003FF80000000000003FF00000000000003FE80000000000003FE3333333333333401000000000000040000000000000003FF55555555555553FF00000000000003FE999999999999A401400000000000040040000000000003FFAAAAAAAAAAAAB3FF40000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FD55555555555553FD24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FD1745D1745D1743FD00000000000003FCD89D89D89D89E3FCB6DB6DB6DB6DB3FC999999999999A3FD00000000000003FCE1E1E1E1E1E1E3FCC71C71C71C71C3FCAF286BCA1AF283FC999999999999A3FCE79E79E79E79E3FCD1745D1745D173FCBD37A6F4DE9BD3FCAAAAAAAAAAAAB3FC999999999999A"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000003FE00000000000003FD555555555555540000000000000003FF00000000000003FE555555555555540080000000000003FF80000000000003FF00000000000003FD00000000000003FC999999999999A3FC55555555555553FE00000000000003FD999999999999A3FD55555555555553FE80000000000003FE33333333333333FE0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC24924924924923FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FC999999999999A3FC80000000000003FC69696969696973FC55555555555553FC435E50D79435E3FC33333333333333FC24924924924923FC745D1745D17463FC642C8590B21643FC55555555555553FC47AE147AE147B3FC3B13B13B13B143FC2F684BDA12F683FC24924924924923FC611A7B9611A7C3FC55555555555553FC4A5294A5294A53FC40000000000003FC364D9364D93653FC2D2D2D2D2D2D33FC24924924924924018000000000000400800000000000040000000000000003FF80000000000003FF33333333333333FF00000000000003FEB6DB6DB6DB6DB3FEC0000000000003FE8E38E38E38E393FE66666666666663FE45D1745D1745D3FE2AAAAAAAAAAAB3FE13B13B13B13B13FE00000000000003FE11111111111113FE00000000000003FDE1E1E1E1E1E1E3FDC71C71C71C71C3FDAF286BCA1AF283FD999999999999A3FD86186186186183FDA2E8BA2E8BA2F3FD90B21642C85913FD80000000000003FD70A3D70A3D70A3FD62762762762763FD55555555555553FD49249249249253FD611A7B9611A7C3FD55555555555553FD4A5294A5294A53FD40000000000003FD364D9364D93653FD2D2D2D2D2D2D33FD249249249249240260000000000004016000000000000400D5555555555554006000000000000400199999999999A3FFD5555555555553FF92492492492493FF80000000000003FF55555555555553FF33333333333333FF1745D1745D1743FF00000000000003FED89D89D89D89E3FEB6DB6DB6DB6DB3FEBBBBBBBBBBBBC3FEA0000000000003FE87878787878783FE71C71C71C71C73FE5E50D79435E513FE4CCCCCCCCCCCD3FE3CF3CF3CF3CF43FE45D1745D1745D3FE37A6F4DE9BD383FE2AAAAAAAAAAAB3FE1EB851EB851EC3FE13B13B13B13B13FE097B425ED097B3FE00000000000003FE08D3DCB08D3DD3FE00000000000003FDEF7BDEF7BDEF83FDE0000000000003FDD1745D1745D173FDC3C3C3C3C3C3C3FDB6DB6DB6DB6DB"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000003F0000003EAAAAAB3E8000003E4CCCCD3E2AAAAB3E1249253E8000003E638E393E4CCCCD3E3A2E8C3E2AAAAB3E1D89D93E1249253E4CCCCD3E4000003E34B4B53E2AAAAB3E21AF283E19999A3E1249253E3A2E8C3E3216433E2AAAAB3E23D70A3E1D89D93E17B4263E1249253E308D3E3E2AAAAB3E25294A3E2000003E1B26CA3E1696973E12492540C0000040400000400000003FC000003F99999A3F8000003F5B6DB73F6000003F471C723F3333333F22E8BA3F1555553F09D89E3F0000003F0888893F0000003EF0F0F13EE38E393ED794363ECCCCCD3EC30C313ED1745D3EC8590B3EC000003EB851EC3EB13B143EAAAAAB3EA492493EB08D3E3EAAAAAB3EA5294A3EA000003E9B26CA3E9696973E9249254130000040B00000406AAAAB40300000400CCCCD3FEAAAAB3FC924923FC000003FAAAAAB3F99999A3F8BA2E93F8000003F6C4EC53F5B6DB73F5DDDDE3F5000003F43C3C43F38E38E3F2F286C3F2666663F1E79E83F22E8BA3F1BD37A3F1555553F0F5C293F09D89E3F04BDA13F0000003F0469EE3F0000003EF7BDEF3EF000003EE8BA2F3EE1E1E23EDB6DB7"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE000000000000001610362617A3FD5555555555555016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FE5555555555555016203666F6F40000000000000000163036261723FF800000000000001630362617A3FF0000000000000016303666F6F4008000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE000000000000001610362617A3FD5555555555555016103666F6F3FF00000000000000162036261723FD999999999999A01620362617A3FD5555555555555016203666F6F3FE00000000000000163036261723FD800000000000001630362617A3FD5555555555555016303666F6F3FDB6DB6DB6DB6DB"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF4000000000000016203666F6F3FF5555555555555"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD999999999999A016103626172016A3FD5555555555555016103626172016B3FD2492492492492016103626172016C3FD0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FE0000000000000016103666F6F016B3FD5555555555555016103666F6F016C3FD000000000000001620362617201693FF0000000000000016203626172016A3FEAAAAAAAAAAAAB016203626172016B3FE6DB6DB6DB6DB7016203626172016C3FE4000000000000016203666F6F01694010000000000000016203666F6F016A4000000000000000016203666F6F016B3FF5555555555555016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693ECCCCCD016103626172016A3EAAAAAB016103626172016B3E924925016103626172016C3E800000016103666F6F01693F800000016103666F6F016A3F000000016103666F6F016B3EAAAAAB016103666F6F016C3E80000001620362617201693F800000016203626172016A3F555555016203626172016B3F36DB6E016203626172016C3F200000016203666F6F016940800000016203666F6F016A40000000016203666F6F016B3FAAAAAB016203666F6F016C3F800000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD00000000000003FCC71C71C71C71C3FC999999999999A3FC745D1745D17463FC55555555555553FC3B13B13B13B143FC24924924924923FE00000000000003FDC71C71C71C71C3FD999999999999A3FD745D1745D17463FD55555555555553FD3B13B13B13B143FD24924924924923FE80000000000003FE55555555555553FE33333333333333FE1745D1745D1743FE00000000000003FDD89D89D89D89E3FDB6DB6DB6DB6DB03666F6F3FF00000000000003FE00000000000003FD55555555555553FD00000000000003FC999999999999A3FC55555555555553FC249249249249240080000000000003FF80000000000003FF00000000000003FE80000000000003FE33333333333333FE00000000000003FDB6DB6DB6DB6DB401400000000000040040000000000003FFAAAAAAAAAAAAB3FF40000000000003FF00000000000003FEAAAAAAAAAAAAB3FE6DB6DB6DB6DB7"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FD999999999999A3FD55555555555553FD3B13B13B13B143FD2D2D2D2D2D2D30161016A3FE00000000000003FD55555555555553FD33333333333333FD24924924924923FD1C71C71C71C720161016B3FD55555555555553FD24924924924923FD1745D1745D1743FD11111111111113FD0D79435E50D790161016C3FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000000162016940180000000000003FF66666666666663FEC71C71C71C71C3FE62762762762763FE2D2D2D2D2D2D30162016A40080000000000003FF2AAAAAAAAAAAB3FE999999999999A3FE49249249249253FE1C71C71C71C720162016B40000000000000003FF00000000000003FE745D1745D17463FE33333333333333FE0D79435E50D790162016C3FF80000000000003FEC0000000000003FE55555555555553FE20000000000003FE000000000000001630169402600000000000040033333333333333FF71C71C71C71C73FF13B13B13B13B13FEC3C3C3C3C3C3C0163016A401600000000000040000000000000003FF4CCCCCCCCCCCD3FF00000000000003FEAAAAAAAAAAAAB0163016B400D5555555555553FFB6DB6DB6DB6DB3FF2E8BA2E8BA2E93FEDDDDDDDDDDDDE3FE9435E50D794360163016C40060000000000003FF80000000000003FF15555555555553FEC0000000000003FE8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a/b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003ECCCCCD3EAAAAAB3E9D89D93E9696970161016A3F0000003EAAAAAB3E99999A3E9249253E8E38E40161016B3EAAAAAB3E9249253E8BA2E93E8888893E86BCA20161016C3E8000003E8000003E8000003E8000003E8000000162016940C000003FB333333F638E393F313B143F1696970162016A404000003F9555553F4CCCCD3F2492493F0E38E40162016B400000003F8000003F3A2E8C3F19999A3F06BCA20162016C3FC000003F6000003F2AAAAB3F1000003F00000001630169413000004019999A3FB8E38E3F89D89E3F61E1E20163016A40B00000400000003FA666663F8000003F5555550163016B406AAAAB3FDB6DB73F9745D13F6EEEEF3F4A1AF30163016C403000003FC000003F8AAAAB3F6000003F400000"}}
-{"expression":"a%b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003D8000003D8000003D8000003D800000"}}
-{"expression":"a%b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC00000000000003FC00000000000003FC000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC8000000000000000000000000000000000000000000003FB000000000000000000000000000003FD000000000000000000000000000003FB00000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC000000000000000000000000000003FB000000000000000000000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000000000000000000000000000003E0000003D800000000000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F200000000000003D8000003E0000003E4000003D8000003EA000003E8000003E8000003E4000003E0000003D800000000000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"a%b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FC0000000000000016203666F6F00000000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F00000000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F016900000000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D800000016203626172016900000000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"a%b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F00000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC80000000000003FC80000000000003FC800000000000000000000000000003FB00000000000003FC00000000000003FB000000000000000000000000000003FD40000000000003FD4000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"a%b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA0000001620169000000003E0000003F0000003F1000003F2000000162016A000000003D8000003F0000003F1000003F2000000162016B00000000000000003F0000003F1000003F2000000162016C3E0000003EE000003F0000003F1000003F20000001630169000000003E0000003E8000003D8000003F7000000163016A3D800000000000003E400000000000003F7000000163016B3E0000003EA000003E0000003F6000003F7000000163016C3E4000003E8000003D8000003F6000003F700000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003D8000003D8000003D8000003D800000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC00000000000003FC00000000000003FC000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC8000000000000000000000000000000000000000000003FB000000000000000000000000000003FD000000000000000000000000000003FB00000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC000000000000000000000000000003FB000000000000000000000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000000000000000000000000000003E0000003D800000000000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F200000000000003D8000003E0000003E4000003D8000003EA000003E8000003E8000003E4000003E0000003D800000000000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FC0000000000000016203666F6F00000000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F00000000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F016900000000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D800000016203626172016900000000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F00000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC80000000000003FC80000000000003FC800000000000000000000000000003FB00000000000003FC00000000000003FB000000000000000000000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(a%b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA0000001620169000000003E0000003F0000003F1000003F2000000162016A000000003D8000003F0000003F1000003F2000000162016B00000000000000003F0000003F1000003F2000000162016C3E0000003EE000003F0000003F1000003F20000001630169000000003E0000003E8000003D8000003F7000000163016A3D800000000000003E400000000000003F7000000163016B3E0000003EA000003E0000003F6000003F7000000163016C3E4000003E8000003D8000003F6000003F700000"}}
-{"expression":"a^b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEAE89F995AD3AD"}}
-{"expression":"a^b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD"}}
-{"expression":"a^b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FEC199BDD85529C3FECD23C550063613FED5818DCFBA4873FEDC1992D6172F6"}}
-{"expression":"a^b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F5744FD3F3504F33F1837F03F0000003ED744FD"}}
-{"expression":"a^b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F5744FD3F60CCDF3F6691E33F6AC0C73F6E0CC9"}}
-{"expression":"a^b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE8ACE5422AA0DB3FE7612FB975A7143FE6A09E667F3BCD3FE63F7BB335DC60"}}
-{"expression":"a^b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FE306FE0A31B7153FE0B5586CF9890F3FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FED5818DCFBA4873FEAE89F995AD3AD3FE8ACE5422AA0DB3FE6A09E667F3BCD3FE4BFDAD5362A273FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC60"}}
-{"expression":"a^b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FDD5818DCFBA4873FD9C49182A3F0903FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FD43F52D03122773FD23C6E3224F9D03FD06CAF60C8C89A3FCD960356091EFE3FCAA5A32909AD093FD00000000000003FCD5818DCFBA4873FCAE89F995AD3AD3FC8ACE5422AA0DB3FC6A09E667F3BCD3FCBCF5AA00353783FC9DC29DA71ACA83FC80BF993B8F9A33FC65C55827DF1D23FC4CAF56B2BF322"}}
-{"expression":"a^b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FE306FE0A31B7153FE0B5586CF9890F3FDD5818DCFBA4873FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E"}}
-{"expression":"a^b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"a^b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"a^b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"a^b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F5744FD3F3504F33F1837F03F0000003ED744FD3EB504F33E9837F03EB504F33E9EF5323E8B95C23E75257D3E5744FD3E3D08A43E25FED73E552D193E4000003E2CED6A3E1BBFD93E0C471E3DFCAFAB3DE395D33E1837F03E0B95C23E0000003DEAC0C73DD744FD3DC5672A3DB504F33DF8BD703DE74C8B3DD714B73DC800003DB9F9FD3DACEFB43DA0CF7C3F70C72F3F6276143F54FEE63F4854B13F3C6B453F31372B3F26AD9B3F2953FD3F20CD303F18B44D3F1103CB3F09B6693F02C72A3EF8629E3F05AAC33F0000003EF5257D3EEAC0C73EE0CCDF3ED744FD3ECE248C3EE81B6B3EDFE8A53ED800003ED05EDF3EC902BA3EC1E9223EBB0FBE3EDA6CD23ED41A243ECDF6523EC800003EC235DD3EBC96A23EB721113F7A13163F7449493F6EA1C83F691BC83F63B6823F5E71363F594B243F5DB3D73F59C07C3F55DF263F520F833F4E51433F4AA4163F4707AF3F52B7873F5000003F4D51713F4AABBC3F480EC43F457A6C3F42EE983F550F403F5349F13F5188663F4FCA993F4E107F3F4C5A123F4AA74A3F63BD403F62D28F3F61E8CF3F6100003F6018213F5F31313F5E4B2F"}}
-{"expression":"a^b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEAE89F995AD3AD01623FE8ACE5422AA0DB01633FE7612FB975A714"}}
-{"expression":"a^b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FEAE89F995AD3AD01623FE8ACE5422AA0DB"}}
-{"expression":"a^b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE8ACE5422AA0DB01620362617A3FE5AB07DD485429016203666F6F3FEC199BDD85529C0163036261723FE9F54ECD0E12A501630362617A3FE7612FB975A714016303666F6F3FECD23C55006361"}}
-{"expression":"a^b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE0B5586CF9890F01620362617A3FDD5818DCFBA487016203666F6F3FE306FE0A31B7150163036261723FDBB67AE8584CAA01630362617A3FD8F5BD51A586BC016303666F6F3FDEC4F2C4C2AFA9"}}
-{"expression":"a^b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE8ACE5422AA0DB016103666F6F3FEAE89F995AD3AD0162036261723FE7ECF2D7F7566E016203666F6F3FE8ACE5422AA0DB"}}
-{"expression":"a^b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"a^b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"a^b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"a^b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F05AAC3016103626172016A3EEAC0C7016103626172016B3ECE248C016103626172016C3EB504F3016103666F6F01693F5744FD016103666F6F016A3F3504F3016103666F6F016B3F1837F0016103666F6F016C3F00000001620362617201693F31FBDE016203626172016A3F25810C016203626172016B3F19E63D016203626172016C3F0F1BBD016203666F6F01693F6AC0C7016203666F6F016A3F5744FD016203666F6F016B3F45672A016203666F6F016C3F3504F3"}}
-{"expression":"a^b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FE00000000000003FDD5818DCFBA4873FDAE89F995AD3AD3FD8ACE5422AA0DB3FD6A09E667F3BCD3FD4BFDAD5362A273FD306FE0A31B7153FE3988E1409212E3FE26E44673282E13FE155B73ED4E4963FE04DD89F79CA703FDEAB5536A3A3563FDCD87CBBAFA5093FDB21668BF75D6A03666F6F3FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E3FDEC4F2C4C2AFA93FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC603FE4B0217B8E23BA3FE33CC7A960C7B6"}}
-{"expression":"a^b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"a^b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"a^b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"a^b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F5744FD3F05AAC33EC7ADEB3EA5FED73E94C7FE0161016A3F3504F33EEAC0C73EB3D80B3E9837F03E8A595C0161016B3F1837F03ECE248C3EA1FA973E8B95C23E80A5FD0161016C3F0000003EB504F33E91E3723E8000003E6F417C016201693F70C72F3F45B7BD3F2D583F3F20675C3F1B5E4B0162016A3F6276143F3BC2F73F25FED73F1ABCF23F16DEE80162016B3F54FEE63F324E893F1EF5323F1545C33F1280DA0162016C3F4854B13F2953FD3F1837F03F1000003F0E432A016301693F7A13163F69FD583F63C7AF3F65ADDB3F6F08AC0163016A3F7449493F65D1F03F60D7D63F63C5303F6E12570163016B3F6EA1C83F61B98C3F5DF1AE3F61E0943F6D1CFF0163016C3F691BC83F5DB3D73F5B15183F6000003F6C28A5"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEAE89F995AD3AD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FEC199BDD85529C3FECD23C550063613FED5818DCFBA4873FEDC1992D6172F6"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F5744FD3F3504F33F1837F03F0000003ED744FD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F5744FD3F60CCDF3F6691E33F6AC0C73F6E0CC9"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE8ACE5422AA0DB3FE7612FB975A7143FE6A09E667F3BCD3FE63F7BB335DC60"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FE306FE0A31B7153FE0B5586CF9890F3FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FED5818DCFBA4873FEAE89F995AD3AD3FE8ACE5422AA0DB3FE6A09E667F3BCD3FE4BFDAD5362A273FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC60"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FDD5818DCFBA4873FD9C49182A3F0903FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FD43F52D03122773FD23C6E3224F9D03FD06CAF60C8C89A3FCD960356091EFE3FCAA5A32909AD093FD00000000000003FCD5818DCFBA4873FCAE89F995AD3AD3FC8ACE5422AA0DB3FC6A09E667F3BCD3FCBCF5AA00353783FC9DC29DA71ACA83FC80BF993B8F9A33FC65C55827DF1D23FC4CAF56B2BF322"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FE306FE0A31B7153FE0B5586CF9890F3FDD5818DCFBA4873FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F5744FD3F3504F33F1837F03F0000003ED744FD3EB504F33E9837F03EB504F33E9EF5323E8B95C23E75257D3E5744FD3E3D08A43E25FED73E552D193E4000003E2CED6A3E1BBFD93E0C471E3DFCAFAB3DE395D33E1837F03E0B95C23E0000003DEAC0C73DD744FD3DC5672A3DB504F33DF8BD703DE74C8B3DD714B73DC800003DB9F9FD3DACEFB43DA0CF7C3F70C72F3F6276143F54FEE63F4854B13F3C6B453F31372B3F26AD9B3F2953FD3F20CD303F18B44D3F1103CB3F09B6693F02C72A3EF8629E3F05AAC33F0000003EF5257D3EEAC0C73EE0CCDF3ED744FD3ECE248C3EE81B6B3EDFE8A53ED800003ED05EDF3EC902BA3EC1E9223EBB0FBE3EDA6CD23ED41A243ECDF6523EC800003EC235DD3EBC96A23EB721113F7A13163F7449493F6EA1C83F691BC83F63B6823F5E71363F594B243F5DB3D73F59C07C3F55DF263F520F833F4E51433F4AA4163F4707AF3F52B7873F5000003F4D51713F4AABBC3F480EC43F457A6C3F42EE983F550F403F5349F13F5188663F4FCA993F4E107F3F4C5A123F4AA74A3F63BD403F62D28F3F61E8CF3F6100003F6018213F5F31313F5E4B2F"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEAE89F995AD3AD01623FE8ACE5422AA0DB01633FE7612FB975A714"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FEAE89F995AD3AD01623FE8ACE5422AA0DB"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE8ACE5422AA0DB01620362617A3FE5AB07DD485429016203666F6F3FEC199BDD85529C0163036261723FE9F54ECD0E12A501630362617A3FE7612FB975A714016303666F6F3FECD23C55006361"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE0B5586CF9890F01620362617A3FDD5818DCFBA487016203666F6F3FE306FE0A31B7150163036261723FDBB67AE8584CAA01630362617A3FD8F5BD51A586BC016303666F6F3FDEC4F2C4C2AFA9"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE8ACE5422AA0DB016103666F6F3FEAE89F995AD3AD0162036261723FE7ECF2D7F7566E016203666F6F3FE8ACE5422AA0DB"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F05AAC3016103626172016A3EEAC0C7016103626172016B3ECE248C016103626172016C3EB504F3016103666F6F01693F5744FD016103666F6F016A3F3504F3016103666F6F016B3F1837F0016103666F6F016C3F00000001620362617201693F31FBDE016203626172016A3F25810C016203626172016B3F19E63D016203626172016C3F0F1BBD016203666F6F01693F6AC0C7016203666F6F016A3F5744FD016203666F6F016B3F45672A016203666F6F016C3F3504F3"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FE00000000000003FDD5818DCFBA4873FDAE89F995AD3AD3FD8ACE5422AA0DB3FD6A09E667F3BCD3FD4BFDAD5362A273FD306FE0A31B7153FE3988E1409212E3FE26E44673282E13FE155B73ED4E4963FE04DD89F79CA703FDEAB5536A3A3563FDCD87CBBAFA5093FDB21668BF75D6A03666F6F3FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E3FDEC4F2C4C2AFA93FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC603FE4B0217B8E23BA3FE33CC7A960C7B6"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(a^b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F5744FD3F05AAC33EC7ADEB3EA5FED73E94C7FE0161016A3F3504F33EEAC0C73EB3D80B3E9837F03E8A595C0161016B3F1837F03ECE248C3EA1FA973E8B95C23E80A5FD0161016C3F0000003EB504F33E91E3723E8000003E6F417C016201693F70C72F3F45B7BD3F2D583F3F20675C3F1B5E4B0162016A3F6276143F3BC2F73F25FED73F1ABCF23F16DEE80162016B3F54FEE63F324E893F1EF5323F1545C33F1280DA0162016C3F4854B13F2953FD3F1837F03F1000003F0E432A016301693F7A13163F69FD583F63C7AF3F65ADDB3F6F08AC0163016A3F7449493F65D1F03F60D7D63F63C5303F6E12570163016B3F6EA1C83F61B98C3F5DF1AE3F61E0943F6D1CFF0163016C3F691BC83F5DB3D73F5B15183F6000003F6C28A5"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEAE89F995AD3AD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FEC199BDD85529C3FECD23C550063613FED5818DCFBA4873FEDC1992D6172F6"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F5744FD3F3504F33F1837F03F0000003ED744FD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F5744FD3F60CCDF3F6691E33F6AC0C73F6E0CC9"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE8ACE5422AA0DB3FE7612FB975A7143FE6A09E667F3BCD3FE63F7BB335DC60"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FE306FE0A31B7153FE0B5586CF9890F3FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FED5818DCFBA4873FEAE89F995AD3AD3FE8ACE5422AA0DB3FE6A09E667F3BCD3FE4BFDAD5362A273FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC60"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FDD5818DCFBA4873FD9C49182A3F0903FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FD43F52D03122773FD23C6E3224F9D03FD06CAF60C8C89A3FCD960356091EFE3FCAA5A32909AD093FD00000000000003FCD5818DCFBA4873FCAE89F995AD3AD3FC8ACE5422AA0DB3FC6A09E667F3BCD3FCBCF5AA00353783FC9DC29DA71ACA83FC80BF993B8F9A33FC65C55827DF1D23FC4CAF56B2BF322"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FE306FE0A31B7153FE0B5586CF9890F3FDD5818DCFBA4873FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F5744FD3F3504F33F1837F03F0000003ED744FD3EB504F33E9837F03EB504F33E9EF5323E8B95C23E75257D3E5744FD3E3D08A43E25FED73E552D193E4000003E2CED6A3E1BBFD93E0C471E3DFCAFAB3DE395D33E1837F03E0B95C23E0000003DEAC0C73DD744FD3DC5672A3DB504F33DF8BD703DE74C8B3DD714B73DC800003DB9F9FD3DACEFB43DA0CF7C3F70C72F3F6276143F54FEE63F4854B13F3C6B453F31372B3F26AD9B3F2953FD3F20CD303F18B44D3F1103CB3F09B6693F02C72A3EF8629E3F05AAC33F0000003EF5257D3EEAC0C73EE0CCDF3ED744FD3ECE248C3EE81B6B3EDFE8A53ED800003ED05EDF3EC902BA3EC1E9223EBB0FBE3EDA6CD23ED41A243ECDF6523EC800003EC235DD3EBC96A23EB721113F7A13163F7449493F6EA1C83F691BC83F63B6823F5E71363F594B243F5DB3D73F59C07C3F55DF263F520F833F4E51433F4AA4163F4707AF3F52B7873F5000003F4D51713F4AABBC3F480EC43F457A6C3F42EE983F550F403F5349F13F5188663F4FCA993F4E107F3F4C5A123F4AA74A3F63BD403F62D28F3F61E8CF3F6100003F6018213F5F31313F5E4B2F"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEAE89F995AD3AD01623FE8ACE5422AA0DB01633FE7612FB975A714"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FEAE89F995AD3AD01623FE8ACE5422AA0DB"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE8ACE5422AA0DB01620362617A3FE5AB07DD485429016203666F6F3FEC199BDD85529C0163036261723FE9F54ECD0E12A501630362617A3FE7612FB975A714016303666F6F3FECD23C55006361"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE0B5586CF9890F01620362617A3FDD5818DCFBA487016203666F6F3FE306FE0A31B7150163036261723FDBB67AE8584CAA01630362617A3FD8F5BD51A586BC016303666F6F3FDEC4F2C4C2AFA9"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE8ACE5422AA0DB016103666F6F3FEAE89F995AD3AD0162036261723FE7ECF2D7F7566E016203666F6F3FE8ACE5422AA0DB"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F05AAC3016103626172016A3EEAC0C7016103626172016B3ECE248C016103626172016C3EB504F3016103666F6F01693F5744FD016103666F6F016A3F3504F3016103666F6F016B3F1837F0016103666F6F016C3F00000001620362617201693F31FBDE016203626172016A3F25810C016203626172016B3F19E63D016203626172016C3F0F1BBD016203666F6F01693F6AC0C7016203666F6F016A3F5744FD016203666F6F016B3F45672A016203666F6F016C3F3504F3"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FE00000000000003FDD5818DCFBA4873FDAE89F995AD3AD3FD8ACE5422AA0DB3FD6A09E667F3BCD3FD4BFDAD5362A273FD306FE0A31B7153FE3988E1409212E3FE26E44673282E13FE155B73ED4E4963FE04DD89F79CA703FDEAB5536A3A3563FDCD87CBBAFA5093FDB21668BF75D6A03666F6F3FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E3FDEC4F2C4C2AFA93FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC603FE4B0217B8E23BA3FE33CC7A960C7B6"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"pow(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F5744FD3F05AAC33EC7ADEB3EA5FED73E94C7FE0161016A3F3504F33EEAC0C73EB3D80B3E9837F03E8A595C0161016B3F1837F03ECE248C3EA1FA973E8B95C23E80A5FD0161016C3F0000003EB504F33E91E3723E8000003E6F417C016201693F70C72F3F45B7BD3F2D583F3F20675C3F1B5E4B0162016A3F6276143F3BC2F73F25FED73F1ABCF23F16DEE80162016B3F54FEE63F324E893F1EF5323F1545C33F1280DA0162016C3F4854B13F2953FD3F1837F03F1000003F0E432A016301693F7A13163F69FD583F63C7AF3F65ADDB3F6F08AC0163016A3F7449493F65D1F03F60D7D63F63C5303F6E12570163016B3F6EA1C83F61B98C3F5DF1AE3F61E0943F6D1CFF0163016C3F691BC83F5DB3D73F5B15183F6000003F6C28A5"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FEAE89F995AD3AD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FEC199BDD85529C3FECD23C550063613FED5818DCFBA4873FEDC1992D6172F6"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F5744FD3F3504F33F1837F03F0000003ED744FD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F5744FD3F60CCDF3F6691E33F6AC0C73F6E0CC9"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FEAE89F995AD3AD3FE8ACE5422AA0DB3FE7612FB975A7143FE6A09E667F3BCD3FE63F7BB335DC60"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FE306FE0A31B7153FE0B5586CF9890F3FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FED5818DCFBA4873FEAE89F995AD3AD3FE8ACE5422AA0DB3FE6A09E667F3BCD3FE4BFDAD5362A273FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC60"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FDD5818DCFBA4873FD9C49182A3F0903FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FD43F52D03122773FD23C6E3224F9D03FD06CAF60C8C89A3FCD960356091EFE3FCAA5A32909AD093FD00000000000003FCD5818DCFBA4873FCAE89F995AD3AD3FC8ACE5422AA0DB3FC6A09E667F3BCD3FCBCF5AA00353783FC9DC29DA71ACA83FC80BF993B8F9A33FC65C55827DF1D23FC4CAF56B2BF322"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FEC199BDD85529C3FE8ACE5422AA0DB3FE5AB07DD4854293FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FE306FE0A31B7153FE0B5586CF9890F3FDD5818DCFBA4873FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FCAA5A32909AD093FC80000000000003FC59DAD3FC04A893FC377FB19CA8DFC3FC188E3CB183D4F3FBF95F56FB1EA1A3FBC72BA697B93DD3FC306FE0A31B7153FC172B83C7D517B3FC00000000000003FBD5818DCFBA4873FBAE89F995AD3AD3FB8ACE5422AA0DB3FB6A09E667F3BCD3FBF17AE04649A0B3FBCE9915AD5AB8E3FBAE296D4BCF6C03FB90000000000003FB73F3FAB7421D03FB59DF672C37B9A3FB419EF884F9ECA3FEE18E5E81A61343FEC4EC2728166603FEA9FDCBE210C2E3FE90A9620EE37F63FE78D6898DBC7E33FE626E55489D6E33FE4D5B35246075A3FE52A7FA9D2F8EA3FE419A5F83CBA873FE3168994D2D71C3FE22079621CAADF3FE136CD2DD107AA3FE058E53DDDBCA13FDF0C53C67265DD3FE0B5586CF9890F3FE00000000000003FDEA4AFA2A490DA3FDD5818DCFBA4873FDC199BDD85529C3FDAE89F995AD3AD3FD9C49182A3F0903FDD036D680A12183FDBFD1498E9176B3FDB0000000000003FDA0BDBD320664C3FD920573DC23D533FD83D244640F0CB3FD761F7B40A80B03FDB4D9A35BB6F283FDA834480E197343FD9BECA3C41A9BA3FD90000000000003FD846BBA5EB5FC63FD792D4402D38463FD6E422103EE0843FEF4262C6AAAADA3FEE8929198F10AF3FEDD438F728B7833FED2378F80BE1D93FEC76D04B5477763FEBCE26B32A10A13FEB29648158A6A73FEBB67AE8584CAA3FEB380F7403CA5C3FEABBE4B2A13DED3FEA41F05D6A93C03FE9CA285C7ABAC03FE95482C5F7CA693FE8E0F5DD40F85F3FEA56F0DE44EF8A3FEA0000000000003FE9AA2E1A70518E3FE955777A5C19BD3FE901D878C020133FE8AF4D7AA76E023FE85DD2F10383E13FEAA1E7F72554723FEA693E1BC5E3383FEA310CCF3B37603FE9F953110531EA3FE9C20FE2C56F973FE98B42483ABFCD3FE954E9473CA51F3FEC77A803167AE13FEC5A51D0E999BB3FEC3D19DA44BAFB3FEC2000000000003FEC03042313A5923FEBE6262497E2D13FEBC965E5C4C83F"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F5744FD3F3504F33F1837F03F0000003ED744FD3EB504F33E9837F03EB504F33E9EF5323E8B95C23E75257D3E5744FD3E3D08A43E25FED73E552D193E4000003E2CED6A3E1BBFD93E0C471E3DFCAFAB3DE395D33E1837F03E0B95C23E0000003DEAC0C73DD744FD3DC5672A3DB504F33DF8BD703DE74C8B3DD714B73DC800003DB9F9FD3DACEFB43DA0CF7C3F70C72F3F6276143F54FEE63F4854B13F3C6B453F31372B3F26AD9B3F2953FD3F20CD303F18B44D3F1103CB3F09B6693F02C72A3EF8629E3F05AAC33F0000003EF5257D3EEAC0C73EE0CCDF3ED744FD3ECE248C3EE81B6B3EDFE8A53ED800003ED05EDF3EC902BA3EC1E9223EBB0FBE3EDA6CD23ED41A243ECDF6523EC800003EC235DD3EBC96A23EB721113F7A13163F7449493F6EA1C83F691BC83F63B6823F5E71363F594B243F5DB3D73F59C07C3F55DF263F520F833F4E51433F4AA4163F4707AF3F52B7873F5000003F4D51713F4AABBC3F480EC43F457A6C3F42EE983F550F403F5349F13F5188663F4FCA993F4E107F3F4C5A123F4AA74A3F63BD403F62D28F3F61E8CF3F6100003F6018213F5F31313F5E4B2F"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FEAE89F995AD3AD01623FE8ACE5422AA0DB01633FE7612FB975A714"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FEAE89F995AD3AD01623FE8ACE5422AA0DB"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE8ACE5422AA0DB01620362617A3FE5AB07DD485429016203666F6F3FEC199BDD85529C0163036261723FE9F54ECD0E12A501630362617A3FE7612FB975A714016303666F6F3FECD23C55006361"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FE6A09E667F3BCD01610362617A3FE306FE0A31B715016103666F6F3FEAE89F995AD3AD0162036261723FE0B5586CF9890F01620362617A3FDD5818DCFBA487016203666F6F3FE306FE0A31B7150163036261723FDBB67AE8584CAA01630362617A3FD8F5BD51A586BC016303666F6F3FDEC4F2C4C2AFA9"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE8ACE5422AA0DB016103666F6F3FEAE89F995AD3AD0162036261723FE7ECF2D7F7566E016203666F6F3FE8ACE5422AA0DB"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FE0B5586CF9890F016103626172016A3FDD5818DCFBA487016103626172016B3FD9C49182A3F090016103626172016C3FD6A09E667F3BCD016103666F6F01693FEAE89F995AD3AD016103666F6F016A3FE6A09E667F3BCD016103666F6F016B3FE306FE0A31B715016103666F6F016C3FE000000000000001620362617201693FE63F7BB335DC60016203626172016A3FE4B0217B8E23BA016203626172016B3FE33CC7A960C7B6016203626172016C3FE1E3779B97F4A8016203666F6F01693FED5818DCFBA487016203666F6F016A3FEAE89F995AD3AD016203666F6F016B3FE8ACE5422AA0DB016203666F6F016C3FE6A09E667F3BCD"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F05AAC3016103626172016A3EEAC0C7016103626172016B3ECE248C016103626172016C3EB504F3016103666F6F01693F5744FD016103666F6F016A3F3504F3016103666F6F016B3F1837F0016103666F6F016C3F00000001620362617201693F31FBDE016203626172016A3F25810C016203626172016B3F19E63D016203626172016C3F0F1BBD016203666F6F01693F6AC0C7016203666F6F016A3F5744FD016203666F6F016B3F45672A016203666F6F016C3F3504F3"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FD6A09E667F3BCD3FD3DEA64C1234223FD172B83C7D517B3FCEA4AFA2A490DA3FCAE89F995AD3AD3FC7A11473EB01873FC4BFDAD5362A273FE00000000000003FDD5818DCFBA4873FDAE89F995AD3AD3FD8ACE5422AA0DB3FD6A09E667F3BCD3FD4BFDAD5362A273FD306FE0A31B7153FE3988E1409212E3FE26E44673282E13FE155B73ED4E4963FE04DD89F79CA703FDEAB5536A3A3563FDCD87CBBAFA5093FDB21668BF75D6A03666F6F3FEAE89F995AD3AD3FE6A09E667F3BCD3FE306FE0A31B7153FE00000000000003FDAE89F995AD3AD3FD6A09E667F3BCD3FD306FE0A31B7153FECD23C550063613FE9F54ECD0E12A53FE7612FB975A7143FE50EA39FCBF1663FE2F726F0FD0D3E3FE114DBC434A66E3FDEC4F2C4C2AFA93FEDC1992D6172F63FEBAB78E4D1420D3FE9BACC33991D2B3FE7ECF2D7F7566E3FE63F7BB335DC603FE4B0217B8E23BA3FE33CC7A960C7B6"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FEAE89F995AD3AD3FE0B5586CF9890F3FD8F5BD51A586BC3FD4BFDAD5362A273FD298FFBC5CE7DA0161016A3FE6A09E667F3BCD3FDD5818DCFBA4873FD67B0160E8A9A33FD306FE0A31B7153FD14B2B8F02C9480161016B3FE306FE0A31B7153FD9C49182A3F0903FD43F52D03122773FD172B83C7D517B3FD014BFA03FB23B0161016C3FE00000000000003FD6A09E667F3BCD3FD23C6E3224F9D03FD00000000000003FCDE82F8DF52C0A016201693FEE18E5E81A61343FE8B6F79DCD314B3FE5AB07DD4854293FE40CEB85F8EE713FE36BC95189196B0162016A3FEC4EC2728166603FE7785EE226A6343FE4BFDAD5362A273FE3579E455C0C103FE2DBDD00242D050162016B3FEA9FDCBE210C2E3FE649D12B4ECF943FE3DEA64C1234223FE2A8B865F0BA473FE2501B40324D370162016C3FE90A9620EE37F63FE52A7FA9D2F8EA3FE306FE0A31B7153FE20000000000003FE1C86531B4AC69016301693FEF4262C6AAAADA3FED3FAB0BE595653FEC78F5DAE56B173FECB5BB51F591A53FEDE1157ABF9F8B0163016A3FEE8929198F10AF3FECBA3DF472E47F3FEC1AFAB455D9983FEC78A5F1E124063FEDC24AD1B314120163016B3FEDD438F728B7833FEC3731861F96323FEBBE35C364FED83FEC3C12881004A43FEDA39FE40519DD0163016C3FED2378F80BE1D93FEBB67AE8584CAA3FEB62A3082519673FEC0000000000003FED851491024321"}}
-{"expression":"join(a,b,f(a,b)(pow(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F5744FD3F05AAC33EC7ADEB3EA5FED73E94C7FE0161016A3F3504F33EEAC0C73EB3D80B3E9837F03E8A595C0161016B3F1837F03ECE248C3EA1FA973E8B95C23E80A5FD0161016C3F0000003EB504F33E91E3723E8000003E6F417C016201693F70C72F3F45B7BD3F2D583F3F20675C3F1B5E4B0162016A3F6276143F3BC2F73F25FED73F1ABCF23F16DEE80162016B3F54FEE63F324E893F1EF5323F1545C33F1280DA0162016C3F4854B13F2953FD3F1837F03F1000003F0E432A016301693F7A13163F69FD583F63C7AF3F65ADDB3F6F08AC0163016A3F7449493F65D1F03F60D7D63F63C5303F6E12570163016B3F6EA1C83F61B98C3F5DF1AE3F61E0943F6D1CFF0163016C3F691BC83F5DB3D73F5B15183F6000003F6C28A5"}}
-{"expression":"a==b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000000000000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"a==b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a==b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B000000003F8000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A0000000000000000000000003F800000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000000000000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a==b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B000000003F8000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A0000000000000000000000003F800000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"a!=b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"a!=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a!=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A0000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F800000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"a!=b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a!=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F800000000000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F800000000000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A0000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F800000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a!=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F800000000000003F8000003F8000003F8000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F8000003F800000000000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a~=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000000000000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"a~=b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a~=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B000000003F8000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A0000000000000000000000003F800000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000000000000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001620169000000000000000000000000000000000000000000000000000000000000000000000000000000000162016A000000000000000000000000000000000000000000000000000000000000000000000000000000000162016B00000000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C0000000000000000000000000000000000000000000000000000000000000000000000000000000001630169000000000000000000000000000000000000000000000000000000000000000000000000000000000163016A0000000000000000000000000000000000000000000000003FF000000000000000000000000000000163016B000000000000000000000000000000000000000000000000000000000000000000000000000000000163016C00000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a~=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000162016900000000000000000000000000000000000000000162016A00000000000000000000000000000000000000000162016B000000003F8000000000000000000000000000000162016C00000000000000000000000000000000000000000163016900000000000000000000000000000000000000000163016A0000000000000000000000003F800000000000000163016B00000000000000000000000000000000000000000163016C0000000000000000000000000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"a<b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a<b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FF0000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F800000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000"}}
-{"expression":"a<b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F8000000162016900000000000000003F8000003F8000003F8000000162016A00000000000000003F8000003F8000003F8000000162016B00000000000000003F8000003F8000003F8000000162016C000000003F8000003F8000003F8000003F80000001630169000000000000000000000000000000003F8000000163016A000000000000000000000000000000003F8000000163016B0000000000000000000000003F8000003F8000000163016C0000000000000000000000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FF0000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201690000000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F800000016203626172016900000000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A00000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F8000000162016900000000000000003F8000003F8000003F8000000162016A00000000000000003F8000003F8000003F8000000162016B00000000000000003F8000003F8000003F8000000162016C000000003F8000003F8000003F8000003F80000001630169000000000000000000000000000000003F8000000163016A000000000000000000000000000000003F8000000163016B0000000000000000000000003F8000003F8000000163016C0000000000000000000000003F8000003F800000"}}
-{"expression":"a<=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a<=b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a<=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F01693F800000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F80000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"a<=b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a<=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F8000000162016900000000000000003F8000003F8000003F8000000162016A00000000000000003F8000003F8000003F8000000162016B000000003F8000003F8000003F8000003F8000000162016C000000003F8000003F8000003F8000003F80000001630169000000000000000000000000000000003F8000000163016A0000000000000000000000003F8000003F8000000163016B0000000000000000000000003F8000003F8000000163016C0000000000000000000000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01693FF0000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C3FF000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F01693F800000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C3F80000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C3F800000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000001620169000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016A000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000000162016B00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016C00000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016900000000000000000000000000000000000000000000000000000000000000003FF00000000000000163016A0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016B0000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000163016C0000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a<=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F8000003F8000003F8000003F8000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C3F8000003F8000003F8000003F8000003F8000000162016900000000000000003F8000003F8000003F8000000162016A00000000000000003F8000003F8000003F8000000162016B000000003F8000003F8000003F8000003F8000000162016C000000003F8000003F8000003F8000003F80000001630169000000000000000000000000000000003F8000000163016A0000000000000000000000003F8000003F8000000163016B0000000000000000000000003F8000003F8000000163016C0000000000000000000000003F8000003F800000"}}
-{"expression":"a>b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"a>b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x0202017805017905000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A030000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A0000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"a>b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201693F8000003F8000000000000000000000000000000162016A3F8000003F8000000000000000000000000000000162016B3F800000000000000000000000000000000000000162016C3F80000000000000000000000000000000000000016301693F8000003F8000003F8000003F800000000000000163016A3F8000003F8000003F80000000000000000000000163016B3F8000003F8000003F80000000000000000000000163016C3F8000003F8000003F8000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x060101017805000000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x0202017805017905000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A030000000000000000000000000000000000000000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A0000000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201690000000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C00000000016203626172016900000000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C01610169000000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF000000000000000000000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C0161016900000000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201693F8000003F8000000000000000000000000000000162016A3F8000003F8000000000000000000000000000000162016B3F800000000000000000000000000000000000000162016C3F80000000000000000000000000000000000000016301693F8000003F8000003F8000003F800000000000000163016A3F8000003F8000003F80000000000000000000000163016B3F8000003F8000003F80000000000000000000000163016C3F8000003F8000003F8000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a>=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF0000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C3F800000"}}
-{"expression":"a>=b","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"a>=b","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201693F8000003F8000000000000000000000000000000162016A3F8000003F8000000000000000000000000000000162016B3F8000003F8000000000000000000000000000000162016C3F80000000000000000000000000000000000000016301693F8000003F8000003F8000003F800000000000000163016A3F8000003F8000003F8000003F800000000000000163016B3F8000003F8000003F80000000000000000000000163016C3F8000003F8000003F8000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F80000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FF0000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FF000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FF000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF00000000000000162036261723FF000000000000001620362617A0000000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F3FF0000000000000016203626172000000000000000001620362617A0000000000000000016203666F6F0000000000000000016303626172000000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F3FF00000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201690000000000000000016103626172016A0000000000000000016103626172016B0000000000000000016103626172016C0000000000000000016103666F6F01693FF0000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A0000000000000000016203626172016B0000000000000000016203626172016C0000000000000000016203666F6F01693FF0000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016900000000016103626172016A00000000016103626172016B00000000016103626172016C00000000016103666F6F01693F800000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A00000000016203626172016B00000000016203626172016C00000000016203666F6F01693F800000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C3F800000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A07020362617200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003666F6F3FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FF000000000000000000000000000000000000000000000000000000000000000000000000000000161016A000000000000000000000000000000000000000000000000000000000000000000000000000000000161016B000000000000000000000000000000000000000000000000000000000000000000000000000000000161016C00000000000000000000000000000000000000000000000000000000000000000000000000000000016201693FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016A3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016B3FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000162016C3FF00000000000000000000000000000000000000000000000000000000000000000000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016A3FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000163016B3FF00000000000003FF00000000000003FF0000000000000000000000000000000000000000000000163016C3FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a>=b))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F800000000000000000000000000000000000000161016A00000000000000000000000000000000000000000161016B00000000000000000000000000000000000000000161016C0000000000000000000000000000000000000000016201693F8000003F8000000000000000000000000000000162016A3F8000003F8000000000000000000000000000000162016B3F8000003F8000000000000000000000000000000162016C3F80000000000000000000000000000000000000016301693F8000003F8000003F8000003F800000000000000163016A3F8000003F8000003F8000003F800000000000000163016B3F8000003F8000003F80000000000000000000000163016C3F8000003F8000003F8000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x02000000000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x02000000000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x02000000000000000000","b":"0x060101017805000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x060101017805000000003F8000003F800000000000003F800000","b":"0x02000000000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101790500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x02020178050179050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0202017805017905000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020101790300000000000000003FF00000000000003FF0000000000000","b":"0x0202017802017A0300000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060103017803017905017A07000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F800000000000003F8000003F800000000000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F80000000000000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"}}
-{"expression":"a&&b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178020161000000000000000001623FF0000000000000"},"result":{"expect":"0x01010178020161000000000000000001623FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x0101017903036261723FF00000000000000362617A3FF000000000000003666F6F0000000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B00000000016103626172016C3F800000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A3F800000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000"}}
-{"expression":"a&&b","inputs":{"a":"0x030101790101780302036261723FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF0000000000000","b":"0x0301017901017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"a&&b","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A000000003F80000000000000000000003F8000000161016B00000000000000003F80000000000000000000000161016C000000003F8000003F800000000000003F8000000162016900000000000000003F80000000000000000000000162016A3F80000000000000000000003F800000000000000162016B3F800000000000003F8000003F800000000000000162016C00000000000000003F800000000000000000000001630169000000003F80000000000000000000003F8000000163016A3F8000003F800000000000003F8000003F8000000163016B3F80000000000000000000003F800000000000000163016C000000003F80000000000000000000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x02000000000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x02000000000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x02000000000000000000","b":"0x060101017805000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x060101017805000000003F8000003F800000000000003F800000","b":"0x02000000000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101790500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x02020178050179050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0202017805017905000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020101790300000000000000003FF00000000000003FF0000000000000","b":"0x0202017802017A0300000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0203017803017905017A0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060103017803017905017A07000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F800000000000003F8000003F800000000000003F8000003F80000000000000000000000000000000000000000000000000000000000000000000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000000000000000000000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F80000000000000000000000000000000000000000000000000000000000000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178020161000000000000000001623FF0000000000000"},"result":{"expect":"0x01010178020161000000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x0101017903036261723FF00000000000000362617A3FF000000000000003666F6F0000000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"},"result":{"expect":"0x01020178017909016103626172000000000000000001610362617A0000000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B0000000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A0000000000000000016103666F6F016B0000000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B0000000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B0000000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B00000000016103626172016C3F800000016103666F6F016900000000016103666F6F016A00000000016103666F6F016B00000000016103666F6F016C0000000001620362617201693F800000016203626172016A3F800000016203626172016B00000000016203626172016C3F800000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B00000000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x030101790101780302036261723FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF0000000000000","b":"0x0301017901017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A00000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000161016B000000000000000000000000000000003FF0000000000000000000000000000000000000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001620169000000000000000000000000000000003FF0000000000000000000000000000000000000000000000162016A3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C000000000000000000000000000000003FF0000000000000000000000000000000000000000000000163016900000000000000003FF0000000000000000000000000000000000000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF0000000000000000000000000000000000000000000003FF000000000000000000000000000000163016C00000000000000003FF0000000000000000000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a&&b))","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A000000003F80000000000000000000003F8000000161016B00000000000000003F80000000000000000000000161016C000000003F8000003F800000000000003F8000000162016900000000000000003F80000000000000000000000162016A3F80000000000000000000003F800000000000000162016B3F800000000000003F8000003F800000000000000162016C00000000000000003F800000000000000000000001630169000000003F80000000000000000000003F8000000163016A3F8000003F800000000000003F8000003F8000000163016B3F80000000000000000000003F800000000000000163016C000000003F80000000000000000000003F800000"}}
-{"expression":"a||b","inputs":{"a":"0x02000000000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x02000000000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x02000000000000000000","b":"0x060101017805000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060101017805000000003F8000003F800000000000003F800000"}}
-{"expression":"a||b","inputs":{"a":"0x060101017805000000003F8000003F800000000000003F800000","b":"0x02000000000000000000"},"result":{"expect":"0x060101017805000000003F8000003F800000000000003F800000"}}
-{"expression":"a||b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101790500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020101790300000000000000003FF00000000000003FF0000000000000","b":"0x0202017802017A0300000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"a||b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178020161000000000000000001623FF0000000000000"},"result":{"expect":"0x01010178020161000000000000000001623FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x0101017903036261723FF00000000000000362617A3FF000000000000003666F6F0000000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C0000000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"a||b","inputs":{"a":"0x030101790101780302036261723FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF0000000000000","b":"0x0301017901017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"a||b","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C000000003F8000003F800000000000003F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F800000000000003F8000003F800000000000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F800000000000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x02000000000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x02000000000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x02000000000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x02000000000000000000","b":"0x060101017805000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060101017805000000003F8000003F800000000000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x060101017805000000003F8000003F800000000000003F800000","b":"0x02000000000000000000"},"result":{"expect":"0x060101017805000000003F8000003F800000000000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020101790500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020101780500000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000","b":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x020201780501790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020101790300000000000000003FF00000000000003FF0000000000000","b":"0x0202017802017A0300000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x0202017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x020201780301790500000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x060102017803017905000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000","b":"0x060102017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F800000"},"result":{"expect":"0x060103017803017905017A07000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000000000003F8000003F800000000000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"},"result":{"expect":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x01010178020161000000000000000001623FF0000000000000"},"result":{"expect":"0x01010178020161000000000000000001623FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x0101017903036261723FF00000000000000362617A3FF000000000000003666F6F0000000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x01010178030161000000000000000001623FF000000000000001633FF0000000000000","b":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F00000000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F0000000000000000"},"result":{"expect":"0x010201780179090161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F3FF00000000000000163036261723FF000000000000001630362617A3FF0000000000000016303666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x010201780179060161036261723FF0000000000000016103666F6F00000000000000000162036261720000000000000000016203666F6F3FF00000000000000163036261723FF0000000000000016303666F6F3FF0000000000000"},"result":{"expect":"0x010201780179040161036261723FF0000000000000016103666F6F00000000000000000162036261723FF0000000000000016203666F6F3FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x01020179017A080362617201693FF000000000000003626172016A3FF000000000000003626172016B000000000000000003626172016C3FF000000000000003666F6F0169000000000000000003666F6F016A3FF000000000000003666F6F016B3FF000000000000003666F6F016C0000000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x010201780179060161036261723FF000000000000001610362617A3FF0000000000000016103666F6F00000000000000000162036261723FF000000000000001620362617A3FF0000000000000016203666F6F0000000000000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x010301780179017A1001610362617201693FF0000000000000016103626172016A3FF0000000000000016103626172016B3FF0000000000000016103626172016C3FF0000000000000016103666F6F01690000000000000000016103666F6F016A3FF0000000000000016103666F6F016B3FF0000000000000016103666F6F016C000000000000000001620362617201693FF0000000000000016203626172016A3FF0000000000000016203626172016B3FF0000000000000016203626172016C3FF0000000000000016203666F6F01690000000000000000016203666F6F016A3FF0000000000000016203666F6F016B3FF0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x05010201780179060161036261723F80000001610362617A3F800000016103666F6F000000000162036261723F80000001620362617A3F800000016203666F6F00000000","b":"0x0501020179017A080362617201693F80000003626172016A3F80000003626172016B0000000003626172016C3F80000003666F6F01690000000003666F6F016A3F80000003666F6F016B3F80000003666F6F016C00000000"},"result":{"expect":"0x05010301780179017A1001610362617201693F800000016103626172016A3F800000016103626172016B3F800000016103626172016C3F800000016103666F6F016900000000016103666F6F016A3F800000016103666F6F016B3F800000016103666F6F016C0000000001620362617201693F800000016203626172016A3F800000016203626172016B3F800000016203626172016C3F800000016203666F6F016900000000016203666F6F016A3F800000016203666F6F016B3F800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x030101790101780302036261723FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF0000000000000","b":"0x0301017901017A0702036261723FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF000000000000003666F6F00000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x0301017A0101790504016900000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000016B3FF000000000000000000000000000003FF00000000000003FF00000000000000000000000000000016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x030101780101790503016100000000000000003FF00000000000003FF000000000000000000000000000003FF000000000000001623FF000000000000000000000000000003FF00000000000003FF0000000000000000000000000000001633FF00000000000003FF000000000000000000000000000003FF00000000000003FF0000000000000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FF00000000000003FF000000000000000000000000000003FF00000000000000161016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000161016C00000000000000003FF00000000000003FF000000000000000000000000000003FF0000000000000016201693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016A3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000162016B3FF000000000000000000000000000003FF00000000000003FF000000000000000000000000000000162016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000016301693FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016A3FF00000000000003FF000000000000000000000000000003FF00000000000003FF00000000000000163016B3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000000163016C3FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF0000000000000"}}
-{"expression":"join(a,b,f(a,b)(a||b))","inputs":{"a":"0x070101017801017905030161000000003F8000003F800000000000003F80000001623F800000000000003F8000003F8000000000000001633F8000003F800000000000003F8000003F800000","b":"0x070101017A01017905040169000000003F8000003F800000000000003F800000016A3F8000003F800000000000003F8000003F800000016B3F800000000000003F8000003F80000000000000016C000000003F8000003F800000000000003F800000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003F8000003F800000000000003F8000000161016A3F8000003F8000003F8000003F8000003F8000000161016B3F8000003F8000003F8000003F8000003F8000000161016C000000003F8000003F800000000000003F800000016201693F8000003F8000003F8000003F8000003F8000000162016A3F8000003F8000003F8000003F8000003F8000000162016B3F800000000000003F8000003F800000000000000162016C3F8000003F8000003F8000003F8000003F800000016301693F8000003F8000003F8000003F8000003F8000000163016A3F8000003F800000000000003F8000003F8000000163016B3F8000003F8000003F8000003F8000003F8000000163016C3F8000003F8000003F8000003F8000003F800000"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FF1B6E192EBBE443FF3FC176B7A85603FF5368C951E9CFD3FF5F97315254857"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F490FDB3EED63383EA4BC7D3E7ADBB03E4A2210"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F490FDB3F8DB70D3F9FE0BB3FA9B4653FAFCB99"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FE921FB54442D183FE921FB54442D183FE921FB54442D183FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FF1B6E192EBBE443FE921FB54442D183FE2D0EAD60663953FDDAC670561BB4F3FD85A376B677DC03FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FE4978FA3269EE13FE14B1DD5F90CE13FF5368C951E9CFD3FF1B6E192EBBE443FEDAC670561BB4F3FE921FB54442D183FE5977A5103EA923FF5F973152548573FF30B6D796A4DA83FF07C6C6947A6A83FECAC7C57846F9E3FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FD4978FA3269EE13FD1CFA95F7A8DCE3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FD10A4608E6284A3FCF5B75F92C80DD3FCD07BEA194B9913FCB051B394C33AA3FC94441F8F7260B3FCF5B75F92C80DD3FCD94610502338B3FCBFD581196F5C13FCA8F3C814A92D63FC94441F8F7260B3FCDEB4BEABF5A573FCC9AE19AA8FE1F3FCB665729A20CE23FCA4A6567A8DCF33FC94441F8F7260B"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FF1B6E192EBBE443FE921FB54442D183FE2D0EAD60663953FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FDDAC670561BB4F3FD85A376B677DC03FD4978FA3269EE13FE4978FA3269EE13FE14B1DD5F90CE13FDDAC670561BB4F"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F490FDB3EED63383EA4BC7D3E7ADBB03E4A22103E291CBC3E114D763E7ADBB03E5FEAC13E4A22103E382B843E291CBC3E1C501B3E114D763E4A22103E3DCBDA3E32DD453E291CBC3E205C3E3E18769B3E114D763E382B843E3052CA3E291CBC3E2276863E1C501B3E169BB53E114D763E2ED5363E291CBC3E23C0443E1EB7773E19FAF83E15843D3E114D763FB3EC433F9FE0BB3F8DB70D3F7B985F3F6045573F490FDB3F3568883F38053E3F293A203F1C58893F11152A3F072FE33EFCE5E23EED63383EFADBB03EED63383EE1330C3ED621803ECC0B223EC2D1BB3EBA5B733EC6D1B63EBEF83F3EB7B0CA3EB0ECA93EAA9EFF3EA4BC7D3E9F3B2B3EAA03B33EA4BC7D3E9FC3FC3E9B13BA3E96A5EA3E9275563E8E7D4B3FBD751C3FB20A6A3FA6FB4F3F9C6B533F9274203F8925433F8085453F7B985F3F6D63383F6045573F542F743F490FDB3F3ED3D03F3568883F36CEA63F2EAC4C3F2720F53F201FCA3F199CE43F138D543F0DE7193F11152A3F0BFA5A3F072FE33F02AF5D3EFCE5E23EF4EA9C3EED63383EF4669D3EED63383EE6BD153EE06DA63EDA6EEB3ED4BB613ECF4DFA"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FE921FB54442D1801623FE921FB54442D1801633FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FE921FB54442D1801623FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FDDAC670561BB4F01610362617A3FD4978FA3269EE1016103666F6F3FE921FB54442D180162036261723FE921FB54442D1801620362617A3FE2D0EAD6066395016203666F6F3FF1B6E192EBBE440163036261723FEF730BD281F69B01630362617A3FE921FB54442D18016303666F6F3FF3FC176B7A8560"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FDDAC670561BB4F01610362617A3FD4978FA3269EE1016103666F6F3FE921FB54442D180162036261723FD85A376B677DC001620362617A3FD4978FA3269EE1016203666F6F3FDDAC670561BB4F0163036261723FD6F61941E4DEF101630362617A3FD4978FA3269EE1016303666F6F3FD9E9BF3D20DC71"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE921FB54442D18016103666F6F3FE921FB54442D180162036261723FECAC7C57846F9E016203666F6F3FEDAC670561BB4F"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EC2D1BB016103626172016A3EA4BC7D016103626172016B3E8E7D4B016103626172016C3E7ADBB0016103666F6F01693F490FDB016103666F6F016A3EED6338016103666F6F016B3EA4BC7D016103666F6F016C3E7ADBB001620362617201693F490FDB016203626172016A3F31DA5E016203626172016B3F1EC8AC016203626172016C3F0F005D016203666F6F01693FA9B465016203666F6F016A3F8DB70D016203666F6F016B3F6D6338016203666F6F016C3F490FDB"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FDDAC670561BB4F3FDAC42FFA7BCBCF3FD85A376B677DC03FD652439D8BE7163FD4978FA3269EE13FD31A9B43436DE13FD1CFA95F7A8DCE3FE4978FA3269EE13FE2D0EAD60663953FE14B1DD5F90CE13FDFF54BF3BEC8433FDDAC670561BB4F3FDBAC91A9A723ED3FD9E9BF3D20DC7103666F6F3FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FE4978FA3269EE13FE14B1DD5F90CE13FDDAC670561BB4F3FD9E9BF3D20DC713FF5F973152548573FF30B6D796A4DA83FF07C6C6947A6A83FECAC7C57846F9E3FE921FB54442D183FE63B4BC3F16A8A3FE3D91573350661"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"atan2(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F490FDB3EC2D1BB3EA4BC7D3E98D4DA3E9275560161016A3EED63383EA4BC7D3E9539D33E8E7D4B3E8AB98C0161016B3EA4BC7D3E8E7D4B3E8852303E856DAD3E83BFEF0161016C3E7ADBB03E7ADBB03E7ADBB03E7ADBB03E7ADBB0016201693FB3EC433F73570A3F3A053C3F1B04FA3F081F120162016A3F9FE0BB3F5CB72D3F2CBBD33F12432C3F01D1350162016B3F8DB70D3F490FDB3F20F8CB3F0A58EF3EF80D7E0162016C3F7B985F3F38053E3F1687573F032BF53EED6338016301693FBD751C3F9687573F771ABC3F528A013F39152D0163016A3FB20A6A3F8DB70D3F6A440A3F490FDB3F31DA5E0163016B3FA6FB4F3F8577E93F5E58993F403CE33F2B15040163016C3F9C6B533F7B985F3F534BE63F38053E3F24BC7D"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FF1B6E192EBBE443FF3FC176B7A85603FF5368C951E9CFD3FF5F97315254857"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053F490FDB3EED63383EA4BC7D3E7ADBB03E4A2210"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053F490FDB3F8DB70D3F9FE0BB3FA9B4653FAFCB99"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FE921FB54442D183FE921FB54442D183FE921FB54442D183FE921FB54442D183FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FF1B6E192EBBE443FE921FB54442D183FE2D0EAD60663953FDDAC670561BB4F3FD85A376B677DC03FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FE4978FA3269EE13FE14B1DD5F90CE13FF5368C951E9CFD3FF1B6E192EBBE443FEDAC670561BB4F3FE921FB54442D183FE5977A5103EA923FF5F973152548573FF30B6D796A4DA83FF07C6C6947A6A83FECAC7C57846F9E3FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FD4978FA3269EE13FD1CFA95F7A8DCE3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FD10A4608E6284A3FCF5B75F92C80DD3FCD07BEA194B9913FCB051B394C33AA3FC94441F8F7260B3FCF5B75F92C80DD3FCD94610502338B3FCBFD581196F5C13FCA8F3C814A92D63FC94441F8F7260B3FCDEB4BEABF5A573FCC9AE19AA8FE1F3FCB665729A20CE23FCA4A6567A8DCF33FC94441F8F7260B"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FF1B6E192EBBE443FE921FB54442D183FE2D0EAD60663953FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FDDAC670561BB4F3FD85A376B677DC03FD4978FA3269EE13FE4978FA3269EE13FE14B1DD5F90CE13FDDAC670561BB4F"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FC94441F8F7260B3FC7B97B4BCE5B023FC65BA89B2161AB3FC52397843C9ADD3FC40B87C210A2E53FC30ED367D7CD043FC229AEC47638DD3FC7057081D704E63FC60A593E8618933FC52397843C9ADD3FC44ED0CD36E62E3FC38A03609B65453FC2D376AB2BDC173FC229AEC47638DD3FC5DAA6C2C7EF143FC52397843C9ADD3FC47808811538043FC3D6EEE8C6626C3FC33F5EF6C590243FC2B08797D7AFC63FC229AEC47638DD3FF67D8863BC99BD3FF3FC176B7A85603FF1B6E192EBBE443FEF730BD281F69B3FEC08AAE496EFA63FE921FB54442D183FE6AD1100FBFDDF3FE700A7C57846343FE5274400EEA72B3FE38B112D7BD4AD3FE222A54FDE6FA83FE0E5FC62BB05C33FDF9CBC4269AB2B3FDDAC670561BB4F3FDF5B75F92C80DD3FDDAC670561BB4F3FDC266181253B883FDAC42FFA7BCBCF3FD9816449B6FD543FD85A376B677DC03FD74B6E64A9083C3FD8DA36C0BE6CAA3FD7DF07E4BC36343FD6F61941E4DEF13FD61D9527631EA93FD553DFE7B697BA3FD4978FA3269EE13FD3E765551408AD3FD540765A5B20A13FD4978FA3269EE13FD3F87F84C579703FD362773707EBCC3FD2D4BD36A057653FD24EAAB4C991EE3FD1CFA95F7A8DCE3FF7AEA38C1ACBD13FF6414D44094C7C3FF4DF69D20AA3063FF38D6A6CE133533FF24E83FA9B4E483FF124A857547B083FF010A8AC54F5443FEF730BD281F69B3FEDAC670561BB4F3FEC08AAE496EFA63FEA85EE761A35A23FE921FB54442D183FE7DA79F20CC4433FE6AD1100FBFDDF3FE6D9D4BC9D58283FE5D58987169B183FE4E41E9E3C36153FE403F933FEDF173FE3339C815096583FE271AA72553ED53FE1BCE31303A0353FE222A54FDE6FA83FE17F4B4FADFC703FE0E5FC62BB05C33FE055EB9AF3EB4A3FDF9CBC4269AB2B3FDE9D53842EF0543FDDAC670561BB4F3FDE8CD3A58C421F3FDDAC670561BB4F3FDCD7A29A45A6ED3FDC0DB4C94EC9F03FDB4DDD66A37B403FDA976C28F401F63FD9E9BF3D20DC71"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073F490FDB3EED63383EA4BC7D3E7ADBB03E4A22103E291CBC3E114D763E7ADBB03E5FEAC13E4A22103E382B843E291CBC3E1C501B3E114D763E4A22103E3DCBDA3E32DD453E291CBC3E205C3E3E18769B3E114D763E382B843E3052CA3E291CBC3E2276863E1C501B3E169BB53E114D763E2ED5363E291CBC3E23C0443E1EB7773E19FAF83E15843D3E114D763FB3EC433F9FE0BB3F8DB70D3F7B985F3F6045573F490FDB3F3568883F38053E3F293A203F1C58893F11152A3F072FE33EFCE5E23EED63383EFADBB03EED63383EE1330C3ED621803ECC0B223EC2D1BB3EBA5B733EC6D1B63EBEF83F3EB7B0CA3EB0ECA93EAA9EFF3EA4BC7D3E9F3B2B3EAA03B33EA4BC7D3E9FC3FC3E9B13BA3E96A5EA3E9275563E8E7D4B3FBD751C3FB20A6A3FA6FB4F3F9C6B533F9274203F8925433F8085453F7B985F3F6D63383F6045573F542F743F490FDB3F3ED3D03F3568883F36CEA63F2EAC4C3F2720F53F201FCA3F199CE43F138D543F0DE7193F11152A3F0BFA5A3F072FE33F02AF5D3EFCE5E23EF4EA9C3EED63383EF4669D3EED63383EE6BD153EE06DA63EDA6EEB3ED4BB613ECF4DFA"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FE921FB54442D1801623FE921FB54442D1801633FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FE921FB54442D1801623FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FDDAC670561BB4F01610362617A3FD4978FA3269EE1016103666F6F3FE921FB54442D180162036261723FE921FB54442D1801620362617A3FE2D0EAD6066395016203666F6F3FF1B6E192EBBE440163036261723FEF730BD281F69B01630362617A3FE921FB54442D18016303666F6F3FF3FC176B7A8560"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FDDAC670561BB4F01610362617A3FD4978FA3269EE1016103666F6F3FE921FB54442D180162036261723FD85A376B677DC001620362617A3FD4978FA3269EE1016203666F6F3FDDAC670561BB4F0163036261723FD6F61941E4DEF101630362617A3FD4978FA3269EE1016303666F6F3FD9E9BF3D20DC71"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FE921FB54442D18016103666F6F3FE921FB54442D180162036261723FECAC7C57846F9E016203666F6F3FEDAC670561BB4F"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD85A376B677DC0016103626172016A3FD4978FA3269EE1016103626172016B3FD1CFA95F7A8DCE016103626172016C3FCF5B75F92C80DD016103666F6F01693FE921FB54442D18016103666F6F016A3FDDAC670561BB4F016103666F6F016B3FD4978FA3269EE1016103666F6F016C3FCF5B75F92C80DD01620362617201693FE921FB54442D18016203626172016A3FE63B4BC3F16A8A016203626172016B3FE3D91573350661016203626172016C3FE1E00BABDEFEB4016203666F6F01693FF5368C951E9CFD016203666F6F016A3FF1B6E192EBBE44016203666F6F016B3FEDAC670561BB4F016203666F6F016C3FE921FB54442D18"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EC2D1BB016103626172016A3EA4BC7D016103626172016B3E8E7D4B016103626172016C3E7ADBB0016103666F6F01693F490FDB016103666F6F016A3EED6338016103666F6F016B3EA4BC7D016103666F6F016C3E7ADBB001620362617201693F490FDB016203626172016A3F31DA5E016203626172016B3F1EC8AC016203626172016C3F0F005D016203666F6F01693FA9B465016203666F6F016A3F8DB70D016203666F6F016B3F6D6338016203666F6F016C3F490FDB"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FCF5B75F92C80DD3FCBFD581196F5C13FC94441F8F7260B3FC7057081D704E63FC52397843C9ADD3FC38A03609B65453FC229AEC47638DD3FDDAC670561BB4F3FDAC42FFA7BCBCF3FD85A376B677DC03FD652439D8BE7163FD4978FA3269EE13FD31A9B43436DE13FD1CFA95F7A8DCE3FE4978FA3269EE13FE2D0EAD60663953FE14B1DD5F90CE13FDFF54BF3BEC8433FDDAC670561BB4F3FDBAC91A9A723ED3FD9E9BF3D20DC7103666F6F3FE921FB54442D183FDDAC670561BB4F3FD4978FA3269EE13FCF5B75F92C80DD3FC94441F8F7260B3FC52397843C9ADD3FC229AEC47638DD3FF3FC176B7A85603FEF730BD281F69B3FE921FB54442D183FE4978FA3269EE13FE14B1DD5F90CE13FDDAC670561BB4F3FD9E9BF3D20DC713FF5F973152548573FF30B6D796A4DA83FF07C6C6947A6A83FECAC7C57846F9E3FE921FB54442D183FE63B4BC3F16A8A3FE3D91573350661"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FE921FB54442D183FD85A376B677DC03FD4978FA3269EE13FD31A9B43436DE13FD24EAAB4C991EE0161016A3FDDAC670561BB4F3FD4978FA3269EE13FD2A73A661EAF063FD1CFA95F7A8DCE3FD15731754A18210161016B3FD4978FA3269EE13FD1CFA95F7A8DCE3FD10A4608E6284A3FD0ADB5A7741C043FD077FDE3124EAA0161016C3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD3FCF5B75F92C80DD016201693FF67D8863BC99BD3FEE6AE1355353D03FE740A77023BDA93FE3609F33CE6BDF3FE103E230EBECF30162016A3FF3FC176B7A85603FEB96E5A78C5C523FE5977A5103EA923FE2486589DBA9E03FE03A26A486E6310162016B3FF1B6E192EBBE443FE921FB54442D183FE41F1963C0045F3FE14B1DD5F90CE13FDF01AFB73642BD0162016C3FEF730BD281F69B3FE700A7C57846343FE2D0EAD60663953FE0657E94DB30D03FDDAC670561BB4F016301693FF7AEA38C1ACBD13FF2D0EAD60663953FEEE35774B9EE523FEA514023A34D203FE722A598D15D3A0163016A3FF6414D44094C7C3FF1B6E192EBBE443FED488143AD8C443FE921FB54442D183FE63B4BC3F16A8A0163016B3FF4DF69D20AA3063FF0AEFD22E6AA373FEBCB1321414BE03FE8079C6293AEE03FE562A07DC47C8F0163016C3FF38D6A6CE133533FEF730BD281F69B3FEA697CB67B95EE3FE700A7C57846343FE4978FA3269EE1"}}
-{"expression":"join(a,b,f(a,b)(atan2(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693F490FDB3EC2D1BB3EA4BC7D3E98D4DA3E9275560161016A3EED63383EA4BC7D3E9539D33E8E7D4B3E8AB98C0161016B3EA4BC7D3E8E7D4B3E8852303E856DAD3E83BFEF0161016C3E7ADBB03E7ADBB03E7ADBB03E7ADBB03E7ADBB0016201693FB3EC433F73570A3F3A053C3F1B04FA3F081F120162016A3F9FE0BB3F5CB72D3F2CBBD33F12432C3F01D1350162016B3F8DB70D3F490FDB3F20F8CB3F0A58EF3EF80D7E0162016C3F7B985F3F38053E3F1687573F032BF53EED6338016301693FBD751C3F9687573F771ABC3F528A013F39152D0163016A3FB20A6A3F8DB70D3F6A440A3F490FDB3F31DA5E0163016B3FA6FB4F3F8577E93F5E58993F403CE33F2B15040163016C3F9C6B533F7B985F3F534BE63F38053E3F24BC7D"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE4000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003EC000003EC000003EC000003EC000003EC000003EC000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F2000003F2000003F2000003FA000003FA000003FA000003FA000003EC000003EC000003EC000003EC000003EC000003EC000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F8000003F8000003F8000003F8000003F8000003F8000003F9000003F9000003F9000003F9000003F9000003F9000003F9000003FA000003FA000003FA00000402000004020000040200000402000003F3000003F3000003F3000003F3000003F3000003F3000003F3000003F4000003F4000003F4000003F4000003F4000003F4000003F4000003F5000003FD000003FD000003FD000003FD000003FD000003FD000003FE000003FE000003FE000003FE000003FE000003FE000003FE000003FF000003FF000003FF0000040700000407000004070000040700000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD4000000000000016203666F6F3FD0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F01693D800000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D80000001620362617201693EA00000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F01693E800000016203666F6F016A3E800000016203666F6F016B3E800000016203666F6F016C3E800000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F3FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"ldexp(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003E0000003E4000003E8000003F2000000161016A3D8000003E0000003E4000003E8000003F2000000161016B3D8000003E0000003E4000003E8000003F2000000161016C3D8000003E0000003E4000003F0000003F200000016201693EC000003EE000003F0000003F1000003FA000000162016A3EC000003EE000003F0000003F1000003FA000000162016B3EC000003EE000003F0000003F1000003FA000000162016C3EC000003EE000003F0000003F9000003FA00000016301693F3000003F4000003F5000003F6000003FF000000163016A3F3000003F4000003F5000003F6000003FF000000163016B3F3000003F4000003F5000003F6000003FF000000163016C3F3000003F4000003F5000003FE000003FF00000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE4000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE40000000000003FE40000000000003FE40000000000003FF40000000000003FF40000000000003FF40000000000003FF40000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF00000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF20000000000003FF40000000000003FF40000000000003FF400000000000040040000000000004004000000000000400400000000000040040000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFA0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFC0000000000003FFE0000000000003FFE0000000000003FFE000000000000400E000000000000400E000000000000400E000000000000400E000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003EC000003EC000003EC000003EC000003EC000003EC000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F2000003F2000003F2000003FA000003FA000003FA000003FA000003EC000003EC000003EC000003EC000003EC000003EC000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F8000003F8000003F8000003F8000003F8000003F8000003F9000003F9000003F9000003F9000003F9000003F9000003F9000003FA000003FA000003FA00000402000004020000040200000402000003F3000003F3000003F3000003F3000003F3000003F3000003F3000003F4000003F4000003F4000003F4000003F4000003F4000003F4000003F5000003FD000003FD000003FD000003FD000003FD000003FD000003FE000003FE000003FE000003FE000003FE000003FE000003FE000003FF000003FF000003FF0000040700000407000004070000040700000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD4000000000000016203666F6F3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F01693D800000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D80000001620362617201693EA00000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F01693E800000016203666F6F016A3E800000016203666F6F016B3E800000016203666F6F016C3E800000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F3FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FE40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FE00000000000003FE4000000000000016201693FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016A3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016B3FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FF40000000000000162016C3FD80000000000003FDC0000000000003FE00000000000003FF20000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FFE0000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FFC0000000000003FFE000000000000"}}
-{"expression":"join(a,b,f(a,b)(ldexp(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003E0000003E4000003E8000003F2000000161016A3D8000003E0000003E4000003E8000003F2000000161016B3D8000003E0000003E4000003E8000003F2000000161016C3D8000003E0000003E4000003F0000003F200000016201693EC000003EE000003F0000003F1000003FA000000162016A3EC000003EE000003F0000003F1000003FA000000162016B3EC000003EE000003F0000003F1000003FA000000162016C3EC000003EE000003F0000003F9000003FA00000016301693F3000003F4000003F5000003F6000003FF000000163016A3F3000003F4000003F5000003F6000003FF000000163016B3F3000003F4000003F5000003F6000003FF000000163016C3F3000003F4000003F5000003FE000003FF00000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003D8000003D8000003D8000003D800000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC00000000000003FC00000000000003FC000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC8000000000000000000000000000000000000000000003FB000000000000000000000000000003FD000000000000000000000000000003FB00000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC000000000000000000000000000003FB000000000000000000000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000000000000000000000000000003E0000003D800000000000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F200000000000003D8000003E0000003E4000003D8000003EA000003E8000003E8000003E4000003E0000003D800000000000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FC0000000000000016203666F6F00000000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F00000000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F016900000000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D800000016203626172016900000000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F00000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC80000000000003FC80000000000003FC800000000000000000000000000003FB00000000000003FC00000000000003FB000000000000000000000000000003FD40000000000003FD4000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"fmod(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA0000001620169000000003E0000003F0000003F1000003F2000000162016A000000003D8000003F0000003F1000003F2000000162016B00000000000000003F0000003F1000003F2000000162016C3E0000003EE000003F0000003F1000003F20000001630169000000003E0000003E8000003D8000003F7000000163016A3D800000000000003E400000000000003F7000000163016B3E0000003EA000003E0000003F6000003F7000000163016C3E4000003E8000003D8000003F6000003F700000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x060101017805000000003D8000003D8000003D8000003D800000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178050000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780500000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC00000000000003FC00000000000003FC000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC8000000000000000000000000000000000000000000003FB000000000000000000000000000003FD000000000000000000000000000003FB00000000000003FC00000000000003FB00000000000000000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x020201780501790500000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0300000000000000003FB00000000000003FB0000000000000000000000000000000000000000000003FC000000000000000000000000000003FB000000000000000000000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A0700000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000000000000000000000000000000000000000000000000000003FC00000000000003FB000000000000000000000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE400000000000000000000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FD40000000000003FD00000000000003FD00000000000003FC80000000000003FC00000000000003FB000000000000000000000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A07000000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000000000000000000000000000003E0000003D800000000000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F200000000000003D8000003E0000003E4000003D8000003EA000003E8000003E8000003E4000003E0000003D800000000000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016100000000000000000162000000000000000001630000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161000000000000000001620000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F0000000000000000016203626172000000000000000001620362617A3FC0000000000000016203666F6F00000000000000000163036261723FB000000000000001630362617A0000000000000000016303666F6F0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F00000000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261720000000000000000016103666F6F00000000000000000162036261723FB0000000000000016203666F6F3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01690000000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201690000000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01690000000000000000016203666F6F016A0000000000000000016203666F6F016B3FB0000000000000016203666F6F016C0000000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F016900000000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D800000016203626172016900000000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F016900000000016203666F6F016A00000000016203666F6F016B3D800000016203666F6F016C00000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F00000000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB000000000000000000000000000003FB000000000000000000000000000003FC80000000000003FC80000000000003FC80000000000003FC800000000000000000000000000003FB00000000000003FC00000000000003FB000000000000000000000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016900000000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000162016900000000000000003FC00000000000003FE00000000000003FE20000000000003FE40000000000000162016A00000000000000003FB00000000000003FE00000000000003FE20000000000003FE40000000000000162016B000000000000000000000000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FC00000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000163016900000000000000003FC00000000000003FD00000000000003FB00000000000003FEE0000000000000163016A3FB000000000000000000000000000003FC800000000000000000000000000003FEE0000000000000163016B3FC00000000000003FD40000000000003FC00000000000003FEC0000000000003FEE0000000000000163016C3FC80000000000003FD00000000000003FB00000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(fmod(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169000000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA0000001620169000000003E0000003F0000003F1000003F2000000162016A000000003D8000003F0000003F1000003F2000000162016B00000000000000003F0000003F1000003F2000000162016C3E0000003EE000003F0000003F1000003F20000001630169000000003E0000003E8000003D8000003F7000000163016A3D800000000000003E400000000000003F7000000163016B3E0000003EA000003E0000003F6000003F7000000163016C3E4000003E8000003D8000003F6000003F700000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FB00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD00000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000003D8000003E0000003E4000003E8000003EA000003EC000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F2000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FB00000000000000163036261723FC000000000000001630362617A3FC8000000000000016303666F6F3FB0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC8000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F01693D800000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D80000001620362617201693EA00000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F01693D800000016203666F6F016A3E000000016203666F6F016B3E400000016203666F6F016C3E800000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F3FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"min(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA00000016201693D8000003EA000003F0000003F1000003F2000000162016A3E0000003EC000003F0000003F1000003F2000000162016B3E4000003EE000003F0000003F1000003F2000000162016C3E8000003EE000003F0000003F1000003F200000016301693D8000003EA000003F1000003F5000003F7000000163016A3E0000003EC000003F2000003F6000003F7000000163016B3E4000003EE000003F3000003F6000003F7000000163016C3E8000003F0000003F4000003F6000003F700000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003D8000003D8000003D8000003D800000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FB00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD00000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FB00000000000003FC00000000000003FC80000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD80000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FDC0000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE00000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE20000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FE40000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEA0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEC0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003D8000003D8000003D8000003D8000003D8000003D8000003E0000003E0000003E0000003E0000003E0000003E0000003E0000003E4000003E4000003E4000003E4000003E4000003E4000003E4000003E8000003E8000003E8000003E8000003E8000003E8000003E8000003EA000003EA000003EA000003EA000003EA000003EA000003EA000003D8000003E0000003E4000003E8000003EA000003EC000003EC000003EE000003EE000003EE000003EE000003EE000003EE000003EE000003F0000003F0000003F0000003F0000003F0000003F0000003F0000003F1000003F1000003F1000003F1000003F1000003F1000003F1000003F2000003F2000003F2000003F2000003F2000003F2000003F2000003D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F4000003F4000003F5000003F5000003F5000003F5000003F5000003F5000003F5000003F6000003F6000003F6000003F6000003F6000003F6000003F6000003F7000003F7000003F7000003F7000003F7000003F7000003F700000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FB00000000000000163036261723FC000000000000001630362617A3FC8000000000000016303666F6F3FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FB000000000000001610362617A3FB0000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC0000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FC0000000000000016103626172016A3FC0000000000000016103626172016B3FC0000000000000016103626172016C3FC0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FB0000000000000016103666F6F016B3FB0000000000000016103666F6F016C3FB000000000000001620362617201693FD4000000000000016203626172016A3FD4000000000000016203626172016B3FD4000000000000016203626172016C3FD4000000000000016203666F6F01693FB0000000000000016203666F6F016A3FC0000000000000016203666F6F016B3FC8000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693E000000016103626172016A3E000000016103626172016B3E000000016103626172016C3E000000016103666F6F01693D800000016103666F6F016A3D800000016103666F6F016B3D800000016103666F6F016C3D80000001620362617201693EA00000016203626172016A3EA00000016203626172016B3EA00000016203626172016C3EA00000016203666F6F01693D800000016203666F6F016A3E000000016203666F6F016B3E400000016203666F6F016C3E800000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FC00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD800000000000003666F6F3FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FB00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016A3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016B3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000000161016C3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000016201693FB00000000000003FD40000000000003FE00000000000003FE20000000000003FE40000000000000162016A3FC00000000000003FD80000000000003FE00000000000003FE20000000000003FE40000000000000162016B3FC80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000000162016C3FD00000000000003FDC0000000000003FE00000000000003FE20000000000003FE4000000000000016301693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FEE0000000000000163016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FEE0000000000000163016B3FC80000000000003FDC0000000000003FE60000000000003FEC0000000000003FEE0000000000000163016C3FD00000000000003FE00000000000003FE80000000000003FEC0000000000003FEE000000000000"}}
-{"expression":"join(a,b,f(a,b)(min(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003E0000003E4000003E8000003EA000000161016A3D8000003E0000003E4000003E8000003EA000000161016B3D8000003E0000003E4000003E8000003EA000000161016C3D8000003E0000003E4000003E8000003EA00000016201693D8000003EA000003F0000003F1000003F2000000162016A3E0000003EC000003F0000003F1000003F2000000162016B3E4000003EE000003F0000003F1000003F2000000162016C3E8000003EE000003F0000003F1000003F200000016301693D8000003EA000003F1000003F5000003F7000000163016A3E0000003EC000003F2000003F6000003F7000000163016B3E4000003EE000003F3000003F6000003F7000000163016C3E8000003F0000003F4000003F6000003F700000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FC00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FC00000000000003FC80000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD00000000000003FD40000000000003FD80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C00003EC000003EC000003EC000003EC000003EC000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C00003F3000003F3000003F3000003F3000003F3000003F3000003F3000003F4000003F4000003F4000003F4000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC8000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD4000000000000016203666F6F3FD0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693EA00000016203626172016A3EC00000016203626172016B3EE00000016203626172016C3F000000016203666F6F01693E800000016203666F6F016A3E800000016203666F6F016B3E800000016203666F6F016C3E800000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD80000000000003FDC000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"max(a,b)","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693EC000003EE000003F1000003F5000003F8800000162016A3EC000003EE000003F2000003F6000003F9000000162016B3EC000003EE000003F3000003F7000003F9800000162016C3EC000003F0000003F4000003F8000003FA00000016301693F3000003F4000003F5000003F6000003F8800000163016A3F3000003F4000003F5000003F6000003F9000000163016B3F3000003F4000003F5000003F7000003F9800000163016C3F3000003F4000003F5000003F8000003FA00000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02003FB0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FC00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD00000000000003FD00000000000003FD00000000000003FD00000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A033FB00000000000003FC00000000000003FC80000000000003FC00000000000003FC00000000000003FC80000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FD00000000000003FD40000000000003FD80000000000003FD00000000000003FD40000000000003FD8000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF00000000000040000000000000004000800000000000400100000000000040018000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE60000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C00003EC000003EC000003EC000003EC000003EC000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C00003F3000003F3000003F3000003F3000003F3000003F3000003F3000003F4000003F4000003F4000003F4000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x010101780201613FB000000000000001623FC0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FC000000000000001620362617A3FC8000000000000016203666F6F3FC00000000000000163036261723FC800000000000001630362617A3FC8000000000000016303666F6F3FC8000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD4000000000000016203666F6F3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201693FD4000000000000016103626172016A3FD8000000000000016103626172016B3FDC000000000000016103626172016C3FE0000000000000016103666F6F01693FB0000000000000016103666F6F016A3FC0000000000000016103666F6F016B3FC8000000000000016103666F6F016C3FD000000000000001620362617201693FD4000000000000016203626172016A3FD8000000000000016203626172016B3FDC000000000000016203626172016C3FE0000000000000016203666F6F01693FD0000000000000016203666F6F016A3FD0000000000000016203666F6F016B3FD0000000000000016203666F6F016C3FD0000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A1001610362617201693EA00000016103626172016A3EC00000016103626172016B3EE00000016103626172016C3F000000016103666F6F01693D800000016103666F6F016A3E000000016103666F6F016B3E400000016103666F6F016C3E80000001620362617201693EA00000016203626172016A3EC00000016203626172016B3EE00000016203626172016C3F000000016203666F6F01693E800000016203666F6F016A3E800000016203666F6F016B3E800000016203666F6F016C3E800000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FC80000000000003FC80000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD40000000000003FD80000000000003FDC000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C016101693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF10000000000000161016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF20000000000000161016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000161016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016201693FD80000000000003FDC0000000000003FE20000000000003FEA0000000000003FF10000000000000162016A3FD80000000000003FDC0000000000003FE40000000000003FEC0000000000003FF20000000000000162016B3FD80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF30000000000000162016C3FD80000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000016301693FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF10000000000000163016A3FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FF20000000000000163016B3FE60000000000003FE80000000000003FEA0000000000003FEE0000000000003FF30000000000000163016C3FE60000000000003FE80000000000003FEA0000000000003FF00000000000003FF4000000000000"}}
-{"expression":"join(a,b,f(a,b)(max(a,b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C016101693D8000003EA000003F1000003F5000003F8800000161016A3E0000003EC000003F2000003F6000003F9000000161016B3E4000003EE000003F3000003F7000003F9800000161016C3E8000003F0000003F4000003F8000003FA00000016201693EC000003EE000003F1000003F5000003F8800000162016A3EC000003EE000003F2000003F6000003F9000000162016B3EC000003EE000003F3000003F7000003F9800000162016C3EC000003F0000003F4000003F8000003FA00000016301693F3000003F4000003F5000003F6000003F8800000163016A3F3000003F4000003F5000003F6000003F9000000163016B3F3000003F4000003F5000003F7000003F9800000163016C3F3000003F4000003F5000003F8000003FA00000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x02004040000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x020101780540400000000000004038000000000000403555555555555540340000000000004033333333333333"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02003FB0000000000000"},"result":{"expect":"0x020101780540400000000000004038000000000000403555555555555540340000000000004033333333333333"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02003FB0000000000000","b":"0x0601010178053D8000003E0000003E4000003E8000003EA00000"},"result":{"expect":"0x0601010178054200000041C0000041AAAAAB41A000004199999A"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x0601010178053D8000003E0000003E4000003E8000003EA00000","b":"0x02003FB0000000000000"},"result":{"expect":"0x0601010178054200000041C0000041AAAAAB41A000004199999A"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02010178054040000000000000403000000000000040255555555555554020000000000000401999999999999A"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02010179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000"},"result":{"expect":"0x02020178050179054040000000000000403800000000000040355555555555554034000000000000403333333333333340380000000000004030000000000000402AAAAAAAAAAAAB402800000000000040266666666666664035555555555555402AAAAAAAAAAAAB40255555555555554022AAAAAAAAAAAB4021111111111111403400000000000040280000000000004022AAAAAAAAAAAB4020000000000000401CCCCCCCCCCCCD403333333333333340266666666666664021111111111111401CCCCCCCCCCCCD401999999999999A"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02010178053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD4000000000000","b":"0x02020178050179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF9000000000000"},"result":{"expect":"0x02020178050179054040000000000000403800000000000040355555555555554034000000000000403333333333333340255555555555554024924924924925402400000000000040238E38E38E38E44023333333333333401B26C9B26C9B27401AAAAAAAAAAAAB401A41A41A41A41A4019E79E79E79E7A401999999999999A40140000000000004013C3C3C3C3C3C440138E38E38E38E440135E50D79435E54013333333333333400FB1FB1FB1FB20400F6B0DF6B0DF6B400F2A4BAFDC61F3400EEEEEEEEEEEEF400EB851EB851EB8"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02010179033FB00000000000003FC00000000000003FC8000000000000","b":"0x0202017802017A033FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD8000000000000"},"result":{"expect":"0x0203017802017903017A0340400000000000004038000000000000403555555555555540380000000000004030000000000000402AAAAAAAAAAAAB4035555555555555402AAAAAAAAAAAAB4025555555555555403400000000000040333333333333334032AAAAAAAAAAAB4028000000000000402666666666666640255555555555554022AAAAAAAAAAAB40211111111111114020000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07404000000000000040380000000000004035555555555555403400000000000040333333333333334032AAAAAAAAAAAB4032492492492492402400000000000040238E38E38E38E440233333333333334022E8BA2E8BA2E94022AAAAAAAAAAAB40227627627627624022492492492492401999999999999A401955555555555540191919191919194018E38E38E38E394018B3A62CE98B3A401888888888888940186186186186184012E8BA2E8BA2E94012C8590B21642D4012AAAAAAAAAAAB40128F5C28F5C28F401276276276276240125ED097B425ED4012492492492492400E0387F1E0387F400DDDDDDDDDDDDE400DBAA1DBAA1DBB400D99999999999A400D7A91D7A91D7B400D5D5D5D5D5D5D400D41D41D41D41D4032AAAAAAAAAAAB40255555555555554020000000000000401AAAAAAAAAAAAB401777777777777740155555555555554013CF3CF3CF3CF440112492492492494010410410410410400F15F15F15F15F400DEC0D4C77B035400CF3CF3CF3CF3D400C21C21C21C21C400B6DB6DB6DB6DB40088888888888894008000000000000400787878787878840071C71C71C71C74006BCA1AF286BCA4006666666666666400618618618618640040A57EB5029604003C995A47BABE740038E38E38E38E44003579BE02468AD40032532532532534002F684BDA12F684002CB2CB2CB2CB3400136BB25136BB240011111111111114000EDD50EDD50EE4000CCCCCCCCCCCD4000ADC50ADC50AE400090909090909140007507507507504031745D1745D1744022E8BA2E8BA2E9401B26C9B26C9B274015D1745D1745D140129E4129E4129E40107C1F07C1F07C400DEC0D4C77B035400AAAAAAAAAAAAB4008E38E38E38E39400777777777777740064D9364D9364E400555555555555540048348348348354003CF3CF3CF3CF440026126126126124001D89D89D89D8A40016025116025114000F50F50F50F514000953F3901095440003F03F03F03F03FFFE1FE1FE1FE203FFDEC0D4C77B0353FFD6A88BECEB5443FFCF3CF3CF3CF3D3FFC869536202ED03FFC21C21C21C21C3FFBC466F119BC463FFB6DB6DB6DB6DB3FF9E4EDC19E4EDC3FF999999999999A3FF95321953219533FF91111111111113FF8D3018D3018D33FF89898989898993FF8618618618618"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x0202017905017A073FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE0000000000003FF00000000000003FF10000000000003FF20000000000003FF30000000000003FF40000000000003FF50000000000003FF60000000000003FF70000000000003FF80000000000003FF90000000000003FFA0000000000003FFB0000000000003FFC0000000000003FFD0000000000003FFE0000000000003FFF0000000000004000000000000000400080000000000040010000000000004001800000000000"},"result":{"expect":"0x0203017803017905017A07404000000000000040380000000000004035555555555555403400000000000040333333333333334032AAAAAAAAAAAB4032492492492492402400000000000040238E38E38E38E440233333333333334022E8BA2E8BA2E94022AAAAAAAAAAAB40227627627627624022492492492492401999999999999A401955555555555540191919191919194018E38E38E38E394018B3A62CE98B3A401888888888888940186186186186184012E8BA2E8BA2E94012C8590B21642D4012AAAAAAAAAAAB40128F5C28F5C28F401276276276276240125ED097B425ED4012492492492492400E0387F1E0387F400DDDDDDDDDDDDE400DBAA1DBAA1DBB400D99999999999A400D7A91D7A91D7B400D5D5D5D5D5D5D400D41D41D41D41D4032AAAAAAAAAAAB40255555555555554020000000000000401AAAAAAAAAAAAB401777777777777740155555555555554013CF3CF3CF3CF440112492492492494010410410410410400F15F15F15F15F400DEC0D4C77B035400CF3CF3CF3CF3D400C21C21C21C21C400B6DB6DB6DB6DB40088888888888894008000000000000400787878787878840071C71C71C71C74006BCA1AF286BCA4006666666666666400618618618618640040A57EB5029604003C995A47BABE740038E38E38E38E44003579BE02468AD40032532532532534002F684BDA12F684002CB2CB2CB2CB3400136BB25136BB240011111111111114000EDD50EDD50EE4000CCCCCCCCCCCD4000ADC50ADC50AE400090909090909140007507507507504031745D1745D1744022E8BA2E8BA2E9401B26C9B26C9B274015D1745D1745D140129E4129E4129E40107C1F07C1F07C400DEC0D4C77B035400AAAAAAAAAAAAB4008E38E38E38E39400777777777777740064D9364D9364E400555555555555540048348348348354003CF3CF3CF3CF440026126126126124001D89D89D89D8A40016025116025114000F50F50F50F514000953F3901095440003F03F03F03F03FFFE1FE1FE1FE203FFDEC0D4C77B0353FFD6A88BECEB5443FFCF3CF3CF3CF3D3FFC869536202ED03FFC21C21C21C21C3FFBC466F119BC463FFB6DB6DB6DB6DB3FF9E4EDC19E4EDC3FF999999999999A3FF95321953219533FF91111111111113FF8D3018D3018D33FF89898989898993FF8618618618618"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x02020178030179053FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x0203017803017905017A07404000000000000040380000000000004035555555555555403400000000000040333333333333334032AAAAAAAAAAAB4032492492492492402400000000000040238E38E38E38E440233333333333334022E8BA2E8BA2E94022AAAAAAAAAAAB40227627627627624022492492492492401999999999999A401955555555555540191919191919194018E38E38E38E394018B3A62CE98B3A401888888888888940186186186186184012E8BA2E8BA2E94012C8590B21642D4012AAAAAAAAAAAB40128F5C28F5C28F401276276276276240125ED097B425ED4012492492492492400E0387F1E0387F400DDDDDDDDDDDDE400DBAA1DBAA1DBB400D99999999999A400D7A91D7A91D7B400D5D5D5D5D5D5D400D41D41D41D41D4032AAAAAAAAAAAB40255555555555554020000000000000401AAAAAAAAAAAAB401777777777777740155555555555554013CF3CF3CF3CF440112492492492494010410410410410400F15F15F15F15F400DEC0D4C77B035400CF3CF3CF3CF3D400C21C21C21C21C400B6DB6DB6DB6DB40088888888888894008000000000000400787878787878840071C71C71C71C74006BCA1AF286BCA4006666666666666400618618618618640040A57EB5029604003C995A47BABE740038E38E38E38E44003579BE02468AD40032532532532534002F684BDA12F684002CB2CB2CB2CB3400136BB25136BB240011111111111114000EDD50EDD50EE4000CCCCCCCCCCCD4000ADC50ADC50AE400090909090909140007507507507504031745D1745D1744022E8BA2E8BA2E9401B26C9B26C9B274015D1745D1745D140129E4129E4129E40107C1F07C1F07C400DEC0D4C77B035400AAAAAAAAAAAAB4008E38E38E38E39400777777777777740064D9364D9364E400555555555555540048348348348354003CF3CF3CF3CF440026126126126124001D89D89D89D8A40016025116025114000F50F50F50F514000953F3901095440003F03F03F03F03FFFE1FE1FE1FE203FFDEC0D4C77B0353FFD6A88BECEB5443FFCF3CF3CF3CF3D3FFC869536202ED03FFC21C21C21C21C3FFBC466F119BC463FFB6DB6DB6DB6DB3FF9E4EDC19E4EDC3FF999999999999A3FF95321953219533FF91111111111113FF8D3018D3018D33FF89898989898993FF8618618618618"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x0601020178030179053D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F700000","b":"0x060102017905017A073D8000003E0000003E4000003E8000003EA000003EC000003EE000003F0000003F1000003F2000003F3000003F4000003F5000003F6000003F7000003F8000003F8800003F9000003F9800003FA000003FA800003FB000003FB800003FC000003FC800003FD000003FD800003FE000003FE800003FF000003FF80000400000004004000040080000400C0000"},"result":{"expect":"0x060103017803017905017A074200000041C0000041AAAAAB41A000004199999A419555554192492541200000411C71C74119999A411745D1411555554113B13B4112492540CCCCCD40CAAAAB40C8C8C940C71C7240C59D3140C4444440C30C31409745D1409642C84095555540947AE14093B13B4092F6854092492540701C40406EEEEF406DD50F406CCCCD406BD48F406AEAEB406A0EA141955555412AAAAB4100000040D5555540BBBBBC40AAAAAB409E79E840892492408208214078AF8B406F606A40679E7A40610E11405B6DB74044444440400000403C3C3C4038E38E4035E50D403333334030C30C402052BF401E4CAD401C71C7401ABCDF401929934017B426401659664009B5D94008888940076EA84006666640056E28400484854003A83B418BA2E9411745D140D9364E40AE8BA34094F2094083E0F8406F606A4055555540471C72403BBBBC40326C9B402AAAAB40241A42401E79E840130931400EC4EC400B01294007A87B4004A9FA4001F8203FFF0FF13FEF606A3FEB54463FE79E7A3FE434AA3FE10E113FDE23383FDB6DB73FCF276E3FCCCCCD3FCA990D3FC888893FC6980C3FC4C4C53FC30C31"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000"},"result":{"expect":"0x0101017803016140400000000000000162403000000000000001634025555555555555"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010101780201613FB000000000000001623FC0000000000000"},"result":{"expect":"0x01010178020161404000000000000001624030000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x0101017903036261723FC00000000000000362617A3FC800000000000003666F6F3FB0000000000000"},"result":{"expect":"0x01020178017909016103626172403800000000000001610362617A4035555555555555016103666F6F4040000000000000016203626172403000000000000001620362617A402AAAAAAAAAAAAB016203666F6F4038000000000000016303626172402AAAAAAAAAAAAB01630362617A4025555555555555016303666F6F4035555555555555"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010101780301613FB000000000000001623FC000000000000001633FC8000000000000","b":"0x010201780179090161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD00000000000000163036261723FE000000000000001630362617A3FE2000000000000016303666F6F3FDC000000000000"},"result":{"expect":"0x01020178017909016103626172403800000000000001610362617A4035555555555555016103666F6F4040000000000000016203626172402666666666666601620362617A4025555555555555016203666F6F4028000000000000016303626172401D55555555555501630362617A401C71C71C71C71C016303666F6F401E79E79E79E79E"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x010201780179060161036261723FC0000000000000016103666F6F3FB00000000000000162036261723FD0000000000000016203666F6F3FC80000000000000163036261723FD8000000000000016303666F6F3FD4000000000000"},"result":{"expect":"0x010201780179040161036261724030000000000000016103666F6F4040000000000000016203626172401CCCCCCCCCCCCD016203666F6F4022AAAAAAAAAAAB"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201694026666666666666016103626172016A4025555555555555016103626172016B4024924924924925016103626172016C4024000000000000016103666F6F01694040000000000000016103666F6F016A4038000000000000016103666F6F016B4035555555555555016103666F6F016C40340000000000000162036261720169401999999999999A016203626172016A4017777777777777016203626172016B4015F15F15F15F16016203626172016C4014CCCCCCCCCCCD016203666F6F01694034000000000000016203666F6F016A4028000000000000016203666F6F016B4022AAAAAAAAAAAB016203666F6F016C4020000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x01020179017A080362617201693FD400000000000003626172016A3FD800000000000003626172016B3FDC00000000000003626172016C3FE000000000000003666F6F01693FB000000000000003666F6F016A3FC000000000000003666F6F016B3FC800000000000003666F6F016C3FD0000000000000"},"result":{"expect":"0x010301780179017A1001610362617201694026666666666666016103626172016A4025555555555555016103626172016B4024924924924925016103626172016C4024000000000000016103666F6F01694040000000000000016103666F6F016A4038000000000000016103666F6F016B4035555555555555016103666F6F016C40340000000000000162036261720169401999999999999A016203626172016A4017777777777777016203626172016B4015F15F15F15F16016203626172016C4014CCCCCCCCCCCD016203666F6F01694034000000000000016203666F6F016A4028000000000000016203666F6F016B4022AAAAAAAAAAAB016203666F6F016C4020000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x010201780179060161036261723FC000000000000001610362617A3FC8000000000000016103666F6F3FB00000000000000162036261723FD400000000000001620362617A3FD8000000000000016203666F6F3FD0000000000000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x010301780179017A1001610362617201694026666666666666016103626172016A4025555555555555016103626172016B4024924924924925016103626172016C4024000000000000016103666F6F01694040000000000000016103666F6F016A4038000000000000016103666F6F016B4035555555555555016103666F6F016C40340000000000000162036261720169401999999999999A016203626172016A4017777777777777016203626172016B4015F15F15F15F16016203626172016C4014CCCCCCCCCCCD016203666F6F01694034000000000000016203666F6F016A4028000000000000016203666F6F016B4022AAAAAAAAAAAB016203666F6F016C4020000000000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x05010201780179060161036261723E00000001610362617A3E400000016103666F6F3D8000000162036261723EA0000001620362617A3EC00000016203666F6F3E800000","b":"0x0501020179017A080362617201693EA0000003626172016A3EC0000003626172016B3EE0000003626172016C3F00000003666F6F01693D80000003666F6F016A3E00000003666F6F016B3E40000003666F6F016C3E800000"},"result":{"expect":"0x05010301780179017A10016103626172016941333333016103626172016A412AAAAB016103626172016B41249249016103626172016C41200000016103666F6F016942000000016103666F6F016A41C00000016103666F6F016B41AAAAAB016103666F6F016C41A00000016203626172016940CCCCCD016203626172016A40BBBBBC016203626172016B40AF8AF9016203626172016C40A66666016203666F6F016941A00000016203666F6F016A41400000016203666F6F016B41155555016203666F6F016C41000000"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x030101790101780302036261723FC00000000000003FD00000000000003FD800000000000003666F6F3FB00000000000003FC80000000000003FD4000000000000","b":"0x0301017901017A0702036261723FE00000000000003FE20000000000003FE40000000000003FE60000000000003FE80000000000003FEA0000000000003FEC00000000000003666F6F3FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD40000000000003FD80000000000003FDC000000000000"},"result":{"expect":"0x0301017902017803017A070203626172402400000000000040238E38E38E38E440233333333333334022E8BA2E8BA2E94022AAAAAAAAAAAB40227627627627624022492492492492401800000000000040171C71C71C71C740166666666666664015D1745D1745D140155555555555554014EC4EC4EC4EC540149249249249254012AAAAAAAAAAAB4011C71C71C71C72401111111111111140107C1F07C1F07C4010000000000000400F2DF2DF2DF2DF400E79E79E79E79E03666F6F404000000000000040380000000000004035555555555555403400000000000040333333333333334032AAAAAAAAAAAB40324924924924924035555555555555402AAAAAAAAAAAAB40255555555555554022AAAAAAAAAAAB40211111111111114020000000000000401E79E79E79E79E403333333333333340266666666666664021111111111111401CCCCCCCCCCCCD401999999999999A40177777777777774015F15F15F15F16"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016940400000000000004026666666666666401C71C71C71C71C4014EC4EC4EC4EC540109090909090910161016A40380000000000004025555555555555401BBBBBBBBBBBBC401492492492492540105B05B05B05B00161016B40355555555555554024924924924925401B26C9B26C9B27401444444444444440102B1DA46102B20161016C40340000000000004024000000000000401AAAAAAAAAAAAB40140000000000004010000000000000016201694032AAAAAAAAAAAB4015F15F15F15F16400E38E38E38E38E400811811811811840045454545454540162016A40255555555555554013CF3CF3CF3CF4400CCCCCCCCCCCCD40075D75D75D75D74003E93E93E93E940162016B40200000000000004012492492492492400BA2E8BA2E8BA34006C16C16C16C174003896E7BF538970162016C401AAAAAAAAAAAAB4011249249249249400AAAAAAAAAAAAB400638E38E38E38E4003333333333333016301694031745D1745D174401222222222222240081181181181184002FD2FD2FD2FD340001010101010100163016A4022E8BA2E8BA2E940100000000000004006A56A56A56A5740024924924924923FFF49F49F49F49F0163016B401B26C9B26C9B27400CF3CF3CF3CF3D40057B864407292D4001AD1AD1AD1AD23FFE8A546F61E8A50163016C4015D1745D1745D1400AAAAAAAAAAAAB400483483483483540012492492492493FFDDDDDDDDDDDDE"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x0301017A010179050401693FB00000000000003FD40000000000003FE20000000000003FEA0000000000003FF1000000000000016A3FC00000000000003FD80000000000003FE40000000000003FEC0000000000003FF2000000000000016B3FC80000000000003FDC0000000000003FE60000000000003FEE0000000000003FF3000000000000016C3FD00000000000003FE00000000000003FE80000000000003FF00000000000003FF4000000000000"},"result":{"expect":"0x03020178017A010179050C0161016940400000000000004026666666666666401C71C71C71C71C4014EC4EC4EC4EC540109090909090910161016A40380000000000004025555555555555401BBBBBBBBBBBBC401492492492492540105B05B05B05B00161016B40355555555555554024924924924925401B26C9B26C9B27401444444444444440102B1DA46102B20161016C40340000000000004024000000000000401AAAAAAAAAAAAB40140000000000004010000000000000016201694032AAAAAAAAAAAB4015F15F15F15F16400E38E38E38E38E400811811811811840045454545454540162016A40255555555555554013CF3CF3CF3CF4400CCCCCCCCCCCCD40075D75D75D75D74003E93E93E93E940162016B40200000000000004012492492492492400BA2E8BA2E8BA34006C16C16C16C174003896E7BF538970162016C401AAAAAAAAAAAAB4011249249249249400AAAAAAAAAAAAB400638E38E38E38E4003333333333333016301694031745D1745D174401222222222222240081181181181184002FD2FD2FD2FD340001010101010100163016A4022E8BA2E8BA2E940100000000000004006A56A56A56A5740024924924924923FFF49F49F49F49F0163016B401B26C9B26C9B27400CF3CF3CF3CF3D40057B864407292D4001AD1AD1AD1AD23FFE8A546F61E8A50163016C4015D1745D1745D1400AAAAAAAAAAAAB400483483483483540012492492492493FFDDDDDDDDDDDDE"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x03010178010179050301613FB00000000000003FC00000000000003FC80000000000003FD00000000000003FD400000000000001623FD80000000000003FDC0000000000003FE00000000000003FE20000000000003FE400000000000001633FE60000000000003FE80000000000003FEA0000000000003FEC0000000000003FEE000000000000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x03020178017A010179050C0161016940400000000000004026666666666666401C71C71C71C71C4014EC4EC4EC4EC540109090909090910161016A40380000000000004025555555555555401BBBBBBBBBBBBC401492492492492540105B05B05B05B00161016B40355555555555554024924924924925401B26C9B26C9B27401444444444444440102B1DA46102B20161016C40340000000000004024000000000000401AAAAAAAAAAAAB40140000000000004010000000000000016201694032AAAAAAAAAAAB4015F15F15F15F16400E38E38E38E38E400811811811811840045454545454540162016A40255555555555554013CF3CF3CF3CF4400CCCCCCCCCCCCD40075D75D75D75D74003E93E93E93E940162016B40200000000000004012492492492492400BA2E8BA2E8BA34006C16C16C16C174003896E7BF538970162016C401AAAAAAAAAAAAB4011249249249249400AAAAAAAAAAAAB400638E38E38E38E4003333333333333016301694031745D1745D174401222222222222240081181181181184002FD2FD2FD2FD340001010101010100163016A4022E8BA2E8BA2E940100000000000004006A56A56A56A5740024924924924923FFF49F49F49F49F0163016B401B26C9B26C9B27400CF3CF3CF3CF3D40057B864407292D4001AD1AD1AD1AD23FFE8A546F61E8A50163016C4015D1745D1745D1400AAAAAAAAAAAAB400483483483483540012492492492493FFDDDDDDDDDDDDE"}}
-{"expression":"join(a,b,f(a,b)((a+b)/(a*b)))","inputs":{"a":"0x0701010178010179050301613D8000003E0000003E4000003E8000003EA0000001623EC000003EE000003F0000003F1000003F20000001633F3000003F4000003F5000003F6000003F700000","b":"0x070101017A010179050401693D8000003EA000003F1000003F5000003F880000016A3E0000003EC000003F2000003F6000003F900000016B3E4000003EE000003F3000003F7000003F980000016C3E8000003F0000003F4000003F8000003FA00000"},"result":{"expect":"0x0701020178017A010179050C01610169420000004133333340E38E3940A76276408484850161016A41C00000412AAAAB40DDDDDE40A492494082D82E0161016B41AAAAAB4124924940D9364E40A22222408158ED0161016C41A000004120000040D5555540A0000040800000016201694195555540AF8AF94071C71C40408C094022A2A30162016A412AAAAB409E79E840666666403AEBAF401F49F50162016B4100000040924925405D174640360B61401C4B740162016C40D5555540892492405555554031C71C4019999A01630169418BA2E94091111140408C094017E97F400080810163016A411745D14080000040352B53401249253FFA4FA50163016B40D9364E40679E7A402BDC32400D68D73FF452A30163016C40AE8BA34055555540241A42400924923FEEEEEF"}}
-{"expression":"reduce(a*b,sum)","inputs":{"a":"0x0201017803400000000000000040080000000000004014000000000000","b":"0x0201017803401C0000000000004026000000000000402A000000000000"},"result":{"expect":"0x0200405C000000000000"}}
-{"expression":"reduce(a*b,sum)","inputs":{"a":"0x060101017803400000004040000040A00000","b":"0x0201017803401C0000000000004026000000000000402A000000000000"},"result":{"expect":"0x0200405C000000000000"}}
-{"expression":"reduce(a*b,sum)","inputs":{"a":"0x0201017803400000000000000040080000000000004014000000000000","b":"0x06010101780340E000004130000041500000"},"result":{"expect":"0x0200405C000000000000"}}
-{"expression":"reduce(a*b,sum)","inputs":{"a":"0x060101017803400000004040000040A00000","b":"0x06010101780340E000004130000041500000"},"result":{"expect":"0x0200405C000000000000"}}
-{"expression":"reduce(a*b,sum,x)","inputs":{"a":"0x02010178023FF00000000000004000000000000000","b":"0x020201780201790340080000000000004014000000000000401C0000000000004026000000000000402A0000000000004031000000000000"},"result":{"expect":"0x02010179034039000000000000403F0000000000004044800000000000"}}
-{"expression":"reduce(a*b,sum,x)","inputs":{"a":"0x0601010178023F80000040000000","b":"0x020201780201790340080000000000004014000000000000401C0000000000004026000000000000402A0000000000004031000000000000"},"result":{"expect":"0x02010179034039000000000000403F0000000000004044800000000000"}}
-{"expression":"reduce(a*b,sum,x)","inputs":{"a":"0x02010178023FF00000000000004000000000000000","b":"0x0601020178020179034040000040A0000040E00000413000004150000041880000"},"result":{"expect":"0x02010179034039000000000000403F0000000000004044800000000000"}}
-{"expression":"reduce(a*b,sum,x)","inputs":{"a":"0x0601010178023F80000040000000","b":"0x0601020178020179034040000040A0000040E00000413000004150000041880000"},"result":{"expect":"0x06010101790341C8000041F8000042240000"}}
-{"expression":"reduce(a*b,sum,y)","inputs":{"a":"0x02010179033FF000000000000040000000000000004008000000000000","b":"0x020201780201790340080000000000004014000000000000401C0000000000004026000000000000402A0000000000004031000000000000"},"result":{"expect":"0x020101780240410000000000004056000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02004024000000000000","b":"0x02004034000000000000"},"result":{"expect":"0x020101780240240000000000004034000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02010178014024000000000000","b":"0x02004034000000000000"},"result":{"expect":"0x020101780240240000000000004034000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02004024000000000000","b":"0x02010178014034000000000000"},"result":{"expect":"0x020101780240240000000000004034000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000","b":"0x020101780240100000000000004014000000000000"},"result":{"expect":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"concat(a,b,y)","inputs":{"a":"0x02020178020179023FF0000000000000400000000000000040080000000000004010000000000000","b":"0x020101790240140000000000004018000000000000"},"result":{"expect":"0x02020178020179043FF00000000000004000000000000000401400000000000040180000000000004008000000000000401000000000000040140000000000004018000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02020178020179023FF0000000000000400000000000000040080000000000004010000000000000","b":"0x020101780240140000000000004018000000000000"},"result":{"expect":"0x02020178040179023FF00000000000004000000000000000400800000000000040100000000000004014000000000000401400000000000040180000000000004018000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x0201017A033FF000000000000040000000000000004008000000000000","b":"0x020101790240100000000000004014000000000000"},"result":{"expect":"0x0203017802017902017A033FF0000000000000400000000000000040080000000000003FF000000000000040000000000000004008000000000000401000000000000040100000000000004010000000000000401400000000000040140000000000004014000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02010179023FF00000000000004000000000000000","b":"0x020101790240100000000000004014000000000000"},"result":{"expect":"0x02020178020179023FF0000000000000400000000000000040100000000000004014000000000000"}}
-{"expression":"concat(concat(a,b,x),concat(c,d,x),y)","inputs":{"a":"0x02003FF0000000000000","b":"0x02004000000000000000","c":"0x02004008000000000000","d":"0x02004010000000000000"},"result":{"expect":"0x02020178020179023FF0000000000000400800000000000040000000000000004010000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x06010101780141200000","b":"0x02004034000000000000"},"result":{"expect":"0x0601010178024120000041A00000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02004024000000000000","b":"0x06010101780141A00000"},"result":{"expect":"0x0601010178024120000041A00000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x0601010178033F8000004000000040400000","b":"0x020101780240100000000000004014000000000000"},"result":{"expect":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x02010178033FF000000000000040000000000000004008000000000000","b":"0x0601010178024080000040A00000"},"result":{"expect":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"concat(a,b,x)","inputs":{"a":"0x0601010178033F8000004000000040400000","b":"0x0601010178024080000040A00000"},"result":{"expect":"0x0601010178053F80000040000000404000004080000040A00000"}}
-{"expression":"rename(a,x,y)","inputs":{"a":"0x02010178053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"},"result":{"expect":"0x02010179053FF00000000000004000000000000000400800000000000040100000000000004014000000000000"}}
-{"expression":"rename(a,y,x)","inputs":{"a":"0x0202017905017A053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"},"result":{"expect":"0x0202017805017A053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"}}
-{"expression":"rename(a,z,x)","inputs":{"a":"0x0202017905017A053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"},"result":{"expect":"0x02020178050179053FF000000000000040180000000000004026000000000000403000000000000040350000000000004000000000000000401C00000000000040280000000000004031000000000000403600000000000040080000000000004020000000000000402A0000000000004032000000000000403700000000000040100000000000004022000000000000402C0000000000004033000000000000403800000000000040140000000000004024000000000000402E00000000000040340000000000004039000000000000"}}
-{"expression":"rename(a,x,z)","inputs":{"a":"0x02020178050179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"},"result":{"expect":"0x0202017905017A053FF000000000000040180000000000004026000000000000403000000000000040350000000000004000000000000000401C00000000000040280000000000004031000000000000403600000000000040080000000000004020000000000000402A0000000000004032000000000000403700000000000040100000000000004022000000000000402C0000000000004033000000000000403800000000000040140000000000004024000000000000402E00000000000040340000000000004039000000000000"}}
-{"expression":"rename(a,y,z)","inputs":{"a":"0x02020178050179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"},"result":{"expect":"0x0202017805017A053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"}}
-{"expression":"rename(a,y,z)","inputs":{"a":"0x0601020178050179053F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C80000"},"result":{"expect":"0x060102017805017A053F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A0000041A8000041B0000041B8000041C0000041C80000"}}
-{"expression":"rename(a,(x,y),(y,x))","inputs":{"a":"0x02020178050179053FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E0000000000004030000000000000403100000000000040320000000000004033000000000000403400000000000040350000000000004036000000000000403700000000000040380000000000004039000000000000"},"result":{"expect":"0x02020178050179053FF000000000000040180000000000004026000000000000403000000000000040350000000000004000000000000000401C00000000000040280000000000004031000000000000403600000000000040080000000000004020000000000000402A0000000000004032000000000000403700000000000040100000000000004022000000000000402C0000000000004033000000000000403800000000000040140000000000004024000000000000402E00000000000040340000000000004039000000000000"}}
-{"expression":"tensor(x[10])(x+1)","inputs":{},"result":{"expect":"0x020101780A3FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C000000000000402000000000000040220000000000004024000000000000"}}
-{"expression":"tensor<float>(x[5],y[4])(x*4+(y+1))","inputs":{},"result":{"expect":"0x0601020178050179043F80000040000000404000004080000040A0000040C0000040E0000041000000411000004120000041300000414000004150000041600000417000004180000041880000419000004198000041A00000"}}
-{"expression":"tensor(x[5],y[4])(x*4+(y+1))","inputs":{},"result":{"expect":"0x02020178050179043FF000000000000040000000000000004008000000000000401000000000000040140000000000004018000000000000401C00000000000040200000000000004022000000000000402400000000000040260000000000004028000000000000402A000000000000402C000000000000402E00000000000040300000000000004031000000000000403200000000000040330000000000004034000000000000"}}
-{"expression":"tensor(x[5],y[4])(x==y)","inputs":{},"result":{"expect":"0x02020178050179043FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF000000000000000000000000000000000000000000000000000000000000000000000000000003FF00000000000000000000000000000000000000000000000000000000000000000000000000000"}}
-{"num_tests":1987}
diff --git a/eval/src/tests/eval/engine_or_factory/CMakeLists.txt b/eval/src/tests/eval/engine_or_factory/CMakeLists.txt
deleted file mode 100644
index f0bd0f63251..00000000000
--- a/eval/src/tests/eval/engine_or_factory/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_engine_or_factory_test_app TEST
- SOURCES
- engine_or_factory_test.cpp
- DEPENDS
- vespaeval
- GTest::GTest
-)
-vespa_add_test(NAME eval_engine_or_factory_test_app COMMAND eval_engine_or_factory_test_app)
-vespa_add_executable(eval_engine_or_factory_override_test_app TEST
- SOURCES
- engine_or_factory_override_test.cpp
- DEPENDS
- vespaeval
- GTest::GTest
-)
-vespa_add_test(NAME eval_engine_or_factory_override_test_app COMMAND eval_engine_or_factory_override_test_app)
diff --git a/eval/src/tests/eval/engine_or_factory/engine_or_factory_override_test.cpp b/eval/src/tests/eval/engine_or_factory/engine_or_factory_override_test.cpp
deleted file mode 100644
index 3aa804b0722..00000000000
--- a/eval/src/tests/eval/engine_or_factory/engine_or_factory_override_test.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/eval/fast_value.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/vespalib/gtest/gtest.h>
-
-using namespace vespalib::eval;
-using namespace vespalib::tensor;
-
-TEST(EngineOrFactoryOverrideTest, set_can_override_get_result) {
- EngineOrFactory::set(DefaultTensorEngine::ref());
- EXPECT_EQ(EngineOrFactory::get().to_string(), "DefaultTensorEngine");
-}
-
-TEST(EngineOrFactoryOverrideTest, set_with_same_value_is_allowed) {
- EngineOrFactory::set(DefaultTensorEngine::ref());
-}
-
-TEST(EngineOrFactoryOverrideTest, set_with_another_value_is_not_allowed) {
- EXPECT_THROW(EngineOrFactory::set(FastValueBuilderFactory::get()), vespalib::IllegalStateException);
-}
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/eval/engine_or_factory/engine_or_factory_test.cpp b/eval/src/tests/eval/engine_or_factory/engine_or_factory_test.cpp
deleted file mode 100644
index 3acfc40f5b5..00000000000
--- a/eval/src/tests/eval/engine_or_factory/engine_or_factory_test.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/eval/fast_value.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/vespalib/gtest/gtest.h>
-
-using namespace vespalib::eval;
-using namespace vespalib::tensor;
-
-TEST(EngineOrFactoryTest, default_is_fast_value_builder_factory) {
- EXPECT_EQ(EngineOrFactory::get().to_string(), "FastValueBuilderFactory");
-}
-
-TEST(EngineOrFactoryTest, set_with_same_value_is_allowed) {
- EngineOrFactory::set(FastValueBuilderFactory::get());
-}
-
-TEST(EngineOrFactoryTest, set_with_another_value_is_not_allowed) {
- EXPECT_THROW(EngineOrFactory::set(DefaultTensorEngine::ref()), vespalib::IllegalStateException);
-}
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/eval/fast_sparse_map/fast_sparse_map_test.cpp b/eval/src/tests/eval/fast_sparse_map/fast_sparse_map_test.cpp
index 3d98ec67aa8..18517b34f57 100644
--- a/eval/src/tests/eval/fast_sparse_map/fast_sparse_map_test.cpp
+++ b/eval/src/tests/eval/fast_sparse_map/fast_sparse_map_test.cpp
@@ -117,7 +117,7 @@ TEST(FastSparseMapTest, fast_sparse_map_works_with_no_labels) {
}
TEST(FastSparseMapTest, size_of_internal_types) {
- fprintf(stderr, "fast sparse map hash node size: %zu\n", sizeof(hash_node<FastSparseMap::MapType::value_type>));
+ EXPECT_EQ(sizeof(hash_node<FastSparseMap::MapType::value_type>), 16);
}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/eval/function/function_test.cpp b/eval/src/tests/eval/function/function_test.cpp
index 598d9c251a6..3dbc2e1aed2 100644
--- a/eval/src/tests/eval/function/function_test.cpp
+++ b/eval/src/tests/eval/function/function_test.cpp
@@ -418,6 +418,7 @@ struct MyTraverser : public NodeTraverser {
std::vector<std::pair<bool, const nodes::Node &> > history;
explicit MyTraverser(size_t open_true_cnt_in)
: open_true_cnt(open_true_cnt_in), history() {}
+ ~MyTraverser() override;
virtual bool open(const nodes::Node &node) override {
history.emplace_back(true, node);
if (open_true_cnt == 0) {
@@ -448,6 +449,8 @@ struct MyTraverser : public NodeTraverser {
}
};
+MyTraverser::~MyTraverser() = default;
+
size_t verify_traversal(size_t open_true_cnt, const vespalib::string &expression) {
auto function = Function::parse(expression);
if (!EXPECT_TRUE(!function->has_error())) {
diff --git a/eval/src/tests/eval/function_speed/function_speed_test.cpp b/eval/src/tests/eval/function_speed/function_speed_test.cpp
index 1295f482f76..b4d013fe807 100644
--- a/eval/src/tests/eval/function_speed/function_speed_test.cpp
+++ b/eval/src/tests/eval/function_speed/function_speed_test.cpp
@@ -4,13 +4,12 @@
#include <vespa/eval/eval/llvm/compiled_function.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/vespalib/util/benchmark_timer.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/fast_value.h>
using namespace vespalib::eval;
using vespalib::BenchmarkTimer;
-using vespalib::tensor::DefaultTensorEngine;
double budget = 0.25;
@@ -47,8 +46,9 @@ struct Fixture {
CompiledFunction lazy;
Fixture(const vespalib::string &expr)
: function(Function::parse(expr)),
- interpreted_simple(SimpleTensorEngine::ref(), *function, NodeTypes()),
- interpreted(DefaultTensorEngine::ref(), *function,
+ interpreted_simple(SimpleValueBuilderFactory::get(), *function,
+ NodeTypes(*function, std::vector<ValueType>(function->num_params(), ValueType::double_type()))),
+ interpreted(FastValueBuilderFactory::get(), *function,
NodeTypes(*function, std::vector<ValueType>(function->num_params(), ValueType::double_type()))),
separate(*function, PassParams::SEPARATE),
array(*function, PassParams::ARRAY),
diff --git a/eval/src/tests/eval/gbdt/gbdt_test.cpp b/eval/src/tests/eval/gbdt/gbdt_test.cpp
index e12ea5b9cf3..d7c6b351621 100644
--- a/eval/src/tests/eval/gbdt/gbdt_test.cpp
+++ b/eval/src/tests/eval/gbdt/gbdt_test.cpp
@@ -7,7 +7,7 @@
#include <vespa/eval/eval/llvm/deinline_forest.h>
#include <vespa/eval/eval/llvm/compiled_function.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/vespalib/util/stringfmt.h>
#include "model.cpp"
@@ -26,7 +26,8 @@ bool is_little_endian() {
}
double eval_double(const Function &function, const std::vector<double> &params) {
- InterpretedFunction ifun(SimpleTensorEngine::ref(), function, NodeTypes());
+ NodeTypes node_types(function, std::vector<ValueType>(params.size(), ValueType::double_type()));
+ InterpretedFunction ifun(SimpleValueBuilderFactory::get(), function, node_types);
InterpretedFunction::Context ctx(ifun);
SimpleParams fun_params(params);
return ifun.eval(ctx, fun_params).as_double();
diff --git a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp
index ee595606c14..871a564bfa4 100644
--- a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp
+++ b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp
@@ -1,13 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/function.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/test/eval_spec.h>
#include <vespa/eval/eval/basic_nodes.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/test/insertion_operators.h>
@@ -15,7 +15,6 @@
using namespace vespalib::eval;
using vespalib::Stash;
-using vespalib::tensor::DefaultTensorEngine;
//-----------------------------------------------------------------------------
@@ -53,9 +52,8 @@ struct MyEvalTest : test::EvalSpec::EvalTest {
if (is_supported && !has_issues) {
vespalib::string desc = as_string(param_names, param_values, expression);
SimpleParams params(param_values);
- verify_result(SimpleTensorEngine::ref(), *function, false, "[untyped simple] "+desc, params, expected_result);
- verify_result(DefaultTensorEngine::ref(), *function, false, "[untyped prod] "+desc, params, expected_result);
- verify_result(DefaultTensorEngine::ref(), *function, true, "[typed prod] "+desc, params, expected_result);
+ verify_result(SimpleValueBuilderFactory::get(), *function, "[simple] "+desc, params, expected_result);
+ verify_result(FastValueBuilderFactory::get(), *function, "[prod] "+desc, params, expected_result);
}
}
@@ -72,24 +70,21 @@ struct MyEvalTest : test::EvalSpec::EvalTest {
}
}
- void verify_result(EngineOrFactory engine,
+ void verify_result(const ValueBuilderFactory &factory,
const Function &function,
- bool typed,
const vespalib::string &description,
const SimpleParams &params,
double expected_result)
{
- NodeTypes node_types = typed
- ? NodeTypes(function, std::vector<ValueType>(params.params.size(), ValueType::double_type()))
- : NodeTypes();
- InterpretedFunction ifun(engine, function, node_types);
+ auto node_types = NodeTypes(function, std::vector<ValueType>(params.params.size(), ValueType::double_type()));
+ InterpretedFunction ifun(factory, function, node_types);
InterpretedFunction::Context ictx(ifun);
const Value &result_value = ifun.eval(ictx, params);
report_result(result_value.is_double(), result_value.as_double(), expected_result, description);
}
};
-TEST_FF("require that compiled evaluation passes all conformance tests", MyEvalTest(), test::EvalSpec()) {
+TEST_FF("require that interpreted evaluation passes all conformance tests", MyEvalTest(), test::EvalSpec()) {
f1.print_fail = true;
f2.add_all_cases();
f2.each_case(f1);
@@ -109,7 +104,8 @@ TEST("require that invalid function is tagged with error") {
size_t count_ifs(const vespalib::string &expr, std::initializer_list<double> params_in) {
auto fun = Function::parse(expr);
- InterpretedFunction ifun(SimpleTensorEngine::ref(), *fun, NodeTypes());
+ auto node_types = NodeTypes(*fun, std::vector<ValueType>(params_in.size(), ValueType::double_type()));
+ InterpretedFunction ifun(SimpleValueBuilderFactory::get(), *fun, node_types);
InterpretedFunction::Context ctx(ifun);
SimpleParams params(params_in);
ifun.eval(ctx, params);
@@ -137,7 +133,8 @@ TEST("require that function pointers can be passed as instruction parameters") {
TEST("require that basic addition works") {
auto function = Function::parse("a+10");
- InterpretedFunction interpreted(SimpleTensorEngine::ref(), *function, NodeTypes());
+ auto node_types = NodeTypes(*function, {ValueType::double_type()});
+ InterpretedFunction interpreted(SimpleValueBuilderFactory::get(), *function, node_types);
InterpretedFunction::Context ctx(interpreted);
SimpleParams params_20({20});
SimpleParams params_40({40});
diff --git a/eval/src/tests/eval/multiply_add/multiply_add_test.cpp b/eval/src/tests/eval/multiply_add/multiply_add_test.cpp
index 35cab0a6030..6cee82f9de2 100644
--- a/eval/src/tests/eval/multiply_add/multiply_add_test.cpp
+++ b/eval/src/tests/eval/multiply_add/multiply_add_test.cpp
@@ -1,15 +1,13 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/function.h>
#include <vespa/eval/eval/llvm/compiled_function.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace vespalib::eval;
-using Engine = vespalib::tensor::DefaultTensorEngine;
-
double gcc_fun(double a, double b) {
return (a * 3) + b;
}
@@ -18,7 +16,7 @@ TEST(MultiplyAddTest, multiply_add_gives_same_result) {
auto fun = Function::parse("a*3+b");
CompiledFunction cfun(*fun, PassParams::ARRAY);
NodeTypes node_types = NodeTypes(*fun, {ValueType::double_type(), ValueType::double_type()});
- InterpretedFunction ifun(Engine::ref(), *fun, node_types);
+ InterpretedFunction ifun(FastValueBuilderFactory::get(), *fun, node_types);
auto llvm_fun = cfun.get_function();
//-------------------------------------------------------------------------
double a = -1.0/3.0;
diff --git a/eval/src/tests/eval/reference_evaluation/CMakeLists.txt b/eval/src/tests/eval/reference_evaluation/CMakeLists.txt
new file mode 100644
index 00000000000..0ca6987d689
--- /dev/null
+++ b/eval/src/tests/eval/reference_evaluation/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+vespa_add_executable(eval_reference_evaluation_test_app TEST
+ SOURCES
+ reference_evaluation_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_reference_evaluation_test_app COMMAND eval_reference_evaluation_test_app)
diff --git a/eval/src/tests/eval/reference_evaluation/reference_evaluation_test.cpp b/eval/src/tests/eval/reference_evaluation/reference_evaluation_test.cpp
new file mode 100644
index 00000000000..345f04053ac
--- /dev/null
+++ b/eval/src/tests/eval/reference_evaluation/reference_evaluation_test.cpp
@@ -0,0 +1,209 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/test/reference_evaluation.h>
+#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/test/eval_spec.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+
+//-----------------------------------------------------------------------------
+
+TensorSpec ref_eval(const Function &fun, const std::vector<TensorSpec> &params) {
+ return ReferenceEvaluation::eval(fun, params);
+}
+
+TensorSpec ref_eval(std::shared_ptr<const Function> fun, const std::vector<TensorSpec> &params) {
+ return ref_eval(*fun, params);
+}
+
+TensorSpec ref_eval(const vespalib::string &expr, const std::vector<TensorSpec> &params) {
+ return ref_eval(*Function::parse(expr), params);
+}
+
+TensorSpec make_val(const vespalib::string &expr) {
+ return ref_eval(*Function::parse(expr), {});
+}
+
+//-----------------------------------------------------------------------------
+
+struct MyEvalTest : EvalSpec::EvalTest {
+ size_t pass_cnt = 0;
+ size_t fail_cnt = 0;
+ bool print_pass = false;
+ bool print_fail = false;
+ void next_expression(const std::vector<vespalib::string> &,
+ const vespalib::string &) override {}
+ void handle_case(const std::vector<vespalib::string> &param_names,
+ const std::vector<double> &param_values,
+ const vespalib::string &expression,
+ double expected_result) override
+ {
+ auto function = Function::parse(param_names, expression);
+ ASSERT_FALSE(function->has_error());
+ std::vector<TensorSpec> params;
+ for (double param: param_values) {
+ params.push_back(TensorSpec("double").add({}, param));
+ }
+ auto eval_result = ref_eval(function, params);
+ ASSERT_EQ(eval_result.type(), "double");
+ double result = eval_result.as_double();
+ if (is_same(expected_result, result)) {
+ print_pass && fprintf(stderr, "verifying: %s -> %g ... PASS\n",
+ as_string(param_names, param_values, expression).c_str(),
+ expected_result);
+ ++pass_cnt;
+ } else {
+ print_fail && fprintf(stderr, "verifying: %s -> %g ... FAIL: got %g\n",
+ as_string(param_names, param_values, expression).c_str(),
+ expected_result, result);
+ ++fail_cnt;
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceEvaluationTest, reference_evaluation_passes_all_eval_spec_tests) {
+ MyEvalTest test;
+ EvalSpec spec;
+ test.print_fail = true;
+ spec.add_all_cases();
+ spec.each_case(test);
+ EXPECT_GT(test.pass_cnt, 1000);
+ EXPECT_EQ(test.fail_cnt, 0);
+}
+
+//-----------------------------------------------------------------------------
+
+// 'make_val' will be used to generate tensor specs for inputs and
+// expected outputs for other tests. In the production evaluation
+// pipeline this kind of tensor create will be converted to a constant
+// value when converting the Function to a TensorFunction. With the
+// reference evaluation the Function is evaluated directly with no
+// constant folding.
+
+TEST(ReferenceEvaluationTest, constant_create_expression_works) {
+ auto expect = TensorSpec("tensor(x{},y[2])")
+ .add({{"x", "a"}, {"y", 0}}, 1.0)
+ .add({{"x", "a"}, {"y", 1}}, 2.0);
+ auto result = make_val("tensor(x{},y[2]):{a:[1,2]}");
+ EXPECT_EQ(result, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceEvaluationTest, parameter_expression_works) {
+ auto a = make_val("tensor(x[2]):[1,2]");
+ auto b = make_val("tensor(x[2]):[3,4]");
+ auto fun_a = Function::parse({"a", "b"}, "a");
+ auto fun_b = Function::parse({"a", "b"}, "b");
+ EXPECT_EQ(ref_eval(fun_a, {a, b}), a);
+ EXPECT_EQ(ref_eval(fun_b, {a, b}), b);
+}
+
+TEST(ReferenceEvaluationTest, parameter_expression_will_pad_with_zero) {
+ auto a = TensorSpec("tensor(x[3])")
+ .add({{"x", 1}}, 5.0);
+ auto expect = make_val("tensor(x[3]):[0,5,0]");
+ EXPECT_EQ(ref_eval("a", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, reduce_expression_works) {
+ auto a = make_val("tensor(x[2],y[2]):[[1,2],[3,4]]");
+ auto expect = make_val("tensor(x[2]):[3,7]");
+ EXPECT_EQ(ref_eval("reduce(a,sum,y)", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, reduce_can_expand) {
+ auto a = make_val("tensor(x{},y[2]):{}");
+ auto expect = make_val("tensor(y[2]):[0,0]");
+ EXPECT_EQ(ref_eval("reduce(a,sum,x)", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, map_expression_works) {
+ auto a = make_val("tensor(x[2]):[1,10]");
+ auto expect = make_val("tensor(x[2]):[5,23]");
+ EXPECT_EQ(ref_eval("map(a,f(x)(x*2+3))", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, join_expression_works) {
+ auto a = make_val("tensor(x[2]):[1,2]");
+ auto b = make_val("tensor(y[2]):[3,4]");
+ auto expect = make_val("tensor(x[2],y[2]):[[4,5],[5,6]]");
+ EXPECT_EQ(ref_eval("join(a,b,f(x,y)(x+y))", {a, b}), expect);
+}
+
+TEST(ReferenceEvaluationTest, merge_expression_works) {
+ auto a = make_val("tensor(x{}):{a:1,b:2,c:3}");
+ auto b = make_val("tensor(x{}):{c:3,d:4}");
+ auto expect = make_val("tensor(x{}):{a:1,b:2,c:6,d:4}");
+ EXPECT_EQ(ref_eval("merge(a,b,f(x,y)(x+y))", {a, b}), expect);
+}
+
+TEST(ReferenceEvaluationTest, concat_expression_works) {
+ auto a = make_val("tensor(x[2]):[1,2]");
+ auto b = make_val("tensor(x[2]):[3,4]");
+ auto expect = make_val("tensor(x[4]):[1,2,3,4]");
+ EXPECT_EQ(ref_eval("concat(a,b,x)", {a, b}), expect);
+}
+
+TEST(ReferenceEvaluationTest, rename_expression_works) {
+ auto a = make_val("tensor(x[2]):[1,2]");
+ auto expect = make_val("tensor(y[2]):[1,2]");
+ EXPECT_EQ(ref_eval("rename(a,x,y)", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, create_expression_works) {
+ auto a = make_val("5");
+ auto expect = make_val("tensor(x[3]):[5,10,15]");
+ EXPECT_EQ(ref_eval("tensor(x[3]):[a,2*a,3*a]", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, tensor_create_will_pad_with_zero) {
+ auto a = make_val("5");
+ auto expect = make_val("tensor(x[3]):[0,5,0]");
+ EXPECT_EQ(ref_eval("tensor(x[3]):{{x:1}:a}", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, lambda_expression_works) {
+ auto a = make_val("5");
+ auto expect = make_val("tensor(x[3]):[5,10,15]");
+ EXPECT_EQ(ref_eval("tensor(x[3])((x+1)*a)", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, peek_expression_works) {
+ auto a = make_val("tensor(x{},y[2]):{a:[3,7]}");
+ auto b = make_val("1");
+ auto expect = make_val("7");
+ EXPECT_EQ(ref_eval("a{x:a,y:(b)}", {a, b}), expect);
+}
+
+TEST(ReferenceEvaluationTest, verbatim_peek_of_dense_dimension_works) {
+ auto a = make_val("tensor(x[4]):[1,2,3,4]");
+ auto expect = make_val("3");
+ EXPECT_EQ(ref_eval("a{x:2}", {a}), expect);
+}
+
+TEST(ReferenceEvaluationTest, out_of_bounds_peek_works) {
+ auto a = make_val("tensor(x[4]):[1,2,3,4]");
+ auto b = make_val("4");
+ auto expect = make_val("0");
+ EXPECT_EQ(ref_eval("a{x:(b)}", {a, b}), expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceEvaluationTest, compound_expression_works) {
+ auto a = make_val("10");
+ auto b = make_val("20");
+ auto expect = make_val("20");
+ EXPECT_EQ(ref_eval("reduce(concat(a,b,x)+5,avg,x)", {a, b}), expect);
+}
+
+//-----------------------------------------------------------------------------
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/eval/reference_operations/CMakeLists.txt b/eval/src/tests/eval/reference_operations/CMakeLists.txt
new file mode 100644
index 00000000000..46838f6fc82
--- /dev/null
+++ b/eval/src/tests/eval/reference_operations/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+vespa_add_executable(eval_reference_operations_test_app TEST
+ SOURCES
+ reference_operations_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_reference_operations_test_app COMMAND eval_reference_operations_test_app)
diff --git a/eval/src/tests/eval/reference_operations/reference_operations_test.cpp b/eval/src/tests/eval/reference_operations/reference_operations_test.cpp
new file mode 100644
index 00000000000..0495923018e
--- /dev/null
+++ b/eval/src/tests/eval/reference_operations/reference_operations_test.cpp
@@ -0,0 +1,530 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/test/reference_operations.h>
+#include <vespa/eval/eval/test/tensor_model.hpp>
+#include <vespa/vespalib/gtest/gtest.h>
+#include <iostream>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+
+TensorSpec dense_2d_some_cells(bool square) {
+ return TensorSpec("tensor(a[3],d[5])")
+ .add({{"a", 1}, {"d", 2}}, square ? 9.0 : 3.0)
+ .add({{"a", 2}, {"d", 4}}, square ? 16.0 : 4.0)
+ .add({{"a", 1}, {"d", 0}}, square ? 25.0 : 5.0);
+}
+
+TensorSpec sparse_2d_some_cells(bool square) {
+ return TensorSpec("tensor(c{},e{})")
+ .add({{"c", "foo"}, {"e", "foo"}}, square ? 1.0 : 1.0)
+ .add({{"c", "foo"}, {"e", "bar"}}, square ? 4.0 : 2.0)
+ .add({{"c", "bar"}, {"e", "bar"}}, square ? 9.0 : 3.0)
+ .add({{"c", "qux"}, {"e", "foo"}}, square ? 16.0 : 4.0)
+ .add({{"c", "qux"}, {"e", "qux"}}, square ? 25.0 : 5.0);
+}
+
+TensorSpec mixed_5d_some_cells(bool square) {
+ return TensorSpec("tensor(a[3],b[1],c{},d[5],e{})")
+ .add({{"a", 1}, {"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "bar"}}, square ? 4.0 : 2.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "bar"}, {"d", 3}, {"e", "bar"}}, square ? 9.0 : 3.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 4}, {"e", "foo"}}, square ? 16.0 : 4.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "bar"}, {"d", 0}, {"e", "qux"}}, square ? 25.0 : 5.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "qux"}, {"d", 1}, {"e", "foo"}}, square ? 36.0 : 6.0);
+}
+
+TensorSpec dense_1d_all_two() {
+ return TensorSpec("tensor(a[3])")
+ .add({{"a", 0}}, 2.0)
+ .add({{"a", 1}}, 2.0)
+ .add({{"a", 2}}, 2.0);
+}
+
+TensorSpec sparse_1d_all_two() {
+ return TensorSpec("tensor(c{})")
+ .add({{"c", "foo"}}, 2.0)
+ .add({{"c", "bar"}}, 2.0)
+ .add({{"c", "qux"}}, 2.0);
+}
+
+//-----------------------------------------------------------------------------
+
+
+TEST(ReferenceConcatTest, concat_numbers) {
+ auto a = TensorSpec("double").add({}, 7.0);
+ auto b = TensorSpec("double").add({}, 4.0);
+ auto output = ReferenceOperations::concat(a, b, "x");
+ auto expect = TensorSpec("tensor(x[2])")
+ .add({{"x", 0}}, 7.0)
+ .add({{"x", 1}}, 4.0);
+ EXPECT_EQ(output, expect);
+}
+
+TEST(ReferenceConcatTest, concat_vector_and_number) {
+ auto a = TensorSpec("tensor(a[3])")
+ .add({{"a", 0}}, 1.0)
+ .add({{"a", 1}}, 2.0)
+ .add({{"a", 2}}, 3.0);
+ auto b = TensorSpec("double").add({}, 4.0);
+ auto output = ReferenceOperations::concat(a, b, "a");
+ auto expect = TensorSpec("tensor(a[4])")
+ .add({{"a", 0}}, 1.0)
+ .add({{"a", 1}}, 2.0)
+ .add({{"a", 2}}, 3.0)
+ .add({{"a", 3}}, 4.0);
+ EXPECT_EQ(output, expect);
+ output = ReferenceOperations::concat(b, a, "a");
+ expect = TensorSpec("tensor(a[4])")
+ .add({{"a", 0}}, 4.0)
+ .add({{"a", 1}}, 1.0)
+ .add({{"a", 2}}, 2.0)
+ .add({{"a", 3}}, 3.0);
+ EXPECT_EQ(output, expect);
+}
+
+TEST(ReferenceConcatTest, concat_mixed_tensors) {
+ auto l = TensorSpec("tensor(a{},b[2])")
+ .add({{"a","bar"},{"b",0}}, 2.0)
+ .add({{"a","bar"},{"b",1}}, 3.0)
+ .add({{"a","foo"},{"b",0}}, 4.0)
+ .add({{"a","foo"},{"b",1}}, 5.0)
+ .add({{"a","qux"},{"b",0}}, 6.0)
+ .add({{"a","qux"},{"b",1}}, 7.0);
+ auto r = TensorSpec("tensor(a{},b[3])")
+ .add({{"a","foo"},{"b",0}}, 10.0)
+ .add({{"a","foo"},{"b",1}}, 11.0)
+ .add({{"a","foo"},{"b",2}}, 12.0)
+ .add({{"a","bar"},{"b",0}}, 13.0)
+ .add({{"a","bar"},{"b",1}}, 14.0)
+ .add({{"a","bar"},{"b",2}}, 15.0);
+ auto output = ReferenceOperations::concat(l, r, "a");
+ EXPECT_EQ(output, TensorSpec("error"));
+ output = ReferenceOperations::concat(l, r, "b");
+ auto expect = TensorSpec("tensor(a{},b[5])")
+ .add({{"a","bar"},{"b",0}}, 2.0)
+ .add({{"a","bar"},{"b",1}}, 3.0)
+ .add({{"a","foo"},{"b",0}}, 4.0)
+ .add({{"a","foo"},{"b",1}}, 5.0)
+ .add({{"a","foo"},{"b",2}}, 10.0)
+ .add({{"a","foo"},{"b",3}}, 11.0)
+ .add({{"a","foo"},{"b",4}}, 12.0)
+ .add({{"a","bar"},{"b",2}}, 13.0)
+ .add({{"a","bar"},{"b",3}}, 14.0)
+ .add({{"a","bar"},{"b",4}}, 15.0);
+ EXPECT_EQ(output, expect);
+ output = ReferenceOperations::concat(l, r, "x");
+ EXPECT_EQ(output, TensorSpec("error"));
+ output = ReferenceOperations::concat(r, r, "x");
+ expect = TensorSpec("tensor(a{},b[3],x[2])")
+ .add({{"a","foo"},{"b",0},{"x",0}}, 10.0)
+ .add({{"a","foo"},{"b",1},{"x",0}}, 11.0)
+ .add({{"a","foo"},{"b",2},{"x",0}}, 12.0)
+ .add({{"a","bar"},{"b",0},{"x",0}}, 13.0)
+ .add({{"a","bar"},{"b",1},{"x",0}}, 14.0)
+ .add({{"a","bar"},{"b",2},{"x",0}}, 15.0)
+ .add({{"a","foo"},{"b",0},{"x",1}}, 10.0)
+ .add({{"a","foo"},{"b",1},{"x",1}}, 11.0)
+ .add({{"a","foo"},{"b",2},{"x",1}}, 12.0)
+ .add({{"a","bar"},{"b",0},{"x",1}}, 13.0)
+ .add({{"a","bar"},{"b",1},{"x",1}}, 14.0)
+ .add({{"a","bar"},{"b",2},{"x",1}}, 15.0);
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceCreateTest, simple_create_works) {
+ auto a = TensorSpec("double").add({}, 1.5);
+ auto b = TensorSpec("tensor(z[2])").add({{"z",0}}, 2.0).add({{"z",1}}, 3.0);
+ auto c = TensorSpec("tensor()").add({{}}, 4.0);
+ ReferenceOperations::CreateSpec spec;
+ spec.emplace(TensorSpec::Address{{"x",1},{"y","foo"}}, 0);
+ spec.emplace(TensorSpec::Address{{"x",0},{"y","bar"}}, 1);
+ spec.emplace(TensorSpec::Address{{"x",1},{"y","bar"}}, 2);
+ auto output = ReferenceOperations::create("tensor(x[2],y{})", spec, {a,b,c});
+ auto expect = TensorSpec("tensor(x[2],y{})")
+ .add({{"x",1},{"y","foo"}}, 1.5)
+ .add({{"x",0},{"y","bar"}}, 5.0)
+ .add({{"x",1},{"y","bar"}}, 4.0);
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceJoinTest, join_numbers) {
+ auto a = TensorSpec("tensor()").add({}, 7.0);
+ auto b = TensorSpec("tensor()").add({}, 4.0);
+ auto output = ReferenceOperations::join(a, b, operation::Sub::f);
+ EXPECT_EQ(output, TensorSpec("double").add({}, 3.0));
+}
+
+TEST(ReferenceJoinTest, join_mixed_tensors) {
+ const auto expect_sq = mixed_5d_some_cells(true);
+ auto a = mixed_5d_some_cells(false);
+ auto b = TensorSpec("double").add({}, 2.0);
+ auto output = ReferenceOperations::join(a, b, operation::Pow::f);
+ EXPECT_EQ(output, expect_sq);
+ output = ReferenceOperations::join(a, a, operation::Mul::f);
+ EXPECT_EQ(output, expect_sq);
+ auto c = ReferenceOperations::join(output, a, operation::Div::f);
+ EXPECT_EQ(c, a);
+ b = dense_1d_all_two();
+ output = ReferenceOperations::join(a, b, operation::Pow::f);
+ EXPECT_EQ(output, expect_sq);
+ b = sparse_1d_all_two();
+ output = ReferenceOperations::join(a, b, operation::Pow::f);
+ EXPECT_EQ(output, expect_sq);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceMapTest, map_numbers) {
+ auto input = TensorSpec("tensor()").add({}, 0.0);
+ auto output = ReferenceOperations::map(input, operation::Exp::f);
+ EXPECT_EQ(output, TensorSpec("double").add({}, 1.0));
+ auto out2 = ReferenceOperations::map(output, operation::Neg::f);
+ EXPECT_EQ(out2, TensorSpec("double").add({}, -1.0));
+}
+
+TEST(ReferenceMapTest, map_dense_tensor) {
+ auto input = dense_2d_some_cells(false);
+ auto output = ReferenceOperations::map(input, operation::Square::f);
+ EXPECT_EQ(output, dense_2d_some_cells(true));
+}
+
+TEST(ReferenceMapTest, map_sparse_tensor) {
+ auto input = sparse_2d_some_cells(false);
+ auto output = ReferenceOperations::map(input, operation::Square::f);
+ EXPECT_EQ(output, sparse_2d_some_cells(true));
+}
+
+TEST(ReferenceMapTest, map_mixed_tensor) {
+ auto input = mixed_5d_some_cells(false);
+ auto output = ReferenceOperations::map(input, operation::Square::f);
+ EXPECT_EQ(output, mixed_5d_some_cells(true));
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceMergeTest, simple_mixed_merge) {
+ auto a = mixed_5d_some_cells(false);
+ auto b = TensorSpec("tensor(a[3],b[1],c{},d[5],e{})")
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 4}, {"e", "foo"}}, 0.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "bar"}, {"d", 0}, {"e", "qux"}}, 42.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "new"}, {"d", 0}, {"e", "new"}}, 1.0);
+ auto output = ReferenceOperations::merge(a, b, operation::Max::f);
+ auto expect = TensorSpec("tensor(a[3],b[1],c{},d[5],e{})")
+ .add({{"a", 1}, {"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "bar"}}, 2.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "bar"}, {"d", 3}, {"e", "bar"}}, 3.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 4}, {"e", "foo"}}, 4.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "bar"}, {"d", 0}, {"e", "qux"}}, 42.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "qux"}, {"d", 1}, {"e", "foo"}}, 6.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "new"}, {"d", 0}, {"e", "new"}}, 1.0);
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferencePeekTest, verbatim_labels) {
+ auto input = sparse_2d_some_cells(true);
+ ReferenceOperations::PeekSpec spec;
+ spec.emplace("c", "qux");
+ // peek 1 mapped dimension, verbatim label
+ auto output = ReferenceOperations::peek(spec, {input});
+ auto expect = TensorSpec("tensor(e{})")
+ .add({{"e","foo"}}, 16.0)
+ .add({{"e","qux"}}, 25.0);
+ EXPECT_EQ(output, expect);
+ spec.emplace("e", "foo");
+ // peek all mapped dimensions, verbatim labels
+ output = ReferenceOperations::peek(spec, {input});
+ expect = TensorSpec("double").add({}, 16.0);
+ EXPECT_EQ(output, expect);
+
+ spec.clear();
+ spec.emplace("c", "nomatch");
+ // peek 1 mapped dimension, non-matching verbatim label
+ output = ReferenceOperations::peek(spec, {input});
+ expect = TensorSpec("tensor(e{})");
+ EXPECT_EQ(output, expect);
+ spec.emplace("e", "nomatch");
+ // peek all mapped dimensions, non-matching verbatim labels
+ output = ReferenceOperations::peek(spec, {input});
+ expect = TensorSpec("double");
+ EXPECT_EQ(output, expect);
+
+ input = dense_2d_some_cells(false);
+ spec.clear();
+ spec.emplace("a", TensorSpec::Label(1));
+ // peek 1 indexed dimension, verbatim label
+ output = ReferenceOperations::peek(spec, {input});
+ expect = TensorSpec("tensor(d[5])")
+ .add({{"d", 2}}, 3.0)
+ .add({{"d", 0}}, 5.0);
+ EXPECT_EQ(output, expect);
+ spec.emplace("d", TensorSpec::Label(2));
+ // peek all indexed dimensions, verbatim labels
+ output = ReferenceOperations::peek(spec, {input});
+ expect = TensorSpec("double").add({}, 3.0);
+ EXPECT_EQ(output, expect);
+}
+
+TEST(ReferencePeekTest, labels_from_children) {
+ auto pos_ch = TensorSpec("double").add({}, 1.0);
+ auto zero_ch = TensorSpec("double").add({}, 0.0);
+ auto neg_ch = TensorSpec("double").add({}, -2.0);
+ auto too_big_ch = TensorSpec("double").add({}, 42.0);
+ std::vector<TensorSpec> children = {TensorSpec(""), too_big_ch, too_big_ch, zero_ch, pos_ch, neg_ch, too_big_ch};
+ auto &input = children[0];
+ input = dense_2d_some_cells(false);
+
+ ReferenceOperations::PeekSpec spec;
+ spec.emplace("a", size_t(4));
+ // peek 1 indexed dimension, child (evaluating to 1.0)
+ auto output = ReferenceOperations::peek(spec, children);
+ auto expect = TensorSpec("tensor(d[5])")
+ .add({{"d", 2}}, 3.0)
+ .add({{"d", 0}}, 5.0);
+ EXPECT_EQ(output, expect);
+ spec.emplace("d", size_t(3));
+ // peek 2 indexed dimensions (both children)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("double").add({}, 5.0);
+ EXPECT_EQ(output, expect);
+ spec.clear();
+ spec.emplace("a", size_t(1));
+ // peek 1 indexed dimension, child (evaluating to 42.0)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("tensor(d[5])");
+ EXPECT_EQ(output, expect);
+ spec.clear();
+ spec.emplace("a", size_t(5));
+ // peek 1 indexed dimension, child (evaluating to -2.0)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("tensor(d[5])");
+ EXPECT_EQ(output, expect);
+
+ input = TensorSpec("tensor(c{},e{})")
+ .add({{"c", "0"}, {"e", "0"}}, 2.0)
+ .add({{"c", "1"}, {"e", "1"}}, 3.0)
+ .add({{"c", "1"}, {"e", "0"}}, 4.0)
+ .add({{"c", "-2"}, {"e", "1"}}, 5.0)
+ .add({{"c", "-2"}, {"e", "-2"}}, 6.0);
+ spec.clear();
+ spec.emplace("c", size_t(4));
+ // peek 1 mapped dimension, child (evaluating to 1.0)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("tensor(e{})")
+ .add({{"e", "1"}}, 3.0)
+ .add({{"e", "0"}}, 4.0);
+ EXPECT_EQ(output, expect);
+ spec.emplace("e", size_t(3));
+ // peek 2 mapped dimensions (both children)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("double").add({}, 4.0);
+ EXPECT_EQ(output, expect);
+
+ spec.clear();
+ spec.emplace("c", size_t(5));
+ // peek 1 mapped dimension, child (evaluating to -2.0)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("tensor(e{})")
+ .add({{"e", "1"}}, 5.0)
+ .add({{"e", "-2"}}, 6.0);
+ EXPECT_EQ(output, expect);
+
+ spec.clear();
+ spec.emplace("c", size_t(1));
+ // peek 1 indexed dimension, child (evaluating to 42.0)
+ output = ReferenceOperations::peek(spec, children);
+ expect = TensorSpec("tensor(e{})");
+ EXPECT_EQ(output, expect);
+}
+
+TEST(ReferencePeekTest, peek_mixed) {
+ auto pos_ch = TensorSpec("double").add({}, 1.0);
+ auto zero_ch = TensorSpec("double").add({}, 0.0);
+ auto neg_ch = TensorSpec("double").add({}, -2.0);
+ auto too_big_ch = TensorSpec("double").add({}, 42.0);
+ auto input = TensorSpec("tensor(a[3],b[1],c{},d[5],e{})")
+ .add({{"a", 0}, {"b", 0}, {"c", "-2"}, {"d", 1}, {"e", "foo"}}, 1.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "1"}, {"d", 4}, {"e", "foo"}}, 2.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-1"}, {"d", 4}, {"e", "foo"}}, 3.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 0}, {"e", "qux"}}, 4.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 1}, {"e", "bar"}}, 5.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 1}, {"e", "foo"}}, 6.0) //
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 2}, {"e", "bar"}}, 7.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 2}, {"e", "foo"}}, 8.0) //
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 2}, {"e", "qux"}}, 9.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 3}, {"e", "foo"}}, 10.0) //
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 0}, {"e", "foo"}}, 11.0) //
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 3}, {"e", "nop"}}, 12.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 4}, {"e", "bar"}}, 13.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "-2"}, {"d", 4}, {"e", "foo"}}, 14.0) //
+ .add({{"a", 1}, {"b", 0}, {"c", "0"}, {"d", 1}, {"e", "foo"}}, 15.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "1"}, {"d", 2}, {"e", "foo"}}, 16.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "2"}, {"d", 3}, {"e", "foo"}}, 17.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "-2"}, {"d", 2}, {"e", "foo"}}, 18.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "0"}, {"d", 3}, {"e", "bar"}}, 19.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "1"}, {"d", 1}, {"e", "foo"}}, 20.0);
+ std::vector<TensorSpec> children = {input, too_big_ch, too_big_ch, zero_ch, pos_ch, neg_ch, too_big_ch};
+ ReferenceOperations::PeekSpec spec;
+ spec.emplace("a", size_t(4));
+ spec.emplace("b", size_t(3));
+ spec.emplace("c", size_t(5));
+ spec.emplace("e", "foo");
+ auto output = ReferenceOperations::peek(spec, children);
+ auto expect = TensorSpec("tensor(d[5])")
+ .add({{"d", 1}}, 6.0)
+ .add({{"d", 2}}, 8.0)
+ .add({{"d", 3}}, 10.0)
+ .add({{"d", 0}}, 11.0)
+ .add({{"d", 4}}, 14.0);
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceReduceTest, various_reductions_of_big_mixed_tensor) {
+ auto input = TensorSpec("tensor(a[3],b[1],c{},d[5],e{})")
+ .add({{"a", 0}, {"b", 0}, {"c", "bar"}, {"d", 1}, {"e", "foo"}}, 5.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "bar"}, {"d", 4}, {"e", "foo"}}, 3.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 1}, {"e", "foo"}}, 4.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "foo"}}, 6.0)
+ .add({{"a", 0}, {"b", 0}, {"c", "foo"}, {"d", 4}, {"e", "foo"}}, 2.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "bar"}, {"d", 0}, {"e", "qux"}}, 7.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "bar"}, {"d", 2}, {"e", "qux"}}, 9.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "foo"}, {"d", 1}, {"e", "qux"}}, 8.0)
+ .add({{"a", 1}, {"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "bar"}}, 10.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "bar"}, {"d", 2}, {"e", "bar"}}, 13.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "bar"}, {"d", 3}, {"e", "bar"}}, 12.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "foo"}, {"d", 3}, {"e", "foo"}}, 11.0)
+ .add({{"a", 2}, {"b", 0}, {"c", "qux"}, {"d", 1}, {"e", "foo"}}, 14.0);
+
+ auto output = ReferenceOperations::reduce(input, Aggr::SUM, {"a"});
+ auto expect = TensorSpec("tensor(b[1],c{},d[5],e{})")
+ .add({{"b", 0}, {"c", "bar"}, {"d", 0}, {"e", "qux"}}, 7.0)
+ .add({{"b", 0}, {"c", "bar"}, {"d", 1}, {"e", "foo"}}, 5.0)
+ .add({{"b", 0}, {"c", "bar"}, {"d", 2}, {"e", "bar"}}, 13.0)
+ .add({{"b", 0}, {"c", "bar"}, {"d", 2}, {"e", "qux"}}, 9.0)
+ .add({{"b", 0}, {"c", "bar"}, {"d", 3}, {"e", "bar"}}, 12.0)
+ .add({{"b", 0}, {"c", "bar"}, {"d", 4}, {"e", "foo"}}, 3.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 1}, {"e", "foo"}}, 4.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 1}, {"e", "qux"}}, 8.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "bar"}}, 10.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 2}, {"e", "foo"}}, 6.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 3}, {"e", "foo"}}, 11.0)
+ .add({{"b", 0}, {"c", "foo"}, {"d", 4}, {"e", "foo"}}, 2.0)
+ .add({{"b", 0}, {"c", "qux"}, {"d", 1}, {"e", "foo"}}, 14.0);
+ EXPECT_EQ(output, expect);
+
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {"a", "b", "d"});
+ expect = TensorSpec("tensor(c{},e{})")
+ .add({{"c", "bar"}, {"e", "bar"}}, 25.0)
+ .add({{"c", "bar"}, {"e", "foo"}}, 8.0)
+ .add({{"c", "bar"}, {"e", "qux"}}, 16.0)
+ .add({{"c", "foo"}, {"e", "bar"}}, 10.0)
+ .add({{"c", "foo"}, {"e", "foo"}}, 23.0)
+ .add({{"c", "foo"}, {"e", "qux"}}, 8.0)
+ .add({{"c", "qux"}, {"e", "foo"}}, 14.0);
+ EXPECT_EQ(output, expect);
+
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {"c"});
+ expect = TensorSpec("tensor(a[3],b[1],d[5],e{})")
+ .add({{"a", 0}, {"b", 0}, {"d", 1}, {"e", "foo"}}, 9.0)
+ .add({{"a", 0}, {"b", 0}, {"d", 2}, {"e", "foo"}}, 6.0)
+ .add({{"a", 0}, {"b", 0}, {"d", 4}, {"e", "foo"}}, 5.0)
+ .add({{"a", 1}, {"b", 0}, {"d", 0}, {"e", "qux"}}, 7.0)
+ .add({{"a", 1}, {"b", 0}, {"d", 1}, {"e", "qux"}}, 8.0)
+ .add({{"a", 1}, {"b", 0}, {"d", 2}, {"e", "bar"}}, 10.0)
+ .add({{"a", 1}, {"b", 0}, {"d", 2}, {"e", "qux"}}, 9.0)
+ .add({{"a", 2}, {"b", 0}, {"d", 1}, {"e", "foo"}}, 14.0)
+ .add({{"a", 2}, {"b", 0}, {"d", 2}, {"e", "bar"}}, 13.0)
+ .add({{"a", 2}, {"b", 0}, {"d", 3}, {"e", "bar"}}, 12.0)
+ .add({{"a", 2}, {"b", 0}, {"d", 3}, {"e", "foo"}}, 11.0);
+ EXPECT_EQ(output, expect);
+
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {"a", "c"});
+ expect = TensorSpec("tensor(b[1],d[5],e{})")
+ .add({{"b", 0}, {"d", 0}, {"e", "qux"}}, 7.0)
+ .add({{"b", 0}, {"d", 1}, {"e", "foo"}}, 23.0)
+ .add({{"b", 0}, {"d", 1}, {"e", "qux"}}, 8.0)
+ .add({{"b", 0}, {"d", 2}, {"e", "bar"}}, 23.0)
+ .add({{"b", 0}, {"d", 2}, {"e", "foo"}}, 6.0)
+ .add({{"b", 0}, {"d", 2}, {"e", "qux"}}, 9.0)
+ .add({{"b", 0}, {"d", 3}, {"e", "bar"}}, 12.0)
+ .add({{"b", 0}, {"d", 3}, {"e", "foo"}}, 11.0)
+ .add({{"b", 0}, {"d", 4}, {"e", "foo"}}, 5.0);
+ EXPECT_EQ(output, expect);
+
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {"a", "c", "d"});
+ expect = TensorSpec("tensor(b[1],e{})")
+ .add({{"b", 0}, {"e", "bar"}}, 35.0)
+ .add({{"b", 0}, {"e", "foo"}}, 45.0)
+ .add({{"b", 0}, {"e", "qux"}}, 24.0);
+ EXPECT_EQ(output, expect);
+
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {"a", "b", "c", "d", "e"});
+ expect = TensorSpec("double").add({}, 104);
+ EXPECT_EQ(output, expect);
+ output = ReferenceOperations::reduce(input, Aggr::SUM, {});
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceRenameTest, swap_and_rename_dimensions) {
+ auto input = mixed_5d_some_cells(false);
+ auto output = ReferenceOperations::rename(input,
+ {"a","b","c","e"},
+ {"e","x","b","a"});
+ auto expect = TensorSpec("tensor(a{},b{},d[5],e[3],x[1])")
+ .add({{"e", 1}, {"x", 0}, {"b", "foo"}, {"d", 2}, {"a", "bar"}}, 2.0)
+ .add({{"e", 2}, {"x", 0}, {"b", "bar"}, {"d", 3}, {"a", "bar"}}, 3.0)
+ .add({{"e", 0}, {"x", 0}, {"b", "foo"}, {"d", 4}, {"a", "foo"}}, 4.0)
+ .add({{"e", 1}, {"x", 0}, {"b", "bar"}, {"d", 0}, {"a", "qux"}}, 5.0)
+ .add({{"e", 2}, {"x", 0}, {"b", "qux"}, {"d", 1}, {"a", "foo"}}, 6.0);
+ EXPECT_EQ(output, expect);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ReferenceLambdaTest, make_double) {
+ auto fun = [&](const std::vector<size_t> &indexes) {
+ EXPECT_EQ(indexes.size(), 0);
+ return double(5);
+ };
+ auto expect = TensorSpec("double").add({}, 5.0);
+ EXPECT_EQ(ReferenceOperations::lambda("double", fun), expect);
+}
+
+TEST(ReferenceLambdaTest, make_vector) {
+ auto fun = [&](const std::vector<size_t> &indexes) {
+ EXPECT_EQ(indexes.size(), 1);
+ return double(indexes[0] + 1.0);
+ };
+ auto expect = TensorSpec("tensor(x[3])")
+ .add({{"x", 0}}, 1.0)
+ .add({{"x", 1}}, 2.0)
+ .add({{"x", 2}}, 3.0);
+ EXPECT_EQ(ReferenceOperations::lambda("tensor(x[3])", fun), expect);
+}
+
+TEST(ReferenceLambdaTest, make_matrix) {
+ auto fun = [&](const std::vector<size_t> &indexes) {
+ EXPECT_EQ(indexes.size(), 2);
+ return double(indexes[0] * 10 + indexes[1] + 1.0);
+ };
+ auto expect = TensorSpec("tensor(x[2],y[2])")
+ .add({{"x", 0}, {"y", 0}}, 1.0)
+ .add({{"x", 0}, {"y", 1}}, 2.0)
+ .add({{"x", 1}, {"y", 0}}, 11.0)
+ .add({{"x", 1}, {"y", 1}}, 12.0);
+ EXPECT_EQ(ReferenceOperations::lambda("tensor(x[2],y[2])", fun), expect);
+}
+
+//-----------------------------------------------------------------------------
+
+GTEST_MAIN_RUN_ALL_TESTS()
+
diff --git a/eval/src/tests/eval/simple_tensor/.gitignore b/eval/src/tests/eval/simple_tensor/.gitignore
deleted file mode 100644
index f371f5c6c6d..00000000000
--- a/eval/src/tests/eval/simple_tensor/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-vespalib_simple_tensor_test_app
diff --git a/eval/src/tests/eval/simple_tensor/CMakeLists.txt b/eval/src/tests/eval/simple_tensor/CMakeLists.txt
deleted file mode 100644
index 08fb1c17572..00000000000
--- a/eval/src/tests/eval/simple_tensor/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_simple_tensor_test_app TEST
- SOURCES
- simple_tensor_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_simple_tensor_test_app COMMAND eval_simple_tensor_test_app)
diff --git a/eval/src/tests/eval/simple_tensor/simple_tensor_test.cpp b/eval/src/tests/eval/simple_tensor/simple_tensor_test.cpp
deleted file mode 100644
index f3bea3820c8..00000000000
--- a/eval/src/tests/eval/simple_tensor/simple_tensor_test.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/vespalib/util/stash.h>
-#include <vespa/vespalib/data/memory.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <iostream>
-
-using namespace vespalib::eval;
-
-using Cell = SimpleTensor::Cell;
-using Cells = SimpleTensor::Cells;
-using Address = SimpleTensor::Address;
-using Stash = vespalib::Stash;
-using vespalib::nbostream;
-using vespalib::Memory;
-
-TensorSpec to_spec(const Value &a) { return SimpleTensorEngine::ref().to_spec(a); }
-
-const Tensor &unwrap(const Value &value) {
- ASSERT_TRUE(value.is_tensor());
- return *value.as_tensor();
-}
-
-struct CellBuilder {
- Cells cells;
- CellBuilder &add(const Address &addr, double value) {
- cells.emplace_back(addr, value);
- return *this;
- }
- Cells build() { return cells; }
-};
-
-TEST("require that simple tensors can be built using tensor spec") {
- TensorSpec spec("tensor(w{},x[2],y{},z[2])");
- spec.add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 1.0)
- .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 2.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 3.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 4.0);
- Value::UP tensor = SimpleTensorEngine::ref().from_spec(spec);
- TensorSpec full_spec("tensor(w{},x[2],y{},z[2])");
- full_spec
- .add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 1.0)
- .add({{"w", "xxx"}, {"x", 0}, {"y", "xxx"}, {"z", 1}}, 0.0)
- .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 0}}, 0.0)
- .add({{"w", "xxx"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 2.0)
- .add({{"w", "xxx"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 0.0)
- .add({{"w", "xxx"}, {"x", 1}, {"y", "xxx"}, {"z", 1}}, 0.0)
- .add({{"w", "xxx"}, {"x", 1}, {"y", "yyy"}, {"z", 0}}, 0.0)
- .add({{"w", "xxx"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 0.0)
- .add({{"w", "yyy"}, {"x", 0}, {"y", "xxx"}, {"z", 0}}, 0.0)
- .add({{"w", "yyy"}, {"x", 0}, {"y", "xxx"}, {"z", 1}}, 0.0)
- .add({{"w", "yyy"}, {"x", 0}, {"y", "yyy"}, {"z", 0}}, 0.0)
- .add({{"w", "yyy"}, {"x", 0}, {"y", "yyy"}, {"z", 1}}, 0.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 0}}, 3.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "xxx"}, {"z", 1}}, 0.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 0}}, 0.0)
- .add({{"w", "yyy"}, {"x", 1}, {"y", "yyy"}, {"z", 1}}, 4.0);
- Value::UP full_tensor = SimpleTensorEngine::ref().from_spec(full_spec);
- EXPECT_EQUAL(full_spec, to_spec(*tensor));
- EXPECT_EQUAL(full_spec, to_spec(*full_tensor));
-};
-
-TEST("require that simple tensors can have their values negated") {
- auto tensor = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, 1)
- .add({{"x","2"},{"y","1"}}, -3)
- .add({{"x","1"},{"y","2"}}, 5));
- auto expect = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, -1)
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, -5));
- auto result = tensor->map([](double a){ return -a; });
- EXPECT_EQUAL(to_spec(*expect), to_spec(*result));
- Stash stash;
- const Value &result2 = SimpleTensorEngine::ref().map(*tensor, operation::Neg::f, stash);
- EXPECT_EQUAL(to_spec(*expect), to_spec(unwrap(result2)));
-}
-
-TEST("require that simple tensors can be multiplied with each other") {
- auto lhs = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, 1)
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 5));
- auto rhs = SimpleTensor::create(
- TensorSpec("tensor(y{},z{})")
- .add({{"y","1"},{"z","1"}}, 7)
- .add({{"y","2"},{"z","1"}}, 11)
- .add({{"y","1"},{"z","2"}}, 13));
- auto expect = SimpleTensor::create(
- TensorSpec("tensor(x{},y{},z{})")
- .add({{"x","1"},{"y","1"},{"z","1"}}, 7)
- .add({{"x","1"},{"y","1"},{"z","2"}}, 13)
- .add({{"x","2"},{"y","1"},{"z","1"}}, 21)
- .add({{"x","2"},{"y","1"},{"z","2"}}, 39)
- .add({{"x","1"},{"y","2"},{"z","1"}}, 55));
- auto result = SimpleTensor::join(*lhs, *rhs, [](double a, double b){ return (a * b); });
- EXPECT_EQUAL(to_spec(*expect), to_spec(*result));
- Stash stash;
- const Value &result2 = SimpleTensorEngine::ref().join(*lhs, *rhs, operation::Mul::f, stash);
- EXPECT_EQUAL(to_spec(*expect), to_spec(unwrap(result2)));
-}
-
-TEST("require that simple tensors can be merged") {
- auto lhs = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, 1)
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 5));
- auto rhs = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","2"}}, 7)
- .add({{"x","2"},{"y","2"}}, 11)
- .add({{"x","1"},{"y","1"}}, 13));
- auto expect = SimpleTensor::create(
- TensorSpec("tensor(x{},y{})")
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 7)
- .add({{"x","2"},{"y","2"}}, 11)
- .add({{"x","1"},{"y","1"}}, 13));
- auto result = SimpleTensor::merge(*lhs, *rhs, [](double, double b){ return b; });
- EXPECT_EQUAL(to_spec(*expect), to_spec(*result));
- Stash stash;
- const Value &result2 = SimpleTensorEngine::ref().merge(*lhs, *rhs, [](double, double b){ return b; }, stash);
- EXPECT_EQUAL(to_spec(*expect), to_spec(unwrap(result2)));
-}
-
-TEST("require that simple tensors support dimension reduction") {
- auto tensor = SimpleTensor::create(
- TensorSpec("tensor(x[3],y[2])")
- .add({{"x",0},{"y",0}}, 1)
- .add({{"x",1},{"y",0}}, 2)
- .add({{"x",2},{"y",0}}, 3)
- .add({{"x",0},{"y",1}}, 4)
- .add({{"x",1},{"y",1}}, 5)
- .add({{"x",2},{"y",1}}, 6));
- auto expect_sum_y = SimpleTensor::create(
- TensorSpec("tensor(x[3])")
- .add({{"x",0}}, 5)
- .add({{"x",1}}, 7)
- .add({{"x",2}}, 9));
- auto expect_sum_x = SimpleTensor::create(
- TensorSpec("tensor(y[2])")
- .add({{"y",0}}, 6)
- .add({{"y",1}}, 15));
- auto expect_sum_all = SimpleTensor::create(TensorSpec("double").add({}, 21));
- Stash stash;
- Aggregator &aggr_sum = Aggregator::create(Aggr::SUM, stash);
- auto result_sum_y = tensor->reduce(aggr_sum, {"y"});
- auto result_sum_x = tensor->reduce(aggr_sum, {"x"});
- auto result_sum_all = tensor->reduce(aggr_sum, {"x", "y"});
- EXPECT_EQUAL(to_spec(*expect_sum_y), to_spec(*result_sum_y));
- EXPECT_EQUAL(to_spec(*expect_sum_x), to_spec(*result_sum_x));
- EXPECT_EQUAL(to_spec(*expect_sum_all), to_spec(*result_sum_all));
- const Value &result_sum_y_2 = SimpleTensorEngine::ref().reduce(*tensor, Aggr::SUM, {"y"}, stash);
- const Value &result_sum_x_2 = SimpleTensorEngine::ref().reduce(*tensor, Aggr::SUM, {"x"}, stash);
- const Value &result_sum_all_2 = SimpleTensorEngine::ref().reduce(*tensor, Aggr::SUM, {"x", "y"}, stash);
- const Value &result_sum_all_3 = SimpleTensorEngine::ref().reduce(*tensor, Aggr::SUM, {}, stash);
- EXPECT_EQUAL(to_spec(*expect_sum_y), to_spec(unwrap(result_sum_y_2)));
- EXPECT_EQUAL(to_spec(*expect_sum_x), to_spec(unwrap(result_sum_x_2)));
- EXPECT_TRUE(result_sum_all_2.is_double());
- EXPECT_TRUE(result_sum_all_3.is_double());
- EXPECT_EQUAL(21, result_sum_all_2.as_double());
- EXPECT_EQUAL(21, result_sum_all_3.as_double());
- EXPECT_EQUAL(to_spec(*result_sum_y), to_spec(*result_sum_y));
- EXPECT_NOT_EQUAL(to_spec(*result_sum_y), to_spec(*result_sum_x));
-}
-
-//-----------------------------------------------------------------------------
-
-vespalib::string make_type_spec(bool use_float, const vespalib::string &dims) {
- vespalib::string type_spec = "tensor";
- if (use_float) {
- type_spec.append("<float>");
- }
- type_spec.append(dims);
- return type_spec;
-}
-
-struct TensorExample {
- virtual ~TensorExample();
- virtual TensorSpec make_spec(bool use_float) const = 0;
- virtual std::unique_ptr<SimpleTensor> make_tensor(bool use_float) const = 0;
- virtual void encode_default(nbostream &dst) const = 0;
- virtual void encode_with_double(nbostream &dst) const = 0;
- virtual void encode_with_float(nbostream &dst) const = 0;
- void verify_encode_decode() const {
- nbostream expect_default;
- nbostream expect_double;
- nbostream expect_float;
- encode_default(expect_default);
- encode_with_double(expect_double);
- encode_with_float(expect_float);
- nbostream data_double;
- nbostream data_float;
- SimpleTensor::encode(*make_tensor(false), data_double);
- SimpleTensor::encode(*make_tensor(true), data_float);
- EXPECT_EQUAL(Memory(data_double.peek(), data_double.size()),
- Memory(expect_default.peek(), expect_default.size()));
- EXPECT_EQUAL(Memory(data_float.peek(), data_float.size()),
- Memory(expect_float.peek(), expect_float.size()));
- EXPECT_EQUAL(to_spec(*SimpleTensor::decode(expect_default)), make_spec(false));
- EXPECT_EQUAL(to_spec(*SimpleTensor::decode(expect_double)), make_spec(false));
- EXPECT_EQUAL(to_spec(*SimpleTensor::decode(expect_float)), make_spec(true));
- }
-};
-TensorExample::~TensorExample() = default;
-
-//-----------------------------------------------------------------------------
-
-struct SparseTensorExample : TensorExample {
- TensorSpec make_spec(bool use_float) const override {
- return TensorSpec(make_type_spec(use_float, "(x{},y{})"))
- .add({{"x","a"},{"y","a"}}, 1)
- .add({{"x","a"},{"y","b"}}, 2)
- .add({{"x","b"},{"y","a"}}, 3);
- }
- std::unique_ptr<SimpleTensor> make_tensor(bool use_float) const override {
- return SimpleTensor::create(make_spec(use_float));
- }
- template <typename T>
- void encode_inner(nbostream &dst) const {
- dst.putInt1_4Bytes(2);
- dst.writeSmallString("x");
- dst.writeSmallString("y");
- dst.putInt1_4Bytes(3);
- dst.writeSmallString("a");
- dst.writeSmallString("a");
- dst << (T) 1;
- dst.writeSmallString("a");
- dst.writeSmallString("b");
- dst << (T) 2;
- dst.writeSmallString("b");
- dst.writeSmallString("a");
- dst << (T) 3;
- }
- void encode_default(nbostream &dst) const override {
- dst.putInt1_4Bytes(1);
- encode_inner<double>(dst);
- }
- void encode_with_double(nbostream &dst) const override {
- dst.putInt1_4Bytes(5);
- dst.putInt1_4Bytes(0);
- encode_inner<double>(dst);
- }
- void encode_with_float(nbostream &dst) const override {
- dst.putInt1_4Bytes(5);
- dst.putInt1_4Bytes(1);
- encode_inner<float>(dst);
- }
-};
-
-TEST_F("require that sparse tensors can be encoded and decoded", SparseTensorExample()) {
- TEST_DO(f1.verify_encode_decode());
-}
-
-//-----------------------------------------------------------------------------
-
-struct DenseTensorExample : TensorExample {
- TensorSpec make_spec(bool use_float) const override {
- return TensorSpec(make_type_spec(use_float, "(x[3],y[2])"))
- .add({{"x",0},{"y",0}}, 1)
- .add({{"x",0},{"y",1}}, 2)
- .add({{"x",1},{"y",0}}, 3)
- .add({{"x",1},{"y",1}}, 4)
- .add({{"x",2},{"y",0}}, 5)
- .add({{"x",2},{"y",1}}, 6);
- }
- std::unique_ptr<SimpleTensor> make_tensor(bool use_float) const override {
- return SimpleTensor::create(make_spec(use_float));
- }
- template <typename T>
- void encode_inner(nbostream &dst) const {
- dst.putInt1_4Bytes(2);
- dst.writeSmallString("x");
- dst.putInt1_4Bytes(3);
- dst.writeSmallString("y");
- dst.putInt1_4Bytes(2);
- dst << (T) 1;
- dst << (T) 2;
- dst << (T) 3;
- dst << (T) 4;
- dst << (T) 5;
- dst << (T) 6;
- }
- void encode_default(nbostream &dst) const override {
- dst.putInt1_4Bytes(2);
- encode_inner<double>(dst);
- }
- void encode_with_double(nbostream &dst) const override {
- dst.putInt1_4Bytes(6);
- dst.putInt1_4Bytes(0);
- encode_inner<double>(dst);
- }
- void encode_with_float(nbostream &dst) const override {
- dst.putInt1_4Bytes(6);
- dst.putInt1_4Bytes(1);
- encode_inner<float>(dst);
- }
-};
-
-TEST_F("require that dense tensors can be encoded and decoded", DenseTensorExample()) {
- TEST_DO(f1.verify_encode_decode());
-}
-
-//-----------------------------------------------------------------------------
-
-struct MixedTensorExample : TensorExample {
- TensorSpec make_spec(bool use_float) const override {
- return TensorSpec(make_type_spec(use_float, "(x{},y{},z[2])"))
- .add({{"x","a"},{"y","a"},{"z",0}}, 1)
- .add({{"x","a"},{"y","a"},{"z",1}}, 2)
- .add({{"x","a"},{"y","b"},{"z",0}}, 3)
- .add({{"x","a"},{"y","b"},{"z",1}}, 4)
- .add({{"x","b"},{"y","a"},{"z",0}}, 5)
- .add({{"x","b"},{"y","a"},{"z",1}}, 6);
- }
- std::unique_ptr<SimpleTensor> make_tensor(bool use_float) const override {
- return SimpleTensor::create(make_spec(use_float));
- }
- template <typename T>
- void encode_inner(nbostream &dst) const {
- dst.putInt1_4Bytes(2);
- dst.writeSmallString("x");
- dst.writeSmallString("y");
- dst.putInt1_4Bytes(1);
- dst.writeSmallString("z");
- dst.putInt1_4Bytes(2);
- dst.putInt1_4Bytes(3);
- dst.writeSmallString("a");
- dst.writeSmallString("a");
- dst << (T) 1;
- dst << (T) 2;
- dst.writeSmallString("a");
- dst.writeSmallString("b");
- dst << (T) 3;
- dst << (T) 4;
- dst.writeSmallString("b");
- dst.writeSmallString("a");
- dst << (T) 5;
- dst << (T) 6;
- }
- void encode_default(nbostream &dst) const override {
- dst.putInt1_4Bytes(3);
- encode_inner<double>(dst);
- }
- void encode_with_double(nbostream &dst) const override {
- dst.putInt1_4Bytes(7);
- dst.putInt1_4Bytes(0);
- encode_inner<double>(dst);
- }
- void encode_with_float(nbostream &dst) const override {
- dst.putInt1_4Bytes(7);
- dst.putInt1_4Bytes(1);
- encode_inner<float>(dst);
- }
-};
-
-TEST_F("require that mixed tensors can be encoded and decoded", MixedTensorExample()) {
- TEST_DO(f1.verify_encode_decode());
-}
-
-//-----------------------------------------------------------------------------
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/eval/simple_value/simple_value_test.cpp b/eval/src/tests/eval/simple_value/simple_value_test.cpp
index cac1a93dbf9..c05f9976e1a 100644
--- a/eval/src/tests/eval/simple_value/simple_value_test.cpp
+++ b/eval/src/tests/eval/simple_value/simple_value_test.cpp
@@ -4,6 +4,7 @@
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/instruction/generic_join.h>
#include <vespa/eval/eval/interpreted_function.h>
+#include <vespa/eval/eval/test/reference_operations.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
@@ -59,16 +60,7 @@ std::vector<Layout> join_layouts = {
float_cells({x({"a","b","c"}),y(5)}), float_cells({y(5),z({"i","j","k","l"})})
};
-TensorSpec simple_tensor_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
- Stash stash;
- const auto &engine = SimpleTensorEngine::ref();
- auto lhs = engine.from_spec(a);
- auto rhs = engine.from_spec(b);
- const auto &result = engine.join(*lhs, *rhs, function, stash);
- return engine.to_spec(result);
-}
-
-TensorSpec simple_value_new_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
+TensorSpec simple_value_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
Stash stash;
const auto &factory = SimpleValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
@@ -126,8 +118,8 @@ TEST(SimpleValueTest, new_generic_join_works_for_simple_values) {
TensorSpec rhs = spec(join_layouts[i + 1], Div16(N()));
for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Div::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto expect = simple_tensor_join(lhs, rhs, fun);
- auto actual = simple_value_new_join(lhs, rhs, fun);
+ auto expect = ReferenceOperations::join(lhs, rhs, fun);
+ auto actual = simple_value_join(lhs, rhs, fun);
EXPECT_EQ(actual, expect);
}
}
diff --git a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
index 9441061d6e1..4396a6773ea 100644
--- a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
+++ b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
@@ -1,9 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_function.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/value_type.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -13,15 +13,17 @@ using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::tensor_function;
+const auto &simple_factory = SimpleValueBuilderFactory::get();
+
struct EvalCtx {
- EngineOrFactory engine;
+ const ValueBuilderFactory &factory;
Stash stash;
std::vector<Value::UP> tensors;
std::vector<Value::CREF> params;
InterpretedFunction::UP ifun;
std::unique_ptr<InterpretedFunction::Context> ictx;
- EvalCtx(EngineOrFactory engine_in)
- : engine(engine_in), stash(), tensors(), params(), ifun(), ictx() {}
+ EvalCtx(const ValueBuilderFactory &factory_in)
+ : factory(factory_in), stash(), tensors(), params(), ifun(), ictx() {}
~EvalCtx() {}
size_t add_tensor(Value::UP tensor) {
size_t id = params.size();
@@ -34,18 +36,18 @@ struct EvalCtx {
tensors[idx] = std::move(tensor);
}
const Value &eval(const TensorFunction &fun) {
- ifun = std::make_unique<InterpretedFunction>(engine, fun);
+ ifun = std::make_unique<InterpretedFunction>(factory, fun);
ictx = std::make_unique<InterpretedFunction::Context>(*ifun);
return ifun->eval(*ictx, SimpleObjectParams(params));
}
Value::UP make_double(double value) {
- return engine.from_spec(TensorSpec("double").add({}, value));
+ return value_from_spec(TensorSpec("double").add({}, value), factory);
}
Value::UP make_true() {
- return engine.from_spec(TensorSpec("double").add({}, 1.0));
+ return value_from_spec(TensorSpec("double").add({}, 1.0), factory);
}
Value::UP make_false() {
- return engine.from_spec(TensorSpec("double").add({}, 0.0));
+ return value_from_spec(TensorSpec("double").add({}, 0.0), factory);
}
Value::UP make_vector(std::initializer_list<double> cells, vespalib::string dim = "x", bool mapped = false) {
vespalib::string type_spec = mapped
@@ -59,135 +61,130 @@ struct EvalCtx {
: TensorSpec::Label(idx++);
spec.add({{dim, label}}, cell_value);
}
- return engine.from_spec(spec);
+ return value_from_spec(spec, factory);
}
Value::UP make_mixed_tensor(double a, double b, double c, double d) {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{},y[2])")
.add({{"x", "foo"}, {"y", 0}}, a)
.add({{"x", "foo"}, {"y", 1}}, b)
.add({{"x", "bar"}, {"y", 0}}, c)
- .add({{"x", "bar"}, {"y", 1}}, d));
+ .add({{"x", "bar"}, {"y", 1}}, d), factory);
}
Value::UP make_tensor_matrix_first_half() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x[2])")
.add({{"x", 0}}, 1.0)
- .add({{"x", 1}}, 3.0));
+ .add({{"x", 1}}, 3.0), factory);
}
Value::UP make_tensor_matrix_second_half() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x[2])")
.add({{"x", 0}}, 2.0)
- .add({{"x", 1}}, 4.0));
+ .add({{"x", 1}}, 4.0), factory);
}
Value::UP make_tensor_matrix() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x[2],y[2])")
.add({{"x", 0}, {"y", 0}}, 1.0)
.add({{"x", 0}, {"y", 1}}, 2.0)
.add({{"x", 1}, {"y", 0}}, 3.0)
- .add({{"x", 1}, {"y", 1}}, 4.0));
+ .add({{"x", 1}, {"y", 1}}, 4.0), factory);
}
Value::UP make_tensor_matrix_renamed() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(y[2],z[2])")
.add({{"z", 0}, {"y", 0}}, 1.0)
.add({{"z", 0}, {"y", 1}}, 2.0)
.add({{"z", 1}, {"y", 0}}, 3.0)
- .add({{"z", 1}, {"y", 1}}, 4.0));
+ .add({{"z", 1}, {"y", 1}}, 4.0), factory);
}
Value::UP make_tensor_reduce_input() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x[3],y[2])")
.add({{"x",0},{"y",0}}, 1)
.add({{"x",1},{"y",0}}, 2)
.add({{"x",2},{"y",0}}, 3)
.add({{"x",0},{"y",1}}, 4)
.add({{"x",1},{"y",1}}, 5)
- .add({{"x",2},{"y",1}}, 6));
+ .add({{"x",2},{"y",1}}, 6), factory);
}
Value::UP make_tensor_reduce_y_output() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x[3])")
.add({{"x",0}}, 5)
.add({{"x",1}}, 7)
- .add({{"x",2}}, 9));
+ .add({{"x",2}}, 9), factory);
}
Value::UP make_tensor_map_input() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{},y{})")
.add({{"x","1"},{"y","1"}}, 1)
.add({{"x","2"},{"y","1"}}, -3)
- .add({{"x","1"},{"y","2"}}, 5));
+ .add({{"x","1"},{"y","2"}}, 5), factory);
}
Value::UP make_tensor_map_output() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{},y{})")
.add({{"x","1"},{"y","1"}}, -1)
.add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, -5));
+ .add({{"x","1"},{"y","2"}}, -5), factory);
}
Value::UP make_tensor_join_lhs() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{},y{})")
.add({{"x","1"},{"y","1"}}, 1)
.add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 5));
+ .add({{"x","1"},{"y","2"}}, 5), factory);
}
Value::UP make_tensor_join_rhs() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(y{},z{})")
.add({{"y","1"},{"z","1"}}, 7)
.add({{"y","2"},{"z","1"}}, 11)
- .add({{"y","1"},{"z","2"}}, 13));
+ .add({{"y","1"},{"z","2"}}, 13), factory);
}
Value::UP make_tensor_join_output() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{},y{},z{})")
.add({{"x","1"},{"y","1"},{"z","1"}}, 7)
.add({{"x","1"},{"y","1"},{"z","2"}}, 13)
.add({{"x","2"},{"y","1"},{"z","1"}}, 21)
.add({{"x","2"},{"y","1"},{"z","2"}}, 39)
- .add({{"x","1"},{"y","2"},{"z","1"}}, 55));
+ .add({{"x","1"},{"y","2"},{"z","1"}}, 55), factory);
}
Value::UP make_tensor_merge_lhs() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{})")
.add({{"x","1"}}, 1)
.add({{"x","2"}}, 3)
- .add({{"x","3"}}, 5));
+ .add({{"x","3"}}, 5), factory);
}
Value::UP make_tensor_merge_rhs() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{})")
.add({{"x","2"}}, 7)
.add({{"x","3"}}, 9)
- .add({{"x","4"}}, 11));
+ .add({{"x","4"}}, 11), factory);
}
Value::UP make_tensor_merge_output() {
- return engine.from_spec(
+ return value_from_spec(
TensorSpec("tensor(x{})")
.add({{"x","1"}}, 1)
.add({{"x","2"}}, 10)
.add({{"x","3"}}, 14)
- .add({{"x","4"}}, 11));
+ .add({{"x","4"}}, 11), factory);
}
};
void verify_equal(const Value &expect, const Value &value) {
- const Tensor *tensor = value.as_tensor();
- ASSERT_TRUE(tensor != nullptr);
- const Tensor *expect_tensor = expect.as_tensor();
- ASSERT_TRUE(expect_tensor != nullptr);
- ASSERT_EQUAL(&expect_tensor->engine(), &tensor->engine());
- auto expect_spec = expect_tensor->engine().to_spec(expect);
- auto value_spec = tensor->engine().to_spec(value);
+ auto expect_spec = spec_from_value(expect);
+ auto value_spec = spec_from_value(value);
EXPECT_EQUAL(expect_spec, value_spec);
}
TEST("require that const_value works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
Value::UP my_const = ctx.make_tensor_matrix();
Value::UP expect = ctx.make_tensor_matrix();
const auto &fun = const_value(*my_const, ctx.stash);
@@ -197,7 +194,7 @@ TEST("require that const_value works") {
}
TEST("require that tensor injection works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_matrix());
Value::UP expect = ctx.make_tensor_matrix();
const auto &fun = inject(ValueType::from_spec("tensor(x[2],y[2])"), a_id, ctx.stash);
@@ -207,7 +204,7 @@ TEST("require that tensor injection works") {
}
TEST("require that partial tensor reduction works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_reduce_input());
Value::UP expect = ctx.make_tensor_reduce_y_output();
const auto &fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), a_id, ctx.stash), Aggr::SUM, {"y"}, ctx.stash);
@@ -217,7 +214,7 @@ TEST("require that partial tensor reduction works") {
}
TEST("require that full tensor reduction works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_reduce_input());
const auto &fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), a_id, ctx.stash), Aggr::SUM, {}, ctx.stash);
EXPECT_TRUE(fun.result_is_mutable());
@@ -228,7 +225,7 @@ TEST("require that full tensor reduction works") {
}
TEST("require that tensor map works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_map_input());
Value::UP expect = ctx.make_tensor_map_output();
const auto &fun = map(inject(ValueType::from_spec("tensor(x{},y{})"), a_id, ctx.stash), operation::Neg::f, ctx.stash);
@@ -238,7 +235,7 @@ TEST("require that tensor map works") {
}
TEST("require that tensor join works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_join_lhs());
size_t b_id = ctx.add_tensor(ctx.make_tensor_join_rhs());
Value::UP expect = ctx.make_tensor_join_output();
@@ -251,7 +248,7 @@ TEST("require that tensor join works") {
}
TEST("require that tensor merge works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_merge_lhs());
size_t b_id = ctx.add_tensor(ctx.make_tensor_merge_rhs());
Value::UP expect = ctx.make_tensor_merge_output();
@@ -264,7 +261,7 @@ TEST("require that tensor merge works") {
}
TEST("require that tensor concat works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_matrix_first_half());
size_t b_id = ctx.add_tensor(ctx.make_tensor_matrix_second_half());
Value::UP expect = ctx.make_tensor_matrix();
@@ -277,7 +274,7 @@ TEST("require that tensor concat works") {
}
TEST("require that tensor create works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_double(1.0));
size_t b_id = ctx.add_tensor(ctx.make_double(2.0));
Value::UP my_const = ctx.make_double(3.0);
@@ -298,15 +295,17 @@ TEST("require that tensor create works") {
}
TEST("require that single value tensor peek works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_double(1.0));
+ size_t b_id = ctx.add_tensor(ctx.make_double(1000.0));
Value::UP my_const = ctx.make_mixed_tensor(1.0, 2.0, 3.0, 4.0);
Value::UP expect = ctx.make_vector({2.0, 3.0, 0.0});
const auto &a = inject(ValueType::from_spec("double"), a_id, ctx.stash);
+ const auto &b = inject(ValueType::from_spec("double"), b_id, ctx.stash);
const auto &t = const_value(*my_const, ctx.stash);
const auto &peek1 = peek(t, {{"x", "foo"}, {"y", a}}, ctx.stash);
const auto &peek2 = peek(t, {{"x", "bar"}, {"y", size_t(0)}}, ctx.stash);
- const auto &peek3 = peek(t, {{"x", "bar"}, {"y", size_t(1000)}}, ctx.stash);
+ const auto &peek3 = peek(t, {{"x", "bar"}, {"y", b}}, ctx.stash);
const auto &fun = create(ValueType::from_spec("tensor(x[3])"),
{
{{{"x", 0}}, peek1},
@@ -320,7 +319,7 @@ TEST("require that single value tensor peek works") {
}
TEST("require that tensor subspace tensor peek works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
Value::UP my_const = ctx.make_mixed_tensor(1.0, 2.0, 3.0, 4.0);
Value::UP expect = ctx.make_vector({3.0, 4.0}, "y");
const auto &t = const_value(*my_const, ctx.stash);
@@ -331,7 +330,7 @@ TEST("require that tensor subspace tensor peek works") {
}
TEST("require that automatic string conversion tensor peek works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_double(1.0));
Value::UP my_const = ctx.make_vector({1.0, 2.0, 3.0}, "x", true);
const auto &a = inject(ValueType::from_spec("double"), a_id, ctx.stash);
@@ -345,7 +344,7 @@ TEST("require that automatic string conversion tensor peek works") {
}
TEST("require that tensor rename works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_tensor_matrix());
Value::UP expect = ctx.make_tensor_matrix_renamed();
const auto &fun = rename(inject(ValueType::from_spec("tensor(x[2],y[2])"), a_id, ctx.stash),
@@ -356,7 +355,7 @@ TEST("require that tensor rename works") {
}
TEST("require that if_node works") {
- EvalCtx ctx(SimpleTensorEngine::ref());
+ EvalCtx ctx(simple_factory);
size_t a_id = ctx.add_tensor(ctx.make_true());
size_t b_id = ctx.add_tensor(ctx.make_tensor_matrix_first_half());
size_t c_id = ctx.add_tensor(ctx.make_tensor_matrix_second_half());
diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
index fc6a7e46576..7094686e399 100644
--- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
+++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
@@ -2,17 +2,12 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/fast_value.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
#include <vespa/eval/instruction/dense_cell_range_function.h>
#include <vespa/eval/instruction/dense_lambda_peek_function.h>
-#include <vespa/eval/tensor/dense/dense_lambda_function.h>
-#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/dense_fast_rename_optimizer.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/tensor_nodes.h>
@@ -23,26 +18,10 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-using EvalMode = DenseLambdaFunction::EvalMode;
-
-namespace vespalib::tensor {
-
-std::ostream &operator<<(std::ostream &os, EvalMode eval_mode)
-{
- switch(eval_mode) {
- case EvalMode::COMPILED: return os << "COMPILED";
- case EvalMode::INTERPRETED: return os << "INTERPRETED";
- }
- abort();
-}
-
-}
-
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
const ValueBuilderFactory &simple_factory = SimpleValueBuilderFactory::get();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -60,13 +39,14 @@ EvalFixture::ParamRepo param_repo = make_params();
template <typename T, typename F>
void verify_impl(const vespalib::string &expr, const vespalib::string &expect, F &&inspect) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
EvalFixture simple_factory_fixture(simple_factory, expr, param_repo, false);
- EXPECT_EQUAL(fixture.result(), slow_fixture.result());
- EXPECT_EQUAL(fixture.result(), simple_factory_fixture.result());
- EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expect, param_repo));
+ auto expect_spec = EvalFixture::ref(expect, param_repo);
+ EXPECT_EQUAL(fixture.result(), expect_spec);
+ EXPECT_EQUAL(slow_fixture.result(), expect_spec);
+ EXPECT_EQUAL(simple_factory_fixture.result(), expect_spec);
+ EXPECT_EQUAL(EvalFixture::ref(expr, param_repo), expect_spec);
auto info = fixture.find_all<T>();
if (EXPECT_EQUAL(info.size(), 1u)) {
inspect(info[0]);
@@ -77,14 +57,8 @@ void verify_impl(const vespalib::string &expr, const vespalib::string &expect) {
verify_impl<T>(expr, expect, [](const T*){});
}
-void verify_generic(const vespalib::string &expr, const vespalib::string &expect,
- EvalMode expect_eval_mode)
-{
- verify_impl<DenseLambdaFunction>(expr, expect,
- [&](const DenseLambdaFunction *info)
- {
- EXPECT_EQUAL(info->eval_mode(), expect_eval_mode);
- });
+void verify_generic(const vespalib::string &expr, const vespalib::string &expect) {
+ verify_impl<tensor_function::Lambda>(expr, expect);
}
void verify_reshape(const vespalib::string &expr, const vespalib::string &expect) {
@@ -115,43 +89,15 @@ TEST("require that simple constant tensor lambda works") {
TEST_DO(verify_const("tensor(x[3])(x+1)", "tensor(x[3]):[1,2,3]"));
}
-TEST("require that simple dynamic tensor lambda works") {
- TEST_DO(verify_generic("tensor(x[3])(x+a)", "tensor(x[3]):[1,2,3]", EvalMode::COMPILED));
-}
-
-TEST("require that compiled multi-dimensional multi-param dynamic tensor lambda works") {
- TEST_DO(verify_generic("tensor(x[3],y[2])((b-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::COMPILED));
- TEST_DO(verify_generic("tensor<float>(x[3],y[2])((b-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::COMPILED));
-}
-
-TEST("require that interpreted multi-dimensional multi-param dynamic tensor lambda works") {
- TEST_DO(verify_generic("tensor(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor<float>(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::INTERPRETED));
-}
-
-TEST("require that tensor lambda can be used for tensor slicing") {
- TEST_DO(verify_generic("tensor(x[2])(x3{x:(x+a)})", "tensor(x[2]):[2,3]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor(x[2])(a+x3{x:(x)})", "tensor(x[2]):[2,3]", EvalMode::INTERPRETED));
-}
-
TEST("require that tensor lambda can be used for cell type casting") {
TEST_DO(verify_idx_fun("tensor(x[3])(x3f{x:(x)})", "tensor(x[3]):[1,2,3]", "f(x)(x)"));
TEST_DO(verify_idx_fun("tensor<float>(x[3])(x3{x:(x)})", "tensor<float>(x[3]):[1,2,3]", "f(x)(x)"));
}
-TEST("require that tensor lambda can be used to convert from sparse to dense tensors") {
- TEST_DO(verify_generic("tensor(x[3])(x3m{x:(x)})", "tensor(x[3]):[1,2,3]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor(x[2])(x3m{x:(x)})", "tensor(x[2]):[1,2]", EvalMode::INTERPRETED));
-}
-
TEST("require that constant nested tensor lambda using tensor peek works") {
TEST_DO(verify_const("tensor(x[2])(tensor(y[2])((x+y)+1){y:(x)})", "tensor(x[2]):[1,3]"));
}
-TEST("require that dynamic nested tensor lambda using tensor peek works") {
- TEST_DO(verify_generic("tensor(x[2])(tensor(y[2])((x+y)+a){y:(x)})", "tensor(x[2]):[1,3]", EvalMode::INTERPRETED));
-}
-
TEST("require that tensor reshape is optimized") {
TEST_DO(verify_reshape("tensor(x[15])(x3y5{x:(x/5),y:(x%5)})", "x15"));
TEST_DO(verify_reshape("tensor(x[3],y[5])(x15{x:(x*5+y)})", "x3y5"));
@@ -184,11 +130,39 @@ TEST("require that non-continuous cell extraction is optimized") {
TEST_DO(verify_idx_fun("tensor<float>(x[3])(x3y5f{x:(x),y:2})", "x3y5f{y:2}", "f(x)((floor(x)*5)+2)"));
}
+TEST("require that simple dynamic tensor lambda works") {
+ TEST_DO(verify_generic("tensor(x[3])(x+a)", "tensor(x[3]):[1,2,3]"));
+}
+
+TEST("require that compiled multi-dimensional multi-param dynamic tensor lambda works") {
+ TEST_DO(verify_generic("tensor(x[3],y[2])((b-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]"));
+ TEST_DO(verify_generic("tensor<float>(x[3],y[2])((b-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]"));
+}
+
+TEST("require that interpreted multi-dimensional multi-param dynamic tensor lambda works") {
+ TEST_DO(verify_generic("tensor(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]"));
+ TEST_DO(verify_generic("tensor<float>(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]"));
+}
+
+TEST("require that tensor lambda can be used for tensor slicing") {
+ TEST_DO(verify_generic("tensor(x[2])(x3{x:(x+a)})", "tensor(x[2]):[2,3]"));
+ TEST_DO(verify_generic("tensor(x[2])(a+x3{x:(x)})", "tensor(x[2]):[2,3]"));
+}
+
+TEST("require that tensor lambda can be used to convert from sparse to dense tensors") {
+ TEST_DO(verify_generic("tensor(x[3])(x3m{x:(x)})", "tensor(x[3]):[1,2,3]"));
+ TEST_DO(verify_generic("tensor(x[2])(x3m{x:(x)})", "tensor(x[2]):[1,2]"));
+}
+
+TEST("require that dynamic nested tensor lambda using tensor peek works") {
+ TEST_DO(verify_generic("tensor(x[2])(tensor(y[2])((x+y)+a){y:(x)})", "tensor(x[2]):[1,3]"));
+}
+
TEST("require that out-of-bounds cell extraction is not optimized") {
- TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x+3)})", "tensor(x[3]):[9,10,0]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x-1)})", "tensor(x[3]):[0,6,7]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x+1),y:(x)})", "tensor(x[3]):[6,12,0]", EvalMode::INTERPRETED));
- TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x-1),y:(x)})", "tensor(x[3]):[0,2,8]", EvalMode::INTERPRETED));
+ TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x+3)})", "tensor(x[3]):[9,10,0]"));
+ TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x-1)})", "tensor(x[3]):[0,6,7]"));
+ TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x+1),y:(x)})", "tensor(x[3]):[6,12,0]"));
+ TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x-1),y:(x)})", "tensor(x[3]):[0,2,8]"));
}
TEST("require that non-double result from inner tensor lambda function fails type resolving") {
diff --git a/eval/src/tests/tensor/typed_cells/CMakeLists.txt b/eval/src/tests/eval/typed_cells/CMakeLists.txt
index d57ff33eda6..d57ff33eda6 100644
--- a/eval/src/tests/tensor/typed_cells/CMakeLists.txt
+++ b/eval/src/tests/eval/typed_cells/CMakeLists.txt
diff --git a/eval/src/tests/tensor/typed_cells/typed_cells_test.cpp b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp
index ccb522fd496..ccb522fd496 100644
--- a/eval/src/tests/tensor/typed_cells/typed_cells_test.cpp
+++ b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp
diff --git a/eval/src/tests/eval/value_cache/tensor_loader_test.cpp b/eval/src/tests/eval/value_cache/tensor_loader_test.cpp
index 5dfde15a0ee..3ec57e0eecb 100644
--- a/eval/src/tests/eval/value_cache/tensor_loader_test.cpp
+++ b/eval/src/tests/eval/value_cache/tensor_loader_test.cpp
@@ -1,9 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/value_cache/constant_tensor_loader.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/tensor.h>
using namespace vespalib::eval;
@@ -31,50 +31,51 @@ TensorSpec make_mixed_tensor() {
.add({{"x", "foo"}, {"y", 1}}, 2.0);
}
+const auto &factory = SimpleValueBuilderFactory::get();
+
void verify_tensor(const TensorSpec &expect, ConstantValue::UP actual) {
- const auto &engine = SimpleTensorEngine::ref();
ASSERT_EQUAL(expect.type(), actual->type().to_spec());
- ASSERT_TRUE(&engine == &actual->value().as_tensor()->engine());
- EXPECT_EQUAL(expect, engine.to_spec(actual->value()));
+ EXPECT_TRUE(dynamic_cast<const SimpleValue *>(&actual->value()));
+ EXPECT_EQUAL(expect, spec_from_value(actual->value()));
}
void verify_invalid(ConstantValue::UP actual) {
EXPECT_TRUE(actual->type().is_error());
}
-TEST_F("require that invalid types gives bad constant value", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that invalid types gives bad constant value", ConstantTensorLoader(factory)) {
TEST_DO(verify_invalid(f1.create(TEST_PATH("dense.json"), "invalid type spec")));
}
-TEST_F("require that invalid file name loads an empty tensor", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that invalid file name loads an empty tensor", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(sparse_tensor_nocells(), f1.create(TEST_PATH("missing_file.json"), "tensor(x{},y{})")));
}
-TEST_F("require that invalid json loads an empty tensor", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that invalid json loads an empty tensor", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(sparse_tensor_nocells(), f1.create(TEST_PATH("invalid.json"), "tensor(x{},y{})")));
}
-TEST_F("require that dense tensors can be loaded", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that dense tensors can be loaded", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(make_dense_tensor(), f1.create(TEST_PATH("dense.json"), "tensor(x[2],y[2])")));
}
-TEST_F("require that mixed tensors can be loaded", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that mixed tensors can be loaded", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(make_mixed_tensor(), f1.create(TEST_PATH("mixed.json"), "tensor(x{},y[2])")));
}
-TEST_F("require that lz4 compressed dense tensor can be loaded", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that lz4 compressed dense tensor can be loaded", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(make_dense_tensor(), f1.create(TEST_PATH("dense.json.lz4"), "tensor(x[2],y[2])")));
}
-TEST_F("require that a binary tensor can be loaded", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that a binary tensor can be loaded", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(make_dense_tensor(), f1.create(TEST_PATH("dense.tbf"), "tensor(x[2],y[2])")));
}
-TEST_F("require that lz4 compressed sparse tensor can be loaded", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that lz4 compressed sparse tensor can be loaded", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(make_sparse_tensor(), f1.create(TEST_PATH("sparse.json.lz4"), "tensor(x{},y{})")));
}
-TEST_F("require that bad lz4 file fails to load creating empty result", ConstantTensorLoader(SimpleTensorEngine::ref())) {
+TEST_F("require that bad lz4 file fails to load creating empty result", ConstantTensorLoader(factory)) {
TEST_DO(verify_tensor(sparse_tensor_nocells(), f1.create(TEST_PATH("bad_lz4.json.lz4"), "tensor(x{},y{})")));
}
diff --git a/eval/src/tests/tensor/dense_add_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt
index 1bc9f93b1a2..1bc9f93b1a2 100644
--- a/eval/src/tests/tensor/dense_add_dimension_optimizer/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp b/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp
index 274117ea693..e7660ce8933 100644
--- a/eval/src/tests/tensor/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp
+++ b/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp
@@ -1,13 +1,10 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
-#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_fast_rename_optimizer.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -17,10 +14,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -33,14 +29,14 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_EQUAL(info.size(), 1u);
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_TRUE(info.empty());
diff --git a/eval/src/tests/instruction/dense_dot_product_function/dense_dot_product_function_test.cpp b/eval/src/tests/instruction/dense_dot_product_function/dense_dot_product_function_test.cpp
index ff4a92d4fff..82a0baa8741 100644
--- a/eval/src/tests/instruction/dense_dot_product_function/dense_dot_product_function_test.cpp
+++ b/eval/src/tests/instruction/dense_dot_product_function/dense_dot_product_function_test.cpp
@@ -5,7 +5,6 @@
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_dot_product_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -17,7 +16,6 @@ using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
struct MyVecSeq : Sequence {
@@ -51,12 +49,6 @@ void check_gen_with_result(size_t l, size_t r, double wanted) {
EXPECT_EQUAL(evaluator.result(), EvalFixture::ref(expr, param_repo));
auto info = evaluator.find_all<DenseDotProductFunction>();
EXPECT_EQUAL(info.size(), 1u);
-
- EvalFixture old_evaluator(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(spec(wanted), old_evaluator.result());
- EXPECT_EQUAL(old_evaluator.result(), EvalFixture::ref(expr, param_repo));
- info = old_evaluator.find_all<DenseDotProductFunction>();
- EXPECT_EQUAL(info.size(), 1u);
};
// this should not be possible to set up:
@@ -120,12 +112,6 @@ void assertOptimized(const vespalib::string &expr) {
auto info = fixture.find_all<DenseDotProductFunction>();
ASSERT_EQUAL(info.size(), 1u);
EXPECT_TRUE(info[0]->result_is_mutable());
-
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- info = old_fixture.find_all<DenseDotProductFunction>();
- ASSERT_EQUAL(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
}
void assertNotOptimized(const vespalib::string &expr) {
@@ -133,11 +119,6 @@ void assertNotOptimized(const vespalib::string &expr) {
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseDotProductFunction>();
EXPECT_TRUE(info.empty());
-
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- info = old_fixture.find_all<DenseDotProductFunction>();
- EXPECT_TRUE(info.empty());
}
TEST("require that dot product works with tensor function") {
diff --git a/eval/src/tests/tensor/dense_fast_rename_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt
index 32cf6c45d1e..32cf6c45d1e 100644
--- a/eval/src/tests/tensor/dense_fast_rename_optimizer/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp b/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp
index 55a9414f82b..043c8814c72 100644
--- a/eval/src/tests/tensor/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp
+++ b/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp
@@ -2,12 +2,8 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
-#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_fast_rename_optimizer.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -17,10 +13,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -32,14 +27,14 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_EQUAL(info.size(), 1u);
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_TRUE(info.empty());
diff --git a/eval/src/tests/tensor/dense_inplace_join_function/CMakeLists.txt b/eval/src/tests/instruction/dense_inplace_join_function/CMakeLists.txt
index 2808675bc78..2808675bc78 100644
--- a/eval/src/tests/tensor/dense_inplace_join_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_inplace_join_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_inplace_join_function/dense_inplace_join_function_test.cpp b/eval/src/tests/instruction/dense_inplace_join_function/dense_inplace_join_function_test.cpp
index 0a34e1123de..68aa72428b9 100644
--- a/eval/src/tests/tensor/dense_inplace_join_function/dense_inplace_join_function_test.cpp
+++ b/eval/src/tests/instruction/dense_inplace_join_function/dense_inplace_join_function_test.cpp
@@ -2,10 +2,6 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -15,10 +11,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
double seq_value = 0.0;
@@ -53,7 +48,7 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr, size_t param_idx) {
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
for (size_t i = 0; i < fixture.num_params(); ++i) {
TEST_STATE(vespalib::make_string("param %zu", i).c_str());
@@ -78,7 +73,7 @@ void verify_p2_optimized(const vespalib::string &expr) {
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
for (size_t i = 0; i < fixture.num_params(); ++i) {
EXPECT_NOT_EQUAL(fixture.get_param(i), fixture.result());
diff --git a/eval/src/tests/instruction/dense_matmul_function/dense_matmul_function_test.cpp b/eval/src/tests/instruction/dense_matmul_function/dense_matmul_function_test.cpp
index 1269d82a1e0..0bafa450ca2 100644
--- a/eval/src/tests/instruction/dense_matmul_function/dense_matmul_function_test.cpp
+++ b/eval/src/tests/instruction/dense_matmul_function/dense_matmul_function_test.cpp
@@ -6,7 +6,6 @@
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_matmul_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -16,7 +15,6 @@ using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
@@ -46,19 +44,6 @@ void verify_optimized(const vespalib::string &expr,
EXPECT_EQUAL(info[0]->rhs_size(), rhs_size);
EXPECT_EQUAL(info[0]->lhs_common_inner(), lhs_inner);
EXPECT_EQUAL(info[0]->rhs_common_inner(), rhs_inner);
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseMatMulFunction>();
- ASSERT_EQUAL(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
- EXPECT_EQUAL(info[0]->lhs_size(), lhs_size);
- EXPECT_EQUAL(info[0]->common_size(), common_size);
- EXPECT_EQUAL(info[0]->rhs_size(), rhs_size);
- EXPECT_EQUAL(info[0]->lhs_common_inner(), lhs_inner);
- EXPECT_EQUAL(info[0]->rhs_common_inner(), rhs_inner);
}
void verify_not_optimized(const vespalib::string &expr) {
@@ -68,13 +53,6 @@ void verify_not_optimized(const vespalib::string &expr) {
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseMatMulFunction>();
EXPECT_TRUE(info.empty());
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseMatMulFunction>();
- EXPECT_TRUE(info.empty());
}
TEST("require that matmul can be optimized") {
diff --git a/eval/src/tests/instruction/dense_multi_matmul_function/dense_multi_matmul_function_test.cpp b/eval/src/tests/instruction/dense_multi_matmul_function/dense_multi_matmul_function_test.cpp
index 8f4a06b2335..ac3abe4f05e 100644
--- a/eval/src/tests/instruction/dense_multi_matmul_function/dense_multi_matmul_function_test.cpp
+++ b/eval/src/tests/instruction/dense_multi_matmul_function/dense_multi_matmul_function_test.cpp
@@ -6,7 +6,6 @@
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -16,7 +15,6 @@ using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
@@ -54,20 +52,6 @@ void verify_optimized(const vespalib::string &expr,
EXPECT_EQUAL(info[0]->matmul_cnt(), matmul_cnt);
EXPECT_EQUAL(info[0]->lhs_common_inner(), lhs_inner);
EXPECT_EQUAL(info[0]->rhs_common_inner(), rhs_inner);
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseMultiMatMulFunction>();
- ASSERT_EQUAL(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
- EXPECT_EQUAL(info[0]->lhs_size(), lhs_size);
- EXPECT_EQUAL(info[0]->common_size(), common_size);
- EXPECT_EQUAL(info[0]->rhs_size(), rhs_size);
- EXPECT_EQUAL(info[0]->matmul_cnt(), matmul_cnt);
- EXPECT_EQUAL(info[0]->lhs_common_inner(), lhs_inner);
- EXPECT_EQUAL(info[0]->rhs_common_inner(), rhs_inner);
}
void verify_not_optimized(const vespalib::string &expr) {
@@ -77,13 +61,6 @@ void verify_not_optimized(const vespalib::string &expr) {
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseMultiMatMulFunction>();
EXPECT_TRUE(info.empty());
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseMultiMatMulFunction>();
- EXPECT_TRUE(info.empty());
}
TEST("require that multi matmul can be optimized") {
diff --git a/eval/src/tests/tensor/dense_pow_as_map_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_pow_as_map_optimizer/CMakeLists.txt
index d6ce9f1924c..d6ce9f1924c 100644
--- a/eval/src/tests/tensor/dense_pow_as_map_optimizer/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_pow_as_map_optimizer/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp b/eval/src/tests/instruction/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp
index 38d9ac8aeef..67567b4e289 100644
--- a/eval/src/tests/tensor/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp
+++ b/eval/src/tests/instruction/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp
@@ -1,8 +1,8 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_simple_map_function.h>
+#include <vespa/eval/instruction/dense_simple_map_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/gtest/gtest.h>
@@ -11,10 +11,9 @@ using namespace vespalib::eval::operation;
using namespace vespalib::eval::tensor_function;
using namespace vespalib::eval::test;
using namespace vespalib::eval;
-using namespace vespalib::tensor;
//using namespace vespalib;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -27,8 +26,8 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr, op1_t op1, bool inplace = false) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true, true);
EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQ(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleMapFunction>();
@@ -45,8 +44,8 @@ void verify_optimized(const vespalib::string &expr, op1_t op1, bool inplace = fa
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQ(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<Map>();
diff --git a/eval/src/tests/tensor/dense_remove_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt
index c945bd31609..c945bd31609 100644
--- a/eval/src/tests/tensor/dense_remove_dimension_optimizer/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp b/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp
index 179fdd3eff4..4c3c86be7f8 100644
--- a/eval/src/tests/tensor/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp
+++ b/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp
@@ -2,12 +2,8 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
-#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_fast_rename_optimizer.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -17,10 +13,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -32,14 +27,14 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_EQUAL(info.size(), 1u);
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseReplaceTypeFunction>();
EXPECT_TRUE(info.empty());
diff --git a/eval/src/tests/tensor/dense_replace_type_function/CMakeLists.txt b/eval/src/tests/instruction/dense_replace_type_function/CMakeLists.txt
index dd4a8a58082..dd4a8a58082 100644
--- a/eval/src/tests/tensor/dense_replace_type_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_replace_type_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp
index 84e79ff85e8..6b8e6faecf4 100644
--- a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp
+++ b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp
@@ -1,21 +1,20 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
using namespace vespalib::eval::tensor_function;
using namespace vespalib::eval::test;
using namespace vespalib::eval;
-using namespace vespalib::tensor;
using namespace vespalib;
-const TensorEngine &engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TypedCells getCellsRef(const eval::Value &value) {
+TypedCells getCellsRef(const Value &value) {
return value.cells();
}
@@ -23,7 +22,7 @@ struct ChildMock : Leaf {
bool is_mutable;
ChildMock(const ValueType &type) : Leaf(type), is_mutable(true) {}
bool result_is_mutable() const override { return is_mutable; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory, Stash &) const override { abort(); }
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &, Stash &) const override { abort(); }
};
struct Fixture {
@@ -34,16 +33,16 @@ struct Fixture {
std::vector<TensorFunction::Child::CREF> children;
InterpretedFunction::State state;
Fixture()
- : my_value(engine.from_spec(spec({x(10)}, N()))),
+ : my_value(value_from_spec(spec({x(10)}, N()), prod_factory)),
new_type(ValueType::from_spec("tensor(x[5],y[2])")),
mock_child(my_value->type()),
my_fun(new_type, mock_child),
children(),
- state(engine)
+ state(prod_factory)
{
my_fun.push_children(children);
state.stack.push_back(*my_value);
- my_fun.compile_self(engine, state.stash).perform(state);
+ my_fun.compile_self(prod_factory, state.stash).perform(state);
ASSERT_EQUAL(children.size(), 1u);
ASSERT_EQUAL(state.stack.size(), 1u);
ASSERT_TRUE(!new_type.is_error());
diff --git a/eval/src/tests/instruction/dense_simple_expand_function/dense_simple_expand_function_test.cpp b/eval/src/tests/instruction/dense_simple_expand_function/dense_simple_expand_function_test.cpp
index bf9b8a181aa..2c5566e045a 100644
--- a/eval/src/tests/instruction/dense_simple_expand_function/dense_simple_expand_function_test.cpp
+++ b/eval/src/tests/instruction/dense_simple_expand_function/dense_simple_expand_function_test.cpp
@@ -2,9 +2,6 @@
#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/eval/instruction/dense_simple_expand_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
@@ -17,7 +14,6 @@ using namespace vespalib::eval::tensor_function;
using Inner = DenseSimpleExpandFunction::Inner;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
@@ -49,18 +45,6 @@ void verify_optimized(const vespalib::string &expr, Inner inner) {
ASSERT_EQ(fixture.num_params(), 2);
EXPECT_TRUE(!(fixture.get_param(0) == fixture.result()));
EXPECT_TRUE(!(fixture.get_param(1) == fixture.result()));
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true, true);
- EXPECT_EQ(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQ(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseSimpleExpandFunction>();
- ASSERT_EQ(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
- EXPECT_EQ(info[0]->inner(), inner);
- ASSERT_EQ(old_fixture.num_params(), 2);
- EXPECT_TRUE(!(old_fixture.get_param(0) == old_fixture.result()));
- EXPECT_TRUE(!(old_fixture.get_param(1) == old_fixture.result()));
}
void verify_not_optimized(const vespalib::string &expr) {
@@ -70,13 +54,6 @@ void verify_not_optimized(const vespalib::string &expr) {
EXPECT_EQ(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleExpandFunction>();
EXPECT_TRUE(info.empty());
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQ(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQ(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseSimpleExpandFunction>();
- EXPECT_TRUE(info.empty());
}
TEST(ExpandTest, simple_expand_is_optimized) {
diff --git a/eval/src/tests/tensor/dense_simple_join_function/CMakeLists.txt b/eval/src/tests/instruction/dense_simple_join_function/CMakeLists.txt
index 8a2df392145..8a2df392145 100644
--- a/eval/src/tests/tensor/dense_simple_join_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_simple_join_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_simple_join_function/dense_simple_join_function_test.cpp b/eval/src/tests/instruction/dense_simple_join_function/dense_simple_join_function_test.cpp
index 34e5363d313..2186d49385e 100644
--- a/eval/src/tests/tensor/dense_simple_join_function/dense_simple_join_function_test.cpp
+++ b/eval/src/tests/instruction/dense_simple_join_function/dense_simple_join_function_test.cpp
@@ -2,10 +2,7 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_simple_join_function.h>
+#include <vespa/eval/instruction/dense_simple_join_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
@@ -14,7 +11,6 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
using vespalib::make_string_short::fmt;
@@ -22,7 +18,7 @@ using vespalib::make_string_short::fmt;
using Primary = DenseSimpleJoinFunction::Primary;
using Overlap = DenseSimpleJoinFunction::Overlap;
-namespace vespalib::tensor {
+namespace vespalib::eval {
std::ostream &operator<<(std::ostream &os, Primary primary)
{
@@ -45,7 +41,7 @@ std::ostream &operator<<(std::ostream &os, Overlap overlap)
}
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -69,8 +65,8 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr, Primary primary, Overlap overlap, bool pri_mut, size_t factor, int p_inplace = -1) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleJoinFunction>();
@@ -91,8 +87,8 @@ void verify_optimized(const vespalib::string &expr, Primary primary, Overlap ove
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleJoinFunction>();
diff --git a/eval/src/tests/tensor/dense_simple_map_function/CMakeLists.txt b/eval/src/tests/instruction/dense_simple_map_function/CMakeLists.txt
index 8d3bb8c92aa..8d3bb8c92aa 100644
--- a/eval/src/tests/tensor/dense_simple_map_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_simple_map_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_simple_map_function/dense_simple_map_function_test.cpp b/eval/src/tests/instruction/dense_simple_map_function/dense_simple_map_function_test.cpp
index 99ec719fa2f..13a24c13a2e 100644
--- a/eval/src/tests/tensor/dense_simple_map_function/dense_simple_map_function_test.cpp
+++ b/eval/src/tests/instruction/dense_simple_map_function/dense_simple_map_function_test.cpp
@@ -1,10 +1,7 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_simple_map_function.h>
+#include <vespa/eval/instruction/dense_simple_map_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/gtest/gtest.h>
@@ -13,9 +10,8 @@ using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::eval::tensor_function;
-using namespace vespalib::tensor;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -28,8 +24,8 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify_optimized(const vespalib::string &expr, bool inplace) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true, true);
EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQ(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleMapFunction>();
@@ -45,8 +41,8 @@ void verify_optimized(const vespalib::string &expr, bool inplace) {
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQ(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSimpleMapFunction>();
diff --git a/eval/src/tests/tensor/dense_single_reduce_function/CMakeLists.txt b/eval/src/tests/instruction/dense_single_reduce_function/CMakeLists.txt
index 42b00699c31..42b00699c31 100644
--- a/eval/src/tests/tensor/dense_single_reduce_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_single_reduce_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_single_reduce_function/dense_single_reduce_function_test.cpp b/eval/src/tests/instruction/dense_single_reduce_function/dense_single_reduce_function_test.cpp
index d3495befe7e..c6da0b94de3 100644
--- a/eval/src/tests/tensor/dense_single_reduce_function/dense_single_reduce_function_test.cpp
+++ b/eval/src/tests/instruction/dense_single_reduce_function/dense_single_reduce_function_test.cpp
@@ -3,12 +3,7 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_single_reduce_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
+#include <vespa/eval/instruction/dense_single_reduce_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -18,10 +13,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -45,8 +39,8 @@ struct ReduceSpec {
};
void verify_optimized_impl(const vespalib::string &expr, const std::vector<ReduceSpec> &spec_list) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSingleReduceFunction>();
@@ -69,8 +63,8 @@ void verify_optimized(const vespalib::string &expr, const ReduceSpec &spec1, con
}
void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseSingleReduceFunction>();
diff --git a/eval/src/tests/tensor/dense_tensor_create_function/CMakeLists.txt b/eval/src/tests/instruction/dense_tensor_create_function/CMakeLists.txt
index 883f331bda8..883f331bda8 100644
--- a/eval/src/tests/tensor/dense_tensor_create_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/dense_tensor_create_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/dense_tensor_create_function/dense_tensor_create_function_test.cpp b/eval/src/tests/instruction/dense_tensor_create_function/dense_tensor_create_function_test.cpp
index 6ae0681d2ff..25bbe5b422c 100644
--- a/eval/src/tests/tensor/dense_tensor_create_function/dense_tensor_create_function_test.cpp
+++ b/eval/src/tests/instruction/dense_tensor_create_function/dense_tensor_create_function_test.cpp
@@ -2,11 +2,7 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_tensor_create_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/dense_tensor_create_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -16,10 +12,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -30,7 +25,7 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify(const vespalib::string &expr, size_t expect_optimized_cnt, size_t expect_not_optimized_cnt) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<DenseTensorCreateFunction>();
EXPECT_EQUAL(info.size(), expect_optimized_cnt);
diff --git a/eval/src/tests/instruction/dense_tensor_peek_function/dense_tensor_peek_function_test.cpp b/eval/src/tests/instruction/dense_tensor_peek_function/dense_tensor_peek_function_test.cpp
index df9271784b9..195b1f0e6ab 100644
--- a/eval/src/tests/instruction/dense_tensor_peek_function/dense_tensor_peek_function_test.cpp
+++ b/eval/src/tests/instruction/dense_tensor_peek_function/dense_tensor_peek_function_test.cpp
@@ -5,7 +5,6 @@
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_tensor_peek_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -15,7 +14,6 @@ using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
@@ -43,15 +41,6 @@ void verify(const vespalib::string &expr, double expect, size_t expect_optimized
EXPECT_TRUE(info[i]->result_is_mutable());
}
EXPECT_EQUAL(fixture.find_all<Peek>().size(), expect_not_optimized_cnt);
-
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), expect_spec);
- info = old_fixture.find_all<DenseTensorPeekFunction>();
- EXPECT_EQUAL(info.size(), expect_optimized_cnt);
- for (size_t i = 0; i < info.size(); ++i) {
- EXPECT_TRUE(info[i]->result_is_mutable());
- }
- EXPECT_EQUAL(old_fixture.find_all<Peek>().size(), expect_not_optimized_cnt);
}
//-----------------------------------------------------------------------------
diff --git a/eval/src/tests/instruction/dense_xw_product_function/dense_xw_product_function_test.cpp b/eval/src/tests/instruction/dense_xw_product_function/dense_xw_product_function_test.cpp
index 769657ae0a2..bd69310972c 100644
--- a/eval/src/tests/instruction/dense_xw_product_function/dense_xw_product_function_test.cpp
+++ b/eval/src/tests/instruction/dense_xw_product_function/dense_xw_product_function_test.cpp
@@ -7,7 +7,6 @@
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_xw_product_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>
@@ -17,7 +16,6 @@ using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &old_engine = tensor::DefaultTensorEngine::ref();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
struct First {
@@ -78,17 +76,6 @@ void verify_optimized(const vespalib::string &expr, size_t vec_size, size_t res_
EXPECT_EQUAL(info[0]->vector_size(), vec_size);
EXPECT_EQUAL(info[0]->result_size(), res_size);
EXPECT_EQUAL(info[0]->common_inner(), happy);
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseXWProductFunction>();
- ASSERT_EQUAL(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
- EXPECT_EQUAL(info[0]->vector_size(), vec_size);
- EXPECT_EQUAL(info[0]->result_size(), res_size);
- EXPECT_EQUAL(info[0]->common_inner(), happy);
}
vespalib::string make_expr(const vespalib::string &a, const vespalib::string &b, const vespalib::string &common,
@@ -119,13 +106,6 @@ void verify_not_optimized(const vespalib::string &expr) {
EXPECT_EQUAL(fixture.result(), slow_fixture.result());
auto info = fixture.find_all<DenseXWProductFunction>();
EXPECT_TRUE(info.empty());
-
- EvalFixture old_slow_fixture(old_engine, expr, param_repo, false);
- EvalFixture old_fixture(old_engine, expr, param_repo, true);
- EXPECT_EQUAL(old_fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(old_fixture.result(), old_slow_fixture.result());
- info = old_fixture.find_all<DenseXWProductFunction>();
- EXPECT_TRUE(info.empty());
}
TEST("require that xw product gives same results as reference join/reduce") {
diff --git a/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp b/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
index c59d9783648..cfecdb97aa0 100644
--- a/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
+++ b/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
@@ -3,8 +3,6 @@
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/instruction/generic_concat.h>
#include <vespa/eval/eval/interpreted_function.h>
@@ -58,13 +56,6 @@ std::vector<Layout> concat_layouts = {
{y(2),x({"a","b"})}, {y(3),z({"c","d"})}
};
-TensorSpec perform_simpletensor_concat(const TensorSpec &a, const TensorSpec &b, const std::string &dimension) {
- auto lhs = SimpleTensor::create(a);
- auto rhs = SimpleTensor::create(b);
- auto out = SimpleTensor::concat(*lhs, *rhs, dimension);
- return SimpleTensorEngine::ref().to_spec(*out);
-}
-
TensorSpec perform_generic_concat(const TensorSpec &a, const TensorSpec &b,
const std::string &concat_dim, const ValueBuilderFactory &factory)
{
@@ -76,18 +67,6 @@ TensorSpec perform_generic_concat(const TensorSpec &a, const TensorSpec &b,
return spec_from_value(single.eval(std::vector<Value::CREF>({*lhs,*rhs})));
}
-TEST(GenericConcatTest, generic_reference_concat_works) {
- ASSERT_TRUE((concat_layouts.size() % 2) == 0);
- for (size_t i = 0; i < concat_layouts.size(); i += 2) {
- const TensorSpec lhs = spec(concat_layouts[i], N());
- const TensorSpec rhs = spec(concat_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nin LHS: %s\nin RHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto actual = ReferenceOperations::concat(lhs, rhs, "y");
- auto expect = perform_simpletensor_concat(lhs, rhs, "y");
- EXPECT_EQ(actual, expect);
- }
-}
-
void test_generic_concat_with(const ValueBuilderFactory &factory) {
ASSERT_TRUE((concat_layouts.size() % 2) == 0);
for (size_t i = 0; i < concat_layouts.size(); i += 2) {
@@ -131,24 +110,5 @@ TEST(GenericConcatTest, dense_concat_plan_can_be_created) {
EXPECT_EQ(plan.right.out_stride, expect_right_out_s);
}
-TensorSpec immediate_generic_concat(const TensorSpec &a, const TensorSpec &b, const std::string &concat_dim) {
- const auto &factory = SimpleValueBuilderFactory::get();
- auto lhs = value_from_spec(a, factory);
- auto rhs = value_from_spec(b, factory);
- auto up = GenericConcat::perform_concat(*lhs, *rhs, concat_dim, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericConcatTest, immediate_generic_concat_works) {
- ASSERT_TRUE((concat_layouts.size() % 2) == 0);
- for (size_t i = 0; i < concat_layouts.size(); i += 2) {
- const TensorSpec lhs = spec(concat_layouts[i], N());
- const TensorSpec rhs = spec(concat_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nin LHS: %s\nin RHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto actual = immediate_generic_concat(lhs, rhs, "y");
- auto expect = ReferenceOperations::concat(lhs, rhs, "y");
- EXPECT_EQ(actual, expect);
- }
-}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_create/generic_create_test.cpp b/eval/src/tests/instruction/generic_create/generic_create_test.cpp
index 42af4ba6621..00af75e4d83 100644
--- a/eval/src/tests/instruction/generic_create/generic_create_test.cpp
+++ b/eval/src/tests/instruction/generic_create/generic_create_test.cpp
@@ -94,15 +94,12 @@ void test_generic_create_with(const ValueBuilderFactory &factory) {
for (const auto & layout : create_layouts) {
TensorSpec full = spec(layout, N());
auto actual = perform_generic_create(full, factory);
- auto ref_spec = reference_create(full);
- // use SimpleValue to add implicit cells with default value
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
+ auto expect = reference_create(full).normalize();
EXPECT_EQ(actual, expect);
for (size_t n : {2, 3, 4, 5}) {
TensorSpec partial = remove_each(full, n);
actual = perform_generic_create(partial, factory);
- ref_spec = reference_create(partial);
- expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
+ expect = reference_create(partial).normalize();
EXPECT_EQ(actual, expect);
}
}
diff --git a/eval/src/tests/instruction/generic_join/generic_join_test.cpp b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
index a81294c8d25..f4046b3d059 100644
--- a/eval/src/tests/instruction/generic_join/generic_join_test.cpp
+++ b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
@@ -123,26 +123,5 @@ TEST(GenericJoinTest, generic_join_works_for_simple_and_fast_values) {
}
}
-TensorSpec immediate_generic_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
- const auto &factory = SimpleValueBuilderFactory::get();
- auto lhs = value_from_spec(a, factory);
- auto rhs = value_from_spec(b, factory);
- auto up = GenericJoin::perform_join(*lhs, *rhs, function, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericJoinTest, immediate_generic_join_works) {
- ASSERT_TRUE((join_layouts.size() % 2) == 0);
- for (size_t i = 0; i < join_layouts.size(); i += 2) {
- TensorSpec lhs = spec(join_layouts[i], Div16(N()));
- TensorSpec rhs = spec(join_layouts[i + 1], Div16(N()));
- for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Div::f}) {
- SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto expect = ReferenceOperations::join(lhs, rhs, fun);
- auto actual = immediate_generic_join(lhs, rhs, fun);
- EXPECT_EQ(actual, expect);
- }
- }
-}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_map/generic_map_test.cpp b/eval/src/tests/instruction/generic_map/generic_map_test.cpp
index ba6a1630777..687b6aa60ac 100644
--- a/eval/src/tests/instruction/generic_map/generic_map_test.cpp
+++ b/eval/src/tests/instruction/generic_map/generic_map_test.cpp
@@ -60,24 +60,4 @@ TEST(GenericMapTest, generic_map_works_for_fast_values) {
test_generic_map_with(FastValueBuilderFactory::get());
}
-TensorSpec immediate_generic_map(const TensorSpec &a, map_fun_t func, const ValueBuilderFactory &factory)
-{
- auto lhs = value_from_spec(a, factory);
- auto up = GenericMap::perform_map(*lhs, func, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericMapTest, immediate_generic_map_works) {
- for (const auto & layout : map_layouts) {
- TensorSpec lhs = spec(layout, Div16(N()));
- ValueType lhs_type = ValueType::from_spec(lhs.type());
- for (auto func : {operation::Floor::f, operation::Fabs::f, operation::Square::f, operation::Inv::f}) {
- SCOPED_TRACE(fmt("\n===\nLHS: %s\n===\n", lhs.to_string().c_str()));
- auto expect = ReferenceOperations::map(lhs, func);
- auto actual = immediate_generic_map(lhs, func, SimpleValueBuilderFactory::get());
- EXPECT_EQ(actual, expect);
- }
- }
-}
-
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp b/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
index a43169a6959..60a27e6f6e9 100644
--- a/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
+++ b/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
@@ -65,26 +65,5 @@ TEST(GenericMergeTest, generic_merge_works_for_fast_values) {
test_generic_merge_with(FastValueBuilderFactory::get());
}
-TensorSpec immediate_generic_merge(const TensorSpec &a, const TensorSpec &b, join_fun_t fun) {
- const auto &factory = SimpleValueBuilderFactory::get();
- auto lhs = value_from_spec(a, factory);
- auto rhs = value_from_spec(b, factory);
- auto up = GenericMerge::perform_merge(*lhs, *rhs, fun, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericMergeTest, immediate_generic_merge_works) {
- ASSERT_TRUE((merge_layouts.size() % 2) == 0);
- for (size_t i = 0; i < merge_layouts.size(); i += 2) {
- TensorSpec lhs = spec(merge_layouts[i], N());
- TensorSpec rhs = spec(merge_layouts[i + 1], Div16(N()));
- SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- for (auto fun: {operation::Add::f, operation::Mul::f, operation::Sub::f, operation::Max::f}) {
- auto expect = ReferenceOperations::merge(lhs, rhs, fun);
- auto actual = immediate_generic_merge(lhs, rhs, fun);
- EXPECT_EQ(actual, expect);
- }
- }
-}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp b/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
index 18b1d6903dd..6841215038a 100644
--- a/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
+++ b/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
@@ -39,6 +39,7 @@ using PeekSpec = GenericPeek::SpecMap;
TensorSpec reference_peek(const TensorSpec &param, const PeekSpec &spec) {
std::vector<TensorSpec> children;
+ children.push_back(param);
PeekSpec with_indexes;
for (const auto & [dim_name, label_or_child] : spec) {
const vespalib::string &dim = dim_name;
@@ -59,7 +60,7 @@ TensorSpec reference_peek(const TensorSpec &param, const PeekSpec &spec) {
}
}, label_or_child);
}
- return ReferenceOperations::peek(param, with_indexes, children);
+ return ReferenceOperations::peek(with_indexes, children);
}
TensorSpec perform_generic_peek(const TensorSpec &a, const ValueType &result_type,
@@ -71,7 +72,7 @@ TensorSpec perform_generic_peek(const TensorSpec &a, const ValueType &result_typ
Stash stash;
std::vector<Value::CREF> my_stack;
my_stack.push_back(*param);
- size_t child_idx = 0;
+ size_t child_idx = 1;
for (auto & [dim_name, label_or_child] : spec) {
if (std::holds_alternative<size_t>(label_or_child)) {
// here, label_or_child is a size_t specifying the value
@@ -151,9 +152,7 @@ void verify_peek_equal(const TensorSpec &input,
}
if (reduce_dims.empty()) return;
ValueType result_type = param_type.reduce(reduce_dims);
- auto ref_spec = reference_peek(input, spec);
- // use SimpleValue to add implicit cells with default value
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
+ auto expect = reference_peek(input, spec).normalize();
SCOPED_TRACE(fmt("peek input: %s\n peek spec: %s\n peek result %s\n",
input.to_string().c_str(),
to_str(spec).c_str(),
diff --git a/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp b/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
index fa55406be3a..3ab971dd34d 100644
--- a/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
+++ b/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
@@ -35,8 +35,8 @@ std::vector<Layout> layouts = {
float_cells({x({"a","b","c"}),y(5),z({"i","j","k","l"})})
};
-TensorSpec perform_generic_reduce(const TensorSpec &a, const std::vector<vespalib::string> &dims,
- Aggr aggr, const ValueBuilderFactory &factory)
+TensorSpec perform_generic_reduce(const TensorSpec &a, Aggr aggr, const std::vector<vespalib::string> &dims,
+ const ValueBuilderFactory &factory)
{
Stash stash;
auto lhs = value_from_spec(a, factory);
@@ -71,15 +71,12 @@ void test_generic_reduce_with(const ValueBuilderFactory &factory) {
TensorSpec input = spec(layout, Div16(N()));
for (Aggr aggr: {Aggr::SUM, Aggr::AVG, Aggr::MIN, Aggr::MAX}) {
for (const Domain &domain: layout) {
- auto ref_spec = ReferenceOperations::reduce(input, {domain.dimension}, aggr);
- // use SimpleValue to add implicit cells with default value
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
- auto actual = perform_generic_reduce(input, {domain.dimension}, aggr, factory);
+ auto expect = ReferenceOperations::reduce(input, aggr, {domain.dimension}).normalize();
+ auto actual = perform_generic_reduce(input, aggr, {domain.dimension}, factory);
EXPECT_EQ(actual, expect);
}
- auto ref_spec = ReferenceOperations::reduce(input, {}, aggr);
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
- auto actual = perform_generic_reduce(input, {}, aggr, factory);
+ auto expect = ReferenceOperations::reduce(input, aggr, {}).normalize();
+ auto actual = perform_generic_reduce(input, aggr, {}, factory);
EXPECT_EQ(actual, expect);
}
}
@@ -93,30 +90,5 @@ TEST(GenericReduceTest, generic_reduce_works_for_fast_values) {
test_generic_reduce_with(FastValueBuilderFactory::get());
}
-TensorSpec immediate_generic_reduce(const TensorSpec &a, const std::vector<vespalib::string> &dims, Aggr aggr) {
- const auto &factory = SimpleValueBuilderFactory::get();
- auto lhs = value_from_spec(a, factory);
- auto up = GenericReduce::perform_reduce(*lhs, aggr, dims, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericReduceTest, immediate_generic_reduce_works) {
- for (const Layout &layout: layouts) {
- TensorSpec input = spec(layout, Div16(N()));
- for (Aggr aggr: {Aggr::SUM, Aggr::AVG, Aggr::MIN, Aggr::MAX}) {
- for (const Domain &domain: layout) {
- auto ref_spec = ReferenceOperations::reduce(input, {domain.dimension}, aggr);
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
- auto actual = immediate_generic_reduce(input, {domain.dimension}, aggr);
- EXPECT_EQ(actual, expect);
- }
- auto ref_spec = ReferenceOperations::reduce(input, {}, aggr);
- auto expect = spec_from_value(*value_from_spec(ref_spec, SimpleValueBuilderFactory::get()));
- auto actual = immediate_generic_reduce(input, {}, aggr);
- EXPECT_EQ(actual, expect);
- }
- }
-}
-
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
index a7e6b8d807b..20d155822b5 100644
--- a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
+++ b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
@@ -134,29 +134,4 @@ TEST(GenericRenameTest, generic_rename_works_for_fast_values) {
test_generic_rename_with(FastValueBuilderFactory::get());
}
-TensorSpec immediate_generic_rename(const TensorSpec &a, const FromTo &ft)
-{
- auto &factory = SimpleValueBuilderFactory::get();
- auto lhs = value_from_spec(a, factory);
- auto up = GenericRename::perform_rename(*lhs, ft.from, ft.to, factory);
- return spec_from_value(*up);
-}
-
-TEST(GenericRenameTest, immediate_generic_rename_works) {
- for (const auto & layout : rename_layouts) {
- TensorSpec lhs = spec(layout, N());
- ValueType lhs_type = ValueType::from_spec(lhs.type());
- // printf("lhs_type: %s\n", lhs_type.to_spec().c_str());
- for (const auto & from_to : rename_from_to) {
- ValueType renamed_type = lhs_type.rename(from_to.from, from_to.to);
- if (renamed_type.is_error()) continue;
- // printf("type %s -> %s\n", lhs_type.to_spec().c_str(), renamed_type.to_spec().c_str());
- SCOPED_TRACE(fmt("\n===\nLHS: %s\n===\n", lhs.to_string().c_str()));
- auto expect = ReferenceOperations::rename(lhs, from_to.from, from_to.to);
- auto actual = immediate_generic_rename(lhs, from_to);
- EXPECT_EQ(actual, expect);
- }
- }
-}
-
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/tensor/vector_from_doubles_function/CMakeLists.txt b/eval/src/tests/instruction/vector_from_doubles_function/CMakeLists.txt
index 5b2e47ec498..5b2e47ec498 100644
--- a/eval/src/tests/tensor/vector_from_doubles_function/CMakeLists.txt
+++ b/eval/src/tests/instruction/vector_from_doubles_function/CMakeLists.txt
diff --git a/eval/src/tests/tensor/vector_from_doubles_function/vector_from_doubles_function_test.cpp b/eval/src/tests/instruction/vector_from_doubles_function/vector_from_doubles_function_test.cpp
index 41d98122e0f..4f4829c3ae1 100644
--- a/eval/src/tests/tensor/vector_from_doubles_function/vector_from_doubles_function_test.cpp
+++ b/eval/src/tests/instruction/vector_from_doubles_function/vector_from_doubles_function_test.cpp
@@ -2,11 +2,7 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/vector_from_doubles_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/instruction/vector_from_doubles_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>
@@ -16,10 +12,9 @@
using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
@@ -32,7 +27,7 @@ EvalFixture::ParamRepo make_params() {
EvalFixture::ParamRepo param_repo = make_params();
void verify(const vespalib::string &expr, size_t expect_optimized_cnt, size_t expect_not_optimized_cnt) {
- EvalFixture fixture(prod_engine, expr, param_repo, true);
+ EvalFixture fixture(prod_factory, expr, param_repo, true);
EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
auto info = fixture.find_all<VectorFromDoublesFunction>();
EXPECT_EQUAL(info.size(), expect_optimized_cnt);
diff --git a/eval/src/tests/streamed/value/streamed_value_test.cpp b/eval/src/tests/streamed/value/streamed_value_test.cpp
index 3de6ba0fb63..05d6e20451c 100644
--- a/eval/src/tests/streamed/value/streamed_value_test.cpp
+++ b/eval/src/tests/streamed/value/streamed_value_test.cpp
@@ -1,6 +1,7 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/eval/streamed/streamed_value_builder_factory.h>
+#include <vespa/eval/eval/test/reference_operations.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/instruction/generic_join.h>
#include <vespa/eval/eval/interpreted_function.h>
@@ -59,16 +60,7 @@ std::vector<Layout> join_layouts = {
float_cells({x({"a","b","c"}),y(5)}), float_cells({y(5),z({"i","j","k","l"})})
};
-TensorSpec simple_tensor_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
- Stash stash;
- const auto &engine = SimpleTensorEngine::ref();
- auto lhs = engine.from_spec(a);
- auto rhs = engine.from_spec(b);
- const auto &result = engine.join(*lhs, *rhs, function, stash);
- return engine.to_spec(result);
-}
-
-TensorSpec streamed_value_new_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
+TensorSpec streamed_value_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
Stash stash;
const auto &factory = StreamedValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
@@ -126,8 +118,8 @@ TEST(StreamedValueTest, new_generic_join_works_for_streamed_values) {
TensorSpec rhs = spec(join_layouts[i + 1], Div16(N()));
for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Max::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
- auto expect = simple_tensor_join(lhs, rhs, fun);
- auto actual = streamed_value_new_join(lhs, rhs, fun);
+ auto expect = ReferenceOperations::join(lhs, rhs, fun);
+ auto actual = streamed_value_join(lhs, rhs, fun);
EXPECT_EQ(actual, expect);
}
}
diff --git a/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt b/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt
deleted file mode 100644
index eaee8ebb4e4..00000000000
--- a/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-vespa_add_executable(eval_dense_dimension_combiner_test_app TEST
- SOURCES
- dense_dimension_combiner_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_dense_dimension_combiner_test_app COMMAND eval_dense_dimension_combiner_test_app)
diff --git a/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp b/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp
deleted file mode 100644
index b8949e3a7e6..00000000000
--- a/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/dense/dense_dimension_combiner.h>
-
-using namespace vespalib;
-using namespace vespalib::eval;
-using namespace vespalib::tensor;
-
-void verifyLeft(DenseDimensionCombiner &d, size_t last) {
- d.commonReset();
- d.leftReset();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
- size_t expect = 0;
- while (d.leftInRange()) {
- d.stepLeft();
- EXPECT_GREATER(d.leftIdx(), expect);
- expect = d.leftIdx();
- }
- EXPECT_FALSE(d.leftInRange());
- EXPECT_EQUAL(expect, last);
- d.leftReset();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
-}
-
-void verifyRight(DenseDimensionCombiner &d, size_t last) {
- d.commonReset();
- d.rightReset();
- EXPECT_TRUE(d.rightInRange());
- EXPECT_EQUAL(d.rightIdx(), 0u);
- size_t expect = 0;
- while (d.rightInRange()) {
- d.stepRight();
- EXPECT_GREATER(d.rightIdx(), expect);
- expect = d.rightIdx();
- }
- EXPECT_FALSE(d.rightInRange());
- EXPECT_EQUAL(expect, last);
- d.rightReset();
- EXPECT_TRUE(d.rightInRange());
- EXPECT_EQUAL(d.rightIdx(), 0u);
-}
-
-
-TEST("require that one left, one common, one right dimension works") {
- ValueType t12_lc = ValueType::tensor_type({{"d1_l", 3},{"d2_c", 4}});
- ValueType t23_cr = ValueType::tensor_type({{"d2_c", 4},{"d3_r", 5}});
-
- DenseDimensionCombiner d(t12_lc, t23_cr);
-
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
- EXPECT_EQUAL(d.rightIdx(), 0u);
- EXPECT_EQUAL(d.outputIdx(), 0u);
-
- d.stepCommon();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 1u);
- EXPECT_EQUAL(d.rightIdx(), 5u);
- EXPECT_EQUAL(d.outputIdx(), 5u);
-
- d.stepRight();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 1u);
- EXPECT_EQUAL(d.rightIdx(), 6u);
- EXPECT_EQUAL(d.outputIdx(), 6u);
-
- d.stepLeft();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 5u);
- EXPECT_EQUAL(d.rightIdx(), 6u);
- EXPECT_EQUAL(d.outputIdx(), 26u);
-
- d.stepLeft();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 9u);
- EXPECT_EQUAL(d.rightIdx(), 6u);
- EXPECT_EQUAL(d.outputIdx(), 46u);
-
- d.stepLeft();
- EXPECT_FALSE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 13u);
- EXPECT_EQUAL(d.rightIdx(), 6u);
- EXPECT_EQUAL(d.outputIdx(), 6u);
-
- d.leftReset();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 1u);
- EXPECT_EQUAL(d.rightIdx(), 6u);
- EXPECT_EQUAL(d.outputIdx(), 6u);
-
- d.stepCommon();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 2u);
- EXPECT_EQUAL(d.rightIdx(), 11u);
- EXPECT_EQUAL(d.outputIdx(), 11u);
-
- d.stepRight();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 2u);
- EXPECT_EQUAL(d.rightIdx(), 12u);
- EXPECT_EQUAL(d.outputIdx(), 12u);
-
- TEST_DO(verifyLeft(d, 12));
- TEST_DO(verifyRight(d, 20));
-}
-
-TEST("require that two left, no common, two right dimensions works") {
- ValueType t12_ll = ValueType::tensor_type({{"d1_l", 3},{"d2_l", 4}});
- ValueType t34_rr = ValueType::tensor_type({{"d3_r", 5},{"d4_r", 2}});
-
- DenseDimensionCombiner d(t12_ll, t34_rr);
-
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
- EXPECT_EQUAL(d.rightIdx(), 0u);
- EXPECT_EQUAL(d.outputIdx(), 0u);
-
- d.stepCommon();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_FALSE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
- EXPECT_EQUAL(d.rightIdx(), 0u);
- EXPECT_EQUAL(d.outputIdx(), 120u);
-
- d.commonReset();
- d.stepRight();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 0u);
- EXPECT_EQUAL(d.rightIdx(), 1u);
- EXPECT_EQUAL(d.outputIdx(), 1u);
-
- d.stepLeft();
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 1u);
- EXPECT_EQUAL(d.rightIdx(), 1u);
- EXPECT_EQUAL(d.outputIdx(), 11u);
-
- d.stepLeft();
- d.stepLeft();
- d.stepLeft();
- d.stepLeft();
- d.stepLeft();
- d.stepLeft();
- d.stepLeft();
-
- EXPECT_TRUE(d.leftInRange());
- EXPECT_TRUE(d.rightInRange());
- EXPECT_TRUE(d.commonInRange());
- EXPECT_EQUAL(d.leftIdx(), 8u);
- EXPECT_EQUAL(d.rightIdx(), 1u);
- EXPECT_EQUAL(d.outputIdx(), 81u);
-
- TEST_DO(verifyLeft(d, 12));
- TEST_DO(verifyRight(d, 10));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt b/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt
deleted file mode 100644
index 1fbb35cb2b8..00000000000
--- a/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_dense_generic_join_test_app TEST
- SOURCES
- dense_generic_join_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_dense_generic_join_test_app COMMAND eval_dense_generic_join_test_app)
diff --git a/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp b/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp
deleted file mode 100644
index 395437e13dd..00000000000
--- a/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/typed_dense_tensor_builder.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
-#include <vespa/eval/eval/test/tensor_model.hpp>
-#include <vespa/eval/eval/test/eval_fixture.h>
-
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/util/stash.h>
-
-using namespace vespalib;
-using namespace vespalib::eval;
-using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
-using namespace vespalib::eval::tensor_function;
-
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
-
-double seq_value = 0.0;
-
-struct GlobalSequence : public Sequence {
- GlobalSequence() {}
- double operator[](size_t) const override {
- seq_value += 1.0;
- return seq_value;
- }
- ~GlobalSequence() {}
-};
-GlobalSequence seq;
-
-EvalFixture::ParamRepo make_params() {
- return EvalFixture::ParamRepo()
- .add("con_x5_A", spec({x(5) }, seq))
- .add("con_x5y3_B", spec({x(5),y(3) }, seq))
- .add("con_x5z4_C", spec({x(5), z(4)}, seq))
- .add("con_x5y3z4_D", spec({x(5),y(3),z(4)}, seq))
- .add("con_y3_E", spec({ y(3) }, seq))
- .add("con_y3z4_F", spec({ y(3),z(4)}, seq))
- .add("con_z4_G", spec({ z(4)}, seq))
- .add("con_x5f_H", spec({x(5) }, seq), "tensor<float>(x[5])")
- .add("con_x5y3_I", spec({x(5),y(3) }, seq), "tensor<float>(x[5],y[3])")
- .add("con_x5z4_J", spec({x(5), z(4)}, seq), "tensor<float>(x[5],z[4])")
- .add("con_x5y3z4_K", spec({x(5),y(3),z(4)}, seq), "tensor<float>(x[5],y[3],z[4])")
- .add("con_y3_L", spec({ y(3) }, seq), "tensor<float>(y[3])")
- .add("con_y3z4_M", spec({ y(3),z(4)}, seq), "tensor<float>(y[3],z[4])))")
- .add("con_z4_N", spec({ z(4)}, seq), "tensor<float>(z[4]))")
- .add("con_y2", spec({y(5)}, seq))
- .add("con_y2f", spec({y(5)}, seq), "tensor<float>(y[2]))");
-}
-EvalFixture::ParamRepo param_repo = make_params();
-
-void verify_equal(const vespalib::string &expr) {
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
- EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
-}
-
-
-TEST("require that non-overlapping dense join works") {
- TEST_DO(verify_equal("con_x5_A-con_y3_E"));
- TEST_DO(verify_equal("con_x5_A+con_y3_E"));
- TEST_DO(verify_equal("con_x5_A*con_y3_E"));
-
- TEST_DO(verify_equal("con_x5_A-con_y3z4_F"));
- TEST_DO(verify_equal("con_x5_A+con_y3z4_F"));
- TEST_DO(verify_equal("con_x5_A*con_y3z4_F"));
-
- TEST_DO(verify_equal("con_x5_A-con_z4_G"));
- TEST_DO(verify_equal("con_x5_A+con_z4_G"));
- TEST_DO(verify_equal("con_x5_A*con_z4_G"));
-
- TEST_DO(verify_equal("con_x5y3_B-con_z4_G"));
- TEST_DO(verify_equal("con_x5y3_B+con_z4_G"));
- TEST_DO(verify_equal("con_x5y3_B*con_z4_G"));
-
- TEST_DO(verify_equal("con_y3_E-con_z4_G"));
- TEST_DO(verify_equal("con_y3_E+con_z4_G"));
- TEST_DO(verify_equal("con_y3_E*con_z4_G"));
-}
-
-TEST("require that overlapping dense join works") {
- TEST_DO(verify_equal("con_x5_A-con_x5y3_B"));
- TEST_DO(verify_equal("con_x5_A+con_x5y3_B"));
- TEST_DO(verify_equal("con_x5_A*con_x5y3_B"));
-
- TEST_DO(verify_equal("con_x5_A-con_x5z4_C"));
- TEST_DO(verify_equal("con_x5_A+con_x5z4_C"));
- TEST_DO(verify_equal("con_x5_A*con_x5z4_C"));
-
- TEST_DO(verify_equal("con_x5y3_B-con_y3_E"));
- TEST_DO(verify_equal("con_x5y3_B+con_y3_E"));
- TEST_DO(verify_equal("con_x5y3_B*con_y3_E"));
-
- TEST_DO(verify_equal("con_x5y3_B-con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3_B+con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3_B*con_y3z4_F"));
-
- TEST_DO(verify_equal("con_x5y3z4_D-con_x5y3_B"));
- TEST_DO(verify_equal("con_x5y3z4_D+con_x5y3_B"));
- TEST_DO(verify_equal("con_x5y3z4_D*con_x5y3_B"));
-
- TEST_DO(verify_equal("con_x5y3z4_D-con_x5z4_C"));
- TEST_DO(verify_equal("con_x5y3z4_D+con_x5z4_C"));
- TEST_DO(verify_equal("con_x5y3z4_D*con_x5z4_C"));
-
- TEST_DO(verify_equal("con_x5y3z4_D-con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3z4_D+con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3z4_D*con_y3z4_F"));
-
- TEST_DO(verify_equal("con_x5y3z4_D-con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3z4_D+con_y3z4_F"));
- TEST_DO(verify_equal("con_x5y3z4_D*con_y3z4_F"));
-
- TEST_DO(verify_equal("con_y3_E-con_y3z4_F"));
- TEST_DO(verify_equal("con_y3_E+con_y3z4_F"));
- TEST_DO(verify_equal("con_y3_E*con_y3z4_F"));
-
- TEST_DO(verify_equal("con_y3z4_F-con_z4_G"));
- TEST_DO(verify_equal("con_y3z4_F+con_z4_G"));
- TEST_DO(verify_equal("con_y3z4_F*con_z4_G"));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/dense_number_join_function/CMakeLists.txt b/eval/src/tests/tensor/dense_number_join_function/CMakeLists.txt
deleted file mode 100644
index 73c544cab38..00000000000
--- a/eval/src/tests/tensor/dense_number_join_function/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_dense_number_join_function_test_app TEST
- SOURCES
- dense_number_join_function_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_dense_number_join_function_test_app COMMAND eval_dense_number_join_function_test_app)
diff --git a/eval/src/tests/tensor/dense_number_join_function/dense_number_join_function_test.cpp b/eval/src/tests/tensor/dense_number_join_function/dense_number_join_function_test.cpp
deleted file mode 100644
index 0255c33b295..00000000000
--- a/eval/src/tests/tensor/dense_number_join_function/dense_number_join_function_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_number_join_function.h>
-#include <vespa/eval/eval/test/eval_fixture.h>
-#include <vespa/eval/eval/test/tensor_model.hpp>
-
-#include <vespa/vespalib/util/stringfmt.h>
-
-using namespace vespalib;
-using namespace vespalib::eval;
-using namespace vespalib::eval::test;
-using namespace vespalib::tensor;
-using namespace vespalib::eval::tensor_function;
-
-using vespalib::make_string_short::fmt;
-
-using Primary = DenseNumberJoinFunction::Primary;
-
-namespace vespalib::tensor {
-
-std::ostream &operator<<(std::ostream &os, Primary primary)
-{
- switch(primary) {
- case Primary::LHS: return os << "LHS";
- case Primary::RHS: return os << "RHS";
- }
- abort();
-}
-
-}
-
-const TensorEngine &prod_engine = DefaultTensorEngine::ref();
-
-EvalFixture::ParamRepo make_params() {
- return EvalFixture::ParamRepo()
- .add("a", spec(1.5))
- .add("number", spec(2.5))
- .add("sparse", spec({x({"a"})}, N()))
- .add("dense", spec({y(5)}, N()))
- .add("mixed", spec({x({"a"}),y(5)}, N()))
- .add_matrix("x", 3, "y", 5);
-}
-EvalFixture::ParamRepo param_repo = make_params();
-
-void verify_optimized(const vespalib::string &expr, Primary primary, bool inplace) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true, true);
- EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(fixture.result(), slow_fixture.result());
- auto info = fixture.find_all<DenseNumberJoinFunction>();
- ASSERT_EQUAL(info.size(), 1u);
- EXPECT_TRUE(info[0]->result_is_mutable());
- EXPECT_EQUAL(info[0]->primary(), primary);
- EXPECT_EQUAL(info[0]->inplace(), inplace);
- int p_inplace = inplace ? ((primary == Primary::LHS) ? 0 : 1) : -1;
- EXPECT_TRUE((p_inplace == -1) || (fixture.num_params() > size_t(p_inplace)));
- for (size_t i = 0; i < fixture.num_params(); ++i) {
- if (i == size_t(p_inplace)) {
- EXPECT_EQUAL(fixture.get_param(i), fixture.result());
- } else {
- EXPECT_NOT_EQUAL(fixture.get_param(i), fixture.result());
- }
- }
-}
-
-void verify_not_optimized(const vespalib::string &expr) {
- EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
- EvalFixture fixture(prod_engine, expr, param_repo, true);
- EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
- EXPECT_EQUAL(fixture.result(), slow_fixture.result());
- auto info = fixture.find_all<DenseNumberJoinFunction>();
- EXPECT_TRUE(info.empty());
-}
-
-TEST("require that dense number join can be optimized") {
- TEST_DO(verify_optimized("x3y5+a", Primary::LHS, false));
- TEST_DO(verify_optimized("a+x3y5", Primary::RHS, false));
- TEST_DO(verify_optimized("x3y5f*a", Primary::LHS, false));
- TEST_DO(verify_optimized("a*x3y5f", Primary::RHS, false));
-}
-
-TEST("require that dense number join can be inplace") {
- TEST_DO(verify_optimized("@x3y5*a", Primary::LHS, true));
- TEST_DO(verify_optimized("a*@x3y5", Primary::RHS, true));
- TEST_DO(verify_optimized("@x3y5f+a", Primary::LHS, true));
- TEST_DO(verify_optimized("a+@x3y5f", Primary::RHS, true));
-}
-
-TEST("require that asymmetric operations work") {
- TEST_DO(verify_optimized("x3y5/a", Primary::LHS, false));
- TEST_DO(verify_optimized("a/x3y5", Primary::RHS, false));
- TEST_DO(verify_optimized("x3y5f-a", Primary::LHS, false));
- TEST_DO(verify_optimized("a-x3y5f", Primary::RHS, false));
-}
-
-TEST("require that inappropriate cases are not optimized") {
- int optimized = 0;
- for (vespalib::string lhs: {"number", "dense", "sparse", "mixed"}) {
- for (vespalib::string rhs: {"number", "dense", "sparse", "mixed"}) {
- if (((lhs == "number") && (rhs == "dense")) ||
- ((lhs == "dense") && (rhs == "number")))
- {
- ++optimized;
- } else {
- auto expr = fmt("%s+%s", lhs.c_str(), rhs.c_str());
- TEST_STATE(expr.c_str());
- verify_not_optimized(expr);
- }
- }
- }
- EXPECT_EQUAL(optimized, 2);
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/direct_dense_tensor_builder/CMakeLists.txt b/eval/src/tests/tensor/direct_dense_tensor_builder/CMakeLists.txt
deleted file mode 100644
index 70ccbddd617..00000000000
--- a/eval/src/tests/tensor/direct_dense_tensor_builder/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_direct_dense_tensor_builder_test_app TEST
- SOURCES
- direct_dense_tensor_builder_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_direct_dense_tensor_builder_test_app COMMAND eval_direct_dense_tensor_builder_test_app)
diff --git a/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp b/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp
deleted file mode 100644
index 52768663647..00000000000
--- a/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/test/insertion_operators.h>
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/dense/typed_dense_tensor_builder.h>
-#include <vespa/vespalib/util/exceptions.h>
-
-using namespace vespalib::tensor;
-using vespalib::IllegalArgumentException;
-using BuilderDbl = TypedDenseTensorBuilder<double>;
-using BuilderFlt = TypedDenseTensorBuilder<float>;
-using vespalib::eval::TensorSpec;
-using vespalib::eval::ValueType;
-using vespalib::ConstArrayRef;
-
-struct CallMakeVector {
- template <typename T>
- static std::vector<double> call(const ConstArrayRef<T> &ref) {
- std::vector<double> result;
- result.reserve(ref.size());
- for (T v : ref) {
- result.push_back(v);
- }
- return result;
- }
-};
-
-void assertTensor(const vespalib::string &type_spec,
- const std::vector<double> &expCells,
- const Tensor &tensor)
-{
- EXPECT_EQUAL(ValueType::from_spec(type_spec), tensor.type());
- EXPECT_EQUAL(expCells, dispatch_1<CallMakeVector>(tensor.cells()));
-}
-
-void assertTensorSpec(const TensorSpec &expSpec, const Tensor &tensor) {
- TensorSpec actSpec = tensor.toSpec();
- EXPECT_EQUAL(expSpec, actSpec);
-}
-
-Tensor::UP build1DTensor() {
- BuilderDbl builder(ValueType::from_spec("tensor(x[3])"));
- builder.insertCell(0, 10);
- builder.insertCell(1, 11);
- builder.insertCell(2, 12);
- return builder.build();
-}
-
-TEST("require that 1d tensor can be constructed") {
- assertTensor("tensor(x[3])", {10,11,12}, *build1DTensor());
-}
-
-TEST("require that 1d tensor can be converted to tensor spec") {
- assertTensorSpec(TensorSpec("tensor(x[3])").
- add({{"x", 0}}, 10).
- add({{"x", 1}}, 11).
- add({{"x", 2}}, 12),
- *build1DTensor());
-}
-
-Tensor::UP build2DTensor() {
- BuilderDbl builder(ValueType::from_spec("tensor(x[3],y[2])"));
- builder.insertCell({0, 0}, 10);
- builder.insertCell({0, 1}, 11);
- builder.insertCell({1, 0}, 12);
- builder.insertCell({1, 1}, 13);
- builder.insertCell({2, 0}, 14);
- builder.insertCell({2, 1}, 15);
- return builder.build();
-}
-
-TEST("require that 2d tensor can be constructed") {
- assertTensor("tensor(x[3],y[2])", {10,11,12,13,14,15}, *build2DTensor());
-}
-
-TEST("require that 2d tensor can be converted to tensor spec") {
- assertTensorSpec(TensorSpec("tensor(x[3],y[2])").
- add({{"x", 0},{"y", 0}}, 10).
- add({{"x", 0},{"y", 1}}, 11).
- add({{"x", 1},{"y", 0}}, 12).
- add({{"x", 1},{"y", 1}}, 13).
- add({{"x", 2},{"y", 0}}, 14).
- add({{"x", 2},{"y", 1}}, 15),
- *build2DTensor());
-}
-
-TEST("require that 3d tensor can be constructed") {
- BuilderDbl builder(ValueType::from_spec("tensor(x[3],y[2],z[2])"));
- builder.insertCell({0, 0, 0}, 10);
- builder.insertCell({0, 0, 1}, 11);
- builder.insertCell({0, 1, 0}, 12);
- builder.insertCell({0, 1, 1}, 13);
- builder.insertCell({1, 0, 0}, 14);
- builder.insertCell({1, 0, 1}, 15);
- builder.insertCell({1, 1, 0}, 16);
- builder.insertCell({1, 1, 1}, 17);
- builder.insertCell({2, 0, 0}, 18);
- builder.insertCell({2, 0, 1}, 19);
- builder.insertCell({2, 1, 0}, 20);
- builder.insertCell({2, 1, 1}, 21);
- assertTensor("tensor(x[3],y[2],z[2])",
- {10,11,12,13,14,15,16,17,18,19,20,21},
- *builder.build());
-}
-
-TEST("require that 2d tensor with float cells can be constructed") {
- BuilderFlt builder(ValueType::from_spec("tensor<float>(x[3],y[2])"));
- builder.insertCell({0, 1}, 2.5);
- builder.insertCell({1, 0}, 1.5);
- builder.insertCell({2, 0}, -0.25);
- builder.insertCell({2, 1}, 0.75);
- assertTensor("tensor<float>(x[3],y[2])", {0,2.5,1.5,0,-0.25,0.75},
- *builder.build());
-}
-
-TEST("require that cells get default value 0 if not specified") {
- BuilderDbl builder(ValueType::from_spec("tensor(x[3])"));
- builder.insertCell(1, 11);
- assertTensor("tensor(x[3])", {0,11,0},
- *builder.build());
-}
-
-void assertTensorCell(const DenseTensorView::Address &expAddress,
- double expCell,
- const DenseTensorView::CellsIterator &itr)
-{
- EXPECT_TRUE(itr.valid());
- EXPECT_EQUAL(expAddress, itr.address());
- EXPECT_EQUAL(expCell, itr.cell());
-}
-
-TEST("require that dense tensor cells iterator works for 1d tensor") {
- Tensor::UP tensor;
- {
- BuilderDbl builder(ValueType::from_spec("tensor(x[2])"));
- builder.insertCell(0, 2);
- builder.insertCell(1, 3);
- tensor = builder.build();
- }
-
- const DenseTensorView &denseTensor = dynamic_cast<const DenseTensorView &>(*tensor);
- DenseTensorView::CellsIterator itr = denseTensor.cellsIterator();
-
- assertTensorCell({0}, 2, itr);
- itr.next();
- assertTensorCell({1}, 3, itr);
- itr.next();
- EXPECT_FALSE(itr.valid());
-}
-
-TEST("require that dense tensor cells iterator works for 2d tensor") {
- Tensor::UP tensor;
- {
- BuilderDbl builder(ValueType::from_spec("tensor(x[2],y[2])"));
- builder.insertCell({0, 0}, 2);
- builder.insertCell({0, 1}, 3);
- builder.insertCell({1, 0}, 5);
- builder.insertCell({1, 1}, 7);
- tensor = builder.build();
- }
-
- const DenseTensorView &denseTensor = dynamic_cast<const DenseTensorView &>(*tensor);
- DenseTensorView::CellsIterator itr = denseTensor.cellsIterator();
-
- assertTensorCell({0,0}, 2, itr);
- itr.next();
- assertTensorCell({0,1}, 3, itr);
- itr.next();
- assertTensorCell({1,0}, 5, itr);
- itr.next();
- assertTensorCell({1,1}, 7, itr);
- itr.next();
- EXPECT_FALSE(itr.valid());
-}
-
-TEST("require that memory used count is reasonable") {
- Tensor::UP full = build2DTensor();
- const DenseTensorView &full_view = dynamic_cast<const DenseTensorView &>(*full);
- DenseTensorView ref_view(full_view.fast_type(), full_view.cells());
-
- size_t full_sz = full->get_memory_usage().usedBytes();
- size_t view_sz = full_view.get_memory_usage().usedBytes();
- size_t ref_sz = ref_view.get_memory_usage().usedBytes();
-
- EXPECT_EQUAL(ref_sz, sizeof(DenseTensorView));
- EXPECT_LESS(ref_sz, full_sz);
- EXPECT_EQUAL(full_sz, view_sz);
- EXPECT_LESS(full_sz, 10000u);
- EXPECT_GREATER(full_sz, sizeof(DenseTensor<double>));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt b/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt
deleted file mode 100644
index 00ff230fadd..00000000000
--- a/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_direct_sparse_tensor_builder_test_app TEST
- SOURCES
- direct_sparse_tensor_builder_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_direct_sparse_tensor_builder_test_app COMMAND eval_direct_sparse_tensor_builder_test_app)
diff --git a/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp b/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp
deleted file mode 100644
index bcee6471f76..00000000000
--- a/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h>
-#include <vespa/vespalib/test/insertion_operators.h>
-
-using namespace vespalib::tensor;
-using namespace vespalib::tensor::sparse;
-using vespalib::eval::TensorSpec;
-using vespalib::eval::CellType;
-using vespalib::eval::ValueType;
-
-void
-assertCellValue(double expValue, const TensorAddress &address,
- const ValueType &type,
- const SparseTensor &tensor)
-{
- SparseTensorAddressBuilder addressBuilder;
- auto dimsItr = type.dimensions().cbegin();
- auto dimsItrEnd = type.dimensions().cend();
- for (const auto &element : address.elements()) {
- while ((dimsItr < dimsItrEnd) && (dimsItr->name < element.dimension())) {
- addressBuilder.add("");
- ++dimsItr;
- }
- assert((dimsItr != dimsItrEnd) && (dimsItr->name == element.dimension()));
- addressBuilder.add(element.label());
- ++dimsItr;
- }
- while (dimsItr < dimsItrEnd) {
- addressBuilder.add("");
- ++dimsItr;
- }
- SparseTensorAddressRef addressRef(addressBuilder.getAddressRef());
- size_t idx;
- bool found = tensor.index().lookup_address(addressRef, idx);
- EXPECT_TRUE(found);
- auto cells = tensor.cells();
- if (EXPECT_TRUE(cells.type == CellType::DOUBLE)) {
- auto arr = cells.typify<double>();
- EXPECT_EQUAL(expValue, arr[idx]);
- }
-}
-
-Tensor::UP
-buildTensor()
-{
- DirectSparseTensorBuilder<double> builder(ValueType::from_spec("tensor(a{},b{},c{},d{})"));
- SparseTensorAddressBuilder address;
- address.set({"1", "2", "", ""});
- builder.insertCell(address, 10);
- address.set({"", "", "3", "4"});
- builder.insertCell(address, 20);
- return builder.build();
-}
-
-TEST("require that tensor can be constructed")
-{
- Tensor::UP tensor = buildTensor();
- const SparseTensor &sparseTensor = dynamic_cast<const SparseTensor &>(*tensor);
- const ValueType &type = sparseTensor.type();
- const auto & index = sparseTensor.index();
- EXPECT_EQUAL(2u, index.size());
- assertCellValue(10, TensorAddress({{"a","1"},{"b","2"}}), type, sparseTensor);
- assertCellValue(20, TensorAddress({{"c","3"},{"d","4"}}), type, sparseTensor);
-}
-
-TEST("require that tensor can be converted to tensor spec")
-{
- Tensor::UP tensor = buildTensor();
- TensorSpec expSpec("tensor(a{},b{},c{},d{})");
- expSpec.add({{"a", "1"}, {"b", "2"}, {"c", ""}, {"d", ""}}, 10).
- add({{"a", ""},{"b",""},{"c", "3"}, {"d", "4"}}, 20);
- TensorSpec actSpec = tensor->toSpec();
- EXPECT_EQUAL(expSpec, actSpec);
-}
-
-TEST("require that dimensions are extracted")
-{
- Tensor::UP tensor = buildTensor();
- const SparseTensor &sparseTensor = dynamic_cast<const SparseTensor &>(*tensor);
- const auto &dims = sparseTensor.type().dimensions();
- EXPECT_EQUAL(4u, dims.size());
- EXPECT_EQUAL("a", dims[0].name);
- EXPECT_EQUAL("b", dims[1].name);
- EXPECT_EQUAL("c", dims[2].name);
- EXPECT_EQUAL("d", dims[3].name);
- EXPECT_EQUAL("tensor(a{},b{},c{},d{})", sparseTensor.type().to_spec());
-}
-
-void verifyAddressCombiner(const ValueType & a, const ValueType & b, size_t numDim, size_t numOverlapping) {
- TensorAddressCombiner combiner(a, b);
- EXPECT_EQUAL(numDim, combiner.numDimensions());
- EXPECT_EQUAL(numOverlapping, combiner.numOverlappingDimensions());
-}
-TEST("Test sparse tensor address combiner") {
- verifyAddressCombiner(ValueType::tensor_type({{"a"}}), ValueType::tensor_type({{"b"}}), 2, 0);
- verifyAddressCombiner(ValueType::tensor_type({{"a"}, {"b"}}), ValueType::tensor_type({{"b"}}), 2, 1);
- verifyAddressCombiner(ValueType::tensor_type({{"a"}, {"b"}}), ValueType::tensor_type({{"b"}, {"c"}}), 3, 1);
-
-}
-
-TEST("Test essential object sizes") {
- EXPECT_EQUAL(16u, sizeof(SparseTensorAddressRef));
- EXPECT_EQUAL(24u, sizeof(std::pair<SparseTensorAddressRef, double>));
- EXPECT_EQUAL(32u, sizeof(vespalib::hash_node<std::pair<SparseTensorAddressRef, double>>));
- Tensor::UP tensor = buildTensor();
- size_t used = tensor->get_memory_usage().usedBytes();
- EXPECT_GREATER(used, sizeof(SparseTensor));
- EXPECT_LESS(used, 10000u);
- size_t allocated = tensor->get_memory_usage().allocatedBytes();
- EXPECT_GREATER(allocated, used);
- EXPECT_LESS(allocated, 50000u);
- fprintf(stderr, "tensor using %zu bytes of %zu allocated\n",
- used, allocated);
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/instruction_benchmark/.gitignore b/eval/src/tests/tensor/instruction_benchmark/.gitignore
index dc5c408cf29..5b3eab59ff6 100644
--- a/eval/src/tests/tensor/instruction_benchmark/.gitignore
+++ b/eval/src/tests/tensor/instruction_benchmark/.gitignore
@@ -1 +1,3 @@
vespa-tensor-instructions-benchmark
+/result.json
+/ghost.json
diff --git a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp
index f11678d3ee7..aa1da07bc91 100644
--- a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp
+++ b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp
@@ -29,27 +29,30 @@
#include <vespa/eval/instruction/generic_rename.h>
#include <vespa/eval/instruction/generic_map.h>
#include <vespa/eval/instruction/generic_merge.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/optimize_tensor_function.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include <vespa/vespalib/io/mapped_file_input.h>
+#include <vespa/vespalib/io/fileutil.h>
+#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/data/smart_buffer.h>
#include <optional>
#include <algorithm>
using namespace vespalib;
using namespace vespalib::eval;
-using namespace vespalib::tensor;
using namespace vespalib::eval::instruction;
using vespalib::make_string_short::fmt;
+using vespalib::slime::JsonFormat;
+
using Instruction = InterpretedFunction::Instruction;
using EvalSingle = InterpretedFunction::EvalSingle;
@@ -132,16 +135,16 @@ void my_multi_instruction_op(InterpretedFunction::State &state, uint64_t param_i
}
}
-void collect_op1_chain(const TensorFunction &node, const EngineOrFactory &engine, Stash &stash, std::vector<Instruction> &list) {
+void collect_op1_chain(const TensorFunction &node, const ValueBuilderFactory &factory, Stash &stash, std::vector<Instruction> &list) {
if (auto op1 = as<tensor_function::Op1>(node)) {
- collect_op1_chain(op1->child(), engine, stash, list);
- list.push_back(node.compile_self(engine, stash));
+ collect_op1_chain(op1->child(), factory, stash, list);
+ list.push_back(node.compile_self(factory, stash));
}
}
-Instruction compile_op1_chain(const TensorFunction &node, const EngineOrFactory &engine, Stash &stash) {
+Instruction compile_op1_chain(const TensorFunction &node, const ValueBuilderFactory &factory, Stash &stash) {
auto &param = stash.create<MultiOpParam>();
- collect_op1_chain(node, engine, stash, param.list);
+ collect_op1_chain(node, factory, stash, param.list);
return {my_multi_instruction_op,(uint64_t)(&param)};
}
@@ -151,60 +154,60 @@ struct Impl {
size_t order;
vespalib::string name;
vespalib::string short_name;
- EngineOrFactory engine;
+ const ValueBuilderFactory &factory;
bool optimize;
- Impl(size_t order_in, const vespalib::string &name_in, const vespalib::string &short_name_in, EngineOrFactory engine_in, bool optimize_in)
- : order(order_in), name(name_in), short_name(short_name_in), engine(engine_in), optimize(optimize_in) {}
- Value::UP create_value(const TensorSpec &spec) const { return engine.from_spec(spec); }
- TensorSpec create_spec(const Value &value) const { return engine.to_spec(value); }
+ Impl(size_t order_in, const vespalib::string &name_in, const vespalib::string &short_name_in, const ValueBuilderFactory &factory_in, bool optimize_in)
+ : order(order_in), name(name_in), short_name(short_name_in), factory(factory_in), optimize(optimize_in) {}
+ Value::UP create_value(const TensorSpec &spec) const { return value_from_spec(spec, factory); }
+ TensorSpec create_spec(const Value &value) const { return spec_from_value(value); }
Instruction create_join(const ValueType &lhs, const ValueType &rhs, operation::op2_t function, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &rhs_node = tensor_function::inject(rhs, 1, stash);
const auto &join_node = tensor_function::join(lhs_node, rhs_node, function, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, join_node, stash) : join_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, join_node, stash) : join_node;
+ return node.compile_self(factory, stash);
}
Instruction create_reduce(const ValueType &lhs, Aggr aggr, const std::vector<vespalib::string> &dims, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &reduce_node = tensor_function::reduce(lhs_node, aggr, dims, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, reduce_node, stash) : reduce_node;
+ const auto &node = optimize ? optimize_tensor_function(factory, reduce_node, stash) : reduce_node;
// since reduce might be optimized into multiple chained
// instructions, we need some extra magic to package these
// instructions into a single compound instruction.
- return compile_op1_chain(node, engine, stash);
+ return compile_op1_chain(node, factory, stash);
}
Instruction create_rename(const ValueType &lhs, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &rename_node = tensor_function::rename(lhs_node, from, to, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, rename_node, stash) : rename_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, rename_node, stash) : rename_node;
+ return node.compile_self(factory, stash);
}
Instruction create_merge(const ValueType &lhs, const ValueType &rhs, operation::op2_t function, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &rhs_node = tensor_function::inject(rhs, 1, stash);
const auto &merge_node = tensor_function::merge(lhs_node, rhs_node, function, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, merge_node, stash) : merge_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, merge_node, stash) : merge_node;
+ return node.compile_self(factory, stash);
}
Instruction create_concat(const ValueType &lhs, const ValueType &rhs, const std::string &dimension, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &rhs_node = tensor_function::inject(rhs, 1, stash);
const auto &concat_node = tensor_function::concat(lhs_node, rhs_node, dimension, stash);
- return concat_node.compile_self(engine, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, concat_node, stash) : concat_node;
- return node.compile_self(engine, stash);
+ return concat_node.compile_self(factory, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, concat_node, stash) : concat_node;
+ return node.compile_self(factory, stash);
}
Instruction create_map(const ValueType &lhs, operation::op1_t function, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
const auto &lhs_node = tensor_function::inject(lhs, 0, stash);
const auto &map_node = tensor_function::map(lhs_node, function, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, map_node, stash) : map_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, map_node, stash) : map_node;
+ return node.compile_self(factory, stash);
}
Instruction create_tensor_create(const ValueType &proto_type, const TensorSpec &proto, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
@@ -214,8 +217,8 @@ struct Impl {
spec.emplace(cell.first, my_double);
}
const auto &create_tensor_node = tensor_function::create(proto_type, spec, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, create_tensor_node, stash) : create_tensor_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, create_tensor_node, stash) : create_tensor_node;
+ return node.compile_self(factory, stash);
}
Instruction create_tensor_lambda(const ValueType &type, const Function &function, const ValueType &p0_type, Stash &stash) const {
std::vector<ValueType> arg_types(type.dimensions().size(), ValueType::double_type());
@@ -223,8 +226,8 @@ struct Impl {
NodeTypes types(function, arg_types);
EXPECT_EQ(types.errors(), std::vector<vespalib::string>());
const auto &tensor_lambda_node = tensor_function::lambda(type, {0}, function, std::move(types), stash);
- const auto &node = optimize ? optimize_tensor_function(engine, tensor_lambda_node, stash) : tensor_lambda_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, tensor_lambda_node, stash) : tensor_lambda_node;
+ return node.compile_self(factory, stash);
}
Instruction create_tensor_peek(const ValueType &type, const MyPeekSpec &my_spec, Stash &stash) const {
// create a complete tensor function, but only compile the relevant instruction
@@ -247,30 +250,32 @@ struct Impl {
}
}
const auto &peek_node = tensor_function::peek(my_param, spec, stash);
- const auto &node = optimize ? optimize_tensor_function(engine, peek_node, stash) : peek_node;
- return node.compile_self(engine, stash);
+ const auto &node = optimize ? optimize_tensor_function(factory, peek_node, stash) : peek_node;
+ return node.compile_self(factory, stash);
}
};
//-----------------------------------------------------------------------------
Impl optimized_fast_value_impl(0, " Optimized FastValue", "NEW PROD", FastValueBuilderFactory::get(), true);
-Impl optimized_default_tensor_engine_impl(1, "Optimized DefaultTensorEngine", "OLD PROD", DefaultTensorEngine::ref(), true);
-Impl fast_value_impl(2, " FastValue", " FastV", FastValueBuilderFactory::get(), false);
-Impl default_tensor_engine_impl(3, " DefaultTensorEngine", "DefaultT", DefaultTensorEngine::ref(), false);
-Impl simple_value_impl(4, " SimpleValue", " SimpleV", SimpleValueBuilderFactory::get(), false);
+Impl fast_value_impl(1, " FastValue", " FastV", FastValueBuilderFactory::get(), false);
+Impl simple_value_impl(2, " SimpleValue", " SimpleV", SimpleValueBuilderFactory::get(), false);
vespalib::string short_header("--------");
+vespalib::string ghost_name(" loaded from ghost.json");
+vespalib::string ghost_short_name(" ghost");
constexpr double budget = 5.0;
constexpr double best_limit = 0.95; // everything within 95% of best performance gets a star
-constexpr double bad_limit = 0.90; // BAD: new prod has performance lower than 90% of old prod
-constexpr double good_limit = 1.10; // GOOD: new prod has performance higher than 110% of old prod
+constexpr double bad_limit = 0.90; // BAD: optimized has performance lower than 90% of un-optimized
+constexpr double good_limit = 1.10; // GOOD: optimized has performance higher than 110% of un-optimized
std::vector<CREF<Impl>> impl_list = {simple_value_impl,
optimized_fast_value_impl,
- optimized_default_tensor_engine_impl,
- fast_value_impl,
- default_tensor_engine_impl};
+ fast_value_impl};
+
+Slime ghost; // loaded from 'ghost.json'
+bool has_ghost = false;
+Slime prod_result; // saved to 'result.json'
//-----------------------------------------------------------------------------
@@ -281,6 +286,9 @@ struct BenchmarkHeader {
for (const Impl &impl: impl_list) {
short_names[impl.order] = impl.short_name;
}
+ if (has_ghost) {
+ short_names.push_back(ghost_short_name);
+ }
}
void print_header(const vespalib::string &desc) const {
for (const auto &name: short_names) {
@@ -306,12 +314,17 @@ struct BenchmarkResult {
~BenchmarkResult();
void sample(size_t order, double time) {
relative_perf[order] = time;
- if (order == 1) {
- if (ref_time.has_value()) {
- ref_time = std::min(ref_time.value(), time);
- } else {
- ref_time = time;
+ if (order == 0) {
+ prod_result.get().setDouble(desc, time);
+ if (has_ghost && (relative_perf.size() == impl_list.size())) {
+ double ghost_time = ghost.get()[desc].asDouble();
+ size_t ghost_order = relative_perf.size();
+ fprintf(stderr, " %s(%s): %10.3f us\n", ghost_name.c_str(), ghost_short_name.c_str(), ghost_time);
+ relative_perf.resize(ghost_order + 1);
+ return sample(ghost_order, ghost_time);
}
+ } else if (order == 1) {
+ ref_time = time;
}
}
void normalize() {
@@ -339,6 +352,23 @@ std::vector<BenchmarkResult> benchmark_results;
//-----------------------------------------------------------------------------
+void load_ghost(const vespalib::string &file_name) {
+ MappedFileInput input(file_name);
+ has_ghost = JsonFormat::decode(input, ghost);
+}
+
+void save_result(const vespalib::string &file_name) {
+ SmartBuffer output(4096);
+ JsonFormat::encode(prod_result, output, false);
+ Memory memory = output.obtain();
+ File file(file_name);
+ file.open(File::CREATE | File::TRUNC);
+ file.write(memory.data, memory.size, 0);
+ file.close();
+}
+
+//-----------------------------------------------------------------------------
+
struct MyParam : LazyParams {
Value::UP my_value;
MyParam() : my_value() {}
@@ -362,7 +392,7 @@ struct EvalOp {
EvalOp(const EvalOp &) = delete;
EvalOp &operator=(const EvalOp &) = delete;
EvalOp(Stash &&stash_in, Instruction op, const std::vector<CREF<TensorSpec>> &stack_spec, const Impl &impl_in)
- : my_stash(std::move(stash_in)), impl(impl_in), my_param(), values(), stack(), single(impl.engine, op)
+ : my_stash(std::move(stash_in)), impl(impl_in), my_param(), values(), stack(), single(impl.factory, op)
{
for (const TensorSpec &spec: stack_spec) {
values.push_back(impl.create_value(spec));
@@ -372,7 +402,7 @@ struct EvalOp {
}
}
EvalOp(Stash &&stash_in, Instruction op, const TensorSpec &p0, const Impl &impl_in)
- : my_stash(std::move(stash_in)), impl(impl_in), my_param(p0, impl), values(), stack(), single(impl.engine, op, my_param)
+ : my_stash(std::move(stash_in)), impl(impl_in), my_param(p0, impl), values(), stack(), single(impl.factory, op, my_param)
{
}
TensorSpec result() { return impl.create_spec(single.eval(stack)); }
@@ -439,8 +469,8 @@ void benchmark(const vespalib::string &desc, const std::vector<EvalOp::UP> &list
}
for (const auto &eval: list) {
double time = eval->estimate_cost_us(loop_cnt[eval->impl.order], loop_cnt[1]);
- result.sample(eval->impl.order, time);
fprintf(stderr, " %s(%s): %10.3f us\n", eval->impl.name.c_str(), eval->impl.short_name.c_str(), time);
+ result.sample(eval->impl.order, time);
}
result.normalize();
benchmark_results.push_back(result);
@@ -650,10 +680,10 @@ void benchmark_encode_decode(const vespalib::string &desc, const TensorSpec &pro
for (const Impl &impl: impl_list) {
vespalib::nbostream data;
auto value = impl.create_value(proto);
- impl.engine.encode(*value, data);
- auto new_value = impl.engine.decode(data);
+ encode_value(*value, data);
+ auto new_value = decode_value(data, impl.factory);
ASSERT_EQ(data.size(), 0);
- ASSERT_EQ(proto, impl.engine.to_spec(*new_value));
+ ASSERT_EQ(proto, spec_from_value(*new_value));
}
fprintf(stderr, "--------------------------------------------------------\n");
fprintf(stderr, "Benchmarking encode/decode for: [%s]\n", desc.c_str());
@@ -669,20 +699,20 @@ void benchmark_encode_decode(const vespalib::string &desc, const TensorSpec &pro
std::array<Value::UP, loop_cnt> object;
encode_timer.before();
for (size_t i = 0; i < loop_cnt; ++i) {
- impl.engine.encode(*value, data[i]);
+ encode_value(*value, data[i]);
}
encode_timer.after();
decode_timer.before();
for (size_t i = 0; i < loop_cnt; ++i) {
- object[i] = impl.engine.decode(data[i]);
+ object[i] = decode_value(data[i], impl.factory);
}
decode_timer.after();
}
double encode_us = encode_timer.min_time() * 1000.0 * 1000.0 / double(loop_cnt);
double decode_us = decode_timer.min_time() * 1000.0 * 1000.0 / double(loop_cnt);
- fprintf(stderr, " %s (%s) <encode>: %10.3f us\n", impl.name.c_str(), impl.short_name.c_str(), encode_us);
- fprintf(stderr, " %s (%s) <decode>: %10.3f us\n", impl.name.c_str(), impl.short_name.c_str(), decode_us);
+ fprintf(stderr, " %s(%s): %10.3f us <encode>\n", impl.name.c_str(), impl.short_name.c_str(), encode_us);
encode_result.sample(impl.order, encode_us);
+ fprintf(stderr, " %s(%s): %10.3f us <decode>\n", impl.name.c_str(), impl.short_name.c_str(), decode_us);
decode_result.sample(impl.order, decode_us);
}
encode_result.normalize();
@@ -1083,16 +1113,26 @@ void print_summary() {
}
int main(int argc, char **argv) {
+ prod_result.setObject();
+ load_ghost("ghost.json");
const std::string run_only_prod_option = "--limit-implementations";
+ const std::string ghost_mode_option = "--ghost-mode";
if ((argc > 1) && (argv[1] == run_only_prod_option )) {
impl_list.clear();
impl_list.push_back(optimized_fast_value_impl);
- impl_list.push_back(optimized_default_tensor_engine_impl);
+ impl_list.push_back(fast_value_impl);
+ ++argv;
+ --argc;
+ } else if ((argc > 1) && (argv[1] == ghost_mode_option )) {
+ impl_list.clear();
+ impl_list.push_back(optimized_fast_value_impl);
+ has_ghost = true;
++argv;
--argc;
}
::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
+ save_result("result.json");
print_summary();
return result;
}
diff --git a/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp b/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
index efab0571e62..b474d2458b9 100644
--- a/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
+++ b/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
@@ -1,13 +1,11 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/eval/tensor/dense/onnx_wrapper.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/onnx/onnx_wrapper.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace vespalib::eval;
-using namespace vespalib::tensor;
using vespalib::make_string_short::fmt;
using TensorInfo = Onnx::TensorInfo;
@@ -136,17 +134,17 @@ TEST(OnnxTest, simple_onnx_model_can_be_evaluated)
ValueType query_type = ValueType::from_spec("tensor<float>(a[1],b[4])");
std::vector<float> query_values({1.0, 2.0, 3.0, 4.0});
- DenseTensorView query(query_type, TypedCells(query_values));
+ DenseValueView query(query_type, TypedCells(query_values));
EXPECT_TRUE(planner.bind_input_type(query_type, model.inputs()[0]));
ValueType attribute_type = ValueType::from_spec("tensor<float>(a[4],b[1])");
std::vector<float> attribute_values({5.0, 6.0, 7.0, 8.0});
- DenseTensorView attribute(attribute_type, TypedCells(attribute_values));
+ DenseValueView attribute(attribute_type, TypedCells(attribute_values));
EXPECT_TRUE(planner.bind_input_type(attribute_type, model.inputs()[1]));
ValueType bias_type = ValueType::from_spec("tensor<float>(a[1],b[1])");
std::vector<float> bias_values({9.0});
- DenseTensorView bias(bias_type, TypedCells(bias_values));
+ DenseValueView bias(bias_type, TypedCells(bias_values));
EXPECT_TRUE(planner.bind_input_type(bias_type, model.inputs()[2]));
EXPECT_EQ(planner.make_output_type(model.outputs()[0]).to_spec(),
@@ -165,13 +163,13 @@ TEST(OnnxTest, simple_onnx_model_can_be_evaluated)
auto cells = output.cells();
EXPECT_EQ(cells.type, CellType::FLOAT);
EXPECT_EQ(cells.size, 1);
- EXPECT_EQ(GetCell::from(cells, 0), 79.0);
+ EXPECT_EQ(cells.typify<float>()[0], 79.0);
//-------------------------------------------------------------------------
std::vector<float> new_bias_values({10.0});
- DenseTensorView new_bias(bias_type, TypedCells(new_bias_values));
+ DenseValueView new_bias(bias_type, TypedCells(new_bias_values));
ctx.bind_param(2, new_bias);
ctx.eval();
- EXPECT_EQ(GetCell::from(output.cells(), 0), 80.0);
+ EXPECT_EQ(output.cells().typify<float>()[0], 80.0);
//-------------------------------------------------------------------------
}
@@ -182,17 +180,17 @@ TEST(OnnxTest, dynamic_onnx_model_can_be_evaluated)
ValueType query_type = ValueType::from_spec("tensor<float>(a[1],b[4])");
std::vector<float> query_values({1.0, 2.0, 3.0, 4.0});
- DenseTensorView query(query_type, TypedCells(query_values));
+ DenseValueView query(query_type, TypedCells(query_values));
EXPECT_TRUE(planner.bind_input_type(query_type, model.inputs()[0]));
ValueType attribute_type = ValueType::from_spec("tensor<float>(a[4],b[1])");
std::vector<float> attribute_values({5.0, 6.0, 7.0, 8.0});
- DenseTensorView attribute(attribute_type, TypedCells(attribute_values));
+ DenseValueView attribute(attribute_type, TypedCells(attribute_values));
EXPECT_TRUE(planner.bind_input_type(attribute_type, model.inputs()[1]));
ValueType bias_type = ValueType::from_spec("tensor<float>(a[1],b[2])");
std::vector<float> bias_values({4.0, 5.0});
- DenseTensorView bias(bias_type, TypedCells(bias_values));
+ DenseValueView bias(bias_type, TypedCells(bias_values));
EXPECT_TRUE(planner.bind_input_type(bias_type, model.inputs()[2]));
EXPECT_EQ(planner.make_output_type(model.outputs()[0]).to_spec(),
@@ -211,13 +209,13 @@ TEST(OnnxTest, dynamic_onnx_model_can_be_evaluated)
auto cells = output.cells();
EXPECT_EQ(cells.type, CellType::FLOAT);
EXPECT_EQ(cells.size, 1);
- EXPECT_EQ(GetCell::from(cells, 0), 79.0);
+ EXPECT_EQ(cells.typify<float>()[0], 79.0);
//-------------------------------------------------------------------------
std::vector<float> new_bias_values({5.0,6.0});
- DenseTensorView new_bias(bias_type, TypedCells(new_bias_values));
+ DenseValueView new_bias(bias_type, TypedCells(new_bias_values));
ctx.bind_param(2, new_bias);
ctx.eval();
- EXPECT_EQ(GetCell::from(output.cells(), 0), 81.0);
+ EXPECT_EQ(output.cells().typify<float>()[0], 81.0);
//-------------------------------------------------------------------------
}
@@ -228,17 +226,17 @@ TEST(OnnxTest, int_types_onnx_model_can_be_evaluated)
ValueType query_type = ValueType::from_spec("tensor<float>(a[1],b[4])");
std::vector<float> query_values({1.0, 2.0, 3.0, 4.0});
- DenseTensorView query(query_type, TypedCells(query_values));
+ DenseValueView query(query_type, TypedCells(query_values));
EXPECT_TRUE(planner.bind_input_type(query_type, model.inputs()[0]));
ValueType attribute_type = ValueType::from_spec("tensor<double>(a[4],b[1])");
std::vector<double> attribute_values({5.0, 6.0, 7.0, 8.0});
- DenseTensorView attribute(attribute_type, TypedCells(attribute_values));
+ DenseValueView attribute(attribute_type, TypedCells(attribute_values));
EXPECT_TRUE(planner.bind_input_type(attribute_type, model.inputs()[1]));
ValueType bias_type = ValueType::from_spec("tensor<double>(a[1],b[1])");
std::vector<double> bias_values({9.0});
- DenseTensorView bias(bias_type, TypedCells(bias_values));
+ DenseValueView bias(bias_type, TypedCells(bias_values));
EXPECT_TRUE(planner.bind_input_type(bias_type, model.inputs()[2]));
EXPECT_EQ(planner.make_output_type(model.outputs()[0]),
@@ -257,13 +255,13 @@ TEST(OnnxTest, int_types_onnx_model_can_be_evaluated)
auto cells = output.cells();
EXPECT_EQ(cells.type, CellType::DOUBLE);
EXPECT_EQ(cells.size, 1);
- EXPECT_EQ(GetCell::from(cells, 0), 79.0);
+ EXPECT_EQ(cells.typify<double>()[0], 79.0);
//-------------------------------------------------------------------------
std::vector<double> new_bias_values({10.0});
- DenseTensorView new_bias(bias_type, TypedCells(new_bias_values));
+ DenseValueView new_bias(bias_type, TypedCells(new_bias_values));
ctx.bind_param(2, new_bias);
ctx.eval();
- EXPECT_EQ(GetCell::from(output.cells(), 0), 80.0);
+ EXPECT_EQ(output.cells().typify<double>()[0], 80.0);
//-------------------------------------------------------------------------
}
@@ -274,13 +272,13 @@ TEST(OnnxTest, we_guess_batch_dimension_size_when_inference_fails) {
ValueType in_3_type = ValueType::from_spec("tensor<float>(a[3])");
std::vector<float> in_3_values({1.0, 2.0, 3.0});
- DenseTensorView in_3(in_3_type, TypedCells(in_3_values));
+ DenseValueView in_3(in_3_type, TypedCells(in_3_values));
EXPECT_TRUE(planner_3.bind_input_type(in_3_type, model.inputs()[0]));
EXPECT_TRUE(planner_3.bind_input_type(in_3_type, model.inputs()[1]));
ValueType in_4_type = ValueType::from_spec("tensor<float>(a[4])");
std::vector<float> in_4_values({1.0, 2.0, 3.0, 4.0});
- DenseTensorView in_4(in_4_type, TypedCells(in_4_values));
+ DenseValueView in_4(in_4_type, TypedCells(in_4_values));
EXPECT_TRUE(planner_4.bind_input_type(in_4_type, model.inputs()[0]));
EXPECT_TRUE(planner_4.bind_input_type(in_4_type, model.inputs()[1]));
diff --git a/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt b/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt
deleted file mode 100644
index 275043c8c54..00000000000
--- a/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_add_operation_test_app TEST
- SOURCES
- tensor_add_operation_test.cpp
- DEPENDS
- vespaeval
- GTest::GTest
-)
-vespa_add_test(NAME eval_tensor_add_operation_test_app COMMAND eval_tensor_add_operation_test_app)
diff --git a/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp b/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp
deleted file mode 100644
index 1d39a557114..00000000000
--- a/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
-#include <vespa/eval/tensor/test/test_utils.h>
-#include <vespa/vespalib/gtest/gtest.h>
-
-using vespalib::eval::Value;
-using vespalib::eval::TensorSpec;
-using vespalib::tensor::test::makeTensor;
-using namespace vespalib::tensor;
-
-void
-assertAdd(const TensorSpec &source, const TensorSpec &arg, const TensorSpec &expected)
-{
- auto sourceTensor = makeTensor<Tensor>(source);
- auto argTensor = makeTensor<Tensor>(arg);
- auto resultTensor = sourceTensor->add(*argTensor);
- auto actual = resultTensor->toSpec();
- EXPECT_EQ(actual, expected);
-}
-
-void
-assertNullTensor(const TensorSpec &source, const TensorSpec &arg)
-{
- auto sourceTensor = makeTensor<Tensor>(source);
- auto argTensor = makeTensor<Tensor>(arg);
- auto resultTensor = sourceTensor->add(*argTensor);
- EXPECT_FALSE(resultTensor);
-}
-
-TEST(TensorAddTest, cells_can_be_added_to_a_sparse_tensor)
-{
- assertAdd(TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 2)
- .add({{"x","c"},{"y","d"}}, 3),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 5)
- .add({{"x","e"},{"y","f"}}, 7),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 5)
- .add({{"x","c"},{"y","d"}}, 3)
- .add({{"x","e"},{"y","f"}}, 7));
-}
-
-TEST(TensorAddTest, cells_can_be_added_to_a_mixed_tensor)
-{
- assertAdd(TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3)
- .add({{"x","b"},{"y",0}}, 4)
- .add({{"x","b"},{"y",1}}, 5),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","b"},{"y",0}}, 6)
- .add({{"x","b"},{"y",1}}, 7)
- .add({{"x","c"},{"y",0}}, 8)
- .add({{"x","c"},{"y",1}}, 9),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3)
- .add({{"x","b"},{"y",0}}, 6)
- .add({{"x","b"},{"y",1}}, 7)
- .add({{"x","c"},{"y",0}}, 8)
- .add({{"x","c"},{"y",1}}, 9));
-}
-
-TEST(TensorAddTest, cells_can_be_added_to_empty_mixed_tensor)
-{
- assertAdd(TensorSpec("tensor(x{},y[2])"),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","b"},{"y",0}}, 6)
- .add({{"x","b"},{"y",1}}, 7),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","b"},{"y",0}}, 6)
- .add({{"x","b"},{"y",1}}, 7));
-}
-
-TEST(TensorAddTest, tensors_of_different_types_cannot_be_added_together)
-{
- assertNullTensor(TensorSpec("tensor(x{},y[2])"), TensorSpec("tensor(x{},y{})"));
- assertNullTensor(TensorSpec("tensor(x{},y[2])"), TensorSpec("tensor(x{},y[3])"));
-}
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/tensor/tensor_address/.gitignore b/eval/src/tests/tensor/tensor_address/.gitignore
deleted file mode 100644
index 189adb8710b..00000000000
--- a/eval/src/tests/tensor/tensor_address/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-vespalib_tensor_address_test_app
diff --git a/eval/src/tests/tensor/tensor_address/CMakeLists.txt b/eval/src/tests/tensor/tensor_address/CMakeLists.txt
deleted file mode 100644
index e1daacb7bd4..00000000000
--- a/eval/src/tests/tensor/tensor_address/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_address_test_app TEST
- SOURCES
- tensor_address_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_tensor_address_test_app COMMAND eval_tensor_address_test_app)
diff --git a/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp b/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp
deleted file mode 100644
index c12b7071d02..00000000000
--- a/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/tensor_address.h>
-
-using namespace vespalib::tensor;
-
-void
-assertSortOrder(const TensorAddress::Elements &exp,
- const TensorAddress::Elements &input)
-{
- TensorAddress address(input);
- EXPECT_EQUAL(exp, address.elements());
-}
-
-TEST("require that elements are sorted in constructor")
-{
- assertSortOrder({{"a","1"},{"b","1"},{"c","1"}},
- {{"c","1"},{"a","1"},{"b","1"}});
-}
-
-TEST("require that we can check whether a dimension is present")
-{
- TensorAddress address({{"a","1"},{"b","1"}});
- EXPECT_TRUE(address.hasDimension("a"));
- EXPECT_TRUE(address.hasDimension("b"));
- EXPECT_FALSE(address.hasDimension("c"));
-}
-
-TEST("require that tensor address sort order is defined")
-{
- TensorAddress::Elements single = {{"a","1"}};
- EXPECT_LESS(TensorAddress(single),
- TensorAddress({{"a","1"},{"b","1"}}));
- EXPECT_LESS(TensorAddress({{"a","1"},{"b","1"}}),
- TensorAddress({{"a","1"},{"c","1"}}));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/tensor_conformance/.gitignore b/eval/src/tests/tensor/tensor_conformance/.gitignore
index 60177365cf7..bcc561de73c 100644
--- a/eval/src/tests/tensor/tensor_conformance/.gitignore
+++ b/eval/src/tests/tensor/tensor_conformance/.gitignore
@@ -1,2 +1,2 @@
/binary_test_spec.json
-/conformance_test_spec.json
+/conformance_result.json
diff --git a/eval/src/tests/tensor/tensor_conformance/tensor_conformance_test.cpp b/eval/src/tests/tensor/tensor_conformance/tensor_conformance_test.cpp
index 6468f50a00e..15aa7212a94 100644
--- a/eval/src/tests/tensor/tensor_conformance/tensor_conformance_test.cpp
+++ b/eval/src/tests/tensor/tensor_conformance/tensor_conformance_test.cpp
@@ -1,32 +1,25 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/test/tensor_conformance.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/streamed/streamed_value_builder_factory.h>
#include <vespa/eval/eval/fast_value.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/io/mapped_file_input.h>
+#include <vespa/vespalib/data/slime/slime.h>
using vespalib::eval::SimpleValueBuilderFactory;
using vespalib::eval::StreamedValueBuilderFactory;
using vespalib::eval::FastValueBuilderFactory;
-using vespalib::eval::SimpleTensorEngine;
using vespalib::eval::test::TensorConformance;
-using vespalib::tensor::DefaultTensorEngine;
-using vespalib::make_string;
+using vespalib::make_string_short::fmt;
+using vespalib::Slime;
+using vespalib::slime::JsonFormat;
+using vespalib::MappedFileInput;
vespalib::string module_src_path(TEST_PATH("../../../../"));
vespalib::string module_build_path("../../../../");
-TEST("require that reference tensor implementation passes all conformance tests") {
- TEST_DO(TensorConformance::run_tests(module_src_path, SimpleTensorEngine::ref()));
-}
-
-TEST("require that production tensor implementation passes all conformance tests") {
- TEST_DO(TensorConformance::run_tests(module_src_path, DefaultTensorEngine::ref()));
-}
-
TEST("require that SimpleValue implementation passes all conformance tests") {
TEST_DO(TensorConformance::run_tests(module_src_path, SimpleValueBuilderFactory::get()));
}
@@ -42,21 +35,28 @@ TEST("require that FastValue implementation passes all conformance tests") {
TEST("require that tensor serialization test spec can be generated") {
vespalib::string spec = module_src_path + "src/apps/make_tensor_binary_format_test_spec/test_spec.json";
vespalib::string binary = module_build_path + "src/apps/make_tensor_binary_format_test_spec/eval_make_tensor_binary_format_test_spec_app";
- EXPECT_EQUAL(system(make_string("%s > binary_test_spec.json", binary.c_str()).c_str()), 0);
- EXPECT_EQUAL(system(make_string("diff -u %s binary_test_spec.json", spec.c_str()).c_str()), 0);
-}
-
-TEST("require that cross-language tensor conformance test spec can be generated") {
- vespalib::string spec = module_src_path + "src/apps/tensor_conformance/test_spec.json";
- vespalib::string binary = module_build_path + "src/apps/tensor_conformance/vespa-tensor-conformance";
- EXPECT_EQUAL(system(make_string("%s generate > conformance_test_spec.json", binary.c_str()).c_str()), 0);
- EXPECT_EQUAL(system(make_string("%s compare %s conformance_test_spec.json", binary.c_str(), spec.c_str()).c_str()), 0);
+ EXPECT_EQUAL(system(fmt("%s > binary_test_spec.json", binary.c_str()).c_str()), 0);
+ EXPECT_EQUAL(system(fmt("diff -u %s binary_test_spec.json", spec.c_str()).c_str()), 0);
}
-TEST("require that cross-language tensor conformance tests pass with production C++ expression evaluation") {
- vespalib::string spec = module_src_path + "src/apps/tensor_conformance/test_spec.json";
+TEST("require that cross-language tensor conformance tests pass with C++ expression evaluation") {
+ vespalib::string result_file = "conformance_result.json";
vespalib::string binary = module_build_path + "src/apps/tensor_conformance/vespa-tensor-conformance";
- EXPECT_EQUAL(system(make_string("cat %s | %s evaluate | %s verify", spec.c_str(), binary.c_str(), binary.c_str()).c_str()), 0);
+ EXPECT_EQUAL(system(fmt("%s generate | %s evaluate | %s verify > %s", binary.c_str(), binary.c_str(), binary.c_str(), result_file.c_str()).c_str()), 0);
+ Slime result;
+ MappedFileInput input(result_file);
+ JsonFormat::decode(input, result);
+ fprintf(stderr, "conformance summary: %s\n", result.toString().c_str());
+ int num_tests = result.get()["num_tests"].asLong();
+ int prod_tests = result.get()["stats"]["cpp_prod"].asLong();
+ int simple_tests = result.get()["stats"]["cpp_simple_value"].asLong();
+ int streamed_tests = result.get()["stats"]["cpp_streamed_value"].asLong();
+ int with_expect = result.get()["stats"]["expect"].asLong();
+ EXPECT_GREATER(num_tests, 1000);
+ EXPECT_EQUAL(prod_tests, num_tests);
+ EXPECT_EQUAL(simple_tests, num_tests);
+ EXPECT_EQUAL(streamed_tests, num_tests);
+ EXPECT_EQUAL(with_expect, num_tests);
}
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt b/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt
deleted file mode 100644
index cd4643deae0..00000000000
--- a/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_modify_operation_test_app TEST
- SOURCES
- tensor_modify_operation_test.cpp
- DEPENDS
- vespaeval
- GTest::GTest
-)
-vespa_add_test(NAME eval_tensor_modify_operation_test_app COMMAND eval_tensor_modify_operation_test_app)
diff --git a/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp b/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp
deleted file mode 100644
index 00ee55ed7af..00000000000
--- a/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
-#include <vespa/eval/tensor/test/test_utils.h>
-#include <vespa/vespalib/gtest/gtest.h>
-#include <vespa/vespalib/util/stringfmt.h>
-
-using vespalib::eval::Value;
-using vespalib::eval::TensorSpec;
-using vespalib::tensor::test::makeTensor;
-using namespace vespalib::tensor;
-
-void
-checkUpdate(const TensorSpec &source, const TensorSpec &update, const TensorSpec &expect)
-{
- auto sourceTensor = makeTensor<Tensor>(source);
- auto updateTensor = makeTensor<SparseTensor>(update);
- const CellValues cellValues(*updateTensor);
-
- auto actualTensor = sourceTensor->modify(vespalib::eval::operation::Add::f, cellValues);
- auto actual = actualTensor->toSpec();
- auto expectTensor = makeTensor<Tensor>(expect);
- auto expectPadded = expectTensor->toSpec();
- EXPECT_EQ(actual, expectPadded);
-}
-
-TEST(TensorModifyTest, sparse_tensors_can_be_modified)
-{
- checkUpdate(TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 11)
- .add({{"x","9"},{"y","9"}}, 11),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 2),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 13)
- .add({{"x","9"},{"y","9"}}, 11));
-}
-
-TEST(TensorModifyTest, dense_tensors_can_be_modified)
-{
- checkUpdate(TensorSpec("tensor(x[10],y[10])")
- .add({{"x",8},{"y",9}}, 11)
- .add({{"x",9},{"y",9}}, 11),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 2),
- TensorSpec("tensor(x[10],y[10])")
- .add({{"x",8},{"y",9}}, 13)
- .add({{"x",9},{"y",9}}, 11));
-}
-
-TEST(TensorModifyTest, mixed_tensors_can_be_modified)
-{
- checkUpdate(TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3)
- .add({{"x","b"},{"y",0}}, 4)
- .add({{"x","b"},{"y",1}}, 5),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","0"}}, 6)
- .add({{"x","b"},{"y","1"}}, 7),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 8)
- .add({{"x","a"},{"y",1}}, 3)
- .add({{"x","b"},{"y",0}}, 4)
- .add({{"x","b"},{"y",1}}, 12));
-}
-
-TEST(TensorModifyTest, sparse_tensors_ignore_updates_to_missing_cells)
-{
- checkUpdate(TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 11)
- .add({{"x","9"},{"y","9"}}, 11),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","7"},{"y","9"}}, 2)
- .add({{"x","8"},{"y","9"}}, 2),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 13)
- .add({{"x","9"},{"y","9"}}, 11));
-}
-
-TEST(TensorModifyTest, dense_tensors_ignore_updates_to_out_of_range_cells)
-{
- checkUpdate(TensorSpec("tensor(x[10],y[10])")
- .add({{"x",8},{"y",9}}, 11)
- .add({{"x",9},{"y",9}}, 11),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","8"},{"y","9"}}, 2)
- .add({{"x","10"},{"y","9"}}, 2),
- TensorSpec("tensor(x[10],y[10])")
- .add({{"x",8},{"y",9}}, 13)
- .add({{"x",9},{"y",9}}, 11));
-}
-
-TEST(TensorModifyTest, mixed_tensors_ignore_updates_to_missing_or_out_of_range_cells)
-{
- checkUpdate(TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","2"}}, 4)
- .add({{"x","c"},{"y","0"}}, 5),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3));
-}
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/tensor/tensor_remove_operation/CMakeLists.txt b/eval/src/tests/tensor/tensor_remove_operation/CMakeLists.txt
deleted file mode 100644
index a302cc528e0..00000000000
--- a/eval/src/tests/tensor/tensor_remove_operation/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_remove_operation_test_app TEST
- SOURCES
- tensor_remove_operation_test.cpp
- DEPENDS
- vespaeval
- GTest::GTest
-)
-vespa_add_test(NAME eval_tensor_remove_operation_test_app COMMAND eval_tensor_remove_operation_test_app)
diff --git a/eval/src/tests/tensor/tensor_remove_operation/tensor_remove_operation_test.cpp b/eval/src/tests/tensor/tensor_remove_operation/tensor_remove_operation_test.cpp
deleted file mode 100644
index ceeaf2c99da..00000000000
--- a/eval/src/tests/tensor/tensor_remove_operation/tensor_remove_operation_test.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
-#include <vespa/eval/tensor/test/test_utils.h>
-#include <vespa/vespalib/gtest/gtest.h>
-
-using vespalib::eval::Value;
-using vespalib::eval::TensorSpec;
-using vespalib::tensor::test::makeTensor;
-using namespace vespalib::tensor;
-
-void
-assertRemove(const TensorSpec &source, const TensorSpec &arg, const TensorSpec &expected)
-{
- auto sourceTensor = makeTensor<Tensor>(source);
- auto argTensor = makeTensor<SparseTensor>(arg);
- auto resultTensor = sourceTensor->remove(CellValues(*argTensor));
- auto actual = resultTensor->toSpec();
- EXPECT_EQ(actual, expected);
-}
-
-TEST(TensorRemoveTest, cells_can_be_removed_from_a_sparse_tensor)
-{
- assertRemove(TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 2)
- .add({{"x","c"},{"y","d"}}, 3),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","c"},{"y","d"}}, 1)
- .add({{"x","e"},{"y","f"}}, 1),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 2));
-}
-
-TEST(TensorRemoveTest, all_cells_can_be_removed_from_a_sparse_tensor)
-{
- assertRemove(TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 2),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","a"},{"y","b"}}, 1),
- TensorSpec("tensor(x{},y{})"));
-}
-
-TEST(TensorRemoveTest, cells_can_be_removed_from_a_mixed_tensor)
-{
- assertRemove(TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3)
- .add({{"x","b"},{"y",0}}, 4)
- .add({{"x","b"},{"y",1}}, 5),
- TensorSpec("tensor(x{})")
- .add({{"x","b"}}, 1)
- .add({{"x","c"}}, 1),
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3));
-
- assertRemove(TensorSpec("tensor(x{},y{},z[2])")
- .add({{"x","a"},{"y","c"},{"z",0}}, 2)
- .add({{"x","a"},{"y","c"},{"z",1}}, 3)
- .add({{"x","b"},{"y","c"},{"z",0}}, 4)
- .add({{"x","b"},{"y","c"},{"z",1}}, 5),
- TensorSpec("tensor(x{},y{})")
- .add({{"x","b"},{"y","c"}}, 1)
- .add({{"x","c"},{"y","c"}}, 1),
- TensorSpec("tensor(x{},y{},z[2])")
- .add({{"x","a"},{"y","c"},{"z",0}}, 2)
- .add({{"x","a"},{"y","c"},{"z",1}}, 3));
-
- assertRemove(TensorSpec("tensor(x{},y[1],z[2])")
- .add({{"x","a"},{"y",0},{"z",0}}, 2)
- .add({{"x","a"},{"y",0},{"z",1}}, 3)
- .add({{"x","b"},{"y",0},{"z",0}}, 4)
- .add({{"x","b"},{"y",0},{"z",1}}, 5),
- TensorSpec("tensor(x{})")
- .add({{"x","b"}}, 1)
- .add({{"x","c"}}, 1),
- TensorSpec("tensor(x{},y[1],z[2])")
- .add({{"x","a"},{"y",0},{"z",0}}, 2)
- .add({{"x","a"},{"y",0},{"z",1}}, 3));
-}
-
-TEST(TensorRemoveTest, all_cells_can_be_removed_from_a_mixed_tensor)
-{
- assertRemove(TensorSpec("tensor(x{},y[2])")
- .add({{"x","a"},{"y",0}}, 2)
- .add({{"x","a"},{"y",1}}, 3),
- TensorSpec("tensor(x{})")
- .add({{"x","a"}}, 1),
- TensorSpec("tensor(x{},y[2])"));
-}
-
-GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/tensor/tensor_serialization/.gitignore b/eval/src/tests/tensor/tensor_serialization/.gitignore
deleted file mode 100644
index f8525561c6b..00000000000
--- a/eval/src/tests/tensor/tensor_serialization/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-vespalib_tensor_serialization_test_app
diff --git a/eval/src/tests/tensor/tensor_serialization/CMakeLists.txt b/eval/src/tests/tensor/tensor_serialization/CMakeLists.txt
deleted file mode 100644
index b9fc7e0d544..00000000000
--- a/eval/src/tests/tensor/tensor_serialization/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_serialization_test_app TEST
- SOURCES
- tensor_serialization_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_tensor_serialization_test_app COMMAND eval_tensor_serialization_test_app)
diff --git a/eval/src/tests/tensor/tensor_serialization/tensor_serialization_test.cpp b/eval/src/tests/tensor/tensor_serialization/tensor_serialization_test.cpp
deleted file mode 100644
index 358f5d36101..00000000000
--- a/eval/src/tests/tensor/tensor_serialization/tensor_serialization_test.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
-#include <vespa/eval/tensor/types.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/serialization/typed_binary_format.h>
-#include <vespa/eval/tensor/serialization/sparse_binary_format.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/vespalib/objects/hexdump.h>
-#include <ostream>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/eval/simple_value.h>
-
-using namespace vespalib::tensor;
-using vespalib::eval::TensorSpec;
-using vespalib::nbostream;
-using ExpBuffer = std::vector<uint8_t>;
-
-namespace std {
-
-bool operator==(const std::vector<uint8_t> &exp, const nbostream &stream)
-{
- return ((exp.size() == stream.size()) &&
- (memcmp(&exp[0], stream.peek(), exp.size()) == 0));
-}
-
-std::ostream &operator<<(std::ostream &out, const std::vector<uint8_t> &rhs)
-{
- out << vespalib::HexDump(&rhs[0], rhs.size());
- return out;
-}
-
-}
-
-//-----------------------------------------------------------------------------
-
-template <typename T>
-void verify_cells_only(const ExpBuffer &exp, const TensorSpec &spec) {
- nbostream input(&exp[0], exp.size());
- std::vector<T> cells;
- TypedBinaryFormat::deserializeCellsOnlyFromDenseTensors(input, cells);
- ASSERT_EQUAL(cells.size(), spec.cells().size());
- size_t i = 0;
- for (const auto &cell: spec.cells()) {
- EXPECT_EQUAL(cells[i++], cell.second.value);
- }
- ASSERT_EQUAL(i, cells.size());
-}
-
-TensorSpec verify_new_value_serialized(const ExpBuffer &exp, const TensorSpec &spec) {
- const auto &factory = vespalib::eval::SimpleValueBuilderFactory::get();
- auto new_value = vespalib::eval::value_from_spec(spec, factory);
- auto new_value_spec = vespalib::eval::spec_from_value(*new_value);
- nbostream actual;
- vespalib::eval::encode_value(*new_value, actual);
- ASSERT_EQUAL(exp, actual);
- auto new_decoded = vespalib::eval::decode_value(actual, factory);
- auto new_decoded_spec = vespalib::eval::spec_from_value(*new_decoded);
- EXPECT_EQUAL(0u, actual.size());
- EXPECT_EQUAL(new_value_spec, new_decoded_spec);
- if (new_value->type().is_dense()) {
- TEST_DO(verify_cells_only<float>(exp, new_value_spec));
- TEST_DO(verify_cells_only<double>(exp, new_value_spec));
- }
- return new_decoded_spec;
-}
-
-void verify_serialized(const ExpBuffer &exp, const TensorSpec &spec) {
- auto &engine = DefaultTensorEngine::ref();
- auto value = engine.from_spec(spec);
- auto value_spec = engine.to_spec(*value);
- nbostream actual;
- engine.encode(*value, actual);
- EXPECT_EQUAL(exp, actual);
- auto decoded = engine.decode(actual);
- auto decoded_spec = engine.to_spec(*decoded);
- EXPECT_EQUAL(0u, actual.size());
- EXPECT_EQUAL(value_spec, decoded_spec);
- if (value->type().is_dense()) {
- TEST_DO(verify_cells_only<float>(exp, value_spec));
- TEST_DO(verify_cells_only<double>(exp, value_spec));
- }
- auto new_value_spec = verify_new_value_serialized(exp, spec);
- EXPECT_EQUAL(value_spec, new_value_spec);
-}
-
-//-----------------------------------------------------------------------------
-
-TEST("test tensor serialization for SparseTensor") {
- TEST_DO(verify_serialized({ 0x01, 0x01, 0x01, 0x78, 0x00 },
- TensorSpec("tensor(x{})")));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79, 0x00 },
- TensorSpec("tensor(x{},y{})")));
- TEST_DO(verify_serialized({ 0x01, 0x01, 0x01, 0x78, 0x01, 0x01, 0x31, 0x40,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- TensorSpec("tensor(x{})")
- .add({{"x", "1"}}, 3)));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79, 0x01, 0x00,
- 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00 },
- TensorSpec("tensor(x{},y{})")
- .add({{"x", ""}, {"y", ""}}, 3)));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79, 0x01, 0x01,
- 0x31, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00 },
- TensorSpec("tensor(x{},y{})")
- .add({{"x", "1"}, {"y", ""}}, 3)));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79, 0x01, 0x00,
- 0x01, 0x33, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00 },
- TensorSpec("tensor(x{},y{})")
- .add({{"x", ""}, {"y", "3"}}, 3)));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79, 0x01, 0x01,
- 0x32, 0x01, 0x34, 0x40, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00 },
- TensorSpec("tensor(x{},y{})")
- .add({{"x", "2"}, {"y", "4"}}, 3)));
- TEST_DO(verify_serialized({ 0x01, 0x02, 0x01, 0x78, 0x01, 0x79,
- 0x01, 0x01, 0x31, 0x00, 0x40, 0x08,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
- TensorSpec("tensor(x{},y{})")
- .add({{"x", "1"}, {"y", ""}}, 3)));
-}
-
-TEST("test float cells from sparse tensor") {
- TEST_DO(verify_serialized({ 0x05, 0x01,
- 0x02, 0x01, 0x78, 0x01, 0x79,
- 0x01, 0x01, 0x31, 0x00,
- 0x40, 0x40, 0x00, 0x00 },
- TensorSpec("tensor<float>(x{},y{})")
- .add({{"x", "1"}, {"y", ""}}, 3)));
-}
-
-TEST("test tensor serialization for DenseTensor") {
- TEST_DO(verify_serialized({0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("double")));
- TEST_DO(verify_serialized({0x02, 0x01, 0x01, 0x78, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[1])")
- .add({{"x", 0}}, 0)));
- TEST_DO(verify_serialized({0x02, 0x02, 0x01, 0x78, 0x01,
- 0x01, 0x79, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[1],y[1])")
- .add({{"x", 0}, {"y", 0}}, 0)));
- TEST_DO(verify_serialized({0x02, 0x01, 0x01, 0x78, 0x02,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[2])")
- .add({{"x", 1}}, 3)));
- TEST_DO(verify_serialized({0x02, 0x02, 0x01, 0x78, 0x01,
- 0x01, 0x79, 0x01,
- 0x40, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[1],y[1])")
- .add({{"x", 0}, {"y", 0}}, 3)));
- TEST_DO(verify_serialized({0x02, 0x02, 0x01, 0x78, 0x02,
- 0x01, 0x79, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[2],y[1])")
- .add({{"x", 1}, {"y", 0}}, 3)));
- TEST_DO(verify_serialized({0x02, 0x02, 0x01, 0x78, 0x01,
- 0x01, 0x79, 0x04,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[1],y[4])")
- .add({{"x", 0}, {"y", 3}}, 3)));
- TEST_DO(verify_serialized({0x02, 0x02, 0x01, 0x78, 0x03,
- 0x01, 0x79, 0x05,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- TensorSpec("tensor(x[3],y[5])")
- .add({{"x", 2}, {"y", 4}}, 3)));
-}
-
-TEST("test float cells for dense tensor") {
- TEST_DO(verify_serialized({0x06, 0x01, 0x02, 0x01, 0x78, 0x03,
- 0x01, 0x79, 0x05,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x40, 0x00, 0x00 },
- TensorSpec("tensor<float>(x[3],y[5])")
- .add({{"x", 2}, {"y", 4}}, 3)));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/vespa/eval/CMakeLists.txt b/eval/src/vespa/eval/CMakeLists.txt
index 952640195b1..4160bdf8f34 100644
--- a/eval/src/vespa/eval/CMakeLists.txt
+++ b/eval/src/vespa/eval/CMakeLists.txt
@@ -2,16 +2,13 @@
vespa_add_library(vespaeval
SOURCES
$<TARGET_OBJECTS:eval_eval>
- $<TARGET_OBJECTS:eval_instruction>
$<TARGET_OBJECTS:eval_eval_llvm>
$<TARGET_OBJECTS:eval_eval_test>
$<TARGET_OBJECTS:eval_eval_value_cache>
$<TARGET_OBJECTS:eval_gp>
+ $<TARGET_OBJECTS:eval_instruction>
+ $<TARGET_OBJECTS:eval_onnx>
$<TARGET_OBJECTS:eval_streamed>
- $<TARGET_OBJECTS:eval_tensor>
- $<TARGET_OBJECTS:eval_tensor_dense>
- $<TARGET_OBJECTS:eval_tensor_serialization>
- $<TARGET_OBJECTS:eval_tensor_sparse>
INSTALL lib64
DEPENDS
onnxruntime
diff --git a/eval/src/vespa/eval/eval/CMakeLists.txt b/eval/src/vespa/eval/eval/CMakeLists.txt
index 5cf7440237b..01eeff49662 100644
--- a/eval/src/vespa/eval/eval/CMakeLists.txt
+++ b/eval/src/vespa/eval/eval/CMakeLists.txt
@@ -8,8 +8,8 @@ vespa_add_library(eval_eval OBJECT
cell_type.cpp
compile_tensor_function.cpp
delete_node.cpp
+ dense_cells_value.cpp
double_value_builder.cpp
- engine_or_factory.cpp
fast_forest.cpp
fast_sparse_map.cpp
fast_value.cpp
@@ -25,12 +25,8 @@ vespa_add_library(eval_eval OBJECT
operator_nodes.cpp
optimize_tensor_function.cpp
param_usage.cpp
- simple_tensor.cpp
- simple_tensor_engine.cpp
simple_value.cpp
string_stuff.cpp
- tensor.cpp
- tensor_engine.cpp
tensor_function.cpp
tensor_nodes.cpp
tensor_spec.cpp
diff --git a/eval/src/vespa/eval/eval/basic_nodes.cpp b/eval/src/vespa/eval/eval/basic_nodes.cpp
index b869f2abe22..d7fa76bf1cc 100644
--- a/eval/src/vespa/eval/eval/basic_nodes.cpp
+++ b/eval/src/vespa/eval/eval/basic_nodes.cpp
@@ -4,7 +4,7 @@
#include "node_traverser.h"
#include "node_visitor.h"
#include "interpreted_function.h"
-#include "simple_tensor_engine.h"
+#include "simple_value.h"
namespace vespalib::eval::nodes {
@@ -23,7 +23,8 @@ struct Frame {
double
Node::get_const_value() const {
assert(is_const());
- InterpretedFunction function(SimpleTensorEngine::ref(), *this, NodeTypes());
+ NodeTypes node_types(*this);
+ InterpretedFunction function(SimpleValueBuilderFactory::get(), *this, node_types);
NoParams no_params;
InterpretedFunction::Context ctx(function);
return function.eval(ctx, no_params).as_double();
diff --git a/eval/src/vespa/eval/tensor/serialization/format.txt b/eval/src/vespa/eval/eval/binary_format.txt
index 1a454b0ccf8..4d74c21005a 100644
--- a/eval/src/vespa/eval/tensor/serialization/format.txt
+++ b/eval/src/vespa/eval/eval/binary_format.txt
@@ -12,6 +12,8 @@ with a specific type gives rise to 3 new formats:
sparse_with_cell_type[5], dense_with_cell_type[6] and
mixed_with_cell_type[7].
+(the C++ binary format implementation is located in 'value_codec.cpp')
+
//-----------------------------------------------------------------------------
1_4_int: type (1/5:sparse, 2/6:dense, 3/7:mixed)
diff --git a/eval/src/vespa/eval/eval/cell_type.h b/eval/src/vespa/eval/eval/cell_type.h
index 49114d04bfe..4c4f7e78413 100644
--- a/eval/src/vespa/eval/eval/cell_type.h
+++ b/eval/src/vespa/eval/eval/cell_type.h
@@ -32,16 +32,16 @@ struct CellTypeUtils {
switch (cell_type) {
case CellType::DOUBLE: return sizeof(double);
case CellType::FLOAT: return sizeof(float);
+ default: bad_argument((uint32_t)cell_type);
}
- bad_argument((uint32_t)cell_type);
}
static constexpr size_t mem_size(CellType cell_type, size_t sz) {
switch (cell_type) {
case CellType::DOUBLE: return sz * sizeof(double);
case CellType::FLOAT: return sz * sizeof(float);
+ default: bad_argument((uint32_t)cell_type);
}
- bad_argument((uint32_t)cell_type);
}
};
diff --git a/eval/src/vespa/eval/eval/compile_tensor_function.cpp b/eval/src/vespa/eval/eval/compile_tensor_function.cpp
index 6fd754b9cc8..4f45aa731b5 100644
--- a/eval/src/vespa/eval/eval/compile_tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/compile_tensor_function.cpp
@@ -32,11 +32,11 @@ struct Frame {
};
struct ProgramCompiler {
- EngineOrFactory engine;
+ const ValueBuilderFactory &factory;
Stash &stash;
std::vector<Frame> stack;
std::vector<Instruction> prog;
- ProgramCompiler(EngineOrFactory engine_in, Stash &stash_in) : engine(engine_in), stash(stash_in), stack(), prog() {}
+ ProgramCompiler(const ValueBuilderFactory &factory_in, Stash &stash_in) : factory(factory_in), stash(stash_in), stack(), prog() {}
void append(const std::vector<Instruction> &other_prog) {
prog.insert(prog.end(), other_prog.begin(), other_prog.end());
@@ -44,9 +44,9 @@ struct ProgramCompiler {
void open(const TensorFunction &node) {
if (auto if_node = as<tensor_function::If>(node)) {
- append(compile_tensor_function(engine, if_node->cond(), stash));
- auto true_prog = compile_tensor_function(engine, if_node->true_child(), stash);
- auto false_prog = compile_tensor_function(engine, if_node->false_child(), stash);
+ append(compile_tensor_function(factory, if_node->cond(), stash));
+ auto true_prog = compile_tensor_function(factory, if_node->true_child(), stash);
+ auto false_prog = compile_tensor_function(factory, if_node->false_child(), stash);
true_prog.emplace_back(op_skip, false_prog.size());
prog.emplace_back(op_skip_if_false, true_prog.size());
append(true_prog);
@@ -57,7 +57,7 @@ struct ProgramCompiler {
}
void close(const TensorFunction &node) {
- prog.push_back(node.compile_self(engine, stash));
+ prog.push_back(node.compile_self(factory, stash));
}
std::vector<Instruction> compile(const TensorFunction &function) {
@@ -76,8 +76,8 @@ struct ProgramCompiler {
} // namespace vespalib::eval::<unnamed>
-std::vector<Instruction> compile_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash) {
- ProgramCompiler compiler(engine, stash);
+std::vector<Instruction> compile_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash) {
+ ProgramCompiler compiler(factory, stash);
return compiler.compile(function);
}
diff --git a/eval/src/vespa/eval/eval/compile_tensor_function.h b/eval/src/vespa/eval/eval/compile_tensor_function.h
index b12705e8bb5..b1526f21c5e 100644
--- a/eval/src/vespa/eval/eval/compile_tensor_function.h
+++ b/eval/src/vespa/eval/eval/compile_tensor_function.h
@@ -2,7 +2,6 @@
#pragma once
-#include "engine_or_factory.h"
#include "interpreted_function.h"
#include <vector>
@@ -10,8 +9,9 @@ namespace vespalib { class Stash; }
namespace vespalib::eval {
+struct ValueBuilderFactory;
struct TensorFunction;
-std::vector<InterpretedFunction::Instruction> compile_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash);
+std::vector<InterpretedFunction::Instruction> compile_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash);
} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/eval/dense_cells_value.cpp b/eval/src/vespa/eval/eval/dense_cells_value.cpp
new file mode 100644
index 00000000000..126ef806668
--- /dev/null
+++ b/eval/src/vespa/eval/eval/dense_cells_value.cpp
@@ -0,0 +1,19 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "dense_cells_value.h"
+
+namespace vespalib::eval {
+
+template<typename T> DenseCellsValue<T>::~DenseCellsValue() = default;
+
+template<typename T> MemoryUsage
+DenseCellsValue<T>::get_memory_usage() const {
+ auto usage = self_memory_usage<DenseCellsValue<T>>();
+ usage.merge(vector_extra_memory_usage(_cells));
+ return usage;
+}
+
+template class DenseCellsValue<double>;
+template class DenseCellsValue<float>;
+
+}
diff --git a/eval/src/vespa/eval/eval/dense_cells_value.h b/eval/src/vespa/eval/eval/dense_cells_value.h
new file mode 100644
index 00000000000..ccf6c1388aa
--- /dev/null
+++ b/eval/src/vespa/eval/eval/dense_cells_value.h
@@ -0,0 +1,30 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/value.h>
+#include <cassert>
+
+namespace vespalib::eval {
+
+/**
+ * A dense-only value that just owns a vector of cells.
+ **/
+template<typename T>
+class DenseCellsValue : public Value {
+private:
+ ValueType _type;
+ std::vector<T> _cells;
+public:
+ DenseCellsValue(const ValueType &type_ref, std::vector<T> cells)
+ : _type(type_ref), _cells(std::move(cells))
+ {
+ assert(check_cell_type<T>(_type.cell_type()));
+ assert(_cells.size() == _type.dense_subspace_size());
+ }
+ const ValueType &type() const override { return _type; }
+ TypedCells cells() const override { return TypedCells(_cells); }
+ const Index &index() const override { return TrivialIndex::get(); }
+ MemoryUsage get_memory_usage() const override;
+ ~DenseCellsValue();
+};
+
+}
diff --git a/eval/src/vespa/eval/eval/engine_or_factory.cpp b/eval/src/vespa/eval/eval/engine_or_factory.cpp
deleted file mode 100644
index 36251820c23..00000000000
--- a/eval/src/vespa/eval/eval/engine_or_factory.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "engine_or_factory.h"
-#include "fast_value.h"
-#include "simple_value.h"
-#include "value_codec.h"
-#include "simple_tensor_engine.h"
-#include <vespa/eval/instruction/generic_concat.h>
-#include <vespa/eval/instruction/generic_join.h>
-#include <vespa/eval/instruction/generic_map.h>
-#include <vespa/eval/instruction/generic_merge.h>
-#include <vespa/eval/instruction/generic_reduce.h>
-#include <vespa/eval/instruction/generic_rename.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/vespalib/data/memory.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/vespalib/util/stash.h>
-#include <vespa/vespalib/util/stringfmt.h>
-
-using vespalib::make_string_short::fmt;
-
-using namespace vespalib::eval::instruction;
-
-namespace vespalib::eval {
-
-EngineOrFactory EngineOrFactory::_default{FastValueBuilderFactory::get()};
-
-
-EngineOrFactory
-EngineOrFactory::get_shared(EngineOrFactory hint)
-{
- static EngineOrFactory shared{hint};
- return shared;
-}
-
-TensorSpec
-EngineOrFactory::to_spec(const Value &value) const
-{
- if (is_engine()) {
- return engine().to_spec(value);
- } else {
- return factory(), spec_from_value(value);
- }
-}
-
-std::unique_ptr<Value>
-EngineOrFactory::from_spec(const TensorSpec &spec) const
-{
- if (is_engine()) {
- return engine().from_spec(spec);
- } else {
- return value_from_spec(spec, factory());
- }
-}
-
-void
-EngineOrFactory::encode(const Value &value, nbostream &output) const
-{
- if (is_engine()) {
- return engine().encode(value, output);
- } else {
- return factory(), encode_value(value, output);
- }
-}
-
-std::unique_ptr<Value>
-EngineOrFactory::decode(nbostream &input) const
-{
- if (is_engine()) {
- return engine().decode(input);
- } else {
- return decode_value(input, factory());
- }
-}
-
-std::unique_ptr<Value>
-EngineOrFactory::copy(const Value &value)
-{
- nbostream stream;
- encode(value, stream);
- return decode(stream);
-}
-
-const Value &
-EngineOrFactory::map(const Value &a, operation::op1_t function, Stash &stash) const {
- if (is_engine()) {
- return engine().map(a, function, stash);
- } else {
- return *stash.create<Value::UP>(GenericMap::perform_map(a, function, factory()));
- }
-}
-
-const Value &
-EngineOrFactory::join(const Value &a, const Value &b, operation::op2_t function, Stash &stash) const {
- if (is_engine()) {
- return engine().join(a, b, function, stash);
- } else {
- return *stash.create<Value::UP>(GenericJoin::perform_join(a, b, function, factory()));
- }
-}
-
-const Value &
-EngineOrFactory::merge(const Value &a, const Value &b, operation::op2_t function, Stash &stash) const {
- if (is_engine()) {
- return engine().merge(a, b, function, stash);
- } else {
- return *stash.create<Value::UP>(GenericMerge::perform_merge(a, b, function, factory()));
- }
-}
-
-const Value &
-EngineOrFactory::reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const {
- if (is_engine()) {
- return engine().reduce(a, aggr, dimensions, stash);
- } else {
- return *stash.create<Value::UP>(GenericReduce::perform_reduce(a, aggr, dimensions, factory()));
- }
-}
-
-const Value &
-EngineOrFactory::concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const {
- if (is_engine()) {
- return engine().concat(a, b, dimension, stash);
- } else {
- return *stash.create<Value::UP>(GenericConcat::perform_concat(a, b, dimension, factory()));
- }
-}
-
-const Value &
-EngineOrFactory::rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const {
- if (is_engine()) {
- return engine().rename(a, from, to, stash);
- } else {
- return *stash.create<Value::UP>(GenericRename::perform_rename(a, from, to, factory()));
- }
-}
-
-void
-EngineOrFactory::set(EngineOrFactory wanted)
-{
- auto engine = get_shared(wanted);
- if (engine._value != wanted._value) {
- auto msg = fmt("EngineOrFactory: trying to set implementation to [%s] when [%s] is already in use",
- wanted.to_string().c_str(), engine.to_string().c_str());
- throw IllegalStateException(msg);
- }
-}
-
-EngineOrFactory
-EngineOrFactory::get()
-{
- return get_shared(_default);
-}
-
-vespalib::string
-EngineOrFactory::to_string() const
-{
- if (is_engine()) {
- if (&engine() == &tensor::DefaultTensorEngine::ref()) {
- return "DefaultTensorEngine";
- }
- if (&engine() == &SimpleTensorEngine::ref()) {
- return "SimpleTensorEngine";
- }
- }
- if (is_factory()) {
- if (&factory() == &FastValueBuilderFactory::get()) {
- return "FastValueBuilderFactory";
- }
- if (&factory() == &SimpleValueBuilderFactory::get()) {
- return "SimpleValueBuilderFactory";
- }
- }
- return "???";
-}
-
-}
diff --git a/eval/src/vespa/eval/eval/engine_or_factory.h b/eval/src/vespa/eval/eval/engine_or_factory.h
deleted file mode 100644
index e1f7c503bcd..00000000000
--- a/eval/src/vespa/eval/eval/engine_or_factory.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "aggr.h"
-#include "tensor_spec.h"
-#include "operation.h"
-#include <variant>
-
-namespace vespalib {
-class Stash;
-class nbostream;
-}
-
-namespace vespalib::eval {
-
-struct TensorEngine;
-struct ValueBuilderFactory;
-struct TensorFunction;
-
-/**
- * This utility class contains a reference to either a TensorEngine or
- * a ValueBuilderFactory. This is needed during a transition period to
- * support both evaluation models. We want to get rid of the
- * TensorEngine concept since using the Value API directly removes the
- * need to constrain operations to only calculate on tensors belonging
- * to the same tensor engine. The factory is a hint to the preferred
- * Value implementation.
- **/
-class EngineOrFactory {
-private:
- using engine_t = const TensorEngine *;
- using factory_t = const ValueBuilderFactory *;
- std::variant<engine_t,factory_t> _value;
- static EngineOrFactory _default;
- static EngineOrFactory get_shared(EngineOrFactory hint);
-public:
- EngineOrFactory(const TensorEngine &engine_in) : _value(&engine_in) {}
- EngineOrFactory(const ValueBuilderFactory &factory_in) : _value(&factory_in) {}
- bool is_engine() const { return std::holds_alternative<engine_t>(_value); }
- bool is_factory() const { return std::holds_alternative<factory_t>(_value); }
- const TensorEngine &engine() const { return *std::get<engine_t>(_value); }
- const ValueBuilderFactory &factory() const { return *std::get<factory_t>(_value); }
- // functions that can be called with either engine or factory
- TensorSpec to_spec(const Value &value) const;
- std::unique_ptr<Value> from_spec(const TensorSpec &spec) const;
- void encode(const Value &value, nbostream &output) const;
- std::unique_ptr<Value> decode(nbostream &input) const;
- std::unique_ptr<Value> copy(const Value &value);
- // engine-only forwarding functions
- const Value &map(const Value &a, operation::op1_t function, Stash &stash) const;
- const Value &join(const Value &a, const Value &b, operation::op2_t function, Stash &stash) const;
- const Value &merge(const Value &a, const Value &b, operation::op2_t function, Stash &stash) const;
- const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const;
- const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const;
- const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const;
- // global switch with default; call set before get to override the default
- static void set(EngineOrFactory wanted);
- static EngineOrFactory get();
- // try to describe the value held by this object as a human-readable string
- vespalib::string to_string() const;
-};
-
-}
diff --git a/eval/src/vespa/eval/eval/interpreted_function.cpp b/eval/src/vespa/eval/eval/interpreted_function.cpp
index 1016b929574..5ac401aee39 100644
--- a/eval/src/vespa/eval/eval/interpreted_function.cpp
+++ b/eval/src/vespa/eval/eval/interpreted_function.cpp
@@ -4,11 +4,9 @@
#include "node_visitor.h"
#include "node_traverser.h"
#include "tensor_nodes.h"
-#include "tensor_engine.h"
#include "make_tensor_function.h"
#include "optimize_tensor_function.h"
#include "compile_tensor_function.h"
-#include "simple_tensor_engine.h"
#include <vespa/vespalib/util/classname.h>
#include <vespa/eval/eval/llvm/compile_cache.h>
#include <vespa/vespalib/util/benchmark_timer.h>
@@ -34,8 +32,8 @@ const Function *get_lambda(const nodes::Node &node) {
} // namespace vespalib::<unnamed>
-InterpretedFunction::State::State(EngineOrFactory engine_in)
- : engine(engine_in),
+InterpretedFunction::State::State(const ValueBuilderFactory &factory_in)
+ : factory(factory_in),
params(nullptr),
stash(),
stack(),
@@ -56,26 +54,26 @@ InterpretedFunction::State::init(const LazyParams &params_in) {
}
InterpretedFunction::Context::Context(const InterpretedFunction &ifun)
- : _state(ifun._tensor_engine)
+ : _state(ifun._factory)
{
}
-InterpretedFunction::InterpretedFunction(EngineOrFactory engine, const TensorFunction &function)
+InterpretedFunction::InterpretedFunction(const ValueBuilderFactory &factory, const TensorFunction &function)
: _program(),
_stash(),
- _tensor_engine(engine)
+ _factory(factory)
{
- _program = compile_tensor_function(engine, function, _stash);
+ _program = compile_tensor_function(factory, function, _stash);
}
-InterpretedFunction::InterpretedFunction(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types)
+InterpretedFunction::InterpretedFunction(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types)
: _program(),
_stash(),
- _tensor_engine(engine)
+ _factory(factory)
{
- const TensorFunction &plain_fun = make_tensor_function(engine, root, types, _stash);
- const TensorFunction &optimized = optimize_tensor_function(engine, plain_fun, _stash);
- _program = compile_tensor_function(engine, optimized, _stash);
+ const TensorFunction &plain_fun = make_tensor_function(factory, root, types, _stash);
+ const TensorFunction &optimized = optimize_tensor_function(factory, plain_fun, _stash);
+ _program = compile_tensor_function(factory, optimized, _stash);
}
InterpretedFunction::~InterpretedFunction() = default;
@@ -119,8 +117,8 @@ InterpretedFunction::detect_issues(const Function &function)
return Function::Issues(std::move(checker.issues));
}
-InterpretedFunction::EvalSingle::EvalSingle(EngineOrFactory engine, Instruction op, const LazyParams &params)
- : _state(engine),
+InterpretedFunction::EvalSingle::EvalSingle(const ValueBuilderFactory &factory, Instruction op, const LazyParams &params)
+ : _state(factory),
_op(op)
{
_state.params = &params;
diff --git a/eval/src/vespa/eval/eval/interpreted_function.h b/eval/src/vespa/eval/eval/interpreted_function.h
index f374322ca51..eca434b1260 100644
--- a/eval/src/vespa/eval/eval/interpreted_function.h
+++ b/eval/src/vespa/eval/eval/interpreted_function.h
@@ -2,7 +2,7 @@
#pragma once
-#include "engine_or_factory.h"
+#include "value.h"
#include "function.h"
#include "node_types.h"
#include "lazy_params.h"
@@ -28,14 +28,14 @@ class InterpretedFunction
{
public:
struct State {
- EngineOrFactory engine;
- const LazyParams *params;
- Stash stash;
- std::vector<Value::CREF> stack;
- uint32_t program_offset;
- uint32_t if_cnt;
+ const ValueBuilderFactory &factory;
+ const LazyParams *params;
+ Stash stash;
+ std::vector<Value::CREF> stack;
+ uint32_t program_offset;
+ uint32_t if_cnt;
- State(EngineOrFactory engine_in);
+ State(const ValueBuilderFactory &factory_in);
~State();
void init(const LazyParams &params_in);
@@ -85,17 +85,17 @@ public:
};
private:
- std::vector<Instruction> _program;
- Stash _stash;
- EngineOrFactory _tensor_engine;
+ std::vector<Instruction> _program;
+ Stash _stash;
+ const ValueBuilderFactory &_factory;
public:
typedef std::unique_ptr<InterpretedFunction> UP;
// for testing; use with care; the tensor function must be kept alive
- InterpretedFunction(EngineOrFactory engine, const TensorFunction &function);
- InterpretedFunction(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types);
- InterpretedFunction(EngineOrFactory engine, const Function &function, const NodeTypes &types)
- : InterpretedFunction(engine, function.root(), types) {}
+ InterpretedFunction(const ValueBuilderFactory &factory, const TensorFunction &function);
+ InterpretedFunction(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types);
+ InterpretedFunction(const ValueBuilderFactory &factory, const Function &function, const NodeTypes &types)
+ : InterpretedFunction(factory, function.root(), types) {}
InterpretedFunction(InterpretedFunction &&rhs) = default;
~InterpretedFunction();
size_t program_size() const { return _program.size(); }
@@ -116,8 +116,8 @@ public:
State _state;
Instruction _op;
public:
- EvalSingle(EngineOrFactory engine, Instruction op, const LazyParams &params);
- EvalSingle(EngineOrFactory engine, Instruction op) : EvalSingle(engine, op, NoParams::params) {}
+ EvalSingle(const ValueBuilderFactory &factory, Instruction op, const LazyParams &params);
+ EvalSingle(const ValueBuilderFactory &factory, Instruction op) : EvalSingle(factory, op, NoParams::params) {}
const Value &eval(const std::vector<Value::CREF> &stack);
};
};
diff --git a/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp b/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp
index f6c09f94fc9..8fbb2c5ac09 100644
--- a/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp
+++ b/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp
@@ -12,14 +12,6 @@
#include <llvm/Analysis/Passes.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/Transforms/Scalar.h>
-#if LLVM_VERSION_MAJOR >= 9 && defined(__clang__)
-// Avoid reference to undefined symbol llvm::cfg::Update<llvm::BasicBlock*>::dump() const
-#define NDEBUG
-#endif
-#include <llvm/LinkAllPasses.h>
-#if LLVM_VERSION_MAJOR >= 9 && defined(__clang__)
-#undef NDEBUG
-#endif
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#if LLVM_VERSION_MAJOR > 9
#include <llvm/Support/ManagedStatic.h>
@@ -109,7 +101,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
llvm::PointerType *make_eval_forest_funptr_t() {
std::vector<llvm::Type*> param_types;
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
param_types.push_back(builder.getDoubleTy()->getPointerTo());
llvm::FunctionType *function_type = llvm::FunctionType::get(builder.getDoubleTy(), param_types, false);
return llvm::PointerType::get(function_type, 0);
@@ -117,7 +109,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
llvm::PointerType *make_resolve_param_funptr_t() {
std::vector<llvm::Type*> param_types;
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
param_types.push_back(builder.getInt64Ty());
llvm::FunctionType *function_type = llvm::FunctionType::get(builder.getDoubleTy(), param_types, false);
return llvm::PointerType::get(function_type, 0);
@@ -126,9 +118,9 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
llvm::PointerType *make_eval_forest_proxy_funptr_t() {
std::vector<llvm::Type*> param_types;
param_types.push_back(make_eval_forest_funptr_t());
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
param_types.push_back(make_resolve_param_funptr_t());
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
param_types.push_back(builder.getInt64Ty());
llvm::FunctionType *function_type = llvm::FunctionType::get(builder.getDoubleTy(), param_types, false);
return llvm::PointerType::get(function_type, 0);
@@ -136,7 +128,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
llvm::PointerType *make_check_membership_funptr_t() {
std::vector<llvm::Type*> param_types;
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
param_types.push_back(builder.getDoubleTy());
llvm::FunctionType *function_type = llvm::FunctionType::get(builder.getInt1Ty(), param_types, false);
return llvm::PointerType::get(function_type, 0);
@@ -172,7 +164,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
} else {
assert(pass_params == PassParams::LAZY);
param_types.push_back(make_resolve_param_funptr_t());
- param_types.push_back(builder.getVoidTy()->getPointerTo());
+ param_types.push_back(builder.getInt8Ty()->getPointerTo());
}
llvm::FunctionType *function_type = llvm::FunctionType::get(builder.getDoubleTy(), param_types, false);
function = llvm::Function::Create(function_type, llvm::Function::ExternalLinkage, name_in.c_str(), &module);
@@ -251,7 +243,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
gbdt::Forest *forest = forests.back().get();
llvm::PointerType *eval_funptr_t = make_eval_forest_funptr_t();
llvm::Value *eval_fun = builder.CreateIntToPtr(builder.getInt64((uint64_t)eval_ptr), eval_funptr_t, "inject_eval");
- llvm::Value *ctx = builder.CreateIntToPtr(builder.getInt64((uint64_t)forest), builder.getVoidTy()->getPointerTo(), "inject_ctx");
+ llvm::Value *ctx = builder.CreateIntToPtr(builder.getInt64((uint64_t)forest), builder.getInt8Ty()->getPointerTo(), "inject_ctx");
if (pass_params == PassParams::ARRAY) {
push(builder.CreateCall(llvm::cast<llvm::FunctionType>(eval_fun->getType()->getPointerElementType()),
eval_fun, {ctx, params[0]}, "call_eval"));
@@ -413,7 +405,7 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser {
PluginState *state = plugin_state.back().get();
llvm::PointerType *funptr_t = make_check_membership_funptr_t();
llvm::Value *call_fun = builder.CreateIntToPtr(builder.getInt64((uint64_t)call_ptr), funptr_t, "inject_call_addr");
- llvm::Value *ctx = builder.CreateIntToPtr(builder.getInt64((uint64_t)state), builder.getVoidTy()->getPointerTo(), "inject_ctx");
+ llvm::Value *ctx = builder.CreateIntToPtr(builder.getInt64((uint64_t)state), builder.getInt8Ty()->getPointerTo(), "inject_ctx");
push(builder.CreateCall(llvm::cast<llvm::FunctionType>(call_fun->getType()->getPointerElementType()),
call_fun, {ctx, lhs}, "call_check_membership"));
} else {
diff --git a/eval/src/vespa/eval/eval/make_tensor_function.cpp b/eval/src/vespa/eval/eval/make_tensor_function.cpp
index dc76c914c06..9ee42f164de 100644
--- a/eval/src/vespa/eval/eval/make_tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/make_tensor_function.cpp
@@ -1,13 +1,13 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "make_tensor_function.h"
+#include "value_codec.h"
#include "tensor_function.h"
#include "node_visitor.h"
#include "node_traverser.h"
#include "tensor_spec.h"
#include "operation.h"
#include "node_types.h"
-#include "tensor_engine.h"
#include <vespa/eval/eval/llvm/compile_cache.h>
namespace vespalib::eval {
@@ -19,13 +19,14 @@ using namespace nodes;
//-----------------------------------------------------------------------------
struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser {
- Stash &stash;
- EngineOrFactory tensor_engine;
- const NodeTypes &types;
+ Stash &stash;
+ const ValueBuilderFactory &factory;
+ const NodeTypes &types;
std::vector<TensorFunction::CREF> stack;
- TensorFunctionBuilder(Stash &stash_in, EngineOrFactory tensor_engine_in, const NodeTypes &types_in)
- : stash(stash_in), tensor_engine(tensor_engine_in), types(types_in), stack() {}
+ TensorFunctionBuilder(Stash &stash_in, const ValueBuilderFactory &factory_in, const NodeTypes &types_in)
+ : stash(stash_in), factory(factory_in), types(types_in), stack() {}
+ ~TensorFunctionBuilder() override;
//-------------------------------------------------------------------------
@@ -85,7 +86,7 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser {
for (size_t i = 0; i < create->num_children(); ++i) {
spec.add(create->get_child_address(i), create->get_child(i).get_const_value());
}
- make_const(node, *stash.create<Value::UP>(tensor_engine.from_spec(spec)));
+ make_const(node, *stash.create<Value::UP>(value_from_spec(spec, factory)));
return true;
}
}
@@ -105,9 +106,9 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser {
void make_lambda(const TensorLambda &node) {
if (node.bindings().empty()) {
NoParams no_bound_params;
- InterpretedFunction my_fun(tensor_engine, node.lambda().root(), types);
+ InterpretedFunction my_fun(factory, node.lambda().root(), types);
TensorSpec spec = tensor_function::Lambda::create_spec_impl(node.type(), no_bound_params, node.bindings(), my_fun);
- make_const(node, *stash.create<Value::UP>(tensor_engine.from_spec(spec)));
+ make_const(node, *stash.create<Value::UP>(value_from_spec(spec, factory)));
} else {
stack.push_back(tensor_function::lambda(node.type(), node.bindings(), node.lambda(), types.export_types(node.lambda().root()), stash));
}
@@ -354,10 +355,12 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser {
void close(const Node &node) override { node.accept(*this); }
};
+TensorFunctionBuilder::~TensorFunctionBuilder() = default;
+
} // namespace vespalib::eval::<unnamed>
-const TensorFunction &make_tensor_function(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types, Stash &stash) {
- TensorFunctionBuilder builder(stash, engine, types);
+const TensorFunction &make_tensor_function(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types, Stash &stash) {
+ TensorFunctionBuilder builder(stash, factory, types);
root.traverse(builder);
assert(builder.stack.size() == 1);
return builder.stack[0];
diff --git a/eval/src/vespa/eval/eval/make_tensor_function.h b/eval/src/vespa/eval/eval/make_tensor_function.h
index 7cf9515e243..4ad578d43de 100644
--- a/eval/src/vespa/eval/eval/make_tensor_function.h
+++ b/eval/src/vespa/eval/eval/make_tensor_function.h
@@ -2,17 +2,16 @@
#pragma once
-#include "engine_or_factory.h"
-
namespace vespalib { class Stash; }
namespace vespalib::eval {
+struct ValueBuilderFactory;
class NodeTypes;
struct TensorFunction;
namespace nodes { struct Node; }
-const TensorFunction &make_tensor_function(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types, Stash &stash);
+const TensorFunction &make_tensor_function(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types, Stash &stash);
} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/eval/node_types.cpp b/eval/src/vespa/eval/eval/node_types.cpp
index 9569518417d..7d76f2064a3 100644
--- a/eval/src/vespa/eval/eval/node_types.cpp
+++ b/eval/src/vespa/eval/eval/node_types.cpp
@@ -332,6 +332,15 @@ NodeTypes::NodeTypes()
{
}
+NodeTypes::NodeTypes(const nodes::Node &const_node)
+ : _not_found(ValueType::error_type()),
+ _type_map()
+{
+ std::vector<ValueType> no_input_types;
+ nodes::TypeResolver resolver(no_input_types, _type_map, _errors);
+ const_node.traverse(resolver);
+}
+
NodeTypes::NodeTypes(const Function &function, const std::vector<ValueType> &input_types)
: _not_found(ValueType::error_type()),
_type_map()
diff --git a/eval/src/vespa/eval/eval/node_types.h b/eval/src/vespa/eval/eval/node_types.h
index 72332564409..de867f48847 100644
--- a/eval/src/vespa/eval/eval/node_types.h
+++ b/eval/src/vespa/eval/eval/node_types.h
@@ -28,6 +28,7 @@ public:
NodeTypes();
NodeTypes(NodeTypes &&rhs) = default;
NodeTypes &operator=(NodeTypes &&rhs) = default;
+ NodeTypes(const nodes::Node &const_node);
NodeTypes(const Function &function, const std::vector<ValueType> &input_types);
~NodeTypes();
const std::vector<vespalib::string> &errors() const { return _errors; }
diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
index 21f4ce4dabe..cbd4192a84f 100644
--- a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
@@ -2,26 +2,24 @@
#include "optimize_tensor_function.h"
#include "tensor_function.h"
-#include "tensor_engine.h"
#include "simple_value.h"
#include <vespa/eval/instruction/dense_dot_product_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
-#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_add_dimension_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_single_reduce_function.h>
-#include <vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h>
+#include <vespa/eval/instruction/dense_fast_rename_optimizer.h>
+#include <vespa/eval/instruction/dense_add_dimension_optimizer.h>
+#include <vespa/eval/instruction/dense_single_reduce_function.h>
+#include <vespa/eval/instruction/dense_remove_dimension_optimizer.h>
#include <vespa/eval/instruction/dense_lambda_peek_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_lambda_function.h>
#include <vespa/eval/instruction/dense_simple_expand_function.h>
-#include <vespa/eval/tensor/dense/dense_simple_join_function.h>
+#include <vespa/eval/instruction/dense_simple_join_function.h>
#include <vespa/eval/instruction/join_with_number_function.h>
-#include <vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h>
-#include <vespa/eval/tensor/dense/dense_simple_map_function.h>
-#include <vespa/eval/tensor/dense/vector_from_doubles_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor_create_function.h>
+#include <vespa/eval/instruction/dense_pow_as_map_optimizer.h>
+#include <vespa/eval/instruction/dense_simple_map_function.h>
+#include <vespa/eval/instruction/vector_from_doubles_function.h>
+#include <vespa/eval/instruction/dense_tensor_create_function.h>
#include <vespa/eval/instruction/dense_tensor_peek_function.h>
#include <vespa/log/log.h>
@@ -31,8 +29,6 @@ namespace vespalib::eval {
namespace {
-using namespace vespalib::tensor;
-
const TensorFunction &optimize_for_factory(const ValueBuilderFactory &factory, const TensorFunction &expr, Stash &stash) {
if (&factory == &SimpleValueBuilderFactory::get()) {
// never optimize simple value evaluation
@@ -82,11 +78,9 @@ const TensorFunction &optimize_for_factory(const ValueBuilderFactory &factory, c
} // namespace vespalib::eval::<unnamed>
-const TensorFunction &optimize_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash) {
+const TensorFunction &optimize_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash) {
LOG(debug, "tensor function before optimization:\n%s\n", function.as_string().c_str());
- const TensorFunction &optimized = (engine.is_engine())
- ? engine.engine().optimize(function, stash)
- : optimize_for_factory(engine.factory(), function, stash);
+ const TensorFunction &optimized = optimize_for_factory(factory, function, stash);
LOG(debug, "tensor function after optimization:\n%s\n", optimized.as_string().c_str());
return optimized;
}
diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.h b/eval/src/vespa/eval/eval/optimize_tensor_function.h
index bc2bc10cca6..9973f9d4bf8 100644
--- a/eval/src/vespa/eval/eval/optimize_tensor_function.h
+++ b/eval/src/vespa/eval/eval/optimize_tensor_function.h
@@ -2,14 +2,13 @@
#pragma once
-#include "engine_or_factory.h"
-
namespace vespalib { class Stash; }
namespace vespalib::eval {
+struct ValueBuilderFactory;
struct TensorFunction;
-const TensorFunction &optimize_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash);
+const TensorFunction &optimize_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash);
} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/eval/param_usage.cpp b/eval/src/vespa/eval/eval/param_usage.cpp
index b43c0c01833..1f28c6eaa51 100644
--- a/eval/src/vespa/eval/eval/param_usage.cpp
+++ b/eval/src/vespa/eval/eval/param_usage.cpp
@@ -18,6 +18,7 @@ struct CountUsage : NodeTraverser {
double p;
std::vector<double> result;
CountUsage(size_t num_params) : p(1.0), result(num_params, 0.0) {}
+ ~CountUsage() override;
bool open(const Node &node) override {
if (auto if_node = as<If>(node)) {
double my_p = p;
@@ -38,11 +39,14 @@ struct CountUsage : NodeTraverser {
}
};
+CountUsage::~CountUsage() = default;
+
//-----------------------------------------------------------------------------
struct CheckUsage : NodeTraverser {
std::vector<double> result;
CheckUsage(size_t num_params) : result(num_params, 0.0) {}
+ ~CheckUsage() override;
void merge(const std::vector<double> &true_result,
const std::vector<double> &false_result,
double p_true)
@@ -72,6 +76,8 @@ struct CheckUsage : NodeTraverser {
}
};
+CheckUsage::~CheckUsage() = default;
+
//-----------------------------------------------------------------------------
} // namespace vespalib::eval::<unnamed>
diff --git a/eval/src/vespa/eval/eval/simple_tensor.cpp b/eval/src/vespa/eval/eval/simple_tensor.cpp
deleted file mode 100644
index 98e3bc325cb..00000000000
--- a/eval/src/vespa/eval/eval/simple_tensor.cpp
+++ /dev/null
@@ -1,788 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "simple_tensor.h"
-#include "simple_tensor_engine.h"
-#include "operation.h"
-#include <vespa/vespalib/util/overload.h>
-#include <vespa/vespalib/util/visit_ranges.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <algorithm>
-#include <cassert>
-
-namespace vespalib {
-namespace eval {
-
-using Address = SimpleTensor::Address;
-using Cell = SimpleTensor::Cell;
-using Cells = SimpleTensor::Cells;
-using IndexList = std::vector<size_t>;
-using Label = SimpleTensor::Label;
-using CellRef = std::reference_wrapper<const Cell>;
-
-namespace {
-
-constexpr uint32_t DOUBLE_CELL_TYPE = 0;
-constexpr uint32_t FLOAT_CELL_TYPE = 1;
-
-uint32_t cell_type_to_id(CellType cell_type) {
- switch (cell_type) {
- case CellType::DOUBLE: return DOUBLE_CELL_TYPE;
- case CellType::FLOAT: return FLOAT_CELL_TYPE;
- }
- abort();
-}
-
-CellType id_to_cell_type(uint32_t id) {
- switch (id) {
- case DOUBLE_CELL_TYPE: return CellType::DOUBLE;
- case FLOAT_CELL_TYPE: return CellType::FLOAT;
- }
- abort();
-}
-
-void assert_type(const ValueType &type) {
- (void) type;
- assert(type.is_double() || type.is_tensor());
-}
-
-void assert_address(const Address &address, const ValueType &type) {
- assert(address.size() == type.dimensions().size());
- for (size_t i = 0; i < address.size(); ++i) {
- if (type.dimensions()[i].is_mapped()) {
- assert(address[i].is_mapped());
- } else {
- assert(address[i].is_indexed());
- assert(address[i].index < type.dimensions()[i].size);
- }
- }
-}
-
-Address select(const Address &address, const IndexList &selector) {
- Address result;
- for (size_t index: selector) {
- result.push_back(address[index]);
- }
- return result;
-}
-
-Address select(const Address &a, const Address &b, const IndexList &selector) {
- Address result;
- for (size_t index: selector) {
- if (index < a.size()) {
- result.push_back(a[index]);
- } else {
- result.push_back(b[index - a.size()]);
- }
- }
- return result;
-}
-
-size_t get_dimension_size(const ValueType &type, ValueType::Dimension::size_type dim_idx) {
- if (dim_idx == ValueType::Dimension::npos) {
- return 1;
- }
- return type.dimensions()[dim_idx].size;
-}
-
-size_t get_dimension_index(const Address &addr, ValueType::Dimension::size_type dim_idx) {
- if (dim_idx == ValueType::Dimension::npos) {
- return 0;
- }
- return addr[dim_idx].index;
-}
-
-const vespalib::string &reverse_rename(const vespalib::string &name,
- const std::vector<vespalib::string> &from,
- const std::vector<vespalib::string> &to)
-{
- assert(from.size() == to.size());
- for (size_t idx = 0; idx < to.size(); ++idx) {
- if (to[idx] == name) {
- return from[idx];
- }
- }
- return name;
-}
-
-/**
- * Meta information about how a type can be decomposed into mapped and
- * indexed dimensions and also how large each block is. A block is a
- * dense-subspace consisting of all indexed dimensions that is
- * uniquely specified by the labels of all mapped dimensions.
- **/
-struct TypeMeta {
- IndexList mapped;
- IndexList indexed;
- size_t block_size;
- CellType cell_type;
- explicit TypeMeta(const ValueType &type)
- : mapped(),
- indexed(),
- block_size(1),
- cell_type(type.cell_type())
- {
- for (size_t i = 0; i < type.dimensions().size(); ++i) {
- const auto &dimension = type.dimensions()[i];
- if (dimension.is_mapped()) {
- mapped.push_back(i);
- } else {
- block_size *= dimension.size;
- indexed.push_back(i);
- }
- }
- }
- ~TypeMeta() {}
-};
-
-/**
- * Helper class used when building SimpleTensors. While a tensor
- * in its final form simply contains a collection of cells, the
- * builder keeps track of cell values as a block map instead. Each
- * block is a dense multi-dimensional array that is addressed by
- * the combination of all mapped Labels in a cell address. The
- * indexed labels from the same cell address is used to address
- * the appropriate cell value within the block. The reason for
- * this is to make it easier to make sure that the indexed
- * dimensions have entries for all valid Lables (densify with 0.0
- * as default value).
- **/
-class Builder {
-private:
- using Block = std::vector<double>;
- using BlockMap = std::map<Address,Block>;
-
- ValueType _type;
- TypeMeta _meta;
- BlockMap _blocks;
-
- size_t offset_of(const Address &address) const {
- size_t offset = 0;
- for (size_t index: _meta.indexed) {
- size_t label = address[index].index;
- size_t size = _type.dimensions()[index].size;
- offset = (offset * size) + label;
- }
- return offset;
- }
-
- void convert(const Block &block, Address &address, size_t n, Cells &cells_out) const {
- if (n < _meta.indexed.size()) {
- Label &label = address[_meta.indexed[n]];
- size_t size = _type.dimensions()[_meta.indexed[n]].size;
- for (label.index = 0; label.index < size; ++label.index) {
- convert(block, address, n + 1, cells_out);
- }
- } else {
- cells_out.emplace_back(address, block[offset_of(address)]);
- }
- }
-
-public:
- explicit Builder(const ValueType &type)
- : _type(type),
- _meta(type),
- _blocks()
- {
- assert_type(_type);
- if (_meta.mapped.empty()) {
- _blocks.emplace(Address(), Block(_meta.block_size, 0.0));
- }
- }
- ~Builder() {}
- void set(const Address &address, double value) {
- assert_address(address, _type);
- Address block_key = select(address, _meta.mapped);
- auto pos = _blocks.find(block_key);
- if (pos == _blocks.end()) {
- pos = _blocks.emplace(block_key, Block(_meta.block_size, 0.0)).first;
- }
- pos->second[offset_of(address)] = value;
- }
- void set(const TensorSpec::Address &label_map, double value) {
- Address address;
- for (const auto &dimension: _type.dimensions()) {
- auto pos = label_map.find(dimension.name);
- assert(pos != label_map.end());
- address.emplace_back(pos->second);
- }
- set(address, value);
- }
- std::unique_ptr<SimpleTensor> build() {
- Cells cells;
- Address address(_type.dimensions().size(), Label(size_t(0)));
- for (const auto &entry: _blocks) {
- for (size_t i = 0; i < _meta.mapped.size(); ++i) {
- address[_meta.mapped[i]] = entry.first[i];
- }
- convert(entry.second, address, 0, cells);
- }
- return std::make_unique<SimpleTensor>(_type, std::move(cells));
- }
-};
-
-/**
- * Helper class used to calculate which dimensions are shared between
- * types and which are not. Also calculates how address elements from
- * cells with the different types should be combined into a single
- * address.
- **/
-struct TypeAnalyzer {
- static constexpr size_t npos = -1;
- IndexList only_a;
- IndexList overlap_a;
- IndexList overlap_b;
- IndexList only_b;
- IndexList combine;
- size_t ignored_a;
- size_t ignored_b;
- TypeAnalyzer(const ValueType &lhs, const ValueType &rhs, const vespalib::string &ignore = "")
- : only_a(), overlap_a(), overlap_b(), only_b(), combine(), ignored_a(npos), ignored_b(npos)
- {
- const auto &a = lhs.dimensions();
- const auto &b = rhs.dimensions();
- size_t b_idx = 0;
- for (size_t a_idx = 0; a_idx < a.size(); ++a_idx) {
- while ((b_idx < b.size()) && (b[b_idx].name < a[a_idx].name)) {
- if (b[b_idx].name != ignore) {
- only_b.push_back(b_idx);
- combine.push_back(a.size() + b_idx);
- } else {
- ignored_b = b_idx;
- }
- ++b_idx;
- }
- if ((b_idx < b.size()) && (b[b_idx].name == a[a_idx].name)) {
- if (a[a_idx].name != ignore) {
- overlap_a.push_back(a_idx);
- overlap_b.push_back(b_idx);
- combine.push_back(a_idx);
- } else {
- ignored_a = a_idx;
- ignored_b = b_idx;
- }
- ++b_idx;
- } else {
- if (a[a_idx].name != ignore) {
- only_a.push_back(a_idx);
- combine.push_back(a_idx);
- } else {
- ignored_a = a_idx;
- }
- }
- }
- while (b_idx < b.size()) {
- if (b[b_idx].name != ignore) {
- only_b.push_back(b_idx);
- combine.push_back(a.size() + b_idx);
- } else {
- ignored_b = b_idx;
- }
- ++b_idx;
- }
- }
- ~TypeAnalyzer() {}
-};
-
-/**
- * A view is a total ordering of cells from a SimpleTensor according
- * to a subset of the dimensions in the tensor type.
- **/
-class View {
-public:
- /**
- * A range of cells within a view with equal values for all labels
- * corresponding to the dimensions of the view.
- **/
- class EqualRange {
- private:
- const CellRef *_begin;
- const CellRef *_end;
- public:
- EqualRange(const CellRef *begin_in, const CellRef *end_in)
- : _begin(begin_in), _end(end_in) {}
- const CellRef *begin() const { return _begin; };
- const CellRef *end() const { return _end; }
- bool empty() const { return (_begin == _end); }
- };
-private:
- /**
- * Address comparator only looking at a subset of the labels.
- **/
- struct Less {
- IndexList selector;
- explicit Less(const IndexList &selector_in) : selector(selector_in) {}
- bool operator()(const CellRef &a, const CellRef &b) const {
- for (size_t idx: selector) {
- if (a.get().address[idx] != b.get().address[idx]) {
- return (a.get().address[idx] < b.get().address[idx]);
- }
- }
- return false;
- }
- };
- Less _less;
- std::vector<CellRef> _refs;
-
- EqualRange make_range(const CellRef *begin) const {
- const CellRef *end = (begin < refs_end()) ? (begin + 1) : begin;
- while ((end < refs_end()) && !_less(*(end - 1), *end)) {
- ++end;
- }
- return EqualRange(begin, end);
- }
-
-public:
- View(const SimpleTensor &tensor, const IndexList &selector)
- : _less(selector), _refs()
- {
- for (const auto &cell: tensor.my_cells()) {
- _refs.emplace_back(cell);
- }
- std::sort(_refs.begin(), _refs.end(), _less);
- }
- View(const EqualRange &range, const IndexList &selector)
- : _less(selector), _refs()
- {
- for (const auto &cell: range) {
- _refs.emplace_back(cell);
- }
- std::sort(_refs.begin(), _refs.end(), _less);
- }
- ~View() {}
- const IndexList &selector() const { return _less.selector; }
- const CellRef *refs_begin() const { return &_refs[0]; }
- const CellRef *refs_end() const { return (refs_begin() + _refs.size()); }
- EqualRange first_range() const { return make_range(refs_begin()); }
- EqualRange next_range(const EqualRange &prev) const { return make_range(prev.end()); }
-};
-
-/**
- * Helper class used to find matching EqualRanges from two different
- * SimpleTensor Views.
- **/
-class ViewMatcher {
-public:
- /**
- * Comparator used to cross-compare addresses across two different
- * views only looking at the overlapping dimensions between the
- * views.
- **/
- struct CrossCompare {
- enum class Result { LESS, EQUAL, GREATER };
- IndexList a_selector;
- IndexList b_selector;
- CrossCompare(const IndexList &a_selector_in, const IndexList &b_selector_in)
- : a_selector(a_selector_in), b_selector(b_selector_in)
- {
- assert(a_selector.size() == b_selector.size());
- }
- ~CrossCompare() {}
- Result compare(const Cell &a, const Cell &b) const {
- for (size_t i = 0; i < a_selector.size(); ++i) {
- if (a.address[a_selector[i]] != b.address[b_selector[i]]) {
- if (a.address[a_selector[i]] < b.address[b_selector[i]]) {
- return Result::LESS;
- } else {
- return Result::GREATER;
- }
- }
- }
- return Result::EQUAL;
- }
- };
- using EqualRange = View::EqualRange;
-
-private:
- const View &_a;
- const View &_b;
- EqualRange _a_range;
- EqualRange _b_range;
- CrossCompare _cmp;
-
- bool has_a() const { return !_a_range.empty(); }
- bool has_b() const { return !_b_range.empty(); }
- void next_a() { _a_range = _a.next_range(_a_range); }
- void next_b() { _b_range = _b.next_range(_b_range); }
-
- void find_match() {
- while (valid()) {
- switch (_cmp.compare(*get_a().begin(), *get_b().begin())) {
- case CrossCompare::Result::LESS:
- next_a();
- break;
- case CrossCompare::Result::GREATER:
- next_b();
- break;
- case CrossCompare::Result::EQUAL:
- return;
- }
- }
- }
-
-public:
- ViewMatcher(const View &a, const View &b)
- : _a(a), _b(b), _a_range(_a.first_range()), _b_range(b.first_range()),
- _cmp(a.selector(), b.selector())
- {
- find_match();
- }
- ~ViewMatcher() {}
- bool valid() const { return (has_a() && has_b()); }
- const EqualRange &get_a() const { return _a_range; }
- const EqualRange &get_b() const { return _b_range; }
- void next() {
- next_a();
- next_b();
- find_match();
- }
-};
-
-struct Format {
- bool is_sparse;
- bool is_dense;
- bool with_cell_type;
- uint32_t tag;
- explicit Format(const TypeMeta &meta)
- : is_sparse(meta.mapped.size() > 0),
- is_dense((meta.indexed.size() > 0) || !is_sparse),
- with_cell_type(meta.cell_type != CellType::DOUBLE),
- tag((is_sparse ? 0x1 : 0) | (is_dense ? 0x2 : 0) | (with_cell_type ? 0x4 : 0)) {}
- explicit Format(uint32_t tag_in)
- : is_sparse((tag_in & 0x1) != 0),
- is_dense((tag_in & 0x2) != 0),
- with_cell_type((tag_in & 0x4) != 0),
- tag(tag_in) {}
- ~Format() {}
-};
-
-void maybe_encode_cell_type(nbostream &output, const Format &format, const TypeMeta &meta) {
- if (format.with_cell_type) {
- output.putInt1_4Bytes(cell_type_to_id(meta.cell_type));
- }
-}
-
-void encode_type(nbostream &output, const Format &format, const ValueType &type, const TypeMeta &meta) {
- maybe_encode_cell_type(output, format, meta);
- if (format.is_sparse) {
- output.putInt1_4Bytes(meta.mapped.size());
- for (size_t idx: meta.mapped) {
- output.writeSmallString(type.dimensions()[idx].name);
- }
- }
- if (format.is_dense) {
- output.putInt1_4Bytes(meta.indexed.size());
- for (size_t idx: meta.indexed) {
- output.writeSmallString(type.dimensions()[idx].name);
- output.putInt1_4Bytes(type.dimensions()[idx].size);
- }
- }
-}
-
-void maybe_encode_num_blocks(nbostream &output, const TypeMeta &meta, size_t num_blocks) {
- if ((meta.mapped.size() > 0)) {
- output.putInt1_4Bytes(num_blocks);
- }
-}
-
-void encode_mapped_labels(nbostream &output, const TypeMeta &meta, const Address &addr) {
- for (size_t idx: meta.mapped) {
- output.writeSmallString(addr[idx].name);
- }
-}
-
-CellType maybe_decode_cell_type(nbostream &input, const Format &format) {
- if (format.with_cell_type) {
- return id_to_cell_type(input.getInt1_4Bytes());
- }
- return CellType::DOUBLE;
-}
-
-ValueType decode_type(nbostream &input, const Format &format) {
- CellType cell_type = maybe_decode_cell_type(input, format);
- std::vector<ValueType::Dimension> dim_list;
- if (format.is_sparse) {
- size_t cnt = input.getInt1_4Bytes();
- for (size_t i = 0; i < cnt; ++i) {
- vespalib::string name;
- input.readSmallString(name);
- dim_list.emplace_back(name);
- }
- }
- if (format.is_dense) {
- size_t cnt = input.getInt1_4Bytes();
- for (size_t i = 0; i < cnt; ++i) {
- vespalib::string name;
- input.readSmallString(name);
- dim_list.emplace_back(name, input.getInt1_4Bytes());
- }
- }
- return ValueType::tensor_type(std::move(dim_list), cell_type);
-}
-
-size_t maybe_decode_num_blocks(nbostream &input, const TypeMeta &meta, const Format &format) {
- if ((meta.mapped.size() > 0) || !format.is_dense) {
- return input.getInt1_4Bytes();
- }
- return 1;
-}
-
-void decode_mapped_labels(nbostream &input, const TypeMeta &meta, Address &addr) {
- for (size_t idx: meta.mapped) {
- vespalib::string name;
- input.readSmallString(name);
- addr[idx] = Label(name);
- }
-}
-
-void decode_cells(nbostream &input, const ValueType &type, const TypeMeta meta,
- Address &address, size_t n, Builder &builder)
-{
- if (n < meta.indexed.size()) {
- Label &label = address[meta.indexed[n]];
- size_t size = type.dimensions()[meta.indexed[n]].size;
- for (label.index = 0; label.index < size; ++label.index) {
- decode_cells(input, type, meta, address, n + 1, builder);
- }
- } else {
- double value = (meta.cell_type == CellType::FLOAT)
- ? input.readValue<float>()
- : input.readValue<double>();
- builder.set(address, value);
- }
-}
-
-} // namespace vespalib::eval::<unnamed>
-
-constexpr size_t TensorSpec::Label::npos;
-constexpr size_t SimpleTensor::Label::npos;
-
-SimpleTensor::SimpleTensor()
- : Tensor(SimpleTensorEngine::ref()),
- _type(ValueType::error_type()),
- _cells()
-{
-}
-
-SimpleTensor::SimpleTensor(double value)
- : Tensor(SimpleTensorEngine::ref()),
- _type(ValueType::double_type()),
- _cells({Cell({},value)})
-{
-}
-
-SimpleTensor::SimpleTensor(const ValueType &type_in, Cells cells_in)
- : Tensor(SimpleTensorEngine::ref()),
- _type(type_in),
- _cells(std::move(cells_in))
-{
- assert_type(_type);
- for (const auto &cell: _cells) {
- assert_address(cell.address, _type);
- }
- std::sort(_cells.begin(), _cells.end(),
- [](const auto &a, const auto &b){ return (a.address < b.address); });
-}
-
-double
-SimpleTensor::as_double() const
-{
- double sum = 0.0;
- for (auto &cell: _cells) {
- sum += cell.value;
- }
- return sum;
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::map(map_fun_t function) const
-{
- Cells cells(_cells);
- for (auto &cell: cells) {
- cell.value = function(cell.value);
- }
- return std::make_unique<SimpleTensor>(_type, std::move(cells));
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::reduce(Aggregator &aggr, const std::vector<vespalib::string> &dimensions) const
-{
- ValueType result_type = _type.reduce(dimensions);
- if (result_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(result_type);
- IndexList selector = TypeAnalyzer(_type, result_type).overlap_a;
- View view(*this, selector);
- for (View::EqualRange range = view.first_range(); !range.empty(); range = view.next_range(range)) {
- auto pos = range.begin();
- aggr.first((pos++)->get().value);
- for (; pos != range.end(); ++pos) {
- aggr.next(pos->get().value);
- }
- builder.set(select(range.begin()->get().address, selector), aggr.result());
- }
- return builder.build();
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::rename(const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) const
-{
- ValueType result_type = _type.rename(from, to);
- if (result_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(result_type);
- IndexList selector;
- for (const auto &dim: result_type.dimensions()) {
- selector.push_back(_type.dimension_index(reverse_rename(dim.name, from, to)));
- }
- for (auto &cell: _cells) {
- builder.set(select(cell.address, selector), cell.value);
- }
- return builder.build();
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::create(const TensorSpec &spec)
-{
- ValueType my_type = ValueType::from_spec(spec.type());
- if (my_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(my_type);
- for (const auto &cell: spec.cells()) {
- builder.set(cell.first, cell.second);
- }
- return builder.build();
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::join(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function)
-{
- ValueType result_type = ValueType::join(a.type(), b.type());
- if (result_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(result_type);
- TypeAnalyzer type_info(a.type(), b.type());
- View view_a(a, type_info.overlap_a);
- View view_b(b, type_info.overlap_b);
- for (ViewMatcher matcher(view_a, view_b); matcher.valid(); matcher.next()) {
- for (const auto &ref_a: matcher.get_a()) {
- for (const auto &ref_b: matcher.get_b()) {
- builder.set(select(ref_a.get().address, ref_b.get().address, type_info.combine),
- function(ref_a.get().value, ref_b.get().value));
- }
- }
- }
- return builder.build();
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::merge(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function)
-{
- ValueType result_type = ValueType::merge(a.type(), b.type());
- if (result_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(result_type);
- auto cmp = [](const Cell &x, const Cell &y) { return (x.address < y.address); };
- auto visitor = overload{
- [&builder](visit_ranges_either, const Cell &x) { builder.set(x.address, x.value); },
- [&builder,function](visit_ranges_both, const Cell &x, const Cell &y) {
- builder.set(x.address, function(x.value, y.value));
- }};
- visit_ranges(visitor, a._cells.begin(), a._cells.end(), b._cells.begin(), b._cells.end(), cmp);
- return builder.build();
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::concat(const SimpleTensor &a, const SimpleTensor &b, const vespalib::string &dimension)
-{
- ValueType result_type = ValueType::concat(a.type(), b.type(), dimension);
- if (result_type.is_error()) {
- return std::make_unique<SimpleTensor>();
- }
- Builder builder(result_type);
- TypeAnalyzer type_info(a.type(), b.type(), dimension);
- View view_a(a, type_info.overlap_a);
- View view_b(b, type_info.overlap_b);
- size_t cat_dim_idx = result_type.dimension_index(dimension);
- size_t cat_offset = get_dimension_size(a.type(), type_info.ignored_a);
- for (ViewMatcher matcher(view_a, view_b); matcher.valid(); matcher.next()) {
- View subview_a(matcher.get_a(), type_info.only_a);
- View subview_b(matcher.get_b(), type_info.only_b);
- for (auto range_a = subview_a.first_range(); !range_a.empty(); range_a = subview_a.next_range(range_a)) {
- for (auto range_b = subview_b.first_range(); !range_b.empty(); range_b = subview_b.next_range(range_b)) {
- Address addr = select(range_a.begin()->get().address, range_b.begin()->get().address, type_info.combine);
- addr.insert(addr.begin() + cat_dim_idx, Label(size_t(0)));
- for (const auto &ref: range_a) {
- addr[cat_dim_idx].index = get_dimension_index(ref.get().address, type_info.ignored_a);
- builder.set(addr, ref.get().value);
- }
- for (const auto &ref: range_b) {
- addr[cat_dim_idx].index = cat_offset + get_dimension_index(ref.get().address, type_info.ignored_b);
- builder.set(addr, ref.get().value);
- }
- }
- }
- }
- return builder.build();
-}
-
-void
-SimpleTensor::encode(const SimpleTensor &tensor, nbostream &output)
-{
- TypeMeta meta(tensor.type());
- Format format(meta);
- output.putInt1_4Bytes(format.tag);
- encode_type(output, format, tensor.type(), meta);
- maybe_encode_num_blocks(output, meta, tensor.my_cells().size() / meta.block_size);
- View view(tensor, meta.mapped);
- for (auto block = view.first_range(); !block.empty(); block = view.next_range(block)) {
- encode_mapped_labels(output, meta, block.begin()->get().address);
- View subview(block, meta.indexed);
- for (auto cell = subview.first_range(); !cell.empty(); cell = subview.next_range(cell)) {
- if (meta.cell_type == CellType::FLOAT) {
- output << (float) cell.begin()->get().value;
- } else {
- output << cell.begin()->get().value;
- }
- }
- }
-}
-
-std::unique_ptr<SimpleTensor>
-SimpleTensor::decode(nbostream &input)
-{
- Format format(input.getInt1_4Bytes());
- ValueType type = decode_type(input, format);
- TypeMeta meta(type);
- Builder builder(type);
- size_t num_blocks = maybe_decode_num_blocks(input, meta, format);
- Address address(type.dimensions().size(), Label(size_t(0)));
- for (size_t i = 0; i < num_blocks; ++i) {
- decode_mapped_labels(input, meta, address);
- decode_cells(input, type, meta, address, 0, builder);
- }
- return builder.build();
-}
-
-vespalib::MemoryUsage
-SimpleTensor::get_memory_usage() const {
- size_t addr_use = sizeof(Label) * _type.dimensions().size();
- size_t cell_use = sizeof(Cell) + addr_use;
- size_t cells_use = _cells.size() * cell_use;
-
- size_t addr_alloc = sizeof(Label) * _type.dimensions().capacity();
- size_t cell_alloc = sizeof(Cell) + addr_alloc;
- size_t cells_alloc = _cells.capacity() * cell_alloc;
-
- size_t mine_sz = sizeof(SimpleTensor);
- size_t used = mine_sz + cells_use;
- size_t allocated = mine_sz + cells_alloc;
- return MemoryUsage(allocated, used, 0, 0);
-}
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/simple_tensor.h b/eval/src/vespa/eval/eval/simple_tensor.h
deleted file mode 100644
index 7ab59199af2..00000000000
--- a/eval/src/vespa/eval/eval/simple_tensor.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "value_type.h"
-#include "tensor.h"
-#include "tensor_spec.h"
-#include "aggr.h"
-#include "operation.h"
-#include <vespa/vespalib/stllike/string.h>
-#include <vespa/vespalib/util/stash.h>
-#include <memory>
-#include <map>
-#include <functional>
-
-namespace vespalib {
-
-class nbostream;
-
-namespace eval {
-
-struct UnaryOperation;
-struct BinaryOperation;
-
-/**
- * A tensor supporting a mix of indexed and mapped dimensions. The
- * goal for this class is to be a simple, complete and correct
- * reference implementation supporting all relevant tensor operations.
- **/
-class SimpleTensor : public Tensor
-{
-public:
- /**
- * A label for a single dimension. This is either a string
- * (mapped) or an integer (indexed). A sequence of Labels form an
- * Address. The labels must have the same order as the dimensions
- * in the tensor type (which are sorted on dimension name). Labels
- * for mapped dimensions must be strings and labels for indexed
- * dimensions must be integers smaller than the dimension size.
- **/
- struct Label {
- size_t index;
- vespalib::string name;
- static constexpr size_t npos = -1;
- Label(const TensorSpec::Label &label) noexcept
- : index(label.index), name(label.name) {}
- bool operator<(const Label &rhs) const {
- if (index != rhs.index) {
- return (index < rhs.index);
- }
- return (name < rhs.name);
- }
- bool operator==(const Label &rhs) const {
- return ((index == rhs.index) && (name == rhs.name));
- }
- bool operator!=(const Label &rhs) const { return !(*this == rhs); }
- bool is_mapped() const { return (index == npos); }
- bool is_indexed() const { return (index != npos); }
- };
- using Address = std::vector<Label>;
-
- /**
- * A tensor has a type and contains a collection of Cells. Each
- * cell has an Address and a value.
- **/
- struct Cell {
- Address address;
- double value;
- Cell(const Address &address_in, double value_in)
- : address(address_in), value(value_in) {}
- };
- using Cells = std::vector<Cell>;
-
-private:
- ValueType _type;
- Cells _cells;
-
-public:
- using map_fun_t = vespalib::eval::operation::op1_t;
- using join_fun_t = vespalib::eval::operation::op2_t;
-
- SimpleTensor();
- TypedCells cells() const override { abort(); }
- const Index &index() const override { abort(); }
- explicit SimpleTensor(double value);
- SimpleTensor(const ValueType &type_in, Cells cells_in);
- double as_double() const final override;
- const ValueType &type() const override { return _type; }
- const Cells &my_cells() const { return _cells; }
- std::unique_ptr<SimpleTensor> map(map_fun_t function) const;
- std::unique_ptr<SimpleTensor> reduce(Aggregator &aggr, const std::vector<vespalib::string> &dimensions) const;
- std::unique_ptr<SimpleTensor> rename(const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) const;
- static std::unique_ptr<SimpleTensor> create(const TensorSpec &spec);
- static std::unique_ptr<SimpleTensor> join(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function);
- static std::unique_ptr<SimpleTensor> merge(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function);
- static std::unique_ptr<SimpleTensor> concat(const SimpleTensor &a, const SimpleTensor &b, const vespalib::string &dimension);
- static void encode(const SimpleTensor &tensor, nbostream &output);
- static std::unique_ptr<SimpleTensor> decode(nbostream &input);
- MemoryUsage get_memory_usage() const override;
-};
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/simple_tensor_engine.cpp b/eval/src/vespa/eval/eval/simple_tensor_engine.cpp
deleted file mode 100644
index 491a310dc0b..00000000000
--- a/eval/src/vespa/eval/eval/simple_tensor_engine.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "simple_tensor_engine.h"
-#include "simple_tensor.h"
-#include <vespa/vespalib/util/stringfmt.h>
-#include <cassert>
-
-namespace vespalib {
-namespace eval {
-
-namespace {
-
-const SimpleTensor &as_simple(const Tensor &tensor) {
- assert(&tensor.engine() == &SimpleTensorEngine::ref());
- return static_cast<const SimpleTensor&>(tensor);
-}
-
-const SimpleTensor &to_simple(const Value &value, Stash &stash) {
- if (value.is_double()) {
- return stash.create<SimpleTensor>(value.as_double());
- }
- if (auto tensor = value.as_tensor()) {
- return as_simple(*tensor);
- }
- return stash.create<SimpleTensor>(); // error
-}
-
-template <typename F>
-void with_simple(const Value &value, const F &f) {
- if (value.is_double()) {
- f(SimpleTensor(value.as_double()));
- } else if (auto tensor = value.as_tensor()) {
- f(as_simple(*tensor));
- } else {
- f(SimpleTensor());
- }
-}
-
-const Value &to_value(std::unique_ptr<SimpleTensor> tensor, Stash &stash) {
- if (tensor->type().is_tensor()) {
- return *stash.create<Value::UP>(std::move(tensor));
- }
- return stash.create<DoubleValue>(tensor->as_double());
-}
-
-Value::UP to_value(std::unique_ptr<SimpleTensor> tensor) {
- if (tensor->type().is_tensor()) {
- return tensor;
- }
- return std::make_unique<DoubleValue>(tensor->as_double());
-}
-
-} // namespace vespalib::eval::<unnamed>
-
-const SimpleTensorEngine SimpleTensorEngine::_engine;
-
-//-----------------------------------------------------------------------------
-
-TensorSpec
-SimpleTensorEngine::to_spec(const Value &value) const
-{
- TensorSpec spec(value.type().to_spec());
- const auto &dimensions = value.type().dimensions();
- with_simple(value, [&spec,&dimensions](const SimpleTensor &simple_tensor)
- {
- for (const auto &cell: simple_tensor.my_cells()) {
- TensorSpec::Address addr;
- assert(cell.address.size() == dimensions.size());
- for (size_t i = 0; i < cell.address.size(); ++i) {
- const auto &label = cell.address[i];
- if (label.is_mapped()) {
- addr.emplace(dimensions[i].name, TensorSpec::Label(label.name));
- } else {
- addr.emplace(dimensions[i].name, TensorSpec::Label(label.index));
- }
- }
- spec.add(addr, cell.value);
- }
- });
- return spec;
-}
-
-Value::UP
-SimpleTensorEngine::from_spec(const TensorSpec &spec) const
-{
- return to_value(SimpleTensor::create(spec));
-}
-
-//-----------------------------------------------------------------------------
-
-void
-SimpleTensorEngine::encode(const Value &value, nbostream &output) const
-{
- with_simple(value, [&output](const SimpleTensor &tensor) { SimpleTensor::encode(tensor, output); });
-}
-
-Value::UP
-SimpleTensorEngine::decode(nbostream &input) const
-{
- return to_value(SimpleTensor::decode(input));
-}
-
-//-----------------------------------------------------------------------------
-
-const Value &
-SimpleTensorEngine::map(const Value &a, map_fun_t function, Stash &stash) const
-{
- if (a.is_double()) {
- return stash.create<DoubleValue>(function(a.as_double()));
- }
- return to_value(to_simple(a, stash).map(function), stash);
-}
-
-const Value &
-SimpleTensorEngine::join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const
-{
- if (a.is_double() && b.is_double()) {
- return stash.create<DoubleValue>(function(a.as_double(), b.as_double()));
- }
- return to_value(SimpleTensor::join(to_simple(a, stash), to_simple(b, stash), function), stash);
-}
-
-const Value &
-SimpleTensorEngine::merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) const
-{
- return to_value(SimpleTensor::merge(to_simple(a, stash), to_simple(b, stash), function), stash);
-}
-
-const Value &
-SimpleTensorEngine::reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const
-{
- return to_value(to_simple(a, stash).reduce(Aggregator::create(aggr, stash), dimensions), stash);
-}
-
-const Value &
-SimpleTensorEngine::concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const
-{
- return to_value(SimpleTensor::concat(to_simple(a, stash), to_simple(b, stash), dimension), stash);
-}
-
-const Value &
-SimpleTensorEngine::rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const
-{
- return to_value(to_simple(a, stash).rename(from, to), stash);
-}
-
-//-----------------------------------------------------------------------------
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/simple_tensor_engine.h b/eval/src/vespa/eval/eval/simple_tensor_engine.h
deleted file mode 100644
index 4c71e91c8d3..00000000000
--- a/eval/src/vespa/eval/eval/simple_tensor_engine.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor_engine.h"
-
-namespace vespalib {
-namespace eval {
-
-/**
- * This is a TensorEngine implementation for the SimpleTensor
- * reference implementation.
- **/
-class SimpleTensorEngine : public TensorEngine
-{
-private:
- SimpleTensorEngine() {}
- static const SimpleTensorEngine _engine;
-public:
- static const TensorEngine &ref() { return _engine; };
-
- TensorSpec to_spec(const Value &value) const override;
- std::unique_ptr<Value> from_spec(const TensorSpec &spec) const override;
-
- void encode(const Value &value, nbostream &output) const override;
- std::unique_ptr<Value> decode(nbostream &input) const override;
-
- const Value &map(const Value &a, map_fun_t function, Stash &stash) const override;
- const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override;
- const Value &merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override;
- const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const override;
- const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const override;
- const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const override;
-};
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/simple_value.cpp b/eval/src/vespa/eval/eval/simple_value.cpp
index 17faa635941..113f89f77fb 100644
--- a/eval/src/vespa/eval/eval/simple_value.cpp
+++ b/eval/src/vespa/eval/eval/simple_value.cpp
@@ -2,6 +2,8 @@
#include "simple_value.h"
#include "inline_operation.h"
+#include "value_codec.h"
+#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/stllike/hash_map.hpp>
@@ -203,6 +205,24 @@ SimpleValue::create_view(const std::vector<size_t> &dims) const
}
}
+std::unique_ptr<Value>
+SimpleValue::from_spec(const TensorSpec &spec)
+{
+ return value_from_spec(spec, SimpleValueBuilderFactory::get());
+}
+
+std::unique_ptr<Value>
+SimpleValue::from_value(const Value& value)
+{
+ return from_spec(spec_from_value(value));
+}
+
+std::unique_ptr<Value>
+SimpleValue::from_stream(nbostream &stream)
+{
+ return decode_value(stream, SimpleValueBuilderFactory::get());
+}
+
//-----------------------------------------------------------------------------
template <typename T>
diff --git a/eval/src/vespa/eval/eval/simple_value.h b/eval/src/vespa/eval/eval/simple_value.h
index a8e84a95419..590c0b4ef16 100644
--- a/eval/src/vespa/eval/eval/simple_value.h
+++ b/eval/src/vespa/eval/eval/simple_value.h
@@ -7,10 +7,15 @@
#include <vector>
#include <map>
-namespace vespalib { class Stash; }
+namespace vespalib {
+class Stash;
+class nbostream;
+}
namespace vespalib::eval {
+class TensorSpec;
+
/**
* A simple implementation of a generic value that can also be used to
* build new values. This class focuses on simplicity over speed and
@@ -39,6 +44,9 @@ public:
const Value::Index &index() const override { return *this; }
size_t size() const override { return _index.size(); }
std::unique_ptr<View> create_view(const std::vector<size_t> &dims) const override;
+ static Value::UP from_spec(const TensorSpec &spec);
+ static Value::UP from_value(const Value &value);
+ static Value::UP from_stream(nbostream &stream);
};
/**
diff --git a/eval/src/vespa/eval/eval/tensor.cpp b/eval/src/vespa/eval/eval/tensor.cpp
deleted file mode 100644
index 645208ba8fb..00000000000
--- a/eval/src/vespa/eval/eval/tensor.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor.h"
-#include "tensor_engine.h"
-#include "tensor_spec.h"
-
-namespace vespalib {
-namespace eval {
-
-bool
-operator==(const Tensor &lhs, const Tensor &rhs)
-{
- auto lhs_spec = lhs.engine().to_spec(lhs);
- auto rhs_spec = rhs.engine().to_spec(rhs);
- return (lhs_spec == rhs_spec);
-}
-
-std::ostream &
-operator<<(std::ostream &out, const Tensor &tensor)
-{
- out << tensor.engine().to_spec(tensor).to_string();
- return out;
-}
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/tensor.h b/eval/src/vespa/eval/eval/tensor.h
deleted file mode 100644
index ddc341ed910..00000000000
--- a/eval/src/vespa/eval/eval/tensor.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "value_type.h"
-#include "value.h"
-
-namespace vespalib {
-namespace eval {
-
-struct TensorEngine;
-
-/**
- * Base class for all tensors. Tensor operations are defined by the
- * TensorEngine interface. The Tensor class itself is used as a tagged
- * transport mechanism. Each Tensor is connected to a distinct engine
- * which can be used to operate on it. When operating on multiple
- * tensors at the same time they all need to be connected to the same
- * engine. TensorEngines should only have a single static instance per
- * implementation.
- **/
-class Tensor : public Value
-{
-private:
- const TensorEngine &_engine;
-protected:
- explicit Tensor(const TensorEngine &engine_in)
- : _engine(engine_in) {}
-public:
- Tensor(const Tensor &) = delete;
- Tensor(Tensor &&) = delete;
- Tensor &operator=(const Tensor &) = delete;
- Tensor &operator=(Tensor &&) = delete;
- bool is_tensor() const override { return true; }
- const Tensor *as_tensor() const override { return this; }
- const TensorEngine &engine() const { return _engine; }
- virtual ~Tensor() {}
-};
-
-bool operator==(const Tensor &lhs, const Tensor &rhs);
-std::ostream &operator<<(std::ostream &out, const Tensor &tensor);
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/tensor_engine.cpp b/eval/src/vespa/eval/eval/tensor_engine.cpp
deleted file mode 100644
index 9e7948920df..00000000000
--- a/eval/src/vespa/eval/eval/tensor_engine.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor_engine.h"
-
-namespace vespalib {
-namespace eval {
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/tensor_engine.h b/eval/src/vespa/eval/eval/tensor_engine.h
deleted file mode 100644
index c0625c3e9b8..00000000000
--- a/eval/src/vespa/eval/eval/tensor_engine.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "aggr.h"
-#include "operation.h"
-#include <vespa/vespalib/stllike/string.h>
-#include <memory>
-#include <vector>
-#include <functional>
-
-namespace vespalib {
-
-class Stash;
-class nbostream;
-
-namespace eval {
-
-struct Value;
-class ValueType;
-class TensorSpec;
-struct TensorFunction;
-
-/**
- * Top-level API for a tensor implementation. All Tensor operations
- * are defined by the TensorEngine interface. The Tensor class itself
- * is used as a tagged transport mechanism. Each Tensor is connected
- * to a distinct engine which can be used to operate on it. When
- * operating on multiple tensors at the same time they all need to be
- * connected to the same engine. TensorEngines should only have a
- * single static instance per implementation.
- **/
-struct TensorEngine
-{
- using Aggr = eval::Aggr;
- using TensorFunction = eval::TensorFunction;
- using TensorSpec = eval::TensorSpec;
- using Value = eval::Value;
- using ValueType = eval::ValueType;
- using map_fun_t = vespalib::eval::operation::op1_t;
- using join_fun_t = vespalib::eval::operation::op2_t;
-
- virtual TensorSpec to_spec(const Value &value) const = 0;
- virtual std::unique_ptr<Value> from_spec(const TensorSpec &spec) const = 0;
-
- virtual void encode(const Value &value, nbostream &output) const = 0;
- virtual std::unique_ptr<Value> decode(nbostream &input) const = 0;
-
- virtual const TensorFunction &optimize(const TensorFunction &expr, Stash &) const { return expr; }
-
- virtual const Value &map(const Value &a, map_fun_t function, Stash &stash) const = 0;
- virtual const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const = 0;
- virtual const Value &merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) const = 0;
- virtual const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const = 0;
- virtual const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const = 0;
- virtual const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const = 0;
-
- virtual ~TensorEngine() {}
-};
-
-} // namespace vespalib::eval
-} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp
index 614ef8389d8..4ea7348f61e 100644
--- a/eval/src/vespa/eval/eval/tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/tensor_function.cpp
@@ -3,9 +3,6 @@
#include "tensor_function.h"
#include "value.h"
#include "operation.h"
-#include "tensor.h"
-#include "tensor_engine.h"
-#include "simple_tensor_engine.h"
#include "visit_stuff.h"
#include "string_stuff.h"
#include <vespa/eval/instruction/generic_concat.h>
@@ -61,151 +58,12 @@ using Instruction = InterpretedFunction::Instruction;
//-----------------------------------------------------------------------------
-uint64_t to_param(map_fun_t value) { return (uint64_t)value; }
-uint64_t to_param(join_fun_t value) { return (uint64_t)value; }
-map_fun_t to_map_fun(uint64_t param) { return (map_fun_t)param; }
-join_fun_t to_join_fun(uint64_t param) { return (join_fun_t)param; }
-
-//-----------------------------------------------------------------------------
-
void op_load_const(State &state, uint64_t param) {
state.stack.push_back(unwrap_param<Value>(param));
}
//-----------------------------------------------------------------------------
-void op_double_map(State &state, uint64_t param) {
- state.pop_push(state.stash.create<DoubleValue>(to_map_fun(param)(state.peek(0).as_double())));
-}
-
-void op_double_mul(State &state, uint64_t) {
- state.pop_pop_push(state.stash.create<DoubleValue>(state.peek(1).as_double() * state.peek(0).as_double()));
-}
-
-void op_double_add(State &state, uint64_t) {
- state.pop_pop_push(state.stash.create<DoubleValue>(state.peek(1).as_double() + state.peek(0).as_double()));
-}
-
-void op_double_join(State &state, uint64_t param) {
- state.pop_pop_push(state.stash.create<DoubleValue>(to_join_fun(param)(state.peek(1).as_double(), state.peek(0).as_double())));
-}
-
-//-----------------------------------------------------------------------------
-
-void op_tensor_map(State &state, uint64_t param) {
- state.pop_push(state.engine.map(state.peek(0), to_map_fun(param), state.stash));
-}
-
-void op_tensor_join(State &state, uint64_t param) {
- state.pop_pop_push(state.engine.join(state.peek(1), state.peek(0), to_join_fun(param), state.stash));
-}
-
-void op_tensor_merge(State &state, uint64_t param) {
- state.pop_pop_push(state.engine.merge(state.peek(1), state.peek(0), to_join_fun(param), state.stash));
-}
-
-using ReduceParams = std::pair<Aggr,std::vector<vespalib::string>>;
-void op_tensor_reduce(State &state, uint64_t param) {
- const ReduceParams &params = unwrap_param<ReduceParams>(param);
- state.pop_push(state.engine.reduce(state.peek(0), params.first, params.second, state.stash));
-}
-
-using RenameParams = std::pair<std::vector<vespalib::string>,std::vector<vespalib::string>>;
-void op_tensor_rename(State &state, uint64_t param) {
- const RenameParams &params = unwrap_param<RenameParams>(param);
- state.pop_push(state.engine.rename(state.peek(0), params.first, params.second, state.stash));
-}
-
-void op_tensor_concat(State &state, uint64_t param) {
- const vespalib::string &dimension = unwrap_param<vespalib::string>(param);
- state.pop_pop_push(state.engine.concat(state.peek(1), state.peek(0), dimension, state.stash));
-}
-
-void op_tensor_create(State &state, uint64_t param) {
- const Create &self = unwrap_param<Create>(param);
- TensorSpec spec(self.result_type().to_spec());
- size_t i = 0;
- for (auto pos = self.map().rbegin(); pos != self.map().rend(); ++pos) {
- spec.add(pos->first, state.peek(i++).as_double());
- }
- const Value &result = *state.stash.create<Value::UP>(state.engine.from_spec(spec));
- state.pop_n_push(i, result);
-}
-
-struct LambdaParams {
- const Lambda &parent;
- InterpretedFunction fun;
- LambdaParams(const Lambda &parent_in, InterpretedFunction fun_in)
- : parent(parent_in), fun(std::move(fun_in)) {}
-};
-
-void op_tensor_lambda(State &state, uint64_t param) {
- const LambdaParams &params = unwrap_param<LambdaParams>(param);
- TensorSpec spec = params.parent.create_spec(*state.params, params.fun);
- const Value &result = *state.stash.create<Value::UP>(state.engine.from_spec(spec));
- state.stack.emplace_back(result);
-}
-
-const Value &extract_single_value(const TensorSpec &spec, const TensorSpec::Address &addr, State &state) {
- auto pos = spec.cells().find(addr);
- if (pos == spec.cells().end()) {
- return state.stash.create<DoubleValue>(0.0);
- }
- return state.stash.create<DoubleValue>(pos->second);
-}
-
-const Value &extract_tensor_subspace(const ValueType &my_type, const TensorSpec &spec, const TensorSpec::Address &addr, State &state) {
- TensorSpec my_spec(my_type.to_spec());
- for (const auto &cell: spec.cells()) {
- bool keep = true;
- TensorSpec::Address my_addr;
- for (const auto &binding: cell.first) {
- auto pos = addr.find(binding.first);
- if (pos == addr.end()) {
- my_addr.emplace(binding.first, binding.second);
- } else {
- if (!(pos->second == binding.second)) {
- keep = false;
- }
- }
- }
- if (keep) {
- my_spec.add(my_addr, cell.second);
- }
- }
- return *state.stash.create<Value::UP>(state.engine.from_spec(my_spec));
-}
-
-void op_tensor_peek(State &state, uint64_t param) {
- const Peek &self = unwrap_param<Peek>(param);
- TensorSpec::Address addr;
- size_t child_cnt = 0;
- for (auto pos = self.map().rbegin(); pos != self.map().rend(); ++pos) {
- std::visit(vespalib::overload
- {
- [&](const TensorSpec::Label &label) {
- addr.emplace(pos->first, label);
- },
- [&](const TensorFunction::Child &) {
- double index = state.peek(child_cnt++).as_double();
- size_t dim_idx = self.param_type().dimension_index(pos->first);
- assert(dim_idx != ValueType::Dimension::npos);
- const auto &param_dim = self.param_type().dimensions()[dim_idx];
- if (param_dim.is_mapped()) {
- addr.emplace(pos->first, vespalib::make_string("%" PRId64, int64_t(index)));
- } else {
- addr.emplace(pos->first, size_t(index));
- }
- }
- }, pos->second);
- }
- TensorSpec spec = state.engine.to_spec(state.peek(child_cnt++));
- const Value &result = self.result_type().is_double()
- ? extract_single_value(spec, addr, state)
- : extract_tensor_subspace(self.result_type(), spec, addr, state);
- state.pop_n_push(child_cnt, result);
-}
-
} // namespace vespalib::eval::tensor_function::<unnamed>
//-----------------------------------------------------------------------------
@@ -248,7 +106,7 @@ Op2::visit_children(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-ConstValue::compile_self(EngineOrFactory, Stash &) const
+ConstValue::compile_self(const ValueBuilderFactory &, Stash &) const
{
return Instruction(op_load_const, wrap_param<Value>(_value));
}
@@ -267,7 +125,7 @@ ConstValue::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Inject::compile_self(EngineOrFactory, Stash &) const
+Inject::compile_self(const ValueBuilderFactory &, Stash &) const
{
return Instruction::fetch_param(_param_idx);
}
@@ -282,13 +140,9 @@ Inject::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Reduce::compile_self(EngineOrFactory engine, Stash &stash) const
+Reduce::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericReduce::make_instruction(child().result_type(), aggr(), dimensions(), engine.factory(), stash);
- }
- ReduceParams &params = stash.create<ReduceParams>(_aggr, _dimensions);
- return Instruction(op_tensor_reduce, wrap_param<ReduceParams>(params));
+ return instruction::GenericReduce::make_instruction(child().result_type(), aggr(), dimensions(), factory, stash);
}
void
@@ -302,15 +156,9 @@ Reduce::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Map::compile_self(EngineOrFactory engine, Stash &) const
+Map::compile_self(const ValueBuilderFactory &, Stash &) const
{
- if (engine.is_factory()) {
- return instruction::GenericMap::make_instruction(result_type(), _function);
- }
- if (result_type().is_double()) {
- return Instruction(op_double_map, to_param(_function));
- }
- return Instruction(op_tensor_map, to_param(_function));
+ return instruction::GenericMap::make_instruction(result_type(), _function);
}
void
@@ -323,21 +171,9 @@ Map::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Join::compile_self(EngineOrFactory engine, Stash &stash) const
+Join::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericJoin::make_instruction(lhs().result_type(), rhs().result_type(), function(), engine.factory(), stash);
- }
- if (result_type().is_double()) {
- if (_function == operation::Mul::f) {
- return Instruction(op_double_mul);
- }
- if (_function == operation::Add::f) {
- return Instruction(op_double_add);
- }
- return Instruction(op_double_join, to_param(_function));
- }
- return Instruction(op_tensor_join, to_param(_function));
+ return instruction::GenericJoin::make_instruction(lhs().result_type(), rhs().result_type(), function(), factory, stash);
}
void
@@ -350,12 +186,9 @@ Join::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Merge::compile_self(EngineOrFactory engine, Stash &stash) const
+Merge::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericMerge::make_instruction(lhs().result_type(), rhs().result_type(), function(), engine.factory(), stash);
- }
- return Instruction(op_tensor_merge, to_param(_function));
+ return instruction::GenericMerge::make_instruction(lhs().result_type(), rhs().result_type(), function(), factory, stash);
}
void
@@ -368,12 +201,9 @@ Merge::visit_self(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Concat::compile_self(EngineOrFactory engine, Stash &stash) const
+Concat::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericConcat::make_instruction(lhs().result_type(), rhs().result_type(), dimension(), engine.factory(), stash);
- }
- return Instruction(op_tensor_concat, wrap_param<vespalib::string>(_dimension));
+ return instruction::GenericConcat::make_instruction(lhs().result_type(), rhs().result_type(), dimension(), factory, stash);
}
void
@@ -405,12 +235,9 @@ Create::make_spec() const
}
Instruction
-Create::compile_self(EngineOrFactory engine, Stash &stash) const
+Create::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericCreate::make_instruction(result_type(), make_spec(), engine.factory(), stash);
- }
- return Instruction(op_tensor_create, wrap_param<Create>(*this));
+ return instruction::GenericCreate::make_instruction(result_type(), make_spec(), factory, stash);
}
void
@@ -470,14 +297,9 @@ Lambda::create_spec_impl(const ValueType &type, const LazyParams &params, const
}
InterpretedFunction::Instruction
-Lambda::compile_self(EngineOrFactory engine, Stash &stash) const
+Lambda::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericLambda::make_instruction(*this, engine.factory(), stash);
- }
- InterpretedFunction fun(engine, _lambda->root(), _lambda_types);
- LambdaParams &params = stash.create<LambdaParams>(*this, std::move(fun));
- return Instruction(op_tensor_lambda, wrap_param<LambdaParams>(params));
+ return instruction::GenericLambda::make_instruction(*this, factory, stash);
}
void
@@ -508,7 +330,9 @@ Peek::Spec
Peek::make_spec() const
{
Spec generic_spec;
- size_t child_idx = 0;
+ // the value peeked is child 0, so
+ // children (for label computation) in spec start at 1:
+ size_t child_idx = 1;
for (const auto & [dim_name, label_or_child] : map()) {
std::visit(vespalib::overload {
[&,&dim_name = dim_name](const TensorSpec::Label &label) {
@@ -523,12 +347,9 @@ Peek::make_spec() const
}
Instruction
-Peek::compile_self(EngineOrFactory engine, Stash &stash) const
+Peek::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericPeek::make_instruction(param_type(), result_type(), make_spec(), engine.factory(), stash);
- }
- return Instruction(op_tensor_peek, wrap_param<Peek>(*this));
+ return instruction::GenericPeek::make_instruction(param_type(), result_type(), make_spec(), factory, stash);
}
void
@@ -555,13 +376,9 @@ Peek::visit_children(vespalib::ObjectVisitor &visitor) const
//-----------------------------------------------------------------------------
Instruction
-Rename::compile_self(EngineOrFactory engine, Stash &stash) const
+Rename::compile_self(const ValueBuilderFactory &factory, Stash &stash) const
{
- if (engine.is_factory()) {
- return instruction::GenericRename::make_instruction(child().result_type(), from(), to(), engine.factory(), stash);
- }
- RenameParams &params = stash.create<RenameParams>(_from, _to);
- return Instruction(op_tensor_rename, wrap_param<RenameParams>(params));
+ return instruction::GenericRename::make_instruction(child().result_type(), from(), to(), factory, stash);
}
void
@@ -582,7 +399,7 @@ If::push_children(std::vector<Child::CREF> &children) const
}
Instruction
-If::compile_self(EngineOrFactory, Stash &) const
+If::compile_self(const ValueBuilderFactory &, Stash &) const
{
// 'if' is handled directly by compile_tensor_function to enable
// lazy-evaluation of true/false sub-expressions.
diff --git a/eval/src/vespa/eval/eval/tensor_function.h b/eval/src/vespa/eval/eval/tensor_function.h
index 3c4eb6c53a4..ed1106cccc1 100644
--- a/eval/src/vespa/eval/eval/tensor_function.h
+++ b/eval/src/vespa/eval/eval/tensor_function.h
@@ -104,10 +104,10 @@ struct TensorFunction
* the value stack during execution.
*
* @return instruction representing the operation of this node
- * @param engine the tensor engine used for evaluation
+ * @param factory the value builder factory used during evaluation
* @param stash heterogeneous object store
**/
- virtual InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const = 0;
+ virtual InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const = 0;
// for debug dumping
vespalib::string as_string() const;
@@ -188,7 +188,7 @@ public:
ConstValue(const Value &value_in) : Super(value_in.type()), _value(value_in) {}
const Value &value() const { return _value; }
bool result_is_mutable() const override { return false; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -204,7 +204,7 @@ public:
: Super(result_type_in), _param_idx(param_idx_in) {}
size_t param_idx() const { return _param_idx; }
bool result_is_mutable() const override { return false; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -225,7 +225,7 @@ public:
Aggr aggr() const { return _aggr; }
const std::vector<vespalib::string> &dimensions() const { return _dimensions; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -243,7 +243,7 @@ public:
: Super(result_type_in, child_in), _function(function_in) {}
map_fun_t function() const { return _function; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -262,7 +262,7 @@ public:
: Super(result_type_in, lhs_in, rhs_in), _function(function_in) {}
join_fun_t function() const { return _function; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -281,7 +281,7 @@ public:
: Super(result_type_in, lhs_in, rhs_in), _function(function_in) {}
join_fun_t function() const { return _function; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -300,7 +300,7 @@ public:
: Super(result_type_in, lhs_in, rhs_in), _dimension(dimension_in) {}
const vespalib::string &dimension() const { return _dimension; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -324,7 +324,7 @@ public:
using Spec = std::map<TensorSpec::Address, size_t>;
Spec make_spec() const;
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void push_children(std::vector<Child::CREF> &children) const final override;
void visit_children(vespalib::ObjectVisitor &visitor) const final override;
};
@@ -349,7 +349,7 @@ public:
return create_spec_impl(result_type(), params, _bindings, fun);
}
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -388,7 +388,7 @@ public:
Spec make_spec() const;
const ValueType &param_type() const { return _param.get().result_type(); }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void push_children(std::vector<Child::CREF> &children) const final override;
void visit_children(vespalib::ObjectVisitor &visitor) const final override;
};
@@ -410,7 +410,7 @@ public:
const std::vector<vespalib::string> &from() const { return _from; }
const std::vector<vespalib::string> &to() const { return _to; }
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
};
@@ -436,7 +436,7 @@ public:
return (true_child().result_is_mutable() &&
false_child().result_is_mutable());
}
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override;
void visit_children(vespalib::ObjectVisitor &visitor) const final override;
};
diff --git a/eval/src/vespa/eval/eval/tensor_nodes.h b/eval/src/vespa/eval/eval/tensor_nodes.h
index 07be7e77b71..618e03f229e 100644
--- a/eval/src/vespa/eval/eval/tensor_nodes.h
+++ b/eval/src/vespa/eval/eval/tensor_nodes.h
@@ -22,6 +22,7 @@ private:
public:
TensorMap(Node_UP child, std::shared_ptr<Function const> lambda)
: _child(std::move(child)), _lambda(std::move(lambda)) {}
+ const Node &child() const { return *_child; }
const Function &lambda() const { return *_lambda; }
vespalib::string dump(DumpContext &ctx) const override {
vespalib::string str;
@@ -52,6 +53,8 @@ private:
public:
TensorJoin(Node_UP lhs, Node_UP rhs, std::shared_ptr<Function const> lambda)
: _lhs(std::move(lhs)), _rhs(std::move(rhs)), _lambda(std::move(lambda)) {}
+ const Node &lhs() const { return *_lhs; }
+ const Node &rhs() const { return *_rhs; }
const Function &lambda() const { return *_lambda; }
vespalib::string dump(DumpContext &ctx) const override {
vespalib::string str;
@@ -84,6 +87,8 @@ private:
public:
TensorMerge(Node_UP lhs, Node_UP rhs, std::shared_ptr<Function const> lambda)
: _lhs(std::move(lhs)), _rhs(std::move(rhs)), _lambda(std::move(lambda)) {}
+ const Node &lhs() const { return *_lhs; }
+ const Node &rhs() const { return *_rhs; }
const Function &lambda() const { return *_lambda; }
vespalib::string dump(DumpContext &ctx) const override {
vespalib::string str;
@@ -116,8 +121,9 @@ private:
public:
TensorReduce(Node_UP child, Aggr aggr_in, std::vector<vespalib::string> dimensions_in)
: _child(std::move(child)), _aggr(aggr_in), _dimensions(std::move(dimensions_in)) {}
- const std::vector<vespalib::string> &dimensions() const { return _dimensions; }
+ const Node &child() const { return *_child; }
Aggr aggr() const { return _aggr; }
+ const std::vector<vespalib::string> &dimensions() const { return _dimensions; }
vespalib::string dump(DumpContext &ctx) const override {
vespalib::string str;
str += "reduce(";
@@ -150,6 +156,7 @@ private:
public:
TensorRename(Node_UP child, std::vector<vespalib::string> from_in, std::vector<vespalib::string> to_in)
: _child(std::move(child)), _from(std::move(from_in)), _to(std::move(to_in)) {}
+ const Node &child() const { return *_child; }
const std::vector<vespalib::string> &from() const { return _from; }
const std::vector<vespalib::string> &to() const { return _to; }
vespalib::string dump(DumpContext &ctx) const override {
@@ -196,6 +203,8 @@ private:
public:
TensorConcat(Node_UP lhs, Node_UP rhs, const vespalib::string &dimension_in)
: _lhs(std::move(lhs)), _rhs(std::move(rhs)), _dimension(dimension_in) {}
+ const Node &lhs() const { return *_lhs; }
+ const Node &rhs() const { return *_rhs; }
const vespalib::string &dimension() const { return _dimension; }
vespalib::string dump(DumpContext &ctx) const override {
vespalib::string str;
diff --git a/eval/src/vespa/eval/eval/tensor_spec.cpp b/eval/src/vespa/eval/eval/tensor_spec.cpp
index 98bc09217c1..beafba97ca1 100644
--- a/eval/src/vespa/eval/eval/tensor_spec.cpp
+++ b/eval/src/vespa/eval/eval/tensor_spec.cpp
@@ -1,14 +1,14 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_spec.h"
-#include "value.h"
-#include "value_codec.h"
-#include "tensor.h"
-#include "tensor_engine.h"
-#include "simple_tensor_engine.h"
+#include "array_array_map.h"
#include "function.h"
#include "interpreted_function.h"
+#include "value.h"
+#include "value_codec.h"
+#include "value_type.h"
#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/eval/eval/test/reference_evaluation.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <ostream>
@@ -33,6 +33,73 @@ TensorSpec::Address extract_address(const slime::Inspector &address) {
return extractor.address;
}
+struct NormalizeTensorSpec {
+ /*
+ * This is basically value_from_spec() + spec_from_value()
+ * implementation, taken from value_codec.cpp
+ */
+ template <typename T>
+ static TensorSpec invoke(const ValueType &type, const TensorSpec &spec) {
+ size_t dense_size = type.dense_subspace_size();
+ size_t num_mapped_dims = type.count_mapped_dimensions();
+ size_t max_subspaces = std::max(spec.cells().size() / dense_size, size_t(1));
+ ArrayArrayMap<vespalib::stringref,T> map(num_mapped_dims, dense_size, max_subspaces);
+ std::vector<vespalib::stringref> sparse_key;
+ for (const auto &entry: spec.cells()) {
+ sparse_key.clear();
+ size_t dense_key = 0;
+ auto binding = entry.first.begin();
+ for (const auto &dim : type.dimensions()) {
+ assert(binding != entry.first.end());
+ assert(dim.name == binding->first);
+ assert(dim.is_mapped() == binding->second.is_mapped());
+ if (dim.is_mapped()) {
+ sparse_key.push_back(binding->second.name);
+ } else {
+ assert(binding->second.index < dim.size);
+ dense_key = (dense_key * dim.size) + binding->second.index;
+ }
+ ++binding;
+ }
+ assert(binding == entry.first.end());
+ assert(dense_key < map.values_per_entry());
+ auto [tag, ignore] = map.lookup_or_add_entry(ConstArrayRef<vespalib::stringref>(sparse_key));
+ map.get_values(tag)[dense_key] = entry.second;
+ }
+ // if spec is missing the required dense space, add it here:
+ if ((map.keys_per_entry() == 0) && (map.size() == 0)) {
+ map.add_entry(ConstArrayRef<vespalib::stringref>());
+ }
+ TensorSpec result(type.to_spec());
+ map.each_entry([&](const auto &keys, const auto &values)
+ {
+ auto sparse_addr_iter = keys.begin();
+ TensorSpec::Address address;
+ for (const auto &dim : type.dimensions()) {
+ if (dim.is_mapped()) {
+ address.emplace(dim.name, *sparse_addr_iter++);
+ }
+ }
+ assert(sparse_addr_iter == keys.end());
+ for (size_t i = 0; i < values.size(); ++i) {
+ size_t dense_key = i;
+ for (auto dim = type.dimensions().rbegin();
+ dim != type.dimensions().rend();
+ ++dim)
+ {
+ if (dim->is_indexed()) {
+ size_t label = dense_key % dim->size;
+ address.emplace(dim->name, label).first->second = TensorSpec::Label(label);
+ dense_key /= dim->size;
+ }
+ }
+ result.add(address, values[i]);
+ }
+ });
+ return result;
+ }
+};
+
} // namespace vespalib::eval::<unnamed>
@@ -46,6 +113,16 @@ TensorSpec & TensorSpec::operator = (const TensorSpec &) = default;
TensorSpec::~TensorSpec() { }
+double
+TensorSpec::as_double() const
+{
+ double result = 0.0;
+ for (const auto &[key, value]: _cells) {
+ result += value.value;
+ }
+ return result;
+}
+
TensorSpec &
TensorSpec::add(Address address, double value) {
auto [iter, inserted] = _cells.emplace(std::move(address), value);
@@ -53,7 +130,7 @@ TensorSpec::add(Address address, double value) {
// to simplify reference implementations, allow
// adding the same address several times to a Spec, but
// only with the same value every time:
- assert(iter->second.value == value);
+ assert(iter->second == Value(value));
}
return *this;
}
@@ -116,22 +193,15 @@ TensorSpec::from_slime(const slime::Inspector &tensor)
TensorSpec
TensorSpec::from_value(const eval::Value &value)
{
- if (auto tensor = dynamic_cast<const vespalib::eval::Tensor *>(&value)) {
- return tensor->engine().to_spec(value);
- } else {
- return spec_from_value(value);
- }
+ return spec_from_value(value);
}
TensorSpec
TensorSpec::from_expr(const vespalib::string &expr)
{
- NoParams no_params;
auto fun = Function::parse(expr);
if (!fun->has_error() && (fun->num_params() == 0)) {
- InterpretedFunction ifun(SimpleTensorEngine::ref(), *fun, NodeTypes());
- InterpretedFunction::Context ctx(ifun);
- return from_value(ifun.eval(ctx, no_params));
+ return test::ReferenceEvaluation::eval(*fun, {});
}
return TensorSpec("error");
}
@@ -150,5 +220,16 @@ operator<<(std::ostream &out, const TensorSpec &spec)
return out;
}
+TensorSpec
+TensorSpec::normalize() const
+{
+ ValueType my_type = ValueType::from_spec(type());
+ if (my_type.is_error()) {
+ return TensorSpec(my_type.to_spec());
+ }
+ return typify_invoke<1,TypifyCellType,NormalizeTensorSpec>(my_type.cell_type(), my_type, *this);
+}
+
+
} // namespace vespalib::eval
} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/tensor_spec.h b/eval/src/vespa/eval/eval/tensor_spec.h
index 8f02e56f860..f8a06adf331 100644
--- a/eval/src/vespa/eval/eval/tensor_spec.h
+++ b/eval/src/vespa/eval/eval/tensor_spec.h
@@ -36,11 +36,11 @@ public:
Label(const char *name_in) : index(npos), name(name_in) {}
bool is_mapped() const { return (index == npos); }
bool is_indexed() const { return (index != npos); }
- bool operator==(const Label &rhs) const {
+ bool operator==(const Label &rhs) const noexcept {
return ((index == rhs.index) &&
(name == rhs.name));
}
- bool operator<(const Label &rhs) const {
+ bool operator<(const Label &rhs) const noexcept {
if (index != rhs.index) {
return (index < rhs.index);
}
@@ -68,10 +68,12 @@ public:
TensorSpec(const TensorSpec &);
TensorSpec & operator = (const TensorSpec &);
~TensorSpec();
+ double as_double() const;
TensorSpec &add(Address address, double value);
const vespalib::string &type() const { return _type; }
const Cells &cells() const { return _cells; }
vespalib::string to_string() const;
+ TensorSpec normalize() const;
void to_slime(slime::Cursor &tensor) const;
static TensorSpec from_slime(const slime::Inspector &tensor);
static TensorSpec from_value(const eval::Value &value);
diff --git a/eval/src/vespa/eval/eval/test/CMakeLists.txt b/eval/src/vespa/eval/eval/test/CMakeLists.txt
index f3b0750d503..2e9b50da5e6 100644
--- a/eval/src/vespa/eval/eval/test/CMakeLists.txt
+++ b/eval/src/vespa/eval/eval/test/CMakeLists.txt
@@ -3,8 +3,10 @@ vespa_add_library(eval_eval_test OBJECT
SOURCES
eval_fixture.cpp
eval_spec.cpp
+ reference_evaluation.cpp
reference_operations.cpp
tensor_conformance.cpp
+ tensor_model.cpp
test_io.cpp
value_compare.cpp
)
diff --git a/eval/src/vespa/eval/eval/test/eval_fixture.cpp b/eval/src/vespa/eval/eval/test/eval_fixture.cpp
index b7655a6ee2f..58d8905baf3 100644
--- a/eval/src/vespa/eval/eval/test/eval_fixture.cpp
+++ b/eval/src/vespa/eval/eval/test/eval_fixture.cpp
@@ -2,7 +2,9 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include "eval_fixture.h"
+#include "reference_evaluation.h"
#include <vespa/eval/eval/make_tensor_function.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/optimize_tensor_function.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -80,14 +82,14 @@ const TensorFunction &maybe_patch(bool allow_mutable, const TensorFunction &plai
return root.get();
}
-std::vector<Value::UP> make_params(EngineOrFactory engine, const Function &function,
+std::vector<Value::UP> make_params(const ValueBuilderFactory &factory, const Function &function,
const ParamRepo &param_repo)
{
std::vector<Value::UP> result;
for (size_t i = 0; i < function.num_params(); ++i) {
auto pos = param_repo.map.find(function.param_name(i));
ASSERT_TRUE(pos != param_repo.map.end());
- result.push_back(engine.from_spec(pos->second.value));
+ result.push_back(value_from_spec(pos->second.value, factory));
}
return result;
}
@@ -187,29 +189,29 @@ EvalFixture::detect_param_tampering(const ParamRepo &param_repo, bool allow_muta
ASSERT_TRUE(pos != param_repo.map.end());
bool allow_tampering = allow_mutable && pos->second.is_mutable;
if (!allow_tampering) {
- ASSERT_EQUAL(pos->second.value, _engine.to_spec(*_param_values[i]));
+ ASSERT_EQUAL(pos->second.value, spec_from_value(*_param_values[i]));
}
}
}
-EvalFixture::EvalFixture(EngineOrFactory engine,
+EvalFixture::EvalFixture(const ValueBuilderFactory &factory,
const vespalib::string &expr,
const ParamRepo &param_repo,
bool optimized,
bool allow_mutable)
- : _engine(engine),
+ : _factory(factory),
_stash(),
_function(verify_function(Function::parse(expr))),
_node_types(get_types(*_function, param_repo)),
_mutable_set(get_mutable(*_function, param_repo)),
- _plain_tensor_function(make_tensor_function(_engine, _function->root(), _node_types, _stash)),
+ _plain_tensor_function(make_tensor_function(_factory, _function->root(), _node_types, _stash)),
_patched_tensor_function(maybe_patch(allow_mutable, _plain_tensor_function, _mutable_set, _stash)),
- _tensor_function(optimized ? optimize_tensor_function(engine, _patched_tensor_function, _stash) : _patched_tensor_function),
- _ifun(_engine, _tensor_function),
+ _tensor_function(optimized ? optimize_tensor_function(_factory, _patched_tensor_function, _stash) : _patched_tensor_function),
+ _ifun(_factory, _tensor_function),
_ictx(_ifun),
- _param_values(make_params(_engine, *_function, param_repo)),
+ _param_values(make_params(_factory, *_function, param_repo)),
_params(get_refs(_param_values)),
- _result(_engine.to_spec(_ifun.eval(_ictx, _params)))
+ _result(spec_from_value(_ifun.eval(_ictx, _params)))
{
auto result_type = ValueType::from_spec(_result.type());
ASSERT_TRUE(!result_type.is_error());
@@ -220,7 +222,7 @@ const TensorSpec
EvalFixture::get_param(size_t idx) const
{
ASSERT_LESS(idx, _param_values.size());
- return _engine.to_spec(*(_param_values[idx]));
+ return spec_from_value(*(_param_values[idx]));
}
size_t
@@ -229,4 +231,17 @@ EvalFixture::num_params() const
return _param_values.size();
}
+TensorSpec
+EvalFixture::ref(const vespalib::string &expr, const ParamRepo &param_repo)
+{
+ auto fun = Function::parse(expr);
+ std::vector<TensorSpec> params;
+ for (size_t i = 0; i < fun->num_params(); ++i) {
+ auto pos = param_repo.map.find(fun->param_name(i));
+ ASSERT_TRUE(pos != param_repo.map.end());
+ params.push_back(pos->second.value);
+ }
+ return ReferenceEvaluation::eval(*fun, params);
+}
+
} // namespace vespalib::eval::test
diff --git a/eval/src/vespa/eval/eval/test/eval_fixture.h b/eval/src/vespa/eval/eval/test/eval_fixture.h
index 54693cbc1bb..dc49cf7e4dc 100644
--- a/eval/src/vespa/eval/eval/test/eval_fixture.h
+++ b/eval/src/vespa/eval/eval/test/eval_fixture.h
@@ -2,12 +2,11 @@
#pragma once
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/function.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/util/stash.h>
#include <set>
#include <functional>
@@ -45,7 +44,7 @@ public:
};
private:
- EngineOrFactory _engine;
+ const ValueBuilderFactory &_factory;
Stash _stash;
std::shared_ptr<Function const> _function;
NodeTypes _node_types;
@@ -74,7 +73,7 @@ private:
void detect_param_tampering(const ParamRepo &param_repo, bool allow_mutable) const;
public:
- EvalFixture(EngineOrFactory engine, const vespalib::string &expr, const ParamRepo &param_repo,
+ EvalFixture(const ValueBuilderFactory &factory, const vespalib::string &expr, const ParamRepo &param_repo,
bool optimized = true, bool allow_mutable = false);
~EvalFixture() {}
template <typename T>
@@ -86,11 +85,9 @@ public:
const TensorSpec &result() const { return _result; }
const TensorSpec get_param(size_t idx) const;
size_t num_params() const;
- static TensorSpec ref(const vespalib::string &expr, const ParamRepo &param_repo) {
- return EvalFixture(SimpleTensorEngine::ref(), expr, param_repo, false, false).result();
- }
+ static TensorSpec ref(const vespalib::string &expr, const ParamRepo &param_repo);
static TensorSpec prod(const vespalib::string &expr, const ParamRepo &param_repo) {
- return EvalFixture(tensor::DefaultTensorEngine::ref(), expr, param_repo, true, false).result();
+ return EvalFixture(FastValueBuilderFactory::get(), expr, param_repo, true, false).result();
}
};
diff --git a/eval/src/vespa/eval/eval/test/eval_spec.h b/eval/src/vespa/eval/eval/test/eval_spec.h
index d942129c934..7d4a8cb221f 100644
--- a/eval/src/vespa/eval/eval/test/eval_spec.h
+++ b/eval/src/vespa/eval/eval/test/eval_spec.h
@@ -7,9 +7,7 @@
#include <cassert>
#include <vector>
-namespace vespalib {
-namespace eval {
-namespace test {
+namespace vespalib::eval::test {
/**
* A collection of expressions with parameter bindings and their
@@ -123,7 +121,4 @@ public:
}
};
-} // namespace vespalib::eval::test
-} // namespace vespalib::eval
-} // namespace vespalib
-
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/reference_evaluation.cpp b/eval/src/vespa/eval/eval/test/reference_evaluation.cpp
new file mode 100644
index 00000000000..c20d8af32ec
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/reference_evaluation.cpp
@@ -0,0 +1,352 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "reference_evaluation.h"
+#include "reference_operations.h"
+
+#include <vespa/eval/eval/string_stuff.h>
+#include <vespa/eval/eval/node_visitor.h>
+#include <vespa/eval/eval/node_traverser.h>
+#include <vespa/eval/eval/operation.h>
+
+#include <vespa/vespalib/util/exceptions.h>
+
+#include <functional>
+#include <variant>
+
+namespace vespalib::eval::test {
+
+namespace {
+
+using namespace nodes;
+
+//-----------------------------------------------------------------------------
+
+TensorSpec eval_node(const Node &node, const std::vector<TensorSpec> &params);
+
+struct EvalNode : public NodeVisitor {
+ const std::vector<TensorSpec> &params;
+ TensorSpec result;
+ EvalNode(const std::vector<TensorSpec> &params_in)
+ : params(params_in), result("error") {}
+
+ //-------------------------------------------------------------------------
+
+ using op1_t = std::function<double(double)>;
+ using op2_t = std::function<double(double,double)>;
+
+ static TensorSpec num(double value) {
+ return TensorSpec("double").add({}, value);
+ }
+
+ //-------------------------------------------------------------------------
+
+ void eval_const(TensorSpec spec) {
+ result = spec;
+ }
+
+ void eval_param(size_t idx) {
+ assert(idx < params.size());
+ result = params[idx];
+ }
+
+ void eval_if(const If &node) {
+ if (eval_node(node.cond(), params).as_double() != 0.0) {
+ result = eval_node(node.true_expr(), params);
+ } else {
+ result = eval_node(node.false_expr(), params);
+ }
+ }
+
+ void eval_map(const Node &a, op1_t op1) {
+ result = ReferenceOperations::map(eval_node(a, params), op1);
+ }
+
+ void eval_join(const Node &a, const Node &b, op2_t op2) {
+ result = ReferenceOperations::join(eval_node(a, params), eval_node(b, params), op2);
+ }
+
+ void eval_merge(const Node &a, const Node &b, op2_t op2) {
+ result = ReferenceOperations::merge(eval_node(a, params), eval_node(b, params), op2);
+ }
+
+ void eval_reduce(const Node &a, Aggr aggr, const std::vector<vespalib::string> &dimensions) {
+ result = ReferenceOperations::reduce(eval_node(a, params), aggr, dimensions);
+ }
+
+ void eval_rename(const Node &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) {
+ result = ReferenceOperations::rename(eval_node(a, params), from, to);
+ }
+
+ void eval_concat(const Node &a, const Node &b, const vespalib::string &dimension) {
+ result = ReferenceOperations::concat(eval_node(a, params), eval_node(b, params), dimension);
+ }
+
+ void eval_create(const TensorCreate &node) {
+ std::map<TensorSpec::Address, size_t> spec;
+ std::vector<TensorSpec> children;
+ for (size_t i = 0; i < node.num_children(); ++i) {
+ spec.emplace(node.get_child_address(i), i);
+ children.push_back(eval_node(node.get_child(i), params));
+ }
+ result = ReferenceOperations::create(node.type().to_spec(), spec, children);
+ }
+
+ void eval_lambda(const TensorLambda &node) {
+ auto fun = [&](const std::vector<size_t> &indexes) {
+ std::vector<TensorSpec> lambda_params;
+ for (size_t idx: indexes) {
+ lambda_params.push_back(num(idx));
+ }
+ for (size_t param: node.bindings()) {
+ assert(param < params.size());
+ lambda_params.push_back(params[param]);
+ }
+ return ReferenceEvaluation::eval(node.lambda(), lambda_params).as_double();
+ };
+ result = ReferenceOperations::lambda(node.type().to_spec(), fun);
+ }
+
+ void eval_peek(const TensorPeek &node) {
+ TensorSpec param = eval_node(node.param(), params);
+ ValueType param_type = ValueType::from_spec(param.type());
+ auto is_indexed = [&](const vespalib::string &dim_name) {
+ size_t dim_idx = param_type.dimension_index(dim_name);
+ return ((dim_idx != ValueType::Dimension::npos) &&
+ (param_type.dimensions()[dim_idx].is_indexed()));
+ };
+ std::vector<TensorSpec> children;
+ children.push_back(param);
+ std::map<vespalib::string, std::variant<TensorSpec::Label, size_t>> spec;
+ for (const auto &[name, label]: node.dim_list()) {
+ if (label.is_expr()) {
+ spec.emplace(name, size_t(children.size()));
+ children.push_back(eval_node(*label.expr, params));
+ } else {
+ if (is_indexed(name)) {
+ spec.emplace(name, TensorSpec::Label(as_number(label.label)));
+ } else {
+ spec.emplace(name, TensorSpec::Label(label.label));
+ }
+ }
+ }
+ result = ReferenceOperations::peek(spec, children);
+ }
+
+ //-------------------------------------------------------------------------
+
+ void visit(const Number &node) override {
+ eval_const(num(node.value()));
+ }
+ void visit(const Symbol &node) override {
+ eval_param(node.id());
+ }
+ void visit(const String &node) override {
+ eval_const(num(node.hash()));
+ }
+ void visit(const In &node) override {
+ auto my_op1 = [&](double a) {
+ for (size_t i = 0; i < node.num_entries(); ++i) {
+ if (a == eval_node(node.get_entry(i), params).as_double()) {
+ return 1.0;
+ }
+ }
+ return 0.0;
+ };
+ eval_map(node.child(), my_op1);
+ }
+ void visit(const Neg &node) override {
+ eval_map(node.child(), operation::Neg::f);
+ }
+ void visit(const Not &node) override {
+ eval_map(node.child(), operation::Not::f);
+ }
+ void visit(const If &node) override {
+ eval_if(node);
+ }
+ void visit(const Error &) override {
+ abort();
+ }
+ void visit(const TensorMap &node) override {
+ auto my_op1 = [&](double a) {
+ return ReferenceEvaluation::eval(node.lambda(), {num(a)}).as_double();
+ };
+ eval_map(node.child(), my_op1);
+ }
+ void visit(const TensorJoin &node) override {
+ auto my_op2 = [&](double a, double b) {
+ return ReferenceEvaluation::eval(node.lambda(), {num(a), num(b)}).as_double();
+ };
+ eval_join(node.lhs(), node.rhs(), my_op2);
+ }
+ void visit(const TensorMerge &node) override {
+ auto my_op2 = [&](double a, double b) {
+ return ReferenceEvaluation::eval(node.lambda(), {num(a), num(b)}).as_double();
+ };
+ eval_merge(node.lhs(), node.rhs(), my_op2);
+ }
+ void visit(const TensorReduce &node) override {
+ eval_reduce(node.child(), node.aggr(), node.dimensions());
+ }
+ void visit(const TensorRename &node) override {
+ eval_rename(node.child(), node.from(), node.to());
+ }
+ void visit(const TensorConcat &node) override {
+ eval_concat(node.lhs(), node.rhs(), node.dimension());
+ }
+ void visit(const TensorCreate &node) override {
+ eval_create(node);
+ }
+ void visit(const TensorLambda &node) override {
+ eval_lambda(node);
+ }
+ void visit(const TensorPeek &node) override {
+ eval_peek(node);
+ }
+ void visit(const Add &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Add::f);
+ }
+ void visit(const Sub &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Sub::f);
+ }
+ void visit(const Mul &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Mul::f);
+ }
+ void visit(const Div &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Div::f);
+ }
+ void visit(const Mod &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Mod::f);
+ }
+ void visit(const Pow &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Pow::f);
+ }
+ void visit(const Equal &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Equal::f);
+ }
+ void visit(const NotEqual &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::NotEqual::f);
+ }
+ void visit(const Approx &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Approx::f);
+ }
+ void visit(const Less &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Less::f);
+ }
+ void visit(const LessEqual &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::LessEqual::f);
+ }
+ void visit(const Greater &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Greater::f);
+ }
+ void visit(const GreaterEqual &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::GreaterEqual::f);
+ }
+ void visit(const And &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::And::f);
+ }
+ void visit(const Or &node) override {
+ eval_join(node.lhs(), node.rhs(), operation::Or::f);
+ }
+ void visit(const Cos &node) override {
+ eval_map(node.get_child(0), operation::Cos::f);
+ }
+ void visit(const Sin &node) override {
+ eval_map(node.get_child(0), operation::Sin::f);
+ }
+ void visit(const Tan &node) override {
+ eval_map(node.get_child(0), operation::Tan::f);
+ }
+ void visit(const Cosh &node) override {
+ eval_map(node.get_child(0), operation::Cosh::f);
+ }
+ void visit(const Sinh &node) override {
+ eval_map(node.get_child(0), operation::Sinh::f);
+ }
+ void visit(const Tanh &node) override {
+ eval_map(node.get_child(0), operation::Tanh::f);
+ }
+ void visit(const Acos &node) override {
+ eval_map(node.get_child(0), operation::Acos::f);
+ }
+ void visit(const Asin &node) override {
+ eval_map(node.get_child(0), operation::Asin::f);
+ }
+ void visit(const Atan &node) override {
+ eval_map(node.get_child(0), operation::Atan::f);
+ }
+ void visit(const Exp &node) override {
+ eval_map(node.get_child(0), operation::Exp::f);
+ }
+ void visit(const Log10 &node) override {
+ eval_map(node.get_child(0), operation::Log10::f);
+ }
+ void visit(const Log &node) override {
+ eval_map(node.get_child(0), operation::Log::f);
+ }
+ void visit(const Sqrt &node) override {
+ eval_map(node.get_child(0), operation::Sqrt::f);
+ }
+ void visit(const Ceil &node) override {
+ eval_map(node.get_child(0), operation::Ceil::f);
+ }
+ void visit(const Fabs &node) override {
+ eval_map(node.get_child(0), operation::Fabs::f);
+ }
+ void visit(const Floor &node) override {
+ eval_map(node.get_child(0), operation::Floor::f);
+ }
+ void visit(const Atan2 &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Atan2::f);
+ }
+ void visit(const Ldexp &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Ldexp::f);
+ }
+ void visit(const Pow2 &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Pow::f);
+ }
+ void visit(const Fmod &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Mod::f);
+ }
+ void visit(const Min &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Min::f);
+ }
+ void visit(const Max &node) override {
+ eval_join(node.get_child(0), node.get_child(1), operation::Max::f);
+ }
+ void visit(const IsNan &node) override {
+ eval_map(node.get_child(0), operation::IsNan::f);
+ }
+ void visit(const Relu &node) override {
+ eval_map(node.get_child(0), operation::Relu::f);
+ }
+ void visit(const Sigmoid &node) override {
+ eval_map(node.get_child(0), operation::Sigmoid::f);
+ }
+ void visit(const Elu &node) override {
+ eval_map(node.get_child(0), operation::Elu::f);
+ }
+ void visit(const Erf &node) override {
+ eval_map(node.get_child(0), operation::Erf::f);
+ }
+};
+
+TensorSpec eval_node(const Node &node, const std::vector<TensorSpec> &params) {
+ EvalNode my_eval(params);
+ node.accept(my_eval);
+ return my_eval.result.normalize();
+}
+
+} // <unnamed>
+
+TensorSpec
+ReferenceEvaluation::eval(const Function &function, const std::vector<TensorSpec> &params) {
+ if (function.has_error()) {
+ throw IllegalArgumentException("function.has_error()");
+ }
+ if (function.num_params() != params.size()) {
+ throw IllegalArgumentException("function.num_params() != params.size()");
+ }
+ return eval_node(function.root(), params);
+}
+
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/reference_evaluation.h b/eval/src/vespa/eval/eval/test/reference_evaluation.h
new file mode 100644
index 00000000000..31089c29a93
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/reference_evaluation.h
@@ -0,0 +1,16 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vector>
+
+namespace vespalib::eval { class Function; }
+
+namespace vespalib::eval::test {
+
+struct ReferenceEvaluation {
+ static TensorSpec eval(const Function &function, const std::vector<TensorSpec> &params);
+};
+
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/reference_operations.cpp b/eval/src/vespa/eval/eval/test/reference_operations.cpp
index 89b99526d55..5edd1a4f9a0 100644
--- a/eval/src/vespa/eval/eval/test/reference_operations.cpp
+++ b/eval/src/vespa/eval/eval/test/reference_operations.cpp
@@ -175,14 +175,15 @@ TensorSpec ReferenceOperations::merge(const TensorSpec &a, const TensorSpec &b,
}
-TensorSpec ReferenceOperations::peek(const TensorSpec &param, const PeekSpec &peek_spec, const std::vector<TensorSpec> &children) {
- if (peek_spec.empty()) {
+TensorSpec ReferenceOperations::peek(const PeekSpec &peek_spec, const std::vector<TensorSpec> &children) {
+ if (peek_spec.empty() || children.empty()) {
return TensorSpec(ValueType::error_type().to_spec());
}
std::vector<vespalib::string> peek_dims;
for (const auto & [dim_name, label_or_child] : peek_spec) {
peek_dims.push_back(dim_name);
}
+ const TensorSpec &param = children[0];
ValueType param_type = ValueType::from_spec(param.type());
ValueType result_type = param_type.reduce(peek_dims);
TensorSpec result(result_type.to_spec());
@@ -208,7 +209,7 @@ TensorSpec ReferenceOperations::peek(const TensorSpec &param, const PeekSpec &pe
const auto &child = children[child_idx];
double child_value = value_from_child(child);
if (is_mapped_dim(dim)) {
- addr.emplace(dim, vespalib::make_string("%zd", int64_t(child_value)));
+ addr.emplace(dim, vespalib::make_string("%" PRId64, int64_t(child_value)));
} else {
addr.emplace(dim, child_value);
}
@@ -236,7 +237,7 @@ TensorSpec ReferenceOperations::peek(const TensorSpec &param, const PeekSpec &pe
}
-TensorSpec ReferenceOperations::reduce(const TensorSpec &a, const std::vector<vespalib::string> &dims, Aggr aggr) {
+TensorSpec ReferenceOperations::reduce(const TensorSpec &a, Aggr aggr, const std::vector<vespalib::string> &dims) {
ValueType res_type = ValueType::from_spec(a.type()).reduce(dims);
TensorSpec result(res_type.to_spec());
if (res_type.is_error()) {
@@ -283,5 +284,28 @@ TensorSpec ReferenceOperations::rename(const TensorSpec &a, const std::vector<ve
return result;
}
+TensorSpec ReferenceOperations::lambda(const vespalib::string &type_in, lambda_fun_t fun) {
+ ValueType type = ValueType::from_spec(type_in);
+ TensorSpec result(type.to_spec());
+ if (type.is_error()) {
+ return result;
+ }
+ const auto &dim_list = type.dimensions();
+ TensorSpec::Address addr;
+ std::vector<size_t> indexes(type.dimensions().size());
+ std::function<void(size_t)> loop = [&](size_t idx) {
+ if (idx == dim_list.size()) {
+ result.add(addr, fun(indexes));
+ } else {
+ for (size_t i = 0; i < dim_list[idx].size; ++i) {
+ addr.insert_or_assign(dim_list[idx].name, TensorSpec::Label(i));
+ indexes[idx] = i;
+ loop(idx + 1);
+ }
+ }
+ };
+ loop(0);
+ return result;
+}
} // namespace
diff --git a/eval/src/vespa/eval/eval/test/reference_operations.h b/eval/src/vespa/eval/eval/test/reference_operations.h
index 735454b486a..588215853f9 100644
--- a/eval/src/vespa/eval/eval/test/reference_operations.h
+++ b/eval/src/vespa/eval/eval/test/reference_operations.h
@@ -11,17 +11,21 @@
#include <vector>
#include <map>
#include <variant>
+#include <functional>
namespace vespalib::eval {
struct ReferenceOperations {
- using map_fun_t = vespalib::eval::operation::op1_t;
- using join_fun_t = vespalib::eval::operation::op2_t;
+ using map_fun_t = std::function<double(double)>;
+ using join_fun_t = std::function<double(double,double)>;
+ using lambda_fun_t = std::function<double(const std::vector<size_t> &dimension_indexes)>;
// mapping from cell address to index of child that computes the cell value
using CreateSpec = tensor_function::Create::Spec;
- // mapping from dimension name to verbatim label or child
+ // mapping from dimension name to verbatim label or child index.
+ // Note: child 0 is the input param, so indexes in the spec must
+ // start at 1.
using PeekSpec = tensor_function::Peek::Spec;
static TensorSpec concat(const TensorSpec &a, const TensorSpec &b, const std::string &concat_dim);
@@ -29,9 +33,10 @@ struct ReferenceOperations {
static TensorSpec join(const TensorSpec &a, const TensorSpec &b, join_fun_t function);
static TensorSpec map(const TensorSpec &a, map_fun_t func);
static TensorSpec merge(const TensorSpec &a, const TensorSpec &b, join_fun_t fun);
- static TensorSpec peek(const TensorSpec &param, const PeekSpec &spec, const std::vector<TensorSpec> &children);
- static TensorSpec reduce(const TensorSpec &a, const std::vector<vespalib::string> &dims, Aggr aggr);
+ static TensorSpec peek(const PeekSpec &spec, const std::vector<TensorSpec> &children);
+ static TensorSpec reduce(const TensorSpec &a, Aggr aggr, const std::vector<vespalib::string> &dims);
static TensorSpec rename(const TensorSpec &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to);
+ static TensorSpec lambda(const vespalib::string &type, lambda_fun_t fun);
};
} // namespace
diff --git a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp
index 701595920ac..d95ce9715ae 100644
--- a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp
+++ b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp
@@ -1,12 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_conformance.h"
-#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/function.h>
-#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/aggr.h>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -14,247 +14,60 @@
#include <vespa/vespalib/io/mapped_file_input.h>
#include "tensor_model.hpp"
#include "test_io.h"
+#include "reference_evaluation.h"
+
+using vespalib::make_string_short::fmt;
+
+namespace vespalib::eval::test {
-namespace vespalib {
-namespace eval {
-namespace test {
namespace {
using slime::Cursor;
using slime::Inspector;
using slime::JsonFormat;
-double as_double(const TensorSpec &spec) {
- return spec.cells().empty() ? 0.0 : spec.cells().begin()->second.value;
-}
-
-// abstract evaluation wrapper
-struct Eval {
- // typed result wrapper
- class Result {
- private:
- enum class Type { ERROR, NUMBER, TENSOR };
- Type _type;
- double _number;
- TensorSpec _tensor;
- public:
- Result() : _type(Type::ERROR), _number(0.0), _tensor("error") {}
- Result(EngineOrFactory engine, const Value &value) : _type(Type::ERROR), _number(0.0), _tensor("error") {
- if (value.is_double()) {
- _type = Type::NUMBER;
- }
- if (value.is_tensor()) {
- EXPECT_TRUE(_type == Type::ERROR);
- _type = Type::TENSOR;
- }
- _number = value.as_double();
- _tensor = engine.to_spec(value);
- }
- bool is_error() const { return (_type == Type::ERROR); }
- bool is_number() const { return (_type == Type::NUMBER); }
- bool is_tensor() const { return (_type == Type::TENSOR); }
- double number() const {
- EXPECT_TRUE(is_number());
- return _number;
- }
- const TensorSpec &tensor() const {
- EXPECT_TRUE(is_tensor());
- return _tensor;
- }
- };
- virtual Result eval(EngineOrFactory) const {
- TEST_ERROR("wrong signature");
- return Result();
- }
- virtual Result eval(EngineOrFactory, const TensorSpec &) const {
- TEST_ERROR("wrong signature");
- return Result();
- }
- virtual Result eval(EngineOrFactory, const TensorSpec &, const TensorSpec &) const {
- TEST_ERROR("wrong signature");
- return Result();
- }
- virtual ~Eval() {}
-};
-
-// catches exceptions trying to keep the test itself safe from eval side-effects
-struct SafeEval : Eval {
- const Eval &unsafe;
- SafeEval(const Eval &unsafe_in) : unsafe(unsafe_in) {}
- Result eval(EngineOrFactory engine) const override {
- try {
- return unsafe.eval(engine);
- } catch (std::exception &e) {
- TEST_ERROR(e.what());
- return Result();
- }
- }
- Result eval(EngineOrFactory engine, const TensorSpec &a) const override {
- try {
- return unsafe.eval(engine, a);
- } catch (std::exception &e) {
- TEST_ERROR(e.what());
- return Result();
- }
-
- }
- Result eval(EngineOrFactory engine, const TensorSpec &a, const TensorSpec &b) const override {
- try {
- return unsafe.eval(engine, a, b);
- } catch (std::exception &e) {
- TEST_ERROR(e.what());
- return Result();
- }
- }
-};
-SafeEval safe(const Eval &eval) { return SafeEval(eval); }
+//-----------------------------------------------------------------------------
-const Value &check_type(const Value &value, const ValueType &expect_type) {
- EXPECT_EQUAL(value.type(), expect_type);
- return value;
+TensorSpec ref_eval(const vespalib::string &expr, const std::vector<TensorSpec> &params) {
+ TensorSpec result = ReferenceEvaluation::eval(*Function::parse(expr), params);
+ EXPECT_FALSE(ValueType::from_spec(result.type()).is_error());
+ return result;
}
-// expression(void)
-struct Expr_V : Eval {
- const vespalib::string &expr;
- Expr_V(const vespalib::string &expr_in) : expr(expr_in) {}
- Result eval(EngineOrFactory engine) const override {
- auto fun = Function::parse(expr);
- NodeTypes types(*fun, {});
- InterpretedFunction ifun(engine, *fun, types);
- InterpretedFunction::Context ctx(ifun);
- SimpleObjectParams params({});
- return Result(engine, check_type(ifun.eval(ctx, params), types.get_type(fun->root())));
- }
-};
-
-// expression(tensor)
-struct Expr_T : Eval {
- const vespalib::string &expr;
- Expr_T(const vespalib::string &expr_in) : expr(expr_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a) const override {
- auto fun = Function::parse(expr);
- auto a_type = ValueType::from_spec(a.type());
- NodeTypes types(*fun, {a_type});
- InterpretedFunction ifun(engine, *fun, types);
- InterpretedFunction::Context ctx(ifun);
- Value::UP va = engine.from_spec(a);
- SimpleObjectParams params({*va});
- return Result(engine, check_type(ifun.eval(ctx, params), types.get_type(fun->root())));
- }
-};
-
-// expression(tensor,tensor)
-struct Expr_TT : Eval {
- vespalib::string expr;
- Expr_TT(const vespalib::string &expr_in) : expr(expr_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a, const TensorSpec &b) const override {
- auto fun = Function::parse(expr);
- auto a_type = ValueType::from_spec(a.type());
- auto b_type = ValueType::from_spec(b.type());
- NodeTypes types(*fun, {a_type, b_type});
- InterpretedFunction ifun(engine, *fun, types);
- InterpretedFunction::Context ctx(ifun);
- Value::UP va = engine.from_spec(a);
- Value::UP vb = engine.from_spec(b);
- SimpleObjectParams params({*va,*vb});
- return Result(engine, check_type(ifun.eval(ctx, params), types.get_type(fun->root())));
- }
-};
-
-const Value &make_value(EngineOrFactory engine, const TensorSpec &spec, Stash &stash) {
- return *stash.create<Value::UP>(engine.from_spec(spec));
+TensorSpec eval(const ValueBuilderFactory &factory, const vespalib::string &expr, const std::vector<TensorSpec> &params) {
+ auto fun = Function::parse(expr);
+ std::vector<ValueType> param_types;
+ std::vector<Value::UP> param_values;
+ std::vector<Value::CREF> param_refs;
+ for (const auto &param: params) {
+ param_types.push_back(ValueType::from_spec(param.type()));
+ param_values.push_back(value_from_spec(param, factory));
+ param_refs.emplace_back(*param_values.back());
+ }
+ NodeTypes types(*fun, param_types);
+ const auto &expect_type = types.get_type(fun->root());
+ ASSERT_FALSE(expect_type.is_error());
+ InterpretedFunction ifun(factory, *fun, types);
+ InterpretedFunction::Context ctx(ifun);
+ const Value &result = ifun.eval(ctx, SimpleObjectParams{param_refs});
+ EXPECT_EQUAL(result.type(), expect_type);
+ return spec_from_value(result);
}
-//-----------------------------------------------------------------------------
-
-// evaluate tensor reduce operation using tensor engine immediate api
-struct ImmediateReduce : Eval {
- Aggr aggr;
- std::vector<vespalib::string> dimensions;
- ImmediateReduce(Aggr aggr_in) : aggr(aggr_in), dimensions() {}
- ImmediateReduce(Aggr aggr_in, const vespalib::string &dimension)
- : aggr(aggr_in), dimensions({dimension}) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a) const override {
- Stash stash;
- const auto &lhs = make_value(engine, a, stash);
- return Result(engine, engine.reduce(lhs, aggr, dimensions, stash));
- }
-};
-
-// evaluate tensor map operation using tensor engine immediate api
-struct ImmediateMap : Eval {
- using fun_t = double (*)(double);
- fun_t function;
- ImmediateMap(fun_t function_in) : function(function_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a) const override {
- Stash stash;
- const auto &lhs = make_value(engine, a, stash);
- return Result(engine, engine.map(lhs, function, stash));
- }
-};
-
-// evaluate tensor join operation using tensor engine immediate api
-struct ImmediateJoin : Eval {
- using fun_t = double (*)(double, double);
- fun_t function;
- ImmediateJoin(fun_t function_in) : function(function_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a, const TensorSpec &b) const override {
- Stash stash;
- const auto &lhs = make_value(engine, a, stash);
- const auto &rhs = make_value(engine, b, stash);
- return Result(engine, engine.join(lhs, rhs, function, stash));
- }
-};
-
-// evaluate tensor concat operation using tensor engine immediate api
-struct ImmediateConcat : Eval {
- vespalib::string dimension;
- ImmediateConcat(const vespalib::string &dimension_in) : dimension(dimension_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a, const TensorSpec &b) const override {
- Stash stash;
- const auto &lhs = make_value(engine, a, stash);
- const auto &rhs = make_value(engine, b, stash);
- return Result(engine, engine.concat(lhs, rhs, dimension, stash));
- }
-};
+void verify_result(const ValueBuilderFactory &factory, const vespalib::string &expr, const std::vector<TensorSpec> &params, const TensorSpec &expect) {
+ auto actual = eval(factory, expr, params);
+ EXPECT_EQUAL(actual, expect);
+}
-// evaluate tensor rename operation using tensor engine immediate api
-struct ImmediateRename : Eval {
- std::vector<vespalib::string> from;
- std::vector<vespalib::string> to;
- ImmediateRename(const std::vector<vespalib::string> &from_in, const std::vector<vespalib::string> &to_in)
- : from(from_in), to(to_in) {}
- Result eval(EngineOrFactory engine, const TensorSpec &a) const override {
- Stash stash;
- const auto &lhs = make_value(engine, a, stash);
- return Result(engine, engine.rename(lhs, from, to, stash));
- }
-};
+void verify_result(const ValueBuilderFactory &factory, const vespalib::string &expr, const std::vector<TensorSpec> &params) {
+ TEST_DO(verify_result(factory, expr, params, ref_eval(expr, params)));
+}
//-----------------------------------------------------------------------------
// NaN value
const double my_nan = std::numeric_limits<double>::quiet_NaN();
-void verify_result(const Eval::Result &result, const Eval::Result &expect) {
- if (expect.is_number()) {
- EXPECT_EQUAL(result.number(), expect.number());
- } else if (expect.is_tensor()) {
- EXPECT_EQUAL(result.tensor(), expect.tensor());
- } else {
- TEST_FATAL("expected result should be valid");
- }
-}
-
-void verify_result(const Eval::Result &result, const TensorSpec &expect) {
- if (expect.type() == "double") {
- EXPECT_EQUAL(result.number(), as_double(expect));
- } else {
- EXPECT_EQUAL(result.tensor(), expect);
- }
-}
-
uint8_t unhex(char c) {
if (c >= '0' && c <= '9') {
return (c - '0');
@@ -284,16 +97,15 @@ bool is_same(const nbostream &a, const nbostream &b) {
struct TestContext {
vespalib::string module_path;
- EngineOrFactory ref_engine;
- EngineOrFactory engine;
+ const ValueBuilderFactory &factory;
- TestContext(const vespalib::string &module_path_in, EngineOrFactory engine_in)
- : module_path(module_path_in), ref_engine(SimpleTensorEngine::ref()), engine(engine_in) {}
+ TestContext(const vespalib::string &module_path_in, const ValueBuilderFactory &factory_in)
+ : module_path(module_path_in), factory(factory_in) {}
//-------------------------------------------------------------------------
void verify_create_type(const vespalib::string &type_spec) {
- Value::UP value = engine.from_spec(TensorSpec(type_spec));
+ Value::UP value = value_from_spec(TensorSpec(type_spec), factory);
EXPECT_EQUAL(type_spec, value->type().to_spec());
}
@@ -312,10 +124,6 @@ struct TestContext {
//-------------------------------------------------------------------------
- void verify_reduce_result(const Eval &eval, const TensorSpec &a, const Eval::Result &expect) {
- TEST_DO(verify_result(eval.eval(engine, a), expect));
- }
-
void test_reduce_op(Aggr aggr, const Sequence &seq) {
std::vector<Layout> layouts = {
{x(3)},
@@ -333,21 +141,17 @@ struct TestContext {
for (const Layout &layout: layouts) {
TensorSpec input = spec(layout, seq);
for (const Domain &domain: layout) {
- Eval::Result expect = ImmediateReduce(aggr, domain.dimension).eval(ref_engine, input);
- TEST_STATE(make_string("shape: %s, reduce dimension: %s",
- infer_type(layout).c_str(), domain.dimension.c_str()).c_str());
- vespalib::string expr = make_string("reduce(a,%s,%s)",
- AggrNames::name_of(aggr)->c_str(), domain.dimension.c_str());
- TEST_DO(verify_reduce_result(Expr_T(expr), input, expect));
- TEST_DO(verify_reduce_result(ImmediateReduce(aggr, domain.dimension), input, expect));
+ TEST_STATE(fmt("shape: %s, reduce dimension: %s",
+ infer_type(layout).c_str(), domain.dimension.c_str()).c_str());
+ vespalib::string expr = fmt("reduce(a,%s,%s)",
+ AggrNames::name_of(aggr)->c_str(), domain.dimension.c_str());
+ TEST_DO(verify_result(factory, expr, {input}));
}
{
- Eval::Result expect = ImmediateReduce(aggr).eval(ref_engine, input);
- TEST_STATE(make_string("shape: %s, reduce all dimensions",
- infer_type(layout).c_str()).c_str());
- vespalib::string expr = make_string("reduce(a,%s)", AggrNames::name_of(aggr)->c_str());
- TEST_DO(verify_reduce_result(Expr_T(expr), input, expect));
- TEST_DO(verify_reduce_result(ImmediateReduce(aggr), input, expect));
+ TEST_STATE(fmt("shape: %s, reduce all dimensions",
+ infer_type(layout).c_str()).c_str());
+ vespalib::string expr = fmt("reduce(a,%s)", AggrNames::name_of(aggr)->c_str());
+ TEST_DO(verify_result(factory, expr, {input}));
}
}
}
@@ -364,7 +168,7 @@ struct TestContext {
//-------------------------------------------------------------------------
- void test_map_op(const Eval &eval, map_fun_t ref_op, const Sequence &seq) {
+ void test_map_op_inner(const vespalib::string &expr, map_fun_t ref_op, const Sequence &seq) {
std::vector<Layout> layouts = {
{},
{x(3)},
@@ -380,14 +184,13 @@ struct TestContext {
float_cells({x({"a","b","c"}),y(5),z({"i","j","k","l"})})
};
for (const Layout &layout: layouts) {
- TEST_DO(verify_result(eval.eval(engine, spec(layout, seq)), spec(layout, OpSeq(seq, ref_op))));
+ TEST_DO(verify_result(factory, expr, {spec(layout, seq)}, spec(layout, OpSeq(seq, ref_op))));
}
}
void test_map_op(const vespalib::string &expr, map_fun_t op, const Sequence &seq) {
- TEST_DO(test_map_op(ImmediateMap(op), op, seq));
- TEST_DO(test_map_op(Expr_T(expr), op, seq));
- TEST_DO(test_map_op(Expr_T(make_string("map(x,f(a)(%s))", expr.c_str())), op, seq));
+ TEST_DO(test_map_op_inner(expr, op, seq));
+ TEST_DO(test_map_op_inner(fmt("map(x,f(a)(%s))", expr.c_str()), op, seq));
}
void test_tensor_map() {
@@ -420,29 +223,29 @@ struct TestContext {
//-------------------------------------------------------------------------
- void test_apply_op(const Eval &eval,
+ void test_apply_op(const vespalib::string &expr,
const TensorSpec &expect,
const TensorSpec &lhs,
const TensorSpec &rhs) {
- TEST_DO(verify_result(safe(eval).eval(engine, lhs, rhs), expect));
+ TEST_DO(verify_result(factory, expr, {lhs, rhs}, expect));
}
- void test_fixed_sparse_cases_apply_op(const Eval &eval,
+ void test_fixed_sparse_cases_apply_op(const vespalib::string &expr,
join_fun_t op)
{
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{}", {}),
spec("x{}", { { {{"x","1"}}, 3 } }),
spec("x{}", { { {{"x","2"}}, 5 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{}", { { {{"x","1"}}, op(3,5) } }),
spec("x{}", { { {{"x","1"}}, 3 } }),
spec("x{}", { { {{"x","1"}}, 5 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{}", { { {{"x","1"}}, op(3,-5) } }),
spec("x{}", { { {{"x","1"}}, 3 } }),
spec("x{}", { { {{"x","1"}}, -5 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","-"},{"y","2"},{"z","-"}},
op(5,7) },
@@ -454,7 +257,7 @@ struct TestContext {
spec("y{},z{}",
{ { {{"y","-"},{"z","3"}}, 11 },
{ {{"y","2"},{"z","-"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","-"},{"y","2"},{"z","-"}},
op(7,5) },
@@ -466,7 +269,7 @@ struct TestContext {
spec("x{},y{}",
{ { {{"x","-"},{"y","2"}}, 5 },
{ {{"x","1"},{"y","-"}}, 3 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("y{},z{}",
{ { {{"y","2"},{"z","-"}},
op(5,7) } }),
@@ -474,7 +277,7 @@ struct TestContext {
spec("y{},z{}",
{ { {{"y","-"},{"z","3"}}, 11 },
{ {{"y","2"},{"z","-"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("y{},z{}",
{ { {{"y","2"},{"z","-"}},
op(7,5) } }),
@@ -482,7 +285,7 @@ struct TestContext {
{ { {{"y","-"},{"z","3"}}, 11 },
{ {{"y","2"},{"z","-"}}, 7 } }),
spec("y{}", { { {{"y","2"}}, 5 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{}",
{ { {{"x","-"},{"y","2"}},
op(5,7) } }),
@@ -490,7 +293,7 @@ struct TestContext {
{ { {{"x","-"},{"y","2"}}, 5 },
{ {{"x","1"},{"y","-"}}, 3 } }),
spec("y{}", { { {{"y","2"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{}",
{ { {{"x","-"},{"y","2"}},
op(7,5) } }),
@@ -498,19 +301,19 @@ struct TestContext {
spec("x{},y{}",
{ { {{"x","-"},{"y","2"}}, 5 },
{ {{"x","1"},{"y","-"}}, 3 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},z{}",
{ { {{"x","1"},{"z","3"}},
op(3,11) } }),
spec("x{}", { { {{"x","1"}}, 3 } }),
spec("z{}", { { {{"z","3"}}, 11 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},z{}",
{ { {{"x","1"},{"z","3"}},
op(11,3) } }),
spec("z{}",{ { {{"z","3"}}, 11 } }),
spec("x{}",{ { {{"x","1"}}, 3 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{}",
{ { {{"x","1"},{"y","1"}},
op(3,5) },
@@ -521,7 +324,7 @@ struct TestContext {
{ {{"x","2"}}, 7 } }),
spec("y{}",
{ { {{"y","1"}}, 5 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","1"},{"y","1"},{"z","1"}},
op(1,7) },
@@ -541,7 +344,7 @@ struct TestContext {
{ { {{"y","1"},{"z","1"}}, 7 },
{ {{"y","1"},{"z","2"}}, 13 },
{ {{"y","2"},{"z","1"}}, 11 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","1"},{"y","1"},{"z","1"}},
op(1,7) } }),
@@ -550,7 +353,7 @@ struct TestContext {
{ {{"x","1"},{"y","1"}}, 1 } }),
spec("y{},z{}",
{ { {{"y","1"},{"z","1"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","1"},{"y","-"},{"z","1"}},
op(5,11) },
@@ -562,7 +365,7 @@ struct TestContext {
spec("y{},z{}",
{ { {{"y","-"},{"z","1"}}, 11 },
{ {{"y","1"},{"z","1"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","1"},{"y","1"},{"z","1"}},
op(1,7) } }),
@@ -571,7 +374,7 @@ struct TestContext {
{ {{"x","1"},{"y","1"}}, 1 } }),
spec("y{},z{}",
{ { {{"y","1"},{"z","1"}}, 7 } })));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec("x{},y{},z{}",
{ { {{"x","-"},{"y","-"},{"z", "-"}},
op(5,11) },
@@ -585,28 +388,28 @@ struct TestContext {
{ {{"y","1"},{"z","1"}}, 7 } })));
}
- void test_fixed_dense_cases_apply_op(const Eval &eval,
+ void test_fixed_dense_cases_apply_op(const vespalib::string &expr,
join_fun_t op)
{
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec(op(0.1,0.2)), spec(0.1), spec(0.2)));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec(x(1), Seq({ op(3,5) })),
spec(x(1), Seq({ 3 })),
spec(x(1), Seq({ 5 }))));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec(x(1), Seq({ op(3,-5) })),
spec(x(1), Seq({ 3 })),
spec(x(1), Seq({ -5 }))));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec(x(2), Seq({ op(3,7), op(5,11) })),
spec(x(2), Seq({ 3, 5 })),
spec(x(2), Seq({ 7, 11 }))));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec({x(1),y(1)}, Seq({ op(3,5) })),
spec({x(1),y(1)}, Seq({ 3 })),
spec({x(1),y(1)}, Seq({ 5 }))));
- TEST_DO(test_apply_op(eval,
+ TEST_DO(test_apply_op(expr,
spec({x(2),y(2),z(2)},
Seq({ op(1, 7), op(1, 11),
op(2, 13), op(2, 17),
@@ -621,7 +424,7 @@ struct TestContext {
13, 17 }))));
}
- void test_apply_op(const Eval &eval, join_fun_t op, const Sequence &seq) {
+ void test_apply_op_inner(const vespalib::string &expr, join_fun_t op, const Sequence &seq) {
std::vector<Layout> layouts = {
{}, {},
{x(5)}, {x(5)},
@@ -651,20 +454,18 @@ struct TestContext {
for (size_t i = 0; i < layouts.size(); i += 2) {
TensorSpec lhs_input = spec(layouts[i], seq);
TensorSpec rhs_input = spec(layouts[i + 1], seq);
- TEST_STATE(make_string("lhs shape: %s, rhs shape: %s",
- lhs_input.type().c_str(),
- rhs_input.type().c_str()).c_str());
- Eval::Result expect = ImmediateJoin(op).eval(ref_engine, lhs_input, rhs_input);
- TEST_DO(verify_result(safe(eval).eval(engine, lhs_input, rhs_input), expect));
+ TEST_STATE(fmt("lhs shape: %s, rhs shape: %s",
+ lhs_input.type().c_str(),
+ rhs_input.type().c_str()).c_str());
+ TEST_DO(verify_result(factory, expr, {lhs_input, rhs_input}));
}
- TEST_DO(test_fixed_sparse_cases_apply_op(eval, op));
- TEST_DO(test_fixed_dense_cases_apply_op(eval, op));
+ TEST_DO(test_fixed_sparse_cases_apply_op(expr, op));
+ TEST_DO(test_fixed_dense_cases_apply_op(expr, op));
}
void test_apply_op(const vespalib::string &expr, join_fun_t op, const Sequence &seq) {
- TEST_DO(test_apply_op(ImmediateJoin(op), op, seq));
- TEST_DO(test_apply_op(Expr_TT(expr), op, seq));
- TEST_DO(test_apply_op(Expr_TT(make_string("join(x,y,f(a,b)(%s))", expr.c_str())), op, seq));
+ TEST_DO(test_apply_op_inner(expr, op, seq));
+ TEST_DO(test_apply_op_inner(fmt("join(x,y,f(a,b)(%s))", expr.c_str()), op, seq));
}
void test_tensor_apply() {
@@ -697,8 +498,8 @@ struct TestContext {
const TensorSpec &lhs,
const TensorSpec &rhs)
{
- Expr_TT eval("reduce(a*b,sum)");
- TEST_DO(verify_result(safe(eval).eval(engine, lhs, rhs), spec(expect)));
+ vespalib::string expr("reduce(a*b,sum)");
+ TEST_DO(verify_result(factory, expr, {lhs, rhs}, spec(expect)));
}
void test_dot_product(double expect,
@@ -724,10 +525,8 @@ struct TestContext {
const vespalib::string &dimension,
const TensorSpec &expect)
{
- vespalib::string expr = make_string("concat(a,b,%s)", dimension.c_str());
- ImmediateConcat eval(dimension);
- TEST_DO(verify_result(eval.eval(engine, a, b), expect));
- TEST_DO(verify_result(Expr_TT(expr).eval(engine, a, b), expect));
+ vespalib::string expr = fmt("concat(a,b,%s)", dimension.c_str());
+ TEST_DO(verify_result(factory, expr, {a, b}, expect));
}
void test_concat() {
@@ -760,29 +559,25 @@ struct TestContext {
void test_rename(const vespalib::string &expr,
const TensorSpec &input,
- const std::vector<vespalib::string> &from,
- const std::vector<vespalib::string> &to,
const TensorSpec &expect)
{
- ImmediateRename eval(from, to);
- TEST_DO(verify_result(eval.eval(engine, input), expect));
- TEST_DO(verify_result(Expr_T(expr).eval(engine, input), expect));
+ TEST_DO(verify_result(factory, expr, {input}, expect));
}
void test_rename() {
- TEST_DO(test_rename("rename(a,x,y)", spec(x(5), N()), {"x"}, {"y"}, spec(y(5), N())));
- TEST_DO(test_rename("rename(a,y,x)", spec({y(5),z(5)}, N()), {"y"}, {"x"}, spec({x(5),z(5)}, N())));
- TEST_DO(test_rename("rename(a,y,x)", spec(float_cells({y(5),z(5)}), N()), {"y"}, {"x"}, spec(float_cells({x(5),z(5)}), N())));
- TEST_DO(test_rename("rename(a,z,x)", spec({y(5),z(5)}, N()), {"z"}, {"x"}, spec({y(5),x(5)}, N())));
- TEST_DO(test_rename("rename(a,x,z)", spec({x(5),y(5)}, N()), {"x"}, {"z"}, spec({z(5),y(5)}, N())));
- TEST_DO(test_rename("rename(a,y,z)", spec({x(5),y(5)}, N()), {"y"}, {"z"}, spec({x(5),z(5)}, N())));
- TEST_DO(test_rename("rename(a,(x,y),(y,x))", spec({x(5),y(5)}, N()), {"x","y"}, {"y","x"}, spec({y(5),x(5)}, N())));
+ TEST_DO(test_rename("rename(a,x,y)", spec(x(5), N()), spec(y(5), N())));
+ TEST_DO(test_rename("rename(a,y,x)", spec({y(5),z(5)}, N()), spec({x(5),z(5)}, N())));
+ TEST_DO(test_rename("rename(a,y,x)", spec(float_cells({y(5),z(5)}), N()), spec(float_cells({x(5),z(5)}), N())));
+ TEST_DO(test_rename("rename(a,z,x)", spec({y(5),z(5)}, N()), spec({y(5),x(5)}, N())));
+ TEST_DO(test_rename("rename(a,x,z)", spec({x(5),y(5)}, N()), spec({z(5),y(5)}, N())));
+ TEST_DO(test_rename("rename(a,y,z)", spec({x(5),y(5)}, N()), spec({x(5),z(5)}, N())));
+ TEST_DO(test_rename("rename(a,(x,y),(y,x))", spec({x(5),y(5)}, N()), spec({y(5),x(5)}, N())));
}
//-------------------------------------------------------------------------
void test_tensor_lambda(const vespalib::string &expr, const TensorSpec &expect) {
- TEST_DO(verify_result(Expr_V(expr).eval(engine), expect));
+ TEST_DO(verify_result(factory, expr, {}, expect));
}
void test_tensor_lambda() {
@@ -800,7 +595,7 @@ struct TestContext {
//-------------------------------------------------------------------------
void test_tensor_create(const vespalib::string &expr, double a, double b, const TensorSpec &expect) {
- TEST_DO(verify_result(Expr_TT(expr).eval(engine, spec(a), spec(b)), expect));
+ TEST_DO(verify_result(factory, expr, {spec(a), spec(b)}, expect));
}
void test_tensor_create() {
@@ -813,7 +608,7 @@ struct TestContext {
//-------------------------------------------------------------------------
void test_tensor_peek(const vespalib::string &expr, const TensorSpec &param, const TensorSpec &expect) {
- TEST_DO(verify_result(Expr_TT(expr).eval(engine, param, spec(1.0)), expect));
+ TEST_DO(verify_result(factory, expr, {param, spec(1.0)}, expect));
}
void test_tensor_peek() {
@@ -838,13 +633,13 @@ struct TestContext {
for (bool a_float: {false, true}) {
for (bool b_float: {false, true}) {
bool both_float = a_float && b_float;
- vespalib::string a_expr = make_string("tensor%s(%s):%s", a_float ? "<float>" : "", type_base.c_str(), a_str.c_str());
- vespalib::string b_expr = make_string("tensor%s(%s):%s", b_float ? "<float>" : "", type_base.c_str(), b_str.c_str());
- vespalib::string expect_expr = make_string("tensor%s(%s):%s", both_float ? "<float>" : "", type_base.c_str(), expect_str.c_str());
+ vespalib::string a_expr = fmt("tensor%s(%s):%s", a_float ? "<float>" : "", type_base.c_str(), a_str.c_str());
+ vespalib::string b_expr = fmt("tensor%s(%s):%s", b_float ? "<float>" : "", type_base.c_str(), b_str.c_str());
+ vespalib::string expect_expr = fmt("tensor%s(%s):%s", both_float ? "<float>" : "", type_base.c_str(), expect_str.c_str());
TensorSpec a = spec(a_expr);
TensorSpec b = spec(b_expr);
TensorSpec expect = spec(expect_expr);
- TEST_DO(verify_result(Expr_TT(expr).eval(engine, a, b), expect));
+ TEST_DO(verify_result(factory, expr, {a, b}, expect));
}
}
}
@@ -858,19 +653,22 @@ struct TestContext {
//-------------------------------------------------------------------------
void verify_encode_decode(const TensorSpec &spec,
- EngineOrFactory encode_engine,
- EngineOrFactory decode_engine)
+ const ValueBuilderFactory &encode_factory,
+ const ValueBuilderFactory &decode_factory)
{
- Stash stash;
nbostream data;
- encode_engine.encode(make_value(encode_engine, spec, stash), data);
- TEST_DO(verify_result(Eval::Result(decode_engine, *decode_engine.decode(data)), spec));
+ auto value = value_from_spec(spec, encode_factory);
+ encode_value(*value, data);
+ auto value2 = decode_value(data, decode_factory);
+ TensorSpec spec2 = spec_from_value(*value2);
+ EXPECT_EQUAL(spec2, spec);
}
void verify_encode_decode(const TensorSpec &spec) {
- TEST_DO(verify_encode_decode(spec, engine, ref_engine));
- if (&engine != &ref_engine) {
- TEST_DO(verify_encode_decode(spec, ref_engine, engine));
+ const ValueBuilderFactory &simple = SimpleValueBuilderFactory::get();
+ TEST_DO(verify_encode_decode(spec, factory, simple));
+ if (&factory != &simple) {
+ TEST_DO(verify_encode_decode(spec, simple, factory));
}
}
@@ -880,13 +678,13 @@ struct TestContext {
const Inspector &binary = test["binary"];
EXPECT_GREATER(binary.entries(), 0u);
nbostream encoded;
- engine.encode(make_value(engine, spec, stash), encoded);
+ encode_value(*value_from_spec(spec, factory), encoded);
test.setData("encoded", Memory(encoded.peek(), encoded.size()));
bool matched_encode = false;
for (size_t i = 0; i < binary.entries(); ++i) {
nbostream data = extract_data(binary[i].asString());
matched_encode = (matched_encode || is_same(encoded, data));
- TEST_DO(verify_result(Eval::Result(engine, *engine.decode(data)), spec));
+ EXPECT_EQUAL(spec_from_value(*decode_value(data, factory)), spec);
EXPECT_EQUAL(data.size(), 0u);
}
EXPECT_TRUE(matched_encode);
@@ -946,16 +744,14 @@ struct TestContext {
}
};
-} // namespace vespalib::eval::test::<unnamed>
+} // <unnamed>
void
-TensorConformance::run_tests(const vespalib::string &module_path, EngineOrFactory engine)
+TensorConformance::run_tests(const vespalib::string &module_path, const ValueBuilderFactory &factory)
{
- TestContext ctx(module_path, engine);
+ TestContext ctx(module_path, factory);
fprintf(stderr, "module path: '%s'\n", ctx.module_path.c_str());
ctx.run_tests();
}
-} // namespace vespalib::eval::test
-} // namespace vespalib::eval
-} // namespace vespalib
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/tensor_conformance.h b/eval/src/vespa/eval/eval/test/tensor_conformance.h
index 9aed3840191..ad30b60e24c 100644
--- a/eval/src/vespa/eval/eval/test/tensor_conformance.h
+++ b/eval/src/vespa/eval/eval/test/tensor_conformance.h
@@ -2,21 +2,17 @@
#pragma once
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/stllike/string.h>
-namespace vespalib {
-namespace eval {
-namespace test {
+namespace vespalib::eval::test {
/**
* A collection of tensor-related tests that can be run for various
- * implementations of the TensorEngine interface.
+ * implementations.
**/
struct TensorConformance {
- static void run_tests(const vespalib::string &module_path, EngineOrFactory engine);
+ static void run_tests(const vespalib::string &module_path, const ValueBuilderFactory &factory);
};
-} // namespace vespalib::eval::test
-} // namespace vespalib::eval
-} // namespace vespalib
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/tensor_model.cpp b/eval/src/vespa/eval/eval/test/tensor_model.cpp
new file mode 100644
index 00000000000..646dab459c1
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/tensor_model.cpp
@@ -0,0 +1,12 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "tensor_model.h"
+
+namespace vespalib::eval::test {
+
+Seq::~Seq() = default;
+
+Domain::Domain(const Domain &) = default;
+Domain::~Domain() = default;
+
+}
diff --git a/eval/src/vespa/eval/eval/test/tensor_model.h b/eval/src/vespa/eval/eval/test/tensor_model.h
new file mode 100644
index 00000000000..c56f809c936
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/tensor_model.h
@@ -0,0 +1,260 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/operation.h>
+#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/node_types.h>
+#include <vespa/eval/eval/interpreted_function.h>
+
+namespace vespalib::eval::test {
+
+using map_fun_t = vespalib::eval::operation::op1_t;
+using join_fun_t = vespalib::eval::operation::op2_t;
+
+// Random access sequence of numbers
+struct Sequence {
+ virtual double operator[](size_t i) const = 0;
+ virtual ~Sequence() {}
+};
+
+// Sequence of natural numbers (starting at 1)
+struct N : Sequence {
+ double operator[](size_t i) const override { return (1.0 + i); }
+};
+
+// Sequence of another sequence divided by 10
+struct Div10 : Sequence {
+ const Sequence &seq;
+ Div10(const Sequence &seq_in) : seq(seq_in) {}
+ double operator[](size_t i) const override { return (seq[i] / 10.0); }
+};
+
+// Sequence of another sequence divided by 16
+struct Div16 : Sequence {
+ const Sequence &seq;
+ Div16(const Sequence &seq_in) : seq(seq_in) {}
+ double operator[](size_t i) const override { return (seq[i] / 16.0); }
+};
+
+
+// Sequence of another sequence minus 2
+struct Sub2 : Sequence {
+ const Sequence &seq;
+ Sub2(const Sequence &seq_in) : seq(seq_in) {}
+ double operator[](size_t i) const override { return (seq[i] - 2.0); }
+};
+
+// Sequence of a unary operator applied to a sequence
+struct OpSeq : Sequence {
+ const Sequence &seq;
+ map_fun_t op;
+ OpSeq(const Sequence &seq_in, map_fun_t op_in) : seq(seq_in), op(op_in) {}
+ double operator[](size_t i) const override { return op(seq[i]); }
+};
+
+// Sequence of applying sigmoid to another sequence
+struct Sigmoid : Sequence {
+ const Sequence &seq;
+ Sigmoid(const Sequence &seq_in) : seq(seq_in) {}
+ double operator[](size_t i) const override { return operation::Sigmoid::f(seq[i]); }
+};
+
+// Sequence of applying sigmoid to another sequence, plus rounding to nearest float
+struct SigmoidF : Sequence {
+ const Sequence &seq;
+ SigmoidF(const Sequence &seq_in) : seq(seq_in) {}
+ double operator[](size_t i) const override { return (float)operation::Sigmoid::f(seq[i]); }
+};
+
+// pre-defined sequence of numbers
+struct Seq : Sequence {
+ std::vector<double> seq;
+ Seq() : seq() {}
+ Seq(const std::vector<double> &seq_in) : seq(seq_in) {}
+ ~Seq() override;
+ double operator[](size_t i) const override {
+ ASSERT_LESS(i, seq.size());
+ return seq[i];
+ }
+};
+
+// Random access bit mask
+struct Mask {
+ virtual bool operator[](size_t i) const = 0;
+ virtual ~Mask() {}
+};
+
+// Mask with all bits set
+struct All : Mask {
+ bool operator[](size_t) const override { return true; }
+};
+
+// Mask with no bits set
+struct None : Mask {
+ bool operator[](size_t) const override { return false; }
+};
+
+// Mask with false for each Nth index
+struct SkipNth : Mask {
+ size_t n;
+ SkipNth(size_t n_in) : n(n_in) {}
+ bool operator[](size_t i) const override { return (i % n) != 0; }
+};
+
+// pre-defined mask
+struct Bits : Mask {
+ std::vector<bool> bits;
+ Bits(const std::vector<bool> &bits_in) : bits(bits_in) {}
+ ~Bits() { }
+ bool operator[](size_t i) const override {
+ ASSERT_LESS(i, bits.size());
+ return bits[i];
+ }
+};
+
+// A mask converted to a sequence of two unique values (mapped from true and false)
+struct Mask2Seq : Sequence {
+ const Mask &mask;
+ double true_value;
+ double false_value;
+ Mask2Seq(const Mask &mask_in, double true_value_in = 1.0, double false_value_in = 0.0)
+ : mask(mask_in), true_value(true_value_in), false_value(false_value_in) {}
+ double operator[](size_t i) const override { return mask[i] ? true_value : false_value; }
+};
+
+// custom op1
+struct MyOp {
+ static double f(double a) {
+ return ((a + 1) * 2);
+ }
+};
+
+// 'a in [1,5,7,13,42]'
+struct MyIn {
+ static double f(double a) {
+ if ((a == 1) ||
+ (a == 5) ||
+ (a == 7) ||
+ (a == 13) ||
+ (a == 42))
+ {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+};
+
+// A collection of labels for a single dimension
+struct Domain {
+ vespalib::string dimension;
+ size_t size; // indexed
+ std::vector<vespalib::string> keys; // mapped
+ Domain(const Domain &);
+ Domain(const vespalib::string &dimension_in, size_t size_in)
+ : dimension(dimension_in), size(size_in), keys() {}
+ Domain(const vespalib::string &dimension_in, const std::vector<vespalib::string> &keys_in)
+ : dimension(dimension_in), size(0), keys(keys_in) {}
+ ~Domain();
+};
+
+struct Layout {
+ CellType cell_type;
+ std::vector<Domain> domains;
+ Layout(std::initializer_list<Domain> domains_in)
+ : cell_type(CellType::DOUBLE), domains(domains_in) {}
+ Layout(CellType cell_type_in, std::vector<Domain> domains_in)
+ : cell_type(cell_type_in), domains(std::move(domains_in)) {}
+ auto begin() const { return domains.begin(); }
+ auto end() const { return domains.end(); }
+ auto size() const { return domains.size(); }
+ auto operator[](size_t idx) const { return domains[idx]; }
+};
+
+Layout float_cells(const Layout &layout);
+
+Domain x();
+Domain x(size_t size);
+Domain x(const std::vector<vespalib::string> &keys);
+
+Domain y();
+Domain y(size_t size);
+Domain y(const std::vector<vespalib::string> &keys);
+
+Domain z();
+Domain z(size_t size);
+Domain z(const std::vector<vespalib::string> &keys);
+
+// Infer the tensor type spanned by the given spaces
+vespalib::string infer_type(const Layout &layout);
+
+// Wrapper for the things needed to generate a tensor
+struct Source {
+ using Address = TensorSpec::Address;
+
+ const Layout &layout;
+ const Sequence &seq;
+ const Mask &mask;
+ Source(const Layout &layout_in, const Sequence &seq_in, const Mask &mask_in)
+ : layout(layout_in), seq(seq_in), mask(mask_in) {}
+};
+
+// Mix layout with a number sequence to make a tensor spec
+class TensorSpecBuilder
+{
+private:
+ using Label = TensorSpec::Label;
+ using Address = TensorSpec::Address;
+
+ Source _source;
+ TensorSpec _spec;
+ Address _addr;
+ size_t _idx;
+
+ void generate(size_t layout_idx) {
+ if (layout_idx == _source.layout.size()) {
+ if (_source.mask[_idx]) {
+ _spec.add(_addr, _source.seq[_idx]);
+ }
+ ++_idx;
+ } else {
+ const Domain &domain = _source.layout[layout_idx];
+ if (domain.size > 0) { // indexed
+ for (size_t i = 0; i < domain.size; ++i) {
+ _addr.emplace(domain.dimension, Label(i)).first->second = Label(i);
+ generate(layout_idx + 1);
+ }
+ } else { // mapped
+ for (const vespalib::string &key: domain.keys) {
+ _addr.emplace(domain.dimension, Label(key)).first->second = Label(key);
+ generate(layout_idx + 1);
+ }
+ }
+ }
+ }
+
+public:
+ TensorSpecBuilder(const Layout &layout, const Sequence &seq, const Mask &mask)
+ : _source(layout, seq, mask), _spec(infer_type(layout)), _addr(), _idx(0) {}
+ TensorSpec build() {
+ generate(0);
+ return _spec;
+ }
+};
+TensorSpec spec(const Layout &layout, const Sequence &seq, const Mask &mask);
+TensorSpec spec(const Layout &layout, const Sequence &seq);
+TensorSpec spec(const Layout &layout);
+TensorSpec spec(const Domain &domain, const Sequence &seq, const Mask &mask);
+TensorSpec spec(const Domain &domain, const Sequence &seq);
+TensorSpec spec(const Domain &domain);
+TensorSpec spec(double value);
+TensorSpec spec();
+TensorSpec spec(const vespalib::string &type,
+ const std::vector<std::pair<TensorSpec::Address, TensorSpec::Value>> &cells);
+TensorSpec spec(const vespalib::string &value_expr);
+
+}
diff --git a/eval/src/vespa/eval/eval/test/tensor_model.hpp b/eval/src/vespa/eval/eval/test/tensor_model.hpp
index 78d6798ac4c..4b65862b3e7 100644
--- a/eval/src/vespa/eval/eval/test/tensor_model.hpp
+++ b/eval/src/vespa/eval/eval/test/tensor_model.hpp
@@ -2,183 +2,9 @@
#pragma once
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/tensor_engine.h>
-#include <vespa/eval/eval/function.h>
-#include <vespa/eval/eval/node_types.h>
-#include <vespa/eval/eval/interpreted_function.h>
-#include <vespa/eval/eval/simple_tensor_engine.h>
+#include "tensor_model.h"
-namespace vespalib {
-namespace eval {
-namespace test {
-
-using map_fun_t = vespalib::eval::operation::op1_t;
-using join_fun_t = vespalib::eval::operation::op2_t;
-
-// Random access sequence of numbers
-struct Sequence {
- virtual double operator[](size_t i) const = 0;
- virtual ~Sequence() {}
-};
-
-// Sequence of natural numbers (starting at 1)
-struct N : Sequence {
- double operator[](size_t i) const override { return (1.0 + i); }
-};
-
-// Sequence of another sequence divided by 10
-struct Div10 : Sequence {
- const Sequence &seq;
- Div10(const Sequence &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override { return (seq[i] / 10.0); }
-};
-
-// Sequence of another sequence divided by 16
-struct Div16 : Sequence {
- const Sequence &seq;
- Div16(const Sequence &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override { return (seq[i] / 16.0); }
-};
-
-
-// Sequence of another sequence minus 2
-struct Sub2 : Sequence {
- const Sequence &seq;
- Sub2(const Sequence &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override { return (seq[i] - 2.0); }
-};
-
-// Sequence of a unary operator applied to a sequence
-struct OpSeq : Sequence {
- const Sequence &seq;
- map_fun_t op;
- OpSeq(const Sequence &seq_in, map_fun_t op_in) : seq(seq_in), op(op_in) {}
- double operator[](size_t i) const override { return op(seq[i]); }
-};
-
-// Sequence of applying sigmoid to another sequence
-struct Sigmoid : Sequence {
- const Sequence &seq;
- Sigmoid(const Sequence &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override { return operation::Sigmoid::f(seq[i]); }
-};
-
-// Sequence of applying sigmoid to another sequence, plus rounding to nearest float
-struct SigmoidF : Sequence {
- const Sequence &seq;
- SigmoidF(const Sequence &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override { return (float)operation::Sigmoid::f(seq[i]); }
-};
-
-// pre-defined sequence of numbers
-struct Seq : Sequence {
- std::vector<double> seq;
- Seq() : seq() {}
- Seq(const std::vector<double> &seq_in) : seq(seq_in) {}
- double operator[](size_t i) const override {
- ASSERT_LESS(i, seq.size());
- return seq[i];
- }
-};
-
-// Random access bit mask
-struct Mask {
- virtual bool operator[](size_t i) const = 0;
- virtual ~Mask() {}
-};
-
-// Mask with all bits set
-struct All : Mask {
- bool operator[](size_t) const override { return true; }
-};
-
-// Mask with no bits set
-struct None : Mask {
- bool operator[](size_t) const override { return false; }
-};
-
-// Mask with false for each Nth index
-struct SkipNth : Mask {
- size_t n;
- SkipNth(size_t n_in) : n(n_in) {}
- bool operator[](size_t i) const override { return (i % n) != 0; }
-};
-
-// pre-defined mask
-struct Bits : Mask {
- std::vector<bool> bits;
- Bits(const std::vector<bool> &bits_in) : bits(bits_in) {}
- ~Bits() { }
- bool operator[](size_t i) const override {
- ASSERT_LESS(i, bits.size());
- return bits[i];
- }
-};
-
-// A mask converted to a sequence of two unique values (mapped from true and false)
-struct Mask2Seq : Sequence {
- const Mask &mask;
- double true_value;
- double false_value;
- Mask2Seq(const Mask &mask_in, double true_value_in = 1.0, double false_value_in = 0.0)
- : mask(mask_in), true_value(true_value_in), false_value(false_value_in) {}
- double operator[](size_t i) const override { return mask[i] ? true_value : false_value; }
-};
-
-// custom op1
-struct MyOp {
- static double f(double a) {
- return ((a + 1) * 2);
- }
-};
-
-// 'a in [1,5,7,13,42]'
-struct MyIn {
- static double f(double a) {
- if ((a == 1) ||
- (a == 5) ||
- (a == 7) ||
- (a == 13) ||
- (a == 42))
- {
- return 1.0;
- } else {
- return 0.0;
- }
- }
-};
-
-// A collection of labels for a single dimension
-struct Domain {
- vespalib::string dimension;
- size_t size; // indexed
- std::vector<vespalib::string> keys; // mapped
- Domain(const Domain &);
- Domain(const vespalib::string &dimension_in, size_t size_in)
- : dimension(dimension_in), size(size_in), keys() {}
- Domain(const vespalib::string &dimension_in, const std::vector<vespalib::string> &keys_in)
- : dimension(dimension_in), size(0), keys(keys_in) {}
- ~Domain();
-};
-Domain::Domain(const Domain &) = default;
-Domain::~Domain() {}
-
-struct Layout {
- CellType cell_type;
- std::vector<Domain> domains;
- Layout(std::initializer_list<Domain> domains_in)
- : cell_type(CellType::DOUBLE), domains(domains_in) {}
- Layout(CellType cell_type_in, std::vector<Domain> domains_in)
- : cell_type(cell_type_in), domains(std::move(domains_in)) {}
- auto begin() const { return domains.begin(); }
- auto end() const { return domains.end(); }
- auto size() const { return domains.size(); }
- auto operator[](size_t idx) const { return domains[idx]; }
-};
+namespace vespalib::eval::test {
Layout float_cells(const Layout &layout) {
return Layout(CellType::FLOAT, layout.domains);
@@ -209,59 +35,6 @@ vespalib::string infer_type(const Layout &layout) {
return ValueType::tensor_type(dimensions, layout.cell_type).to_spec();
}
-// Wrapper for the things needed to generate a tensor
-struct Source {
- using Address = TensorSpec::Address;
-
- const Layout &layout;
- const Sequence &seq;
- const Mask &mask;
- Source(const Layout &layout_in, const Sequence &seq_in, const Mask &mask_in)
- : layout(layout_in), seq(seq_in), mask(mask_in) {}
-};
-
-// Mix layout with a number sequence to make a tensor spec
-class TensorSpecBuilder
-{
-private:
- using Label = TensorSpec::Label;
- using Address = TensorSpec::Address;
-
- Source _source;
- TensorSpec _spec;
- Address _addr;
- size_t _idx;
-
- void generate(size_t layout_idx) {
- if (layout_idx == _source.layout.size()) {
- if (_source.mask[_idx]) {
- _spec.add(_addr, _source.seq[_idx]);
- }
- ++_idx;
- } else {
- const Domain &domain = _source.layout[layout_idx];
- if (domain.size > 0) { // indexed
- for (size_t i = 0; i < domain.size; ++i) {
- _addr.emplace(domain.dimension, Label(i)).first->second = Label(i);
- generate(layout_idx + 1);
- }
- } else { // mapped
- for (const vespalib::string &key: domain.keys) {
- _addr.emplace(domain.dimension, Label(key)).first->second = Label(key);
- generate(layout_idx + 1);
- }
- }
- }
- }
-
-public:
- TensorSpecBuilder(const Layout &layout, const Sequence &seq, const Mask &mask)
- : _source(layout, seq, mask), _spec(infer_type(layout)), _addr(), _idx(0) {}
- TensorSpec build() {
- generate(0);
- return _spec;
- }
-};
TensorSpec spec(const Layout &layout, const Sequence &seq, const Mask &mask) {
return TensorSpecBuilder(layout, seq, mask).build();
}
@@ -298,23 +71,7 @@ TensorSpec spec(const vespalib::string &type,
}
TensorSpec spec(const vespalib::string &value_expr) {
- if (value_expr == "error") {
- return TensorSpec("error");
- }
- const auto &engine = SimpleTensorEngine::ref();
- auto fun = Function::parse(value_expr);
- ASSERT_TRUE(!fun->has_error());
- ASSERT_EQUAL(fun->num_params(), 0u);
- NodeTypes types(*fun, {});
- ASSERT_TRUE(!types.get_type(fun->root()).is_error());
- InterpretedFunction ifun(engine, *fun, types);
- InterpretedFunction::Context ctx(ifun);
- SimpleObjectParams params({});
- auto result = engine.to_spec(ifun.eval(ctx, params));
- ASSERT_TRUE(!result.cells().empty());
- return result;
+ return TensorSpec::from_expr(value_expr);
}
-} // namespace vespalib::eval::test
-} // namespace vespalib::eval
-} // namespace vespalib
+}
diff --git a/eval/src/vespa/eval/eval/test/value_compare.cpp b/eval/src/vespa/eval/eval/test/value_compare.cpp
index ff6a4e72ebc..cb6eeca4b86 100644
--- a/eval/src/vespa/eval/eval/test/value_compare.cpp
+++ b/eval/src/vespa/eval/eval/test/value_compare.cpp
@@ -1,8 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "value_compare.h"
-#include <vespa/eval/eval/tensor.h>
-#include <vespa/eval/eval/tensor_engine.h>
#include <vespa/eval/eval/value_codec.h>
namespace vespalib::eval {
diff --git a/eval/src/vespa/eval/eval/typed_cells.h b/eval/src/vespa/eval/eval/typed_cells.h
index a478a419f95..b65fa2b40e4 100644
--- a/eval/src/vespa/eval/eval/typed_cells.h
+++ b/eval/src/vespa/eval/eval/typed_cells.h
@@ -4,7 +4,7 @@
#include <assert.h>
#include <vespa/vespalib/util/arrayref.h>
-#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/cell_type.h>
namespace vespalib::eval {
diff --git a/eval/src/vespa/eval/eval/value.cpp b/eval/src/vespa/eval/eval/value.cpp
index 267d2443112..7abc8d568cb 100644
--- a/eval/src/vespa/eval/eval/value.cpp
+++ b/eval/src/vespa/eval/eval/value.cpp
@@ -1,7 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "value.h"
+#include "value_codec.h"
#include <vespa/vespalib/util/typify.h>
+#include <vespa/vespalib/objects/nbostream.h>
namespace vespalib {
namespace eval {
@@ -62,5 +64,13 @@ ValueType ScalarValue<T>::_type = ValueType::make_type(get_cell_type<T>(), {});
template class ScalarValue<double>;
template class ScalarValue<float>;
+std::unique_ptr<Value>
+ValueBuilderFactory::copy(const Value &value) const
+{
+ nbostream stream;
+ encode_value(value, stream);
+ return decode_value(stream, *this);
+}
+
} // namespace vespalib::eval
} // namespace vespalib
diff --git a/eval/src/vespa/eval/eval/value.h b/eval/src/vespa/eval/eval/value.h
index e876ba7b472..186c3698dcd 100644
--- a/eval/src/vespa/eval/eval/value.h
+++ b/eval/src/vespa/eval/eval/value.h
@@ -12,8 +12,6 @@
namespace vespalib::eval {
-class Tensor;
-
/**
* An abstract Value.
**/
@@ -69,7 +67,6 @@ struct Value {
virtual bool is_tensor() const { return type().is_tensor(); }
virtual double as_double() const;
bool as_bool() const { return (as_double() != 0.0); }
- virtual const Tensor *as_tensor() const { return nullptr; }
// --- end of old interface
};
@@ -198,6 +195,7 @@ struct ValueBuilderFactory {
{
return create_value_builder<T>(type, type.count_mapped_dimensions(), type.dense_subspace_size(), 1);
}
+ std::unique_ptr<Value> copy(const Value &value) const;
virtual ~ValueBuilderFactory() {}
protected:
virtual std::unique_ptr<ValueBuilderBase> create_value_builder_base(const ValueType &type,
diff --git a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp
index 2005caa18ec..07692474234 100644
--- a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp
+++ b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp
@@ -1,9 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "constant_tensor_loader.h"
-#include <vespa/eval/eval/tensor.h>
-#include <vespa/eval/eval/tensor_engine.h>
#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/io/mapped_file_input.h>
#include <vespa/vespalib/data/lz4_input_decoder.h>
@@ -82,7 +81,7 @@ ConstantTensorLoader::create(const vespalib::string &path, const vespalib::strin
vespalib::Memory content = file.get();
vespalib::nbostream stream(content.data, content.size);
try {
- return std::make_unique<SimpleConstantValue>(_engine.decode(stream));
+ return std::make_unique<SimpleConstantValue>(decode_value(stream, _factory));
} catch (std::exception &) {
return std::make_unique<BadConstantValue>();
}
@@ -104,7 +103,7 @@ ConstantTensorLoader::create(const vespalib::string &path, const vespalib::strin
spec.add(address, cells[i]["value"].asDouble());
}
try {
- return std::make_unique<SimpleConstantValue>(_engine.from_spec(spec));
+ return std::make_unique<SimpleConstantValue>(value_from_spec(spec, _factory));
} catch (std::exception &) {
return std::make_unique<BadConstantValue>();
}
diff --git a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h
index 8fb6460efcf..1f32b3119c5 100644
--- a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h
+++ b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h
@@ -3,7 +3,6 @@
#pragma once
#include "constant_value.h"
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/vespalib/stllike/string.h>
namespace vespalib {
@@ -12,16 +11,14 @@ namespace eval {
/**
* A ConstantValueFactory that will load constant tensor values from
* file. The file is expected to be in json format with the same
- * structure used when feeding. The tensor is created by first
- * building a generic TensorSpec object and then converting it to a
- * specific tensor using the TensorEngine interface.
+ * structure used when feeding.
**/
class ConstantTensorLoader : public ConstantValueFactory
{
private:
- EngineOrFactory _engine;
+ const ValueBuilderFactory &_factory;
public:
- ConstantTensorLoader(EngineOrFactory engine) : _engine(engine) {}
+ ConstantTensorLoader(const ValueBuilderFactory &factory) : _factory(factory) {}
ConstantValue::UP create(const vespalib::string &path, const vespalib::string &type) const override;
};
diff --git a/eval/src/vespa/eval/eval/value_type.cpp b/eval/src/vespa/eval/eval/value_type.cpp
index 05ec65bf292..a5960a8de4b 100644
--- a/eval/src/vespa/eval/eval/value_type.cpp
+++ b/eval/src/vespa/eval/eval/value_type.cpp
@@ -138,7 +138,7 @@ struct Renamer {
bool matched_all() const { return (match_cnt == from.size()); }
};
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
constexpr ValueType::Dimension::size_type ValueType::Dimension::npos;
diff --git a/eval/src/vespa/eval/instruction/CMakeLists.txt b/eval/src/vespa/eval/instruction/CMakeLists.txt
index 4f2c59e34e1..42f88c0ee52 100644
--- a/eval/src/vespa/eval/instruction/CMakeLists.txt
+++ b/eval/src/vespa/eval/instruction/CMakeLists.txt
@@ -22,4 +22,14 @@ vespa_add_library(eval_instruction OBJECT
generic_rename.cpp
index_lookup_table.cpp
join_with_number_function.cpp
+ dense_add_dimension_optimizer.cpp
+ dense_fast_rename_optimizer.cpp
+ dense_pow_as_map_optimizer.cpp
+ dense_remove_dimension_optimizer.cpp
+ dense_replace_type_function.cpp
+ dense_simple_join_function.cpp
+ dense_simple_map_function.cpp
+ dense_single_reduce_function.cpp
+ dense_tensor_create_function.cpp
+ vector_from_doubles_function.cpp
)
diff --git a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp
index 9cd7cc88907..ccccb595c6d 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.cpp
+++ b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp
@@ -8,13 +8,10 @@
#include <vespa/log/log.h>
LOG_SETUP(".eval.tensor.dense.add_dimension_optimizer");
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::as;
-using namespace eval::tensor_function;
-using namespace eval::operation;
+using namespace tensor_function;
+using namespace operation;
namespace {
@@ -34,10 +31,10 @@ bool is_unit_constant(const TensorFunction &node) {
return false;
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
const TensorFunction &
-DenseAddDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash)
+DenseAddDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash)
{
if (auto join = as<Join>(expr)) {
const TensorFunction &lhs = join->lhs();
@@ -57,4 +54,4 @@ DenseAddDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &st
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.h b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h
index 4b5cf296292..99ab20614a2 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.h
+++ b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h
@@ -4,14 +4,15 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function optimizer for efficient adding of dimensions with
* size 1 for dense tensors.
+ * TODO: extend to mixed tensors.
**/
struct DenseAddDimensionOptimizer {
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp b/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp
index 5f43e16088d..4c655c67747 100644
--- a/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp
@@ -1,7 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_cell_range_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/value.h>
namespace vespalib::eval {
@@ -15,7 +14,7 @@ void my_cell_range_op(InterpretedFunction::State &state, uint64_t param) {
const auto &self = unwrap_param<DenseCellRangeFunction>(param);
auto old_cells = state.peek(0).cells().typify<CT>();
ConstArrayRef<CT> new_cells(&old_cells[self.offset()], self.length());
- state.pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type(), TypedCells(new_cells)));
+ state.pop_push(state.stash.create<DenseValueView>(self.result_type(), TypedCells(new_cells)));
}
struct MyCellRangeOp {
@@ -37,7 +36,7 @@ DenseCellRangeFunction::DenseCellRangeFunction(const ValueType &result_type,
DenseCellRangeFunction::~DenseCellRangeFunction() = default;
InterpretedFunction::Instruction
-DenseCellRangeFunction::compile_self(EngineOrFactory, Stash &) const
+DenseCellRangeFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
assert(result_type().cell_type() == child().result_type().cell_type());
diff --git a/eval/src/vespa/eval/instruction/dense_cell_range_function.h b/eval/src/vespa/eval/instruction/dense_cell_range_function.h
index 07793f5d72c..b201e15c49f 100644
--- a/eval/src/vespa/eval/instruction/dense_cell_range_function.h
+++ b/eval/src/vespa/eval/instruction/dense_cell_range_function.h
@@ -24,7 +24,7 @@ public:
~DenseCellRangeFunction() override;
size_t offset() const { return _offset; }
size_t length() const { return _length; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
bool result_is_mutable() const override { return child().result_is_mutable(); }
};
diff --git a/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp b/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp
index 5dcfcba025d..e3cf52a8e3f 100644
--- a/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_dot_product_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/value.h>
#include <cblas.h>
@@ -67,7 +66,7 @@ DenseDotProductFunction::DenseDotProductFunction(const TensorFunction &lhs_in,
}
InterpretedFunction::Instruction
-DenseDotProductFunction::compile_self(EngineOrFactory, Stash &) const
+DenseDotProductFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
auto op = my_select(lhs().result_type().cell_type(), rhs().result_type().cell_type());
return InterpretedFunction::Instruction(op);
diff --git a/eval/src/vespa/eval/instruction/dense_dot_product_function.h b/eval/src/vespa/eval/instruction/dense_dot_product_function.h
index d1c1c0538fc..efdfbf561fa 100644
--- a/eval/src/vespa/eval/instruction/dense_dot_product_function.h
+++ b/eval/src/vespa/eval/instruction/dense_dot_product_function.h
@@ -14,7 +14,7 @@ class DenseDotProductFunction : public tensor_function::Op2
public:
DenseDotProductFunction(const TensorFunction &lhs_in,
const TensorFunction &rhs_in);
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
bool result_is_mutable() const override { return true; }
static bool compatible_types(const ValueType &res, const ValueType &lhs, const ValueType &rhs);
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
diff --git a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp
index 7c3dde5fa2e..a4ef32f4701 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp
+++ b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp
@@ -2,16 +2,11 @@
#include "dense_fast_rename_optimizer.h"
#include "dense_replace_type_function.h"
-#include "dense_tensor_view.h"
#include <vespa/eval/eval/value.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::as;
-using namespace eval::tensor_function;
+using namespace tensor_function;
namespace {
@@ -36,10 +31,10 @@ bool is_dense_stable_rename(const ValueType &from_type, const ValueType &to_type
return true;
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
const TensorFunction &
-DenseFastRenameOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash)
+DenseFastRenameOptimizer::optimize(const TensorFunction &expr, Stash &stash)
{
if (auto rename = as<Rename>(expr)) {
const ValueType &from_type = rename->child().result_type();
@@ -52,4 +47,4 @@ DenseFastRenameOptimizer::optimize(const eval::TensorFunction &expr, Stash &stas
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.h b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h
index bbcb38e1f80..2882cdf6f30 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.h
+++ b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h
@@ -4,14 +4,15 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function optimizer for efficient non-transposing rename of a
* dense tensor.
+ * TODO: extend to mixed tensors.
**/
struct DenseFastRenameOptimizer {
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp
index 5e9ff6a0ef0..4a4f6b9be14 100644
--- a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp
@@ -2,7 +2,6 @@
#include "dense_lambda_peek_function.h"
#include "index_lookup_table.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/value.h>
namespace vespalib::eval {
@@ -32,7 +31,7 @@ void my_lambda_peek_op(InterpretedFunction::State &state, uint64_t param) {
for (uint32_t idx: lookup_table) {
*dst++ = src_cells[idx];
}
- state.pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
struct MyLambdaPeekOp {
@@ -53,7 +52,7 @@ DenseLambdaPeekFunction::DenseLambdaPeekFunction(const ValueType &result_type,
DenseLambdaPeekFunction::~DenseLambdaPeekFunction() = default;
InterpretedFunction::Instruction
-DenseLambdaPeekFunction::compile_self(EngineOrFactory, Stash &stash) const
+DenseLambdaPeekFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
const Self &self = stash.create<Self>(result_type(), *_idx_fun);
using MyTypify = TypifyCellType;
diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h
index c7432ed72ee..ecd0a15a86e 100644
--- a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h
+++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h
@@ -23,7 +23,7 @@ public:
const TensorFunction &child,
std::shared_ptr<Function const> idx_fun);
~DenseLambdaPeekFunction() override;
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
vespalib::string idx_fun_dump() const;
bool result_is_mutable() const override { return true; }
};
diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp
index a2ea24dbf0a..f8ce886ae1f 100644
--- a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp
+++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp
@@ -3,8 +3,7 @@
#include "dense_lambda_peek_optimizer.h"
#include "dense_lambda_peek_function.h"
#include "dense_cell_range_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/dense_replace_type_function.h>
+#include <vespa/eval/instruction/dense_replace_type_function.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/node_tools.h>
#include <vespa/eval/eval/basic_nodes.h>
@@ -183,7 +182,7 @@ DenseLambdaPeekOptimizer::optimize(const TensorFunction &expr, Stash &stash)
if (result.cell_range && (dst_type.cell_type() == src_type.cell_type())) {
auto cell_range = result.cell_range.value();
if (cell_range.is_full(src_type.dense_subspace_size())) {
- return tensor::DenseReplaceTypeFunction::create_compact(dst_type, get_param, stash);
+ return DenseReplaceTypeFunction::create_compact(dst_type, get_param, stash);
} else {
return stash.create<DenseCellRangeFunction>(dst_type, get_param,
cell_range.offset, cell_range.length);
diff --git a/eval/src/vespa/eval/instruction/dense_matmul_function.cpp b/eval/src/vespa/eval/instruction/dense_matmul_function.cpp
index 5d4ebb88931..33d9054820b 100644
--- a/eval/src/vespa/eval/instruction/dense_matmul_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_matmul_function.cpp
@@ -1,7 +1,6 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_matmul_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/vespalib/objects/objectvisitor.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
@@ -43,7 +42,7 @@ void my_matmul_op(InterpretedFunction::State &state, uint64_t param) {
}
lhs += (lhs_common_inner ? self.common_size : 1);
}
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
template <bool lhs_common_inner, bool rhs_common_inner>
@@ -57,7 +56,7 @@ void my_cblas_double_matmul_op(InterpretedFunction::State &state, uint64_t param
lhs_cells.cbegin(), lhs_common_inner ? self.common_size : self.lhs_size,
rhs_cells.cbegin(), rhs_common_inner ? self.common_size : self.rhs_size,
0.0, dst_cells.begin(), self.rhs_size);
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
template <bool lhs_common_inner, bool rhs_common_inner>
@@ -71,7 +70,7 @@ void my_cblas_float_matmul_op(InterpretedFunction::State &state, uint64_t param)
lhs_cells.cbegin(), lhs_common_inner ? self.common_size : self.lhs_size,
rhs_cells.cbegin(), rhs_common_inner ? self.common_size : self.rhs_size,
0.0, dst_cells.begin(), self.rhs_size);
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
bool is_matrix(const ValueType &type) {
@@ -160,7 +159,7 @@ DenseMatMulFunction::DenseMatMulFunction(const ValueType &result_type,
DenseMatMulFunction::~DenseMatMulFunction() = default;
InterpretedFunction::Instruction
-DenseMatMulFunction::compile_self(EngineOrFactory, Stash &stash) const
+DenseMatMulFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
using MyTypify = TypifyValue<TypifyCellType,TypifyBool>;
Self &self = stash.create<Self>(result_type(), _lhs_size, _common_size, _rhs_size);
diff --git a/eval/src/vespa/eval/instruction/dense_matmul_function.h b/eval/src/vespa/eval/instruction/dense_matmul_function.h
index 6e4093e70f3..c96f2c35c75 100644
--- a/eval/src/vespa/eval/instruction/dense_matmul_function.h
+++ b/eval/src/vespa/eval/instruction/dense_matmul_function.h
@@ -3,7 +3,6 @@
#pragma once
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
namespace vespalib::eval {
@@ -50,7 +49,7 @@ public:
bool lhs_common_inner() const { return _lhs_common_inner; }
bool rhs_common_inner() const { return _rhs_common_inner; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
diff --git a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp
index 42e7deb9523..6d05c8a8d1e 100644
--- a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp
@@ -1,7 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_multi_matmul_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/vespalib/objects/objectvisitor.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
@@ -36,7 +35,7 @@ void my_cblas_double_multi_matmul_op(InterpretedFunction::State &state, uint64_t
rhs, self.rhs_common_inner() ? self.common_size() : self.rhs_size(),
0.0, dst, self.rhs_size());
}
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type(), TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type(), TypedCells(dst_cells)));
}
void my_cblas_float_multi_matmul_op(InterpretedFunction::State &state, uint64_t param) {
@@ -57,7 +56,7 @@ void my_cblas_float_multi_matmul_op(InterpretedFunction::State &state, uint64_t
rhs, self.rhs_common_inner() ? self.common_size() : self.rhs_size(),
0.0, dst, self.rhs_size());
}
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type(), TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type(), TypedCells(dst_cells)));
}
InterpretedFunction::op_function my_select(CellType cell_type) {
@@ -177,7 +176,7 @@ DenseMultiMatMulFunction::DenseMultiMatMulFunction(const ValueType &result_type,
DenseMultiMatMulFunction::~DenseMultiMatMulFunction() = default;
InterpretedFunction::Instruction
-DenseMultiMatMulFunction::compile_self(EngineOrFactory, Stash &) const
+DenseMultiMatMulFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
auto op = my_select(lhs().result_type().cell_type());
return InterpretedFunction::Instruction(op, wrap_param<DenseMultiMatMulFunction>(*this));
diff --git a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h
index 289ba6c4d89..7dd99b58a2f 100644
--- a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h
+++ b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h
@@ -2,7 +2,6 @@
#pragma once
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/tensor_function.h>
namespace vespalib::eval {
@@ -44,7 +43,7 @@ public:
bool lhs_common_inner() const { return _lhs_common_inner; }
bool rhs_common_inner() const { return _rhs_common_inner; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
diff --git a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.cpp
index f78c23c80ac..61ef2243480 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.cpp
+++ b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.cpp
@@ -4,13 +4,10 @@
#include "dense_simple_map_function.h"
#include <vespa/eval/eval/operation.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::TensorFunction;
-using eval::as;
-
-using namespace eval::tensor_function;
-using namespace eval::operation;
+using namespace tensor_function;
+using namespace operation;
const TensorFunction &
DensePowAsMapOptimizer::optimize(const TensorFunction &expr, Stash &stash)
@@ -35,4 +32,4 @@ DensePowAsMapOptimizer::optimize(const TensorFunction &expr, Stash &stash)
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.h
index 4849a10c070..e61069b87b0 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h
+++ b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.h
@@ -4,15 +4,16 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function optimizer for converting join expressions on the
* form 'join(tensor,<small integer constant>,f(x,y)(pow(x,y))' to
* expressions on the form 'map(tensor,f(x)(x*x...))'.
+ * TODO: extend to mixed tensors.
**/
struct DensePowAsMapOptimizer {
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp
index a48527e83f5..fc7f31fb421 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.cpp
+++ b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp
@@ -4,13 +4,9 @@
#include "dense_replace_type_function.h"
#include <vespa/eval/eval/value_type.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::Aggr;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::as;
-using namespace eval::tensor_function;
+using namespace tensor_function;
namespace {
@@ -25,16 +21,16 @@ bool is_trivial_dim_list(const ValueType &type, const std::vector<vespalib::stri
return true;
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
const TensorFunction &
-DenseRemoveDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash)
+DenseRemoveDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash)
{
if (auto reduce = as<Reduce>(expr)) {
const TensorFunction &child = reduce->child();
if (expr.result_type().is_dense() &&
child.result_type().is_dense() &&
- eval::aggr::is_ident(reduce->aggr()) &&
+ aggr::is_ident(reduce->aggr()) &&
is_trivial_dim_list(child.result_type(), reduce->dimensions()))
{
assert(expr.result_type().cell_type() == child.result_type().cell_type());
@@ -44,4 +40,4 @@ DenseRemoveDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h
index 64b057a62d8..2b4e3588caf 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h
+++ b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h
@@ -4,14 +4,15 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function optimizer for efficient removal of dimensions with
* size 1 for dense tensors.
+ * TODO: extend to mixed tensors.
**/
struct DenseRemoveDimensionOptimizer {
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp b/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp
new file mode 100644
index 00000000000..81d3ca67880
--- /dev/null
+++ b/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp
@@ -0,0 +1,48 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "dense_replace_type_function.h"
+#include <vespa/eval/eval/value.h>
+
+namespace vespalib::eval {
+
+using namespace tensor_function;
+
+namespace {
+
+void my_replace_type_op(InterpretedFunction::State &state, uint64_t param) {
+ const ValueType &type = unwrap_param<ValueType>(param);
+ TypedCells cells = state.peek(0).cells();
+ state.pop_push(state.stash.create<DenseValueView>(type, cells));
+}
+
+} // namespace vespalib::eval::<unnamed>
+
+DenseReplaceTypeFunction::DenseReplaceTypeFunction(const ValueType &result_type,
+ const TensorFunction &child)
+ : tensor_function::Op1(result_type, child)
+{
+}
+
+DenseReplaceTypeFunction::~DenseReplaceTypeFunction()
+{
+}
+
+InterpretedFunction::Instruction
+DenseReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const
+{
+ return InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type()));
+}
+
+const DenseReplaceTypeFunction &
+DenseReplaceTypeFunction::create_compact(const ValueType &result_type,
+ const TensorFunction &child,
+ Stash &stash)
+{
+ if (auto replace = as<DenseReplaceTypeFunction>(child)) {
+ return stash.create<DenseReplaceTypeFunction>(result_type, replace->child());
+ } else {
+ return stash.create<DenseReplaceTypeFunction>(result_type, child);
+ }
+}
+
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h b/eval/src/vespa/eval/instruction/dense_replace_type_function.h
index 504d3f1649b..78ce163aceb 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h
+++ b/eval/src/vespa/eval/instruction/dense_replace_type_function.h
@@ -4,23 +4,24 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function for efficient type-only modification of dense
* tensor.
+ * TODO: extend to handling any tensor, dense/mixed/sparse.
**/
-class DenseReplaceTypeFunction : public eval::tensor_function::Op1
+class DenseReplaceTypeFunction : public tensor_function::Op1
{
public:
- DenseReplaceTypeFunction(const eval::ValueType &result_type,
- const eval::TensorFunction &child);
+ DenseReplaceTypeFunction(const ValueType &result_type,
+ const TensorFunction &child);
~DenseReplaceTypeFunction();
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
bool result_is_mutable() const override { return child().result_is_mutable(); }
- static const DenseReplaceTypeFunction &create_compact(const eval::ValueType &result_type,
- const eval::TensorFunction &child,
+ static const DenseReplaceTypeFunction &create_compact(const ValueType &result_type,
+ const TensorFunction &child,
Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp
index d0318d371f5..e67aa042881 100644
--- a/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp
@@ -1,7 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_simple_expand_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/vespalib/objects/objectvisitor.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
@@ -49,7 +48,7 @@ void my_simple_expand_op(State &state, uint64_t param) {
apply_op2_vec_num(dst, inner_cells.begin(), outer_cell, inner_cells.size(), my_op);
dst += inner_cells.size();
}
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(params.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(params.result_type, TypedCells(dst_cells)));
}
//-----------------------------------------------------------------------------
@@ -95,7 +94,7 @@ DenseSimpleExpandFunction::DenseSimpleExpandFunction(const ValueType &result_typ
DenseSimpleExpandFunction::~DenseSimpleExpandFunction() = default;
Instruction
-DenseSimpleExpandFunction::compile_self(EngineOrFactory, Stash &stash) const
+DenseSimpleExpandFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
size_t result_size = result_type().dense_subspace_size();
const ExpandParams &params = stash.create<ExpandParams>(result_type(), result_size, function());
diff --git a/eval/src/vespa/eval/instruction/dense_simple_expand_function.h b/eval/src/vespa/eval/instruction/dense_simple_expand_function.h
index cca051fcde9..4abb3d5df02 100644
--- a/eval/src/vespa/eval/instruction/dense_simple_expand_function.h
+++ b/eval/src/vespa/eval/instruction/dense_simple_expand_function.h
@@ -32,7 +32,7 @@ public:
Inner inner_in);
~DenseSimpleExpandFunction() override;
Inner inner() const { return _inner; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_join_function.cpp
index f492d12f05a..76d020eef9d 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_simple_join_function.cpp
@@ -1,7 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_simple_join_function.h"
-#include "dense_tensor_view.h"
#include <vespa/vespalib/objects/objectvisitor.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
@@ -10,27 +9,19 @@
#include <optional>
#include <algorithm>
-namespace vespalib::tensor {
+namespace vespalib::eval {
using vespalib::ArrayRef;
-using eval::CellType;
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using eval::TypifyCellType;
-using eval::as;
-
-using namespace eval::operation;
-using namespace eval::tensor_function;
+using namespace operation;
+using namespace tensor_function;
using Primary = DenseSimpleJoinFunction::Primary;
using Overlap = DenseSimpleJoinFunction::Overlap;
-using op_function = eval::InterpretedFunction::op_function;
-using Instruction = eval::InterpretedFunction::Instruction;
-using State = eval::InterpretedFunction::State;
+using op_function = InterpretedFunction::op_function;
+using Instruction = InterpretedFunction::Instruction;
+using State = InterpretedFunction::State;
namespace {
@@ -67,7 +58,7 @@ template <typename LCT, typename RCT, typename Fun, bool swap, Overlap overlap,
void my_simple_join_op(State &state, uint64_t param) {
using PCT = typename std::conditional<swap,RCT,LCT>::type;
using SCT = typename std::conditional<swap,LCT,RCT>::type;
- using OCT = typename eval::UnifyCellTypes<PCT,SCT>::type;
+ using OCT = typename UnifyCellTypes<PCT,SCT>::type;
using OP = typename std::conditional<swap,SwapArgs2<Fun>,Fun>::type;
const JoinParams &params = unwrap_param<JoinParams>(param);
OP my_op(params.function);
@@ -92,7 +83,7 @@ void my_simple_join_op(State &state, uint64_t param) {
offset += sec_cells.size();
}
}
- state.pop_pop_push(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(params.result_type, TypedCells(dst_cells)));
}
//-----------------------------------------------------------------------------
@@ -151,7 +142,7 @@ std::optional<Overlap> detect_overlap(const TensorFunction &lhs, const TensorFun
return (primary == Primary::LHS) ? detect_overlap(lhs, rhs) : detect_overlap(rhs, lhs);
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
//-----------------------------------------------------------------------------
@@ -191,7 +182,7 @@ DenseSimpleJoinFunction::factor() const
}
Instruction
-DenseSimpleJoinFunction::compile_self(eval::EngineOrFactory, Stash &stash) const
+DenseSimpleJoinFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
const JoinParams &params = stash.create<JoinParams>(result_type(), factor(), function());
auto op = typify_invoke<6,MyTypify,MyGetFun>(lhs().result_type().cell_type(),
@@ -221,4 +212,4 @@ DenseSimpleJoinFunction::optimize(const TensorFunction &expr, Stash &stash)
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h b/eval/src/vespa/eval/instruction/dense_simple_join_function.h
index 2cd918e1b06..8fa0be9d021 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h
+++ b/eval/src/vespa/eval/instruction/dense_simple_join_function.h
@@ -5,23 +5,25 @@
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/operation.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function for simple join operations on dense tensors.
+ * TODO: consider if this is useful anymore, maybe we just need
+ * to handle inplace.
**/
-class DenseSimpleJoinFunction : public eval::tensor_function::Join
+class DenseSimpleJoinFunction : public tensor_function::Join
{
- using Super = eval::tensor_function::Join;
+ using Super = tensor_function::Join;
public:
enum class Primary : uint8_t { LHS, RHS };
enum class Overlap : uint8_t { INNER, OUTER, FULL };
- using join_fun_t = vespalib::eval::operation::op2_t;
+ using join_fun_t = operation::op2_t;
private:
Primary _primary;
Overlap _overlap;
public:
- DenseSimpleJoinFunction(const eval::ValueType &result_type,
+ DenseSimpleJoinFunction(const ValueType &result_type,
const TensorFunction &lhs,
const TensorFunction &rhs,
join_fun_t function_in,
@@ -32,8 +34,8 @@ public:
Overlap overlap() const { return _overlap; }
bool primary_is_mutable() const;
size_t factor() const;
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_map_function.cpp
index d3297b335d3..ec7d2014436 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_simple_map_function.cpp
@@ -1,29 +1,21 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_simple_map_function.h"
-#include "dense_tensor_view.h"
#include <vespa/vespalib/util/typify.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/inline_operation.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
using vespalib::ArrayRef;
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using eval::TypifyCellType;
-using eval::as;
+using namespace operation;
+using namespace tensor_function;
-using namespace eval::operation;
-using namespace eval::tensor_function;
-
-using op_function = eval::InterpretedFunction::op_function;
-using Instruction = eval::InterpretedFunction::Instruction;
-using State = eval::InterpretedFunction::State;
+using op_function = InterpretedFunction::op_function;
+using Instruction = InterpretedFunction::Instruction;
+using State = InterpretedFunction::State;
namespace {
@@ -44,7 +36,7 @@ void my_simple_map_op(State &state, uint64_t param) {
auto dst_cells = make_dst_cells<CT, inplace>(src_cells, state.stash);
apply_op1_vec(dst_cells.begin(), src_cells.begin(), dst_cells.size(), my_fun);
if (!inplace) {
- state.pop_push(state.stash.create<DenseTensorView>(child.type(), TypedCells(dst_cells)));
+ state.pop_push(state.stash.create<DenseValueView>(child.type(), TypedCells(dst_cells)));
}
}
@@ -58,7 +50,7 @@ struct MyGetFun {
using MyTypify = TypifyValue<TypifyCellType,TypifyOp1,TypifyBool>;
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
//-----------------------------------------------------------------------------
@@ -72,7 +64,7 @@ DenseSimpleMapFunction::DenseSimpleMapFunction(const ValueType &result_type,
DenseSimpleMapFunction::~DenseSimpleMapFunction() = default;
Instruction
-DenseSimpleMapFunction::compile_self(eval::EngineOrFactory, Stash &) const
+DenseSimpleMapFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
auto op = typify_invoke<3,MyTypify,MyGetFun>(result_type().cell_type(), function(), inplace());
static_assert(sizeof(uint64_t) == sizeof(function()));
@@ -90,4 +82,4 @@ DenseSimpleMapFunction::optimize(const TensorFunction &expr, Stash &stash)
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_simple_map_function.h b/eval/src/vespa/eval/instruction/dense_simple_map_function.h
new file mode 100644
index 00000000000..40432f35c58
--- /dev/null
+++ b/eval/src/vespa/eval/instruction/dense_simple_map_function.h
@@ -0,0 +1,26 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/tensor_function.h>
+
+namespace vespalib::eval {
+
+/**
+ * Tensor function for simple map operations on dense tensors.
+ * TODO: Fix generic map to handle inplace, and remove this.
+ **/
+class DenseSimpleMapFunction : public tensor_function::Map
+{
+public:
+ using map_fun_t = operation::op1_t;
+ DenseSimpleMapFunction(const ValueType &result_type,
+ const TensorFunction &child,
+ map_fun_t function_in);
+ ~DenseSimpleMapFunction() override;
+ bool inplace() const { return child().result_is_mutable(); }
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
+};
+
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp b/eval/src/vespa/eval/instruction/dense_single_reduce_function.cpp
index 5f688657645..53e91f729ee 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_single_reduce_function.cpp
@@ -1,25 +1,14 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_single_reduce_function.h"
-#include "dense_tensor_view.h"
#include <vespa/vespalib/util/typify.h>
#include <vespa/eval/eval/value.h>
#include <cassert>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::Aggr;
-using eval::InterpretedFunction;
-using eval::TensorEngine;
-using eval::TensorFunction;
-using eval::Value;
-using eval::ValueType;
-using eval::TypifyCellType;
-using eval::TypifyAggr;
-using eval::as;
-
-using namespace eval::tensor_function;
-using namespace eval::aggr;
+using namespace tensor_function;
+using namespace aggr;
namespace {
@@ -125,7 +114,7 @@ void my_single_reduce_op(InterpretedFunction::State &state, uint64_t param) {
} else {
trace_reduce_impl<CT,AGGR,atleast_8,is_inner>(params, src, dst);
}
- state.pop_push(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells)));
+ state.pop_push(state.stash.create<DenseValueView>(params.result_type, TypedCells(dst_cells)));
}
struct MyGetFun {
@@ -166,7 +155,7 @@ template <typename T> struct VectorLookupLoop {
const T &get() const { return list[index]; }
};
-DenseSingleReduceSpec extract_next(const eval::ValueType &type, eval::Aggr aggr,
+DenseSingleReduceSpec extract_next(const ValueType &type, Aggr aggr,
std::vector<vespalib::string> &todo)
{
size_t outer_size = 1;
@@ -200,10 +189,10 @@ DenseSingleReduceSpec extract_next(const eval::ValueType &type, eval::Aggr aggr,
return {type.reduce(do_now), outer_size, reduce_size, inner_size, aggr};
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
std::vector<DenseSingleReduceSpec>
-make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr,
+make_dense_single_reduce_list(const ValueType &type, Aggr aggr,
const std::vector<vespalib::string> &reduce_dims)
{
auto res_type = type.reduce(reduce_dims);
@@ -217,7 +206,7 @@ make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr,
curr_type = list.back().result_type;
}
assert(curr_type == res_type);
- if ((list.size() > 1) && !eval::aggr::is_simple(aggr)) {
+ if ((list.size() > 1) && !aggr::is_simple(aggr)) {
return {};
}
return list;
@@ -236,7 +225,7 @@ DenseSingleReduceFunction::DenseSingleReduceFunction(const DenseSingleReduceSpec
DenseSingleReduceFunction::~DenseSingleReduceFunction() = default;
InterpretedFunction::Instruction
-DenseSingleReduceFunction::compile_self(eval::EngineOrFactory, Stash &stash) const
+DenseSingleReduceFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
auto op = typify_invoke<4,MyTypify,MyGetFun>(result_type().cell_type(), _aggr,
(_reduce_size >= 8), (_inner_size == 1));
@@ -261,4 +250,4 @@ DenseSingleReduceFunction::optimize(const TensorFunction &expr, Stash &stash)
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h b/eval/src/vespa/eval/instruction/dense_single_reduce_function.h
index f2db3155290..ed68bd48c15 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h
+++ b/eval/src/vespa/eval/instruction/dense_single_reduce_function.h
@@ -4,14 +4,14 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
struct DenseSingleReduceSpec {
- eval::ValueType result_type;
+ ValueType result_type;
size_t outer_size;
size_t reduce_size;
size_t inner_size;
- eval::Aggr aggr;
+ Aggr aggr;
};
/**
@@ -20,7 +20,7 @@ struct DenseSingleReduceSpec {
* fails.
**/
std::vector<DenseSingleReduceSpec>
-make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr,
+make_dense_single_reduce_list(const ValueType &type, Aggr aggr,
const std::vector<vespalib::string> &reduce_dims);
/**
@@ -30,26 +30,28 @@ make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr,
* operation. Adjacent reduced dimensions will be handled is if they
* were a single dimension. Trivial dimensions will be trivially
* reduced along with any other dimension.
+ * TODO: consider if we should extend this to handling mixed tensors
+ * (handling the spare part as a batch dimension).
**/
-class DenseSingleReduceFunction : public eval::tensor_function::Op1
+class DenseSingleReduceFunction : public tensor_function::Op1
{
private:
size_t _outer_size;
size_t _reduce_size;
size_t _inner_size;
- eval::Aggr _aggr;
+ Aggr _aggr;
public:
DenseSingleReduceFunction(const DenseSingleReduceSpec &spec,
- const eval::TensorFunction &child);
+ const TensorFunction &child);
~DenseSingleReduceFunction() override;
size_t outer_size() const { return _outer_size; }
size_t reduce_size() const { return _reduce_size; }
size_t inner_size() const { return _inner_size; }
- eval::Aggr aggr() const { return _aggr; }
+ Aggr aggr() const { return _aggr; }
bool result_is_mutable() const override { return true; }
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp b/eval/src/vespa/eval/instruction/dense_tensor_create_function.cpp
index 4b7f4936815..0f41158c36e 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_tensor_create_function.cpp
@@ -1,26 +1,17 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_tensor_create_function.h"
-#include "dense_tensor_view.h"
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/tensor.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::Value;
-using eval::DoubleValue;
-using eval::ValueType;
-using eval::TensorSpec;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using Child = eval::TensorFunction::Child;
-using eval::as;
-using namespace eval::tensor_function;
+using Child = TensorFunction::Child;
+using namespace tensor_function;
namespace {
template <typename CT>
-void my_tensor_create_op(eval::InterpretedFunction::State &state, uint64_t param) {
+void my_tensor_create_op(InterpretedFunction::State &state, uint64_t param) {
const auto &self = unwrap_param<DenseTensorCreateFunction::Self>(param);
size_t pending_cells = self.result_size;
ArrayRef<CT> cells = state.stash.create_uninitialized_array<CT>(pending_cells);
@@ -28,7 +19,7 @@ void my_tensor_create_op(eval::InterpretedFunction::State &state, uint64_t param
cells[pending_cells] = (CT) state.peek(0).as_double();
state.stack.pop_back();
}
- const Value &result = state.stash.create<DenseTensorView>(self.result_type, TypedCells(cells));
+ const Value &result = state.stash.create<DenseValueView>(self.result_type, TypedCells(cells));
state.stack.emplace_back(result);
}
@@ -49,7 +40,7 @@ size_t get_index(const TensorSpec::Address &addr, const ValueType &type) {
return cell_idx;
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
DenseTensorCreateFunction::DenseTensorCreateFunction(const ValueType &res_type, std::vector<Child> children)
: TensorFunction(),
@@ -68,16 +59,16 @@ DenseTensorCreateFunction::push_children(std::vector<Child::CREF> &target) const
}
}
-eval::InterpretedFunction::Instruction
-DenseTensorCreateFunction::compile_self(eval::EngineOrFactory, Stash &) const
+InterpretedFunction::Instruction
+DenseTensorCreateFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
- using MyTypify = eval::TypifyCellType;
+ using MyTypify = TypifyCellType;
auto op = typify_invoke<1,MyTypify,MyTensorCreateOp>(result_type().cell_type());
- return eval::InterpretedFunction::Instruction(op, wrap_param<DenseTensorCreateFunction::Self>(_self));
+ return InterpretedFunction::Instruction(op, wrap_param<DenseTensorCreateFunction::Self>(_self));
}
const TensorFunction &
-DenseTensorCreateFunction::optimize(const eval::TensorFunction &expr, Stash &stash)
+DenseTensorCreateFunction::optimize(const TensorFunction &expr, Stash &stash)
{
if (auto create = as<Create>(expr)) {
if (expr.result_type().is_dense()) {
@@ -95,4 +86,4 @@ DenseTensorCreateFunction::optimize(const eval::TensorFunction &expr, Stash &sta
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_tensor_create_function.h b/eval/src/vespa/eval/instruction/dense_tensor_create_function.h
new file mode 100644
index 00000000000..9af912ba788
--- /dev/null
+++ b/eval/src/vespa/eval/instruction/dense_tensor_create_function.h
@@ -0,0 +1,34 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/tensor_function.h>
+
+namespace vespalib::eval {
+
+/**
+ * Tensor function for creating a dense tensor from double values.
+ * TODO: benchmark how useful this is, maybe we can just drop it.
+ */
+class DenseTensorCreateFunction : public TensorFunction
+{
+public:
+ struct Self {
+ ValueType result_type;
+ size_t result_size;
+ Self(const ValueType &r, size_t n) : result_type(r), result_size(n) {}
+ };
+private:
+ Self _self;
+ std::vector<Child> _children;
+public:
+ DenseTensorCreateFunction(const ValueType &res_type, std::vector<Child> children);
+ ~DenseTensorCreateFunction();
+ const ValueType &result_type() const override { return _self.result_type; }
+ void push_children(std::vector<Child::CREF> &children) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
+ bool result_is_mutable() const override { return true; }
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
+};
+
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp
index fd93cd62fa9..07fd0f8938c 100644
--- a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp
@@ -1,7 +1,6 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_tensor_peek_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/value.h>
namespace vespalib::eval {
@@ -61,7 +60,7 @@ DenseTensorPeekFunction::push_children(std::vector<Child::CREF> &target) const
}
InterpretedFunction::Instruction
-DenseTensorPeekFunction::compile_self(EngineOrFactory, Stash &) const
+DenseTensorPeekFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
using MyTypify = TypifyCellType;
auto op = typify_invoke<1,MyTypify,MyTensorPeekOp>(_children[0].get().result_type().cell_type());
diff --git a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h
index 37979cd592d..bfd217991aa 100644
--- a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h
+++ b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h
@@ -26,7 +26,7 @@ public:
~DenseTensorPeekFunction();
const ValueType &result_type() const override { return DoubleValue::shared_type(); }
void push_children(std::vector<Child::CREF> &children) const override;
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
bool result_is_mutable() const override { return true; }
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
diff --git a/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp b/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp
index 44332bbacee..7d124555f55 100644
--- a/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp
+++ b/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_xw_product_function.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/vespalib/objects/objectvisitor.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/operation.h>
@@ -40,7 +39,7 @@ void my_xw_product_op(InterpretedFunction::State &state, uint64_t param) {
*dst++ = my_dot_product<LCT,RCT,common_inner>(vector_cells.cbegin(), matrix, self.vector_size, self.result_size);
matrix += (common_inner ? self.vector_size : 1);
}
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
template <bool common_inner>
@@ -54,7 +53,7 @@ void my_cblas_double_xw_product_op(InterpretedFunction::State &state, uint64_t p
common_inner ? self.vector_size : self.result_size,
1.0, matrix_cells.cbegin(), common_inner ? self.vector_size : self.result_size, vector_cells.cbegin(), 1,
0.0, dst_cells.begin(), 1);
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
template <bool common_inner>
@@ -68,7 +67,7 @@ void my_cblas_float_xw_product_op(InterpretedFunction::State &state, uint64_t pa
common_inner ? self.vector_size : self.result_size,
1.0, matrix_cells.cbegin(), common_inner ? self.vector_size : self.result_size, vector_cells.cbegin(), 1,
0.0, dst_cells.begin(), 1);
- state.pop_pop_push(state.stash.create<tensor::DenseTensorView>(self.result_type, TypedCells(dst_cells)));
+ state.pop_pop_push(state.stash.create<DenseValueView>(self.result_type, TypedCells(dst_cells)));
}
bool isDenseTensor(const ValueType &type, size_t d) {
@@ -137,7 +136,7 @@ DenseXWProductFunction::DenseXWProductFunction(const ValueType &result_type,
}
InterpretedFunction::Instruction
-DenseXWProductFunction::compile_self(EngineOrFactory, Stash &stash) const
+DenseXWProductFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
{
Self &self = stash.create<Self>(result_type(), _vector_size, _result_size);
using MyTypify = TypifyValue<TypifyCellType,vespalib::TypifyBool>;
diff --git a/eval/src/vespa/eval/instruction/dense_xw_product_function.h b/eval/src/vespa/eval/instruction/dense_xw_product_function.h
index e66afa72f93..7e87377f891 100644
--- a/eval/src/vespa/eval/instruction/dense_xw_product_function.h
+++ b/eval/src/vespa/eval/instruction/dense_xw_product_function.h
@@ -3,7 +3,6 @@
#pragma once
#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
namespace vespalib::eval {
@@ -44,7 +43,7 @@ public:
size_t result_size() const { return _result_size; }
bool common_inner() const { return _common_inner; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
diff --git a/eval/src/vespa/eval/instruction/generic_concat.cpp b/eval/src/vespa/eval/instruction/generic_concat.cpp
index 7a2280c5db7..fa9d2192b99 100644
--- a/eval/src/vespa/eval/instruction/generic_concat.cpp
+++ b/eval/src/vespa/eval/instruction/generic_concat.cpp
@@ -4,7 +4,6 @@
#include "generic_join.h"
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/wrap_param.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/typify.h>
@@ -103,7 +102,7 @@ void my_dense_simple_concat_op(State &state, uint64_t param_in) {
for (size_t i = 0; i < b.size(); ++i) {
*pos++ = b[i];
}
- Value &ref = state.stash.create<tensor::DenseTensorView>(param.res_type, TypedCells(result));
+ Value &ref = state.stash.create<DenseValueView>(param.res_type, TypedCells(result));
state.pop_pop_push(ref);
}
@@ -121,15 +120,6 @@ struct SelectGenericConcatOp {
}
};
-struct PerformGenericConcat {
- template <typename LCT, typename RCT, typename OCT>
- static auto invoke(const Value &a, const Value &b, const ConcatParam &param) {
- return generic_concat<LCT, RCT, OCT>(a, b,
- param.sparse_plan, param.dense_plan,
- param.res_type, param.factory);
- }
-};
-
enum class Case { NONE, OUT, CONCAT, BOTH };
} // namespace <unnamed>
@@ -219,15 +209,4 @@ GenericConcat::make_instruction(const ValueType &lhs_type, const ValueType &rhs_
return Instruction(fun, wrap_param<ConcatParam>(param));
}
-Value::UP
-GenericConcat::perform_concat(const Value &a, const Value &b,
- const vespalib::string &dimension,
- const ValueBuilderFactory &factory)
-{
- ConcatParam param(a.type(), b.type(), dimension, factory);
- return typify_invoke<3,TypifyCellType,PerformGenericConcat>(
- a.type().cell_type(), b.type().cell_type(), param.res_type.cell_type(),
- a, b, param);
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_concat.h b/eval/src/vespa/eval/instruction/generic_concat.h
index d41d161900a..5578c5a0dca 100644
--- a/eval/src/vespa/eval/instruction/generic_concat.h
+++ b/eval/src/vespa/eval/instruction/generic_concat.h
@@ -17,11 +17,6 @@ struct GenericConcat {
make_instruction(const ValueType &lhs_type, const ValueType &rhs_type,
const vespalib::string &dimension,
const ValueBuilderFactory &factory, Stash &stash);
-
- static Value::UP
- perform_concat(const Value &a, const Value &b,
- const vespalib::string &dimension,
- const ValueBuilderFactory &factory);
};
struct DenseConcatPlan {
diff --git a/eval/src/vespa/eval/instruction/generic_join.cpp b/eval/src/vespa/eval/instruction/generic_join.cpp
index 25829576ba5..026df5aa993 100644
--- a/eval/src/vespa/eval/instruction/generic_join.cpp
+++ b/eval/src/vespa/eval/instruction/generic_join.cpp
@@ -195,16 +195,6 @@ struct SelectGenericJoinOp {
}
};
-struct PerformGenericJoin {
- template <typename LCT, typename RCT, typename OCT, typename Fun>
- static auto invoke(const Value &a, const Value &b, const JoinParam &param)
- {
- return generic_mixed_join<LCT, RCT, OCT, Fun>(a, b, param);
- }
-};
-
-
-
//-----------------------------------------------------------------------------
} // namespace <unnamed>
@@ -327,15 +317,4 @@ GenericJoin::make_instruction(const ValueType &lhs_type, const ValueType &rhs_ty
return Instruction(fun, wrap_param<JoinParam>(param));
}
-
-Value::UP
-GenericJoin::perform_join(const Value &a, const Value &b, join_fun_t function,
- const ValueBuilderFactory &factory)
-{
- JoinParam param(a.type(), b.type(), function, factory);
- return typify_invoke<4,JoinTypify,PerformGenericJoin>(
- a.type().cell_type(), b.type().cell_type(), param.res_type.cell_type(), function,
- a, b, param);
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_join.h b/eval/src/vespa/eval/instruction/generic_join.h
index 49cdb3499a9..988286be980 100644
--- a/eval/src/vespa/eval/instruction/generic_join.h
+++ b/eval/src/vespa/eval/instruction/generic_join.h
@@ -12,7 +12,7 @@ namespace vespalib::eval { struct ValueBuilderFactory; }
namespace vespalib::eval::instruction {
-using join_fun_t = vespalib::eval::operation::op2_t;
+using join_fun_t = operation::op2_t;
//-----------------------------------------------------------------------------
@@ -21,10 +21,6 @@ struct GenericJoin {
make_instruction(const ValueType &lhs_type, const ValueType &rhs_type,
join_fun_t function,
const ValueBuilderFactory &factory, Stash &stash);
-
- static Value::UP
- perform_join(const Value &a, const Value &b, join_fun_t function,
- const ValueBuilderFactory &factory);
};
//-----------------------------------------------------------------------------
diff --git a/eval/src/vespa/eval/instruction/generic_lambda.cpp b/eval/src/vespa/eval/instruction/generic_lambda.cpp
index 5685f199b9e..f4f8c84a257 100644
--- a/eval/src/vespa/eval/instruction/generic_lambda.cpp
+++ b/eval/src/vespa/eval/instruction/generic_lambda.cpp
@@ -59,7 +59,7 @@ struct CompiledParams {
};
template <typename CT>
-void my_compiled_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) {
+void my_compiled_lambda_op(InterpretedFunction::State &state, uint64_t param) {
const CompiledParams &params = unwrap_param<CompiledParams>(param);
std::vector<double> args(params.result_type.dimensions().size() + params.bindings.size(), 0.0);
double *bind_next = &args[params.result_type.dimensions().size()];
@@ -98,7 +98,7 @@ struct InterpretedParams {
};
template <typename CT>
-void my_interpreted_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) {
+void my_interpreted_lambda_op(InterpretedFunction::State &state, uint64_t param) {
const InterpretedParams &params = unwrap_param<InterpretedParams>(param);
std::vector<double> labels(params.result_type.dimensions().size(), 0.0);
ParamProxy param_proxy(labels, *state.params, params.bindings);
@@ -121,7 +121,7 @@ struct MyInterpretedLambdaOp {
} // namespace <unnamed>
Instruction
-GenericLambda::make_instruction(const eval::tensor_function::Lambda &lambda_in,
+GenericLambda::make_instruction(const tensor_function::Lambda &lambda_in,
const ValueBuilderFactory &factory, Stash &stash)
{
const ValueType & result_type = lambda_in.result_type();
diff --git a/eval/src/vespa/eval/instruction/generic_lambda.h b/eval/src/vespa/eval/instruction/generic_lambda.h
index a9a490f0957..a5f4c10e214 100644
--- a/eval/src/vespa/eval/instruction/generic_lambda.h
+++ b/eval/src/vespa/eval/instruction/generic_lambda.h
@@ -10,7 +10,7 @@ namespace vespalib::eval::instruction {
struct GenericLambda {
static InterpretedFunction::Instruction
- make_instruction(const eval::tensor_function::Lambda &lambda_in,
+ make_instruction(const tensor_function::Lambda &lambda_in,
const ValueBuilderFactory &factory, Stash &stash);
};
diff --git a/eval/src/vespa/eval/instruction/generic_map.cpp b/eval/src/vespa/eval/instruction/generic_map.cpp
index 993f0a45925..8ad6c3ee68b 100644
--- a/eval/src/vespa/eval/instruction/generic_map.cpp
+++ b/eval/src/vespa/eval/instruction/generic_map.cpp
@@ -48,36 +48,6 @@ struct SelectGenericMapOp {
}
};
-struct PerformGenericMap {
- template <typename CT, typename Func>
- static auto invoke(const Value &input, map_fun_t function_in,
- const ValueBuilderFactory &factory)
- {
- Func fun(function_in);
- const auto &type = input.type();
- size_t subspace_size = type.dense_subspace_size();
- size_t num_mapped = type.count_mapped_dimensions();
- auto builder = factory.create_value_builder<CT>(type, num_mapped, subspace_size, input.index().size());
- auto input_cells = input.cells().typify<CT>();
- auto view = input.index().create_view({});
- std::vector<vespalib::stringref> output_address(num_mapped);
- std::vector<vespalib::stringref *> input_address;
- for (auto & label : output_address) {
- input_address.push_back(&label);
- }
- view->lookup({});
- size_t subspace;
- while (view->next_result(input_address, subspace)) {
- auto dst = builder->add_subspace(output_address);
- size_t input_offset = subspace_size * subspace;
- for (size_t i = 0; i < subspace_size; ++i) {
- dst[i] = fun(input_cells[input_offset + i]);
- }
- }
- return builder->build(std::move(builder));
- }
-};
-
} // namespace <unnamed>
using MapTypify = TypifyValue<TypifyCellType,operation::TypifyOp1>;
@@ -89,12 +59,4 @@ GenericMap::make_instruction(const ValueType &lhs_type, map_fun_t function)
return Instruction(op, to_param(function));
}
-Value::UP
-GenericMap::perform_map(const Value &a, map_fun_t function,
- const ValueBuilderFactory &factory)
-{
- return typify_invoke<2,MapTypify,PerformGenericMap>(a.type().cell_type(), function,
- a, function, factory);
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_map.h b/eval/src/vespa/eval/instruction/generic_map.h
index 9c8fb17c153..2c03512a922 100644
--- a/eval/src/vespa/eval/instruction/generic_map.h
+++ b/eval/src/vespa/eval/instruction/generic_map.h
@@ -10,15 +10,11 @@ namespace vespalib::eval { struct ValueBuilderFactory; }
namespace vespalib::eval::instruction {
-using map_fun_t = vespalib::eval::operation::op1_t;
+using map_fun_t = operation::op1_t;
struct GenericMap {
static InterpretedFunction::Instruction
make_instruction(const ValueType &input_type, map_fun_t function);
-
- static Value::UP
- perform_map(const Value &a, map_fun_t function,
- const ValueBuilderFactory &factory);
};
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_merge.cpp b/eval/src/vespa/eval/instruction/generic_merge.cpp
index 8de4ea1adeb..02749a04eb9 100644
--- a/eval/src/vespa/eval/instruction/generic_merge.cpp
+++ b/eval/src/vespa/eval/instruction/generic_merge.cpp
@@ -156,13 +156,6 @@ struct SelectGenericMergeOp {
}
};
-struct PerformGenericMerge {
- template <typename LCT, typename RCT, typename OCT, typename Fun>
- static auto invoke(const Value &a, const Value &b, const MergeParam &param) {
- return generic_mixed_merge<LCT,RCT,OCT,Fun>(a, b, param);
- }
-};
-
//-----------------------------------------------------------------------------
} // namespace <unnamed>
@@ -178,18 +171,4 @@ GenericMerge::make_instruction(const ValueType &lhs_type, const ValueType &rhs_t
return Instruction(fun, wrap_param<MergeParam>(param));
}
-
-Value::UP
-GenericMerge::perform_merge(const Value &a, const Value &b, join_fun_t function,
- const ValueBuilderFactory &factory)
-{
- MergeParam param(a.type(), b.type(), function, factory);
- return typify_invoke<4,MergeTypify,PerformGenericMerge>(
- a.type().cell_type(),
- b.type().cell_type(),
- param.res_type.cell_type(), function,
- a, b, param);
-}
-
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_merge.h b/eval/src/vespa/eval/instruction/generic_merge.h
index e9ffcc87997..2b2964366cc 100644
--- a/eval/src/vespa/eval/instruction/generic_merge.h
+++ b/eval/src/vespa/eval/instruction/generic_merge.h
@@ -11,10 +11,6 @@ struct GenericMerge {
make_instruction(const ValueType &lhs_type, const ValueType &rhs_type,
join_fun_t function,
const ValueBuilderFactory &factory, Stash &stash);
-
- static Value::UP
- perform_merge(const Value &a, const Value &b, join_fun_t function,
- const ValueBuilderFactory &factory);
};
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_peek.cpp b/eval/src/vespa/eval/instruction/generic_peek.cpp
index d8ae9241f44..66538911890 100644
--- a/eval/src/vespa/eval/instruction/generic_peek.cpp
+++ b/eval/src/vespa/eval/instruction/generic_peek.cpp
@@ -24,7 +24,8 @@ using Spec = GenericPeek::SpecMap;
size_t count_children(const Spec &spec)
{
- size_t num_children = 0;
+ // accounts for "input" child:
+ size_t num_children = 1;
for (const auto & [dim_name, child_or_label] : spec) {
if (std::holds_alternative<size_t>(child_or_label)) {
++num_children;
@@ -313,18 +314,19 @@ generic_mixed_peek(const ValueType &res_type,
template <typename ICT, typename OCT>
void my_generic_peek_op(State &state, uint64_t param_in) {
const auto &param = unwrap_param<PeekParam>(param_in);
- const Value & input_value = state.peek(param.num_children);
- const size_t last_child = param.num_children - 1;
+ // stack index for children are in range [0, num_children>
+ size_t last_valid_stack_idx = param.num_children - 1;
+ const Value & input_value = state.peek(last_valid_stack_idx);
auto get_child_value = [&] (size_t child_idx) {
- size_t stack_idx = last_child - child_idx;
+ size_t stack_idx = last_valid_stack_idx - child_idx;
return int64_t(state.peek(stack_idx).as_double());
};
auto up = generic_mixed_peek<ICT,OCT>(param.res_type, input_value,
param.sparse_plan, param.dense_plan,
param.factory, get_child_value);
const Value &result = *state.stash.create<Value::UP>(std::move(up));
- // num_children does not include the "input" param
- state.pop_n_push(param.num_children + 1, result);
+ // num_children includes the "input" param
+ state.pop_n_push(param.num_children, result);
}
struct SelectGenericPeekOp {
diff --git a/eval/src/vespa/eval/instruction/generic_reduce.cpp b/eval/src/vespa/eval/instruction/generic_reduce.cpp
index 9b2e72e45db..afc46e8ee7d 100644
--- a/eval/src/vespa/eval/instruction/generic_reduce.cpp
+++ b/eval/src/vespa/eval/instruction/generic_reduce.cpp
@@ -9,6 +9,7 @@
#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/visit_ranges.h>
#include <cassert>
+#include <array>
using namespace vespalib::eval::tensor_function;
@@ -153,13 +154,6 @@ struct SelectGenericReduceOp {
}
};
-struct PerformGenericReduce {
- template <typename ICT, typename OCT, typename AGGR>
- static auto invoke(const Value &input, const ReduceParam &param) {
- return generic_reduce<ICT, OCT, typename AGGR::template templ<OCT>>(input, param);
- }
-};
-
//-----------------------------------------------------------------------------
} // namespace <unnamed>
@@ -248,16 +242,4 @@ GenericReduce::make_instruction(const ValueType &type, Aggr aggr, const std::vec
return Instruction(fun, wrap_param<ReduceParam>(param));
}
-
-Value::UP
-GenericReduce::perform_reduce(const Value &a, Aggr aggr,
- const std::vector<vespalib::string> &dimensions,
- const ValueBuilderFactory &factory)
-{
- ReduceParam param(a.type(), dimensions, factory);
- return typify_invoke<3,ReduceTypify,PerformGenericReduce>(
- a.type().cell_type(), param.res_type.cell_type(), aggr,
- a, param);
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_reduce.h b/eval/src/vespa/eval/instruction/generic_reduce.h
index cacc0f4cfd3..f753a3e51cd 100644
--- a/eval/src/vespa/eval/instruction/generic_reduce.h
+++ b/eval/src/vespa/eval/instruction/generic_reduce.h
@@ -41,11 +41,6 @@ struct GenericReduce {
make_instruction(const ValueType &type, Aggr aggr,
const std::vector<vespalib::string> &dimensions,
const ValueBuilderFactory &factory, Stash &stash);
-
- static Value::UP
- perform_reduce(const Value &a, Aggr aggr,
- const std::vector<vespalib::string> &dimensions,
- const ValueBuilderFactory &factory);
};
//-----------------------------------------------------------------------------
diff --git a/eval/src/vespa/eval/instruction/generic_rename.cpp b/eval/src/vespa/eval/instruction/generic_rename.cpp
index 3d8de356001..1ce18597ec2 100644
--- a/eval/src/vespa/eval/instruction/generic_rename.cpp
+++ b/eval/src/vespa/eval/instruction/generic_rename.cpp
@@ -107,14 +107,6 @@ struct SelectGenericRenameOp {
}
};
-struct PerformGenericRename {
- template <typename CT>
- static auto invoke(const Value &a, const RenameParam &param) {
- return generic_rename<CT>(a, param.sparse_plan, param.dense_plan,
- param.res_type, param.factory);
- }
-};
-
} // namespace <unnamed>
//-----------------------------------------------------------------------------
@@ -194,19 +186,5 @@ GenericRename::make_instruction(const ValueType &lhs_type,
return Instruction(fun, wrap_param<RenameParam>(param));
}
-
-Value::UP
-GenericRename::perform_rename(const Value &a,
- const std::vector<vespalib::string> &rename_dimension_from,
- const std::vector<vespalib::string> &rename_dimension_to,
- const ValueBuilderFactory &factory)
-{
- RenameParam param(a.type(),
- rename_dimension_from, rename_dimension_to,
- factory);
- return typify_invoke<1,TypifyCellType,PerformGenericRename>(a.type().cell_type(),
- a, param);
-}
-
} // namespace
diff --git a/eval/src/vespa/eval/instruction/generic_rename.h b/eval/src/vespa/eval/instruction/generic_rename.h
index 4088e817b90..6c94ff02b24 100644
--- a/eval/src/vespa/eval/instruction/generic_rename.h
+++ b/eval/src/vespa/eval/instruction/generic_rename.h
@@ -44,12 +44,6 @@ struct GenericRename {
const std::vector<vespalib::string> &rename_dimension_from,
const std::vector<vespalib::string> &rename_dimension_to,
const ValueBuilderFactory &factory, Stash &stash);
-
- static Value::UP
- perform_rename(const Value &a,
- const std::vector<vespalib::string> &rename_dimension_from,
- const std::vector<vespalib::string> &rename_dimension_to,
- const ValueBuilderFactory &factory);
};
} // namespace
diff --git a/eval/src/vespa/eval/instruction/join_with_number_function.cpp b/eval/src/vespa/eval/instruction/join_with_number_function.cpp
index dd3512a5e74..cd95a109e60 100644
--- a/eval/src/vespa/eval/instruction/join_with_number_function.cpp
+++ b/eval/src/vespa/eval/instruction/join_with_number_function.cpp
@@ -73,7 +73,7 @@ JoinWithNumberFunction::inplace() const {
using MyTypify = TypifyValue<TypifyCellType,vespalib::TypifyBool,operation::TypifyOp2>;
InterpretedFunction::Instruction
-JoinWithNumberFunction::compile_self(EngineOrFactory, Stash &) const
+JoinWithNumberFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
auto op = typify_invoke<4,MyTypify,SelectJoinWithNumberOp>(result_type().cell_type(),
_function,
diff --git a/eval/src/vespa/eval/instruction/join_with_number_function.h b/eval/src/vespa/eval/instruction/join_with_number_function.h
index 6e3f9aa4106..546ff75b175 100644
--- a/eval/src/vespa/eval/instruction/join_with_number_function.h
+++ b/eval/src/vespa/eval/instruction/join_with_number_function.h
@@ -20,16 +20,16 @@ private:
tensor_function::join_fun_t _function;
public:
- JoinWithNumberFunction(const vespalib::eval::tensor_function::Join &original_join, bool number_on_left);
+ JoinWithNumberFunction(const tensor_function::Join &original_join, bool number_on_left);
~JoinWithNumberFunction();
Primary primary() const { return _primary; }
bool inplace() const;
bool result_is_mutable() const override { return true; }
- InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
void visit_self(vespalib::ObjectVisitor &visitor) const override;
static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp b/eval/src/vespa/eval/instruction/vector_from_doubles_function.cpp
index ac91d073fd7..40bd9e25dfc 100644
--- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp
+++ b/eval/src/vespa/eval/instruction/vector_from_doubles_function.cpp
@@ -1,25 +1,19 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "vector_from_doubles_function.h"
-#include "dense_tensor_view.h"
#include <vespa/eval/eval/value.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using Child = eval::TensorFunction::Child;
-using eval::as;
-using namespace eval::tensor_function;
+using Child = TensorFunction::Child;
+using namespace tensor_function;
namespace {
struct CallVectorFromDoubles {
template <typename CT>
static TypedCells
- invoke(eval::InterpretedFunction::State &state, size_t numCells) {
+ invoke(InterpretedFunction::State &state, size_t numCells) {
ArrayRef<CT> outputCells = state.stash.create_uninitialized_array<CT>(numCells);
for (size_t i = numCells; i-- > 0; ) {
outputCells[i] = (CT) state.peek(0).as_double();
@@ -29,13 +23,13 @@ struct CallVectorFromDoubles {
}
};
-void my_vector_from_doubles_op(eval::InterpretedFunction::State &state, uint64_t param) {
+void my_vector_from_doubles_op(InterpretedFunction::State &state, uint64_t param) {
const auto &self = unwrap_param<VectorFromDoublesFunction::Self>(param);
CellType ct = self.resultType.cell_type();
size_t numCells = self.resultSize;
- using MyTypify = eval::TypifyCellType;
+ using MyTypify = TypifyCellType;
TypedCells cells = typify_invoke<1,MyTypify,CallVectorFromDoubles>(ct, state, numCells);
- const Value &result = state.stash.create<DenseTensorView>(self.resultType, cells);
+ const Value &result = state.stash.create<DenseValueView>(self.resultType, cells);
state.stack.emplace_back(result);
}
@@ -71,7 +65,7 @@ std::vector<Child> flatten(const TensorFunction &lhs, const TensorFunction &rhs)
return vec;
}
-} // namespace vespalib::tensor::<unnamed>
+} // namespace vespalib::eval::<unnamed>
VectorFromDoublesFunction::VectorFromDoublesFunction(std::vector<Child> children, const ValueType &res_type)
@@ -91,14 +85,14 @@ VectorFromDoublesFunction::push_children(std::vector<Child::CREF> &target) const
}
}
-eval::InterpretedFunction::Instruction
-VectorFromDoublesFunction::compile_self(eval::EngineOrFactory, Stash &) const
+InterpretedFunction::Instruction
+VectorFromDoublesFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
- return eval::InterpretedFunction::Instruction(my_vector_from_doubles_op, wrap_param<VectorFromDoublesFunction::Self>(_self));
+ return InterpretedFunction::Instruction(my_vector_from_doubles_op, wrap_param<VectorFromDoublesFunction::Self>(_self));
}
const TensorFunction &
-VectorFromDoublesFunction::optimize(const eval::TensorFunction &expr, Stash &stash)
+VectorFromDoublesFunction::optimize(const TensorFunction &expr, Stash &stash)
{
if (auto concat = as<Concat>(expr)) {
const vespalib::string &dimension = concat->dimension();
@@ -113,4 +107,4 @@ VectorFromDoublesFunction::optimize(const eval::TensorFunction &expr, Stash &sta
return expr;
}
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h b/eval/src/vespa/eval/instruction/vector_from_doubles_function.h
index e2bd0386331..c22ea99f41a 100644
--- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h
+++ b/eval/src/vespa/eval/instruction/vector_from_doubles_function.h
@@ -4,35 +4,37 @@
#include <vespa/eval/eval/tensor_function.h>
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Tensor function for a concat forming a vector from double values
+ * TODO: consider removing this, since the user can write a tensor
+ * create expression instead.
*/
-class VectorFromDoublesFunction : public eval::TensorFunction
+class VectorFromDoublesFunction : public TensorFunction
{
public:
struct Self {
- const eval::ValueType resultType;
+ const ValueType resultType;
size_t resultSize;
- Self(const eval::ValueType &r, size_t n) : resultType(r), resultSize(n) {}
+ Self(const ValueType &r, size_t n) : resultType(r), resultSize(n) {}
};
private:
Self _self;
std::vector<Child> _children;
- void add(const eval::TensorFunction &child);
+ void add(const TensorFunction &child);
public:
- VectorFromDoublesFunction(std::vector<Child> children, const eval::ValueType &res_type);
+ VectorFromDoublesFunction(std::vector<Child> children, const ValueType &res_type);
~VectorFromDoublesFunction();
- const eval::ValueType &result_type() const override { return _self.resultType; }
+ const ValueType &result_type() const override { return _self.resultType; }
void push_children(std::vector<Child::CREF> &children) const override;
const vespalib::string &dimension() const {
return _self.resultType.dimensions()[0].name;
}
size_t size() const { return _self.resultSize; }
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
bool result_is_mutable() const override { return true; }
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
};
-} // namespace vespalib::tensor
+} // namespace vespalib::eval
diff --git a/python/vespa/vespa/__init__.py b/eval/src/vespa/eval/onnx/CMakeLists.txt
index b506a040722..9b18557c036 100644
--- a/python/vespa/vespa/__init__.py
+++ b/eval/src/vespa/eval/onnx/CMakeLists.txt
@@ -1,3 +1,6 @@
# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-__version__ = "0.0.1"
+vespa_add_library(eval_onnx OBJECT
+ SOURCES
+ onnx_wrapper.cpp
+)
diff --git a/eval/src/vespa/eval/tensor/dense/onnx_wrapper.cpp b/eval/src/vespa/eval/onnx/onnx_wrapper.cpp
index c49809f265f..d9c0d659b1e 100644
--- a/eval/src/vespa/eval/tensor/dense/onnx_wrapper.cpp
+++ b/eval/src/vespa/eval/onnx/onnx_wrapper.cpp
@@ -1,9 +1,8 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "onnx_wrapper.h"
+#include <vespa/eval/eval/dense_cells_value.h>
#include <vespa/eval/eval/value_type.h>
-#include "dense_tensor_view.h"
-#include "dense_tensor.h"
#include <vespa/vespalib/util/arrayref.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/typify.h>
@@ -19,13 +18,10 @@ LOG_SETUP(".eval.onnx_wrapper");
using vespalib::ArrayRef;
using vespalib::ConstArrayRef;
-using vespalib::eval::CellType;
-using vespalib::eval::ValueType;
-using vespalib::eval::TypifyCellType;
using vespalib::make_string_short::fmt;
-namespace vespalib::tensor {
+namespace vespalib::eval {
namespace {
@@ -70,23 +66,23 @@ struct CreateOnnxTensor {
};
struct CreateVespaTensorRef {
- template <typename T> static eval::Value::UP invoke(const eval::ValueType &type_ref, Ort::Value &value) {
+ template <typename T> static Value::UP invoke(const ValueType &type_ref, Ort::Value &value) {
size_t num_cells = type_ref.dense_subspace_size();
ConstArrayRef<T> cells(value.GetTensorMutableData<T>(), num_cells);
- return std::make_unique<DenseTensorView>(type_ref, TypedCells(cells));
+ return std::make_unique<DenseValueView>(type_ref, TypedCells(cells));
}
- eval::Value::UP operator()(const eval::ValueType &type_ref, Ort::Value &value) {
+ Value::UP operator()(const ValueType &type_ref, Ort::Value &value) {
return typify_invoke<1,MyTypify,CreateVespaTensorRef>(type_ref.cell_type(), type_ref, value);
}
};
struct CreateVespaTensor {
- template <typename T> static eval::Value::UP invoke(const eval::ValueType &type) {
+ template <typename T> static Value::UP invoke(const ValueType &type) {
size_t num_cells = type.dense_subspace_size();
std::vector<T> cells(num_cells, T{});
- return std::make_unique<DenseTensor<T>>(type, std::move(cells));
+ return std::make_unique<DenseCellsValue<T>>(type, std::move(cells));
}
- eval::Value::UP operator()(const eval::ValueType &type) {
+ Value::UP operator()(const ValueType &type) {
return typify_invoke<1,MyTypify,CreateVespaTensor>(type.cell_type(), type);
}
};
@@ -203,7 +199,7 @@ Onnx::TensorInfo make_tensor_info(const OnnxString &name, const Ort::TypeInfo &t
return Onnx::TensorInfo{vespalib::string(name.get()), make_dimensions(tensor_info), make_element_type(element_type)};
}
-std::vector<int64_t> extract_sizes(const eval::ValueType &type) {
+std::vector<int64_t> extract_sizes(const ValueType &type) {
std::vector<int64_t> sizes;
for (const auto &dim: type.dimensions()) {
sizes.push_back(dim.size);
@@ -244,7 +240,7 @@ Onnx::WireInfo::~WireInfo() = default;
Onnx::WirePlanner::~WirePlanner() = default;
bool
-Onnx::WirePlanner::bind_input_type(const eval::ValueType &vespa_in, const TensorInfo &onnx_in)
+Onnx::WirePlanner::bind_input_type(const ValueType &vespa_in, const TensorInfo &onnx_in)
{
const auto &type = vespa_in;
const auto &name = onnx_in.name;
@@ -273,7 +269,7 @@ Onnx::WirePlanner::bind_input_type(const eval::ValueType &vespa_in, const Tensor
return true;
}
-eval::ValueType
+ValueType
Onnx::WirePlanner::make_output_type(const TensorInfo &onnx_out) const
{
const auto &dimensions = onnx_out.dimensions;
@@ -345,7 +341,7 @@ Ort::AllocatorWithDefaultOptions Onnx::EvalContext::_alloc;
template <typename T>
void
-Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const eval::Value &param)
+Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const Value &param)
{
const auto &cells_ref = param.cells();
auto cells = unconstify(cells_ref.typify<T>());
@@ -355,7 +351,7 @@ Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const eval::Value
template <typename SRC, typename DST>
void
-Onnx::EvalContext::convert_param(EvalContext &self, size_t idx, const eval::Value &param)
+Onnx::EvalContext::convert_param(EvalContext &self, size_t idx, const Value &param)
{
auto cells = param.cells().typify<SRC>();
size_t n = cells.size();
@@ -382,21 +378,21 @@ Onnx::EvalContext::convert_result(EvalContext &self, size_t idx)
struct Onnx::EvalContext::SelectAdaptParam {
template <typename ...Ts> static auto invoke() { return adapt_param<Ts...>; }
- auto operator()(eval::CellType ct) {
+ auto operator()(CellType ct) {
return typify_invoke<1,MyTypify,SelectAdaptParam>(ct);
}
};
struct Onnx::EvalContext::SelectConvertParam {
template <typename ...Ts> static auto invoke() { return convert_param<Ts...>; }
- auto operator()(eval::CellType ct, Onnx::ElementType et) {
+ auto operator()(CellType ct, Onnx::ElementType et) {
return typify_invoke<2,MyTypify,SelectConvertParam>(ct, et);
}
};
struct Onnx::EvalContext::SelectConvertResult {
template <typename ...Ts> static auto invoke() { return convert_result<Ts...>; }
- auto operator()(Onnx::ElementType et, eval::CellType ct) {
+ auto operator()(Onnx::ElementType et, CellType ct) {
return typify_invoke<2,MyTypify,SelectConvertResult>(et, ct);
}
};
@@ -450,7 +446,7 @@ Onnx::EvalContext::EvalContext(const Onnx &model, const WireInfo &wire_info)
Onnx::EvalContext::~EvalContext() = default;
void
-Onnx::EvalContext::bind_param(size_t i, const eval::Value &param)
+Onnx::EvalContext::bind_param(size_t i, const Value &param)
{
_param_binders[i](*this, i, param);
}
@@ -468,7 +464,7 @@ Onnx::EvalContext::eval()
}
}
-const eval::Value &
+const Value &
Onnx::EvalContext::get_result(size_t i) const
{
return *_results[i];
diff --git a/eval/src/vespa/eval/tensor/dense/onnx_wrapper.h b/eval/src/vespa/eval/onnx/onnx_wrapper.h
index 1f043a7de5e..68c31f04cdc 100644
--- a/eval/src/vespa/eval/tensor/dense/onnx_wrapper.h
+++ b/eval/src/vespa/eval/onnx/onnx_wrapper.h
@@ -2,7 +2,6 @@
#pragma once
-#include "dense_tensor_view.h"
#ifdef __APPLE__
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#else
@@ -10,13 +9,14 @@
#endif
#include <vespa/vespalib/stllike/string.h>
#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/value.h>
#include <vector>
#include <map>
#include <set>
namespace vespalib::eval { struct Value; }
-namespace vespalib::tensor {
+namespace vespalib::eval {
/**
* Wrapper around an ONNX model handeled by onnxruntime.
@@ -72,24 +72,24 @@ public:
// how the model should be wired with inputs/outputs
struct WireInfo {
- std::vector<eval::ValueType> vespa_inputs;
+ std::vector<ValueType> vespa_inputs;
std::vector<Onnx::TensorType> onnx_inputs;
std::vector<Onnx::TensorType> onnx_outputs;
- std::vector<eval::ValueType> vespa_outputs;
+ std::vector<ValueType> vespa_outputs;
~WireInfo();
};
// planning how we should wire the model based on input types
class WirePlanner {
private:
- std::map<vespalib::string,eval::ValueType> _input_types;
+ std::map<vespalib::string,ValueType> _input_types;
std::map<vespalib::string,size_t> _symbolic_sizes;
std::set<size_t> _bound_unknown_sizes;
public:
WirePlanner() : _input_types(), _symbolic_sizes(), _bound_unknown_sizes() {}
~WirePlanner();
- bool bind_input_type(const eval::ValueType &vespa_in, const TensorInfo &onnx_in);
- eval::ValueType make_output_type(const TensorInfo &onnx_out) const;
+ bool bind_input_type(const ValueType &vespa_in, const TensorInfo &onnx_in);
+ ValueType make_output_type(const TensorInfo &onnx_out) const;
WireInfo get_wire_info(const Onnx &model) const;
};
@@ -98,7 +98,7 @@ public:
// output values are pre-allocated and will not change
class EvalContext {
private:
- using param_fun_t = void (*)(EvalContext &, size_t i, const eval::Value &);
+ using param_fun_t = void (*)(EvalContext &, size_t i, const Value &);
using result_fun_t = void (*)(EvalContext &, size_t i);
static Ort::AllocatorWithDefaultOptions _alloc;
@@ -108,15 +108,15 @@ public:
Ort::MemoryInfo _cpu_memory;
std::vector<Ort::Value> _param_values;
std::vector<Ort::Value> _result_values;
- std::vector<eval::Value::UP> _results;
+ std::vector<Value::UP> _results;
std::vector<param_fun_t> _param_binders;
std::vector<std::pair<size_t,result_fun_t>> _result_converters;
template <typename T>
- static void adapt_param(EvalContext &self, size_t idx, const eval::Value &param);
+ static void adapt_param(EvalContext &self, size_t idx, const Value &param);
template <typename SRC, typename DST>
- static void convert_param(EvalContext &self, size_t idx, const eval::Value &param);
+ static void convert_param(EvalContext &self, size_t idx, const Value &param);
template <typename SRC, typename DST>
static void convert_result(EvalContext &self, size_t idx);
@@ -130,9 +130,9 @@ public:
~EvalContext();
size_t num_params() const { return _param_values.size(); }
size_t num_results() const { return _result_values.size(); }
- void bind_param(size_t i, const eval::Value &param);
+ void bind_param(size_t i, const Value &param);
void eval();
- const eval::Value &get_result(size_t i) const;
+ const Value &get_result(size_t i) const;
};
private:
diff --git a/eval/src/vespa/eval/streamed/streamed_value_index.cpp b/eval/src/vespa/eval/streamed/streamed_value_index.cpp
index 38b57e9c660..17cf7316554 100644
--- a/eval/src/vespa/eval/streamed/streamed_value_index.cpp
+++ b/eval/src/vespa/eval/streamed/streamed_value_index.cpp
@@ -39,7 +39,7 @@ struct StreamedFilterView : Value::Index::View
bool next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out) override {
while (const auto block = label_blocks.next_block()) {
- idx_out = block.ss_idx;
+ idx_out = block.subspace_index;
bool matches = true;
size_t out_idx = 0;
size_t vdm_idx = 0;
@@ -73,7 +73,7 @@ struct StreamedIterationView : Value::Index::View
bool next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out) override {
if (auto block = label_blocks.next_block()) {
- idx_out = block.ss_idx;
+ idx_out = block.subspace_index;
size_t i = 0;
assert(addr_out.size() == block.address.size());
for (auto ptr : addr_out) {
diff --git a/eval/src/vespa/eval/streamed/streamed_value_utils.h b/eval/src/vespa/eval/streamed/streamed_value_utils.h
index 3e3da82dd22..b88d4df8581 100644
--- a/eval/src/vespa/eval/streamed/streamed_value_utils.h
+++ b/eval/src/vespa/eval/streamed/streamed_value_utils.h
@@ -29,9 +29,9 @@ struct LabelStream {
**/
struct LabelBlock {
static constexpr size_t npos = -1;
- size_t ss_idx;
+ size_t subspace_index;
ConstArrayRef<vespalib::stringref> address;
- operator bool() const { return ss_idx != npos; }
+ operator bool() const { return subspace_index != npos; }
};
/**
diff --git a/eval/src/vespa/eval/tensor/CMakeLists.txt b/eval/src/vespa/eval/tensor/CMakeLists.txt
deleted file mode 100644
index 75be3e802ea..00000000000
--- a/eval/src/vespa/eval/tensor/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_library(eval_tensor OBJECT
- SOURCES
- default_tensor_engine.cpp
- partial_update.cpp
- tensor.cpp
- tensor_address.cpp
- wrapped_simple_tensor.cpp
- wrapped_simple_value.cpp
-)
diff --git a/eval/src/vespa/eval/tensor/cell_function.h b/eval/src/vespa/eval/tensor/cell_function.h
deleted file mode 100644
index a268c9a34b1..00000000000
--- a/eval/src/vespa/eval/tensor/cell_function.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <functional>
-
-namespace vespalib::tensor {
-
-/**
- * Interface for a function to be applied on cells in a tensor.
- */
-struct CellFunction
-{
- typedef std::reference_wrapper<const CellFunction> CREF;
- virtual ~CellFunction() {}
- virtual double apply(double value) const = 0;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/cell_values.h b/eval/src/vespa/eval/tensor/cell_values.h
deleted file mode 100644
index 4b8fd33376a..00000000000
--- a/eval/src/vespa/eval/tensor/cell_values.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor.h>
-
-namespace vespalib::tensor {
-
-/*
- * A collection of tensor cells, used as argument for modifying a subset
- * of cells in a tensor.
- */
-class CellValues {
- const SparseTensor &_tensor;
-
-public:
- CellValues(const SparseTensor &tensor)
- : _tensor(tensor)
- {
- }
-
- void accept(TensorVisitor &visitor) const {
- _tensor.accept(visitor);
- }
-
- eval::TensorSpec toSpec() const {
- return _tensor.toSpec();
- }
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp
deleted file mode 100644
index 68c8dc990c6..00000000000
--- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "default_tensor_engine.h"
-#include "tensor.h"
-#include "wrapped_simple_value.h"
-#include "serialization/typed_binary_format.h"
-#include "sparse/sparse_tensor_address_builder.h"
-#include "sparse/direct_sparse_tensor_builder.h"
-#include "dense/dense_tensor.h"
-#include "dense/typed_dense_tensor_builder.h"
-#include <vespa/eval/instruction/dense_dot_product_function.h>
-#include <vespa/eval/instruction/dense_xw_product_function.h>
-#include <vespa/eval/instruction/dense_matmul_function.h>
-#include <vespa/eval/instruction/dense_multi_matmul_function.h>
-#include "dense/dense_fast_rename_optimizer.h"
-#include "dense/dense_add_dimension_optimizer.h"
-#include "dense/dense_single_reduce_function.h"
-#include "dense/dense_remove_dimension_optimizer.h"
-#include <vespa/eval/instruction/dense_lambda_peek_optimizer.h>
-#include "dense/dense_lambda_function.h"
-#include <vespa/eval/instruction/dense_simple_expand_function.h>
-#include "dense/dense_simple_join_function.h"
-#include "dense/dense_number_join_function.h"
-#include "dense/dense_pow_as_map_optimizer.h"
-#include "dense/dense_simple_map_function.h"
-#include "dense/vector_from_doubles_function.h"
-#include "dense/dense_tensor_create_function.h"
-#include <vespa/eval/instruction/dense_tensor_peek_function.h>
-#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/simple_value.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <cassert>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.default_tensor_engine");
-
-namespace vespalib::tensor {
-
-using eval::Aggr;
-using eval::Aggregator;
-using eval::DoubleValue;
-using eval::TensorFunction;
-using eval::TensorSpec;
-using eval::Value;
-using eval::ValueType;
-using vespalib::IllegalArgumentException;
-using vespalib::make_string;
-
-using map_fun_t = vespalib::eval::operation::op1_t;
-using join_fun_t = vespalib::eval::operation::op2_t;
-
-namespace {
-
-constexpr size_t UNDEFINED_IDX = std::numeric_limits<size_t>::max();
-
-const eval::EngineOrFactory &simple_engine() {
- static eval::EngineOrFactory engine(eval::SimpleValueBuilderFactory::get());
- return engine;
-}
-const eval::TensorEngine &default_engine() { return DefaultTensorEngine::ref(); }
-
-// map tensors to simple tensors before fall-back evaluation
-
-const Value &to_simple(const Value &value, Stash &stash) {
- if (auto tensor = value.as_tensor()) {
- if (auto wrapped = dynamic_cast<const WrappedSimpleValue *>(tensor)) {
- return wrapped->unwrap();
- }
- nbostream data;
- tensor->engine().encode(*tensor, data);
- return *stash.create<Value::UP>(simple_engine().decode(data));
- }
- return value;
-}
-
-// map tensors to default tensors after fall-back evaluation
-
-const Value &to_default(const Value &value, Stash &stash) {
- if (! value.type().is_double()) {
- if (! Tensor::supported({value.type()})) {
- return stash.create<WrappedSimpleValue>(value);
- }
- nbostream data;
- simple_engine().encode(value, data);
- return *stash.create<Value::UP>(default_engine().decode(data));
- }
- return value;
-}
-
-const Value &to_value(std::unique_ptr<Tensor> tensor, Stash &stash) {
- assert(tensor);
- if (tensor->type().is_tensor()) {
- return *stash.create<Value::UP>(std::move(tensor));
- }
- return stash.create<DoubleValue>(tensor->as_double());
-}
-
-Value::UP to_value(std::unique_ptr<Tensor> tensor) {
- if (tensor->type().is_tensor()) {
- return tensor;
- }
- return std::make_unique<DoubleValue>(tensor->as_double());
-}
-
-const Value &fallback_join(const Value &a, const Value &b, join_fun_t function, Stash &stash) {
- return to_default(simple_engine().join(to_simple(a, stash), to_simple(b, stash), function, stash), stash);
-}
-
-const Value &fallback_merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) {
- return to_default(simple_engine().merge(to_simple(a, stash), to_simple(b, stash), function, stash), stash);
-}
-
-const Value &fallback_reduce(const Value &a, eval::Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) {
- return to_default(simple_engine().reduce(to_simple(a, stash), aggr, dimensions, stash), stash);
-}
-
-size_t calculate_cell_index(const ValueType &type, const TensorSpec::Address &address) {
- if (type.dimensions().size() != address.size()) {
- return UNDEFINED_IDX;
- }
- size_t d = 0;
- size_t idx = 0;
- for (const auto &binding: address) {
- const auto &dim = type.dimensions()[d++];
- if ((dim.name != binding.first) || (binding.second.index >= dim.size)) {
- return UNDEFINED_IDX;
- }
- idx *= dim.size;
- idx += binding.second.index;
- }
- return idx;
-}
-
-bool build_cell_address(const ValueType &type, const TensorSpec::Address &address,
- SparseTensorAddressBuilder &builder)
-{
- if (type.dimensions().size() != address.size()) {
- return false;
- }
- size_t d = 0;
- builder.clear();
- for (const auto &binding: address) {
- const auto &dim = type.dimensions()[d++];
- if (dim.name != binding.first) {
- return false;
- }
- builder.add(binding.second.name);
- }
- return true;
-}
-
-void bad_spec(const TensorSpec &spec) {
- throw IllegalArgumentException(make_string("malformed tensor spec: %s", spec.to_string().c_str()));
-}
-
-} // namespace vespalib::tensor::<unnamed>
-
-const DefaultTensorEngine DefaultTensorEngine::_engine;
-
-TensorSpec
-DefaultTensorEngine::to_spec(const Value &value) const
-{
- if (value.is_double()) {
- return TensorSpec("double").add({}, value.as_double());
- } else if (auto tensor = value.as_tensor()) {
- assert(&tensor->engine() == this);
- const tensor::Tensor &my_tensor = static_cast<const tensor::Tensor &>(*tensor);
- return my_tensor.toSpec();
- } else {
- return TensorSpec("error");
- }
-}
-
-struct CallDenseTensorBuilder {
- template <typename CT>
- static Value::UP
- invoke(const ValueType &type, const TensorSpec &spec)
- {
- TypedDenseTensorBuilder<CT> builder(type);
- for (const auto &cell: spec.cells()) {
- const auto &address = cell.first;
- size_t cell_idx = calculate_cell_index(type, address);
- if (cell_idx == UNDEFINED_IDX) {
- bad_spec(spec);
- }
- builder.insertCell(cell_idx, cell.second);
- }
- return builder.build();
- }
-};
-
-struct CallSparseTensorBuilder {
- template <typename CT>
- static Value::UP
- invoke(const ValueType &type, const TensorSpec &spec)
- {
- DirectSparseTensorBuilder<CT> builder(type);
- builder.reserve(spec.cells().size());
- SparseTensorAddressBuilder address_builder;
- for (const auto &cell: spec.cells()) {
- const auto &address = cell.first;
- if (build_cell_address(type, address, address_builder)) {
- builder.insertCell(address_builder, cell.second);
- } else {
- bad_spec(spec);
- }
- }
- return builder.build();
- }
-};
-
-using MyTypify = eval::TypifyCellType;
-
-Value::UP
-DefaultTensorEngine::from_spec(const TensorSpec &spec) const
-{
- ValueType type = ValueType::from_spec(spec.type());
- if (type.is_error()) {
- bad_spec(spec);
- } else if (type.is_double()) {
- double value = spec.cells().empty() ? 0.0 : spec.cells().begin()->second.value;
- return std::make_unique<DoubleValue>(value);
- } else if (type.is_dense()) {
- return typify_invoke<1,MyTypify,CallDenseTensorBuilder>(type.cell_type(), type, spec);
- } else if (type.is_sparse()) {
- return typify_invoke<1,MyTypify,CallSparseTensorBuilder>(type.cell_type(), type, spec);
- }
- return std::make_unique<WrappedSimpleValue>(simple_engine().from_spec(spec));
-}
-
-struct CellFunctionFunAdapter : tensor::CellFunction {
- map_fun_t fun;
- CellFunctionFunAdapter(map_fun_t fun_in) : fun(fun_in) {}
- virtual double apply(double value) const override { return fun(value); }
-};
-
-struct CellFunctionBindLeftAdapter : tensor::CellFunction {
- join_fun_t fun;
- double a;
- CellFunctionBindLeftAdapter(join_fun_t fun_in, double bound) : fun(fun_in), a(bound) {}
- virtual double apply(double b) const override { return fun(a, b); }
-};
-
-struct CellFunctionBindRightAdapter : tensor::CellFunction {
- join_fun_t fun;
- double b;
- CellFunctionBindRightAdapter(join_fun_t fun_in, double bound) : fun(fun_in), b(bound) {}
- virtual double apply(double a) const override { return fun(a, b); }
-};
-
-//-----------------------------------------------------------------------------
-
-void
-DefaultTensorEngine::encode(const Value &value, nbostream &output) const
-{
- if (auto tensor = value.as_tensor()) {
- TypedBinaryFormat::serialize(output, static_cast<const tensor::Tensor &>(*tensor));
- } else {
- TypedBinaryFormat::serialize(output, DenseTensor<double>(ValueType::double_type(), {value.as_double()}));
- }
-}
-
-Value::UP
-DefaultTensorEngine::decode(nbostream &input) const
-{
- return to_value(TypedBinaryFormat::deserialize(input));
-}
-
-//-----------------------------------------------------------------------------
-
-const TensorFunction &
-DefaultTensorEngine::optimize(const TensorFunction &expr, Stash &stash) const
-{
- using Child = TensorFunction::Child;
- Child root(expr);
- {
- std::vector<Child::CREF> nodes({root});
- for (size_t i = 0; i < nodes.size(); ++i) {
- nodes[i].get().get().push_children(nodes);
- }
- while (!nodes.empty()) {
- const Child &child = nodes.back().get();
- child.set(eval::DenseDotProductFunction::optimize(child.get(), stash));
- child.set(eval::DenseXWProductFunction::optimize(child.get(), stash));
- child.set(eval::DenseMatMulFunction::optimize(child.get(), stash));
- child.set(eval::DenseMultiMatMulFunction::optimize(child.get(), stash));
- nodes.pop_back();
- }
- }
- {
- std::vector<Child::CREF> nodes({root});
- for (size_t i = 0; i < nodes.size(); ++i) {
- nodes[i].get().get().push_children(nodes);
- }
- while (!nodes.empty()) {
- const Child &child = nodes.back().get();
- child.set(eval::DenseSimpleExpandFunction::optimize(child.get(), stash));
- child.set(DenseAddDimensionOptimizer::optimize(child.get(), stash));
- child.set(DenseRemoveDimensionOptimizer::optimize(child.get(), stash));
- child.set(VectorFromDoublesFunction::optimize(child.get(), stash));
- child.set(DenseTensorCreateFunction::optimize(child.get(), stash));
- child.set(eval::DenseTensorPeekFunction::optimize(child.get(), stash));
- child.set(eval::DenseLambdaPeekOptimizer::optimize(child.get(), stash));
- child.set(DenseLambdaFunction::optimize(child.get(), stash));
- child.set(DenseFastRenameOptimizer::optimize(child.get(), stash));
- child.set(DensePowAsMapOptimizer::optimize(child.get(), stash));
- child.set(DenseSimpleMapFunction::optimize(child.get(), stash));
- child.set(DenseSimpleJoinFunction::optimize(child.get(), stash));
- child.set(DenseNumberJoinFunction::optimize(child.get(), stash));
- child.set(DenseSingleReduceFunction::optimize(child.get(), stash));
- nodes.pop_back();
- }
- }
- return root.get();
-}
-
-//-----------------------------------------------------------------------------
-
-const Value &
-DefaultTensorEngine::map(const Value &a, map_fun_t function, Stash &stash) const
-{
- if (auto tensor = a.as_tensor()) {
- assert(&tensor->engine() == this);
- const tensor::Tensor &my_a = static_cast<const tensor::Tensor &>(*tensor);
- if (!tensor::Tensor::supported({my_a.type()})) {
- return to_default(simple_engine().map(to_simple(a, stash), function, stash), stash);
- }
- CellFunctionFunAdapter cell_function(function);
- return to_value(my_a.apply(cell_function), stash);
- } else {
- return stash.create<DoubleValue>(function(a.as_double()));
- }
-}
-
-const Value &
-DefaultTensorEngine::join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const
-{
- if (auto tensor_a = a.as_tensor()) {
- assert(&tensor_a->engine() == this);
- const tensor::Tensor &my_a = static_cast<const tensor::Tensor &>(*tensor_a);
- if (auto tensor_b = b.as_tensor()) {
- assert(&tensor_b->engine() == this);
- const tensor::Tensor &my_b = static_cast<const tensor::Tensor &>(*tensor_b);
- if (!tensor::Tensor::supported({my_a.type(), my_b.type()})) {
- return fallback_join(a, b, function, stash);
- }
- return to_value(my_a.join(function, my_b), stash);
- } else {
- if (!tensor::Tensor::supported({my_a.type()})) {
- return fallback_join(a, b, function, stash);
- }
- CellFunctionBindRightAdapter cell_function(function, b.as_double());
- return to_value(my_a.apply(cell_function), stash);
- }
- } else {
- if (auto tensor_b = b.as_tensor()) {
- assert(&tensor_b->engine() == this);
- const tensor::Tensor &my_b = static_cast<const tensor::Tensor &>(*tensor_b);
- if (!tensor::Tensor::supported({my_b.type()})) {
- return fallback_join(a, b, function, stash);
- }
- CellFunctionBindLeftAdapter cell_function(function, a.as_double());
- return to_value(my_b.apply(cell_function), stash);
- } else {
- return stash.create<DoubleValue>(function(a.as_double(), b.as_double()));
- }
- }
-}
-
-const Value &
-DefaultTensorEngine::merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) const
-{
- if (auto tensor_a = a.as_tensor()) {
- auto tensor_b = b.as_tensor();
- assert(tensor_b);
- assert(&tensor_a->engine() == this);
- assert(&tensor_b->engine() == this);
- const tensor::Tensor &my_a = static_cast<const tensor::Tensor &>(*tensor_a);
- const tensor::Tensor &my_b = static_cast<const tensor::Tensor &>(*tensor_b);
- if (!tensor::Tensor::supported({my_a.type(), my_b.type()})) {
- return fallback_merge(a, b, function, stash);
- }
- return to_value(my_a.merge(function, my_b), stash);
- } else {
- return stash.create<DoubleValue>(function(a.as_double(), b.as_double()));
- }
-}
-
-const Value &
-DefaultTensorEngine::reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const
-{
- if (auto tensor = a.as_tensor()) {
- assert(&tensor->engine() == this);
- const tensor::Tensor &my_a = static_cast<const tensor::Tensor &>(*tensor);
- if (!tensor::Tensor::supported({my_a.type()})) {
- return fallback_reduce(a, aggr, dimensions, stash);
- }
- switch (aggr) {
- case Aggr::PROD: return to_value(my_a.reduce(eval::operation::Mul::f, dimensions), stash);
- case Aggr::SUM:
- if (dimensions.empty()) {
- return stash.create<eval::DoubleValue>(my_a.as_double());
- } else {
- return to_value(my_a.reduce(eval::operation::Add::f, dimensions), stash);
- }
- case Aggr::MAX: return to_value(my_a.reduce(eval::operation::Max::f, dimensions), stash);
- case Aggr::MIN: return to_value(my_a.reduce(eval::operation::Min::f, dimensions), stash);
- default:
- return fallback_reduce(a, aggr, dimensions, stash);
- }
- } else {
- Aggregator &aggregator = Aggregator::create(aggr, stash);
- aggregator.first(a.as_double());
- return stash.create<DoubleValue>(aggregator.result());
- }
-}
-
-size_t vector_size(const ValueType &type, const vespalib::string &dimension) {
- if (type.is_double()) {
- return 1;
- } else if ((type.dimensions().size() == 1) &&
- (type.dimensions()[0].is_indexed()) &&
- (type.dimensions()[0].name == dimension))
- {
- return type.dimensions()[0].size;
- } else {
- return 0;
- }
-}
-
-template <typename OCT>
-struct CallAppendVector {
- template <typename CT>
- static void call(const ConstArrayRef<CT> &arr, OCT *&pos) {
- for (CT cell: arr) { *pos++ = cell; }
- }
-};
-
-template <typename OCT>
-void append_vector(OCT *&pos, const Value &value) {
- if (auto tensor = value.as_tensor()) {
- dispatch_1<CallAppendVector<OCT> >(tensor->cells(), pos);
- } else {
- *pos++ = value.as_double();
- }
-}
-
-template <typename OCT>
-const Value &concat_vectors(const Value &a, const Value &b, const vespalib::string &dimension, size_t vector_size, Stash &stash) {
- ArrayRef<OCT> cells = stash.create_uninitialized_array<OCT>(vector_size);
- OCT *pos = cells.begin();
- append_vector<OCT>(pos, a);
- append_vector<OCT>(pos, b);
- assert(pos == cells.end());
- const ValueType &type = stash.create<ValueType>(ValueType::tensor_type({ValueType::Dimension(dimension, vector_size)}, ValueType::unify_cell_types(a.type(), b.type())));
- return stash.create<DenseTensorView>(type, TypedCells(cells));
-}
-
-struct CallConcatVectors {
- template <typename OCT>
- static const Value &invoke(const Value &a, const Value &b, const vespalib::string &dimension, size_t vector_size, Stash &stash) {
- return concat_vectors<OCT>(a, b, dimension, vector_size, stash);
- }
-};
-
-const Value &
-DefaultTensorEngine::concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const
-{
- size_t a_size = vector_size(a.type(), dimension);
- size_t b_size = vector_size(b.type(), dimension);
- if ((a_size > 0) && (b_size > 0)) {
- CellType result_cell_type = ValueType::unify_cell_types(a.type(), b.type());
- return typify_invoke<1,MyTypify,CallConcatVectors>(result_cell_type, a, b, dimension, (a_size + b_size), stash);
- }
- return to_default(simple_engine().concat(to_simple(a, stash), to_simple(b, stash), dimension, stash), stash);
-}
-
-const Value &
-DefaultTensorEngine::rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const
-{
- return to_default(simple_engine().rename(to_simple(a, stash), from, to, stash), stash);
-}
-
-//-----------------------------------------------------------------------------
-
-}
diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.h b/eval/src/vespa/eval/tensor/default_tensor_engine.h
deleted file mode 100644
index 5c39706b326..00000000000
--- a/eval/src/vespa/eval/tensor/default_tensor_engine.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_engine.h>
-
-namespace vespalib::tensor {
-
-/**
- * This is a tensor engine implementation wrapping the default tensor
- * implementations (dense/sparse).
- **/
-class DefaultTensorEngine : public eval::TensorEngine
-{
-private:
- DefaultTensorEngine() {}
- static const DefaultTensorEngine _engine;
-public:
- static const TensorEngine &ref() { return _engine; };
-
- TensorSpec to_spec(const Value &value) const override;
- std::unique_ptr<Value> from_spec(const TensorSpec &spec) const override;
-
- void encode(const Value &value, nbostream &output) const override;
- std::unique_ptr<Value> decode(nbostream &input) const override;
-
- const TensorFunction &optimize(const TensorFunction &expr, Stash &stash) const override;
-
- const Value &map(const Value &a, map_fun_t function, Stash &stash) const override;
- const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override;
- const Value &merge(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override;
- const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const override;
- const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const override;
- const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const override;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt
deleted file mode 100644
index 2c7732d7720..00000000000
--- a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_library(eval_tensor_dense OBJECT
- SOURCES
- dense_add_dimension_optimizer.cpp
- dense_dimension_combiner.cpp
- dense_fast_rename_optimizer.cpp
- dense_lambda_function.cpp
- dense_number_join_function.cpp
- dense_pow_as_map_optimizer.cpp
- dense_remove_dimension_optimizer.cpp
- dense_replace_type_function.cpp
- dense_simple_join_function.cpp
- dense_simple_map_function.cpp
- dense_single_reduce_function.cpp
- dense_tensor.cpp
- dense_tensor_address_mapper.cpp
- dense_tensor_cells_iterator.cpp
- dense_tensor_create_function.cpp
- dense_tensor_modify.cpp
- dense_tensor_reduce.cpp
- dense_tensor_value_builder.cpp
- dense_tensor_view.cpp
- mutable_dense_tensor_view.cpp
- onnx_wrapper.cpp
- typed_cells_dispatch.cpp
- typed_dense_tensor_builder.cpp
- vector_from_doubles_function.cpp
-)
diff --git a/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.cpp b/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.cpp
deleted file mode 100644
index 22c8ff12ad1..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_dimension_combiner.h"
-#include <cassert>
-
-namespace vespalib::tensor {
-
-DenseDimensionCombiner::~DenseDimensionCombiner() = default;
-
-DenseDimensionCombiner::DenseDimensionCombiner(const eval::ValueType &lhs,
- const eval::ValueType &rhs)
- : _left(), _right(),
- _commonDims(),
- _outputIndex(0),
- _outputSize(1u),
- result_type(eval::ValueType::join(lhs, rhs))
-{
- assert(lhs.is_dense());
- assert(rhs.is_dense());
- assert(result_type.is_dense());
-
- const auto &lDims = lhs.dimensions();
- const auto &rDims = rhs.dimensions();
- const auto &oDims = result_type.dimensions();
-
- size_t i = lDims.size();
- size_t j = rDims.size();
- size_t k = oDims.size();
-
- uint32_t lMul = 1;
- uint32_t rMul = 1;
- uint32_t oMul = 1;
-
- while (k-- > 0) {
- if ((i > 0) && (lDims[i-1].name == oDims[k].name)) {
- --i;
- // left dim match
- if ((j > 0) && (rDims[j-1].name == oDims[k].name)) {
- // both dim match
- --j;
- CommonDim cd;
- cd.idx = 0;
- cd.leftMultiplier = lMul;
- cd.rightMultiplier = rMul;
- cd.outputMultiplier = oMul;
- assert(lDims[i].size == oDims[k].size);
- assert(rDims[j].size == oDims[k].size);
- cd.size = oDims[k].size;
- lMul *= cd.size;
- rMul *= cd.size;
- oMul *= cd.size;
- _left.totalSize *= cd.size;
- _right.totalSize *= cd.size;
- _outputSize *= cd.size;
- _commonDims.push_back(cd);
- } else {
- SideDim ld;
- ld.idx = 0;
- ld.sideMultiplier = lMul;
- ld.outputMultiplier = oMul;
- assert(lDims[i].size == oDims[k].size);
- ld.size = oDims[k].size;
- lMul *= ld.size;
- oMul *= ld.size;
- _outputSize *= ld.size;
- _left.totalSize *= ld.size;
- _left.dims.push_back(ld);
- }
- } else {
- // right dim match
- assert(j > 0);
- assert(rDims[j-1].name == oDims[k].name);
- --j;
- SideDim rd;
- rd.idx = 0;
- rd.sideMultiplier = rMul;
- rd.outputMultiplier = oMul;
- assert(rDims[j].size == oDims[k].size);
- rd.size = oDims[k].size;
- rMul *= rd.size;
- oMul *= rd.size;
- _outputSize *= rd.size;
- _right.totalSize *= rd.size;
- _right.dims.push_back(rd);
- }
- }
-}
-
-
-} // namespace
-
diff --git a/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.h b/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.h
deleted file mode 100644
index dd3f74bad9b..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_dimension_combiner.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/types.h>
-#include <vespa/eval/eval/value_type.h>
-
-namespace vespalib::tensor {
-
-class DenseDimensionCombiner {
-
- struct SideDim {
- uint32_t idx;
- uint32_t size;
- uint32_t sideMultiplier;
- uint32_t outputMultiplier;
- };
- struct CommonDim {
- uint32_t idx;
- uint32_t size;
- uint32_t leftMultiplier;
- uint32_t rightMultiplier;
- uint32_t outputMultiplier;
- };
-
- struct SideDims {
- std::vector<SideDim> dims;
- uint32_t index;
- uint32_t totalSize;
-
- SideDims() : dims(), index(0), totalSize(1u) {}
-
- void reset(uint32_t &outIndex) {
- for (SideDim& d : dims) {
- index -= d.idx * d.sideMultiplier;
- outIndex -= d.idx * d.outputMultiplier;
- d.idx = 0;
- }
- if (index >= totalSize) {
- index -= totalSize;
- }
- }
- void step(uint32_t &outIndex) {
- for (SideDim& d : dims) {
- d.idx++;
- index += d.sideMultiplier;
- outIndex += d.outputMultiplier;
- if (d.idx < d.size) return;
- index -= d.idx * d.sideMultiplier;
- outIndex -= d.idx * d.outputMultiplier;
- d.idx = 0;
- }
- index += totalSize;
- }
- };
- SideDims _left;
- SideDims _right;
- std::vector<CommonDim> _commonDims;
- uint32_t _outputIndex;
- uint32_t _outputSize;
-
-public:
- size_t leftIdx() const { return _left.index; }
- size_t rightIdx() const { return _right.index; }
- size_t outputIdx() const { return _outputIndex; }
-
- bool leftInRange() const { return _left.index < _left.totalSize; }
- bool rightInRange() const { return _right.index < _right.totalSize; }
- bool commonInRange() const { return _outputIndex < _outputSize; }
-
- void leftReset() { _left.reset(_outputIndex); }
- void stepLeft() { _left.step(_outputIndex); }
-
- void rightReset() { _right.reset(_outputIndex); }
- void stepRight() { _right.step(_outputIndex); }
-
- void commonReset() {
- for (CommonDim& cd : _commonDims) {
- _left.index -= cd.idx * cd.leftMultiplier;
- _right.index -= cd.idx * cd.rightMultiplier;
- _outputIndex -= cd.idx * cd.outputMultiplier;
- cd.idx = 0;
- }
- if (_outputIndex >= _outputSize) {
- _outputIndex -= _outputSize;
- }
- }
-
- void stepCommon() {
- size_t lim = _commonDims.size();
- for (size_t i = 0; i < lim; ++i) {
- CommonDim &cd = _commonDims[i];
- cd.idx++;
- _left.index += cd.leftMultiplier;
- _right.index += cd.rightMultiplier;
- _outputIndex += cd.outputMultiplier;
- if (cd.idx < cd.size) return;
- _left.index -= cd.idx * cd.leftMultiplier;
- _right.index -= cd.idx * cd.rightMultiplier;
- _outputIndex -= cd.idx * cd.outputMultiplier;
- cd.idx = 0;
- }
- _outputIndex += _outputSize;
- }
-
- const eval::ValueType result_type;
-
- DenseDimensionCombiner(const eval::ValueType &lhs, const eval::ValueType &rhs);
-
- ~DenseDimensionCombiner();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_generic_join.h b/eval/src/vespa/eval/tensor/dense/dense_generic_join.h
deleted file mode 100644
index daf678d4916..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_generic_join.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-namespace vespalib::tensor {
- class Tensor;
-}
-
-namespace vespalib::tensor::dense {
-
-/**
- * Creates a new tensor using all combinations of input tensor cells with matching
- * labels for common dimensions, using func to calculate new cell value
- * based on the cell values in the input tensors.
- */
-template <typename Function>
-std::unique_ptr<Tensor>
-generic_join(const DenseTensorView &lhs, const Tensor &rhs, Function &&func);
-
-template <typename Function>
-std::unique_ptr<Tensor>
-generic_join(const DenseTensorView &lhs, const DenseTensorView &rhs, Function &&func);
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_generic_join.hpp b/eval/src/vespa/eval/tensor/dense/dense_generic_join.hpp
deleted file mode 100644
index 033ea3631be..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_generic_join.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_generic_join.h"
-#include "dense_dimension_combiner.h"
-#include "typed_dense_tensor_builder.h"
-
-namespace vespalib::tensor::dense {
-
-template <typename LCT, typename RCT, typename OCT, typename Function>
-std::unique_ptr<Tensor>
-generic_join(DenseDimensionCombiner & combiner,
- TypedDenseTensorBuilder<OCT> & builder,
- const ConstArrayRef<LCT> & lhsCells,
- const ConstArrayRef<RCT> & rhsCells, Function &&func) __attribute__((noinline));
-
-template <typename LCT, typename RCT, typename OCT, typename Function>
-std::unique_ptr<Tensor>
-generic_join(DenseDimensionCombiner & combiner,
- TypedDenseTensorBuilder<OCT> & builder,
- const ConstArrayRef<LCT> & lhsCells,
- const ConstArrayRef<RCT> & rhsCells, Function &&func)
-{
- for (combiner.leftReset(); combiner.leftInRange(); combiner.stepLeft()) {
- for (combiner.rightReset(); combiner.rightInRange(); combiner.stepRight()) {
- for (combiner.commonReset(); combiner.commonInRange(); combiner.stepCommon()) {
- size_t outIdx = combiner.outputIdx();
- size_t l = combiner.leftIdx();
- size_t r = combiner.rightIdx();
- builder.insertCell(outIdx, func(lhsCells[l], rhsCells[r]));
- }
- }
- }
- return builder.build();
-}
-
-struct CallGenericJoin {
- template <typename LCT, typename RCT, typename Function>
- static std::unique_ptr<Tensor>
- call(const ConstArrayRef<LCT> & lhsArr,
- const ConstArrayRef<RCT> & rhsArr,
- DenseDimensionCombiner & combiner,
- Function &&func)
- {
- using OCT = typename eval::UnifyCellTypes<LCT, RCT>::type;
- TypedDenseTensorBuilder<OCT> builder(combiner.result_type);
- return generic_join(combiner, builder, lhsArr, rhsArr, std::move(func));
- }
-};
-
-template <typename Function>
-std::unique_ptr<Tensor>
-generic_join(const DenseTensorView &lhs, const Tensor &rhs, Function &&func)
-{
- DenseDimensionCombiner combiner(lhs.fast_type(), rhs.type());
- TypedCells lhsCells = lhs.cells();
- TypedCells rhsCells = rhs.cells();
- return dispatch_2<CallGenericJoin>(lhsCells, rhsCells, combiner, std::move(func));
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp
deleted file mode 100644
index 95d90a02a9e..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_lambda_function.h"
-#include "dense_tensor_view.h"
-#include <vespa/vespalib/objects/objectvisitor.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/eval/llvm/compiled_function.h>
-#include <vespa/eval/eval/llvm/compile_cache.h>
-#include <assert.h>
-
-namespace vespalib::tensor {
-
-using eval::CompileCache;
-using eval::CompiledFunction;
-using eval::InterpretedFunction;
-using eval::LazyParams;
-using eval::PassParams;
-using eval::TensorEngine;
-using eval::TensorFunction;
-using eval::Value;
-using eval::DoubleValue;
-using eval::ValueType;
-using eval::as;
-using vespalib::Stash;
-
-using Instruction = InterpretedFunction::Instruction;
-using State = InterpretedFunction::State;
-
-using namespace eval::tensor_function;
-
-namespace {
-
-//-----------------------------------------------------------------------------
-
-bool step_labels(double *labels, const ValueType &type) {
- for (size_t idx = type.dimensions().size(); idx-- > 0; ) {
- if ((labels[idx] += 1.0) < type.dimensions()[idx].size) {
- return true;
- } else {
- labels[idx] = 0.0;
- }
- }
- return false;
-}
-
-struct ParamProxy : public LazyParams {
- const std::vector<double> &labels;
- const LazyParams &params;
- const std::vector<size_t> &bindings;
- ParamProxy(const std::vector<double> &labels_in, const LazyParams &params_in, const std::vector<size_t> &bindings_in)
- : labels(labels_in), params(params_in), bindings(bindings_in) {}
- const Value &resolve(size_t idx, Stash &stash) const override {
- if (idx < labels.size()) {
- return stash.create<DoubleValue>(labels[idx]);
- }
- return params.resolve(bindings[idx - labels.size()], stash);
- }
-};
-
-//-----------------------------------------------------------------------------
-
-struct CompiledParams {
- const ValueType &result_type;
- const std::vector<size_t> &bindings;
- size_t num_cells;
- CompileCache::Token::UP token;
- CompiledParams(const Lambda &lambda)
- : result_type(lambda.result_type()),
- bindings(lambda.bindings()),
- num_cells(result_type.dense_subspace_size()),
- token(CompileCache::compile(lambda.lambda(), PassParams::ARRAY))
- {
- assert(lambda.lambda().num_params() == (result_type.dimensions().size() + bindings.size()));
- }
-};
-
-template <typename CT>
-void my_compiled_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) {
- const CompiledParams &params = unwrap_param<CompiledParams>(param);
- std::vector<double> args(params.result_type.dimensions().size() + params.bindings.size(), 0.0);
- double *bind_next = &args[params.result_type.dimensions().size()];
- for (size_t binding: params.bindings) {
- *bind_next++ = state.params->resolve(binding, state.stash).as_double();
- }
- auto fun = params.token->get().get_function();
- ArrayRef<CT> dst_cells = state.stash.create_uninitialized_array<CT>(params.num_cells);
- CT *dst = &dst_cells[0];
- do {
- *dst++ = fun(&args[0]);
- } while (step_labels(&args[0], params.result_type));
- state.stack.push_back(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells)));
-}
-
-struct MyCompiledLambdaOp {
- template <typename CT>
- static auto invoke() { return my_compiled_lambda_op<CT>; }
-};
-
-//-----------------------------------------------------------------------------
-
-struct InterpretedParams {
- const ValueType &result_type;
- const std::vector<size_t> &bindings;
- size_t num_cells;
- InterpretedFunction fun;
- InterpretedParams(const Lambda &lambda, eval::EngineOrFactory engine)
- : result_type(lambda.result_type()),
- bindings(lambda.bindings()),
- num_cells(result_type.dense_subspace_size()),
- fun(engine, lambda.lambda().root(), lambda.types())
- {
- assert(lambda.lambda().num_params() == (result_type.dimensions().size() + bindings.size()));
- }
-};
-
-template <typename CT>
-void my_interpreted_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) {
- const InterpretedParams &params = unwrap_param<InterpretedParams>(param);
- std::vector<double> labels(params.result_type.dimensions().size(), 0.0);
- ParamProxy param_proxy(labels, *state.params, params.bindings);
- InterpretedFunction::Context ctx(params.fun);
- ArrayRef<CT> dst_cells = state.stash.create_uninitialized_array<CT>(params.num_cells);
- CT *dst = &dst_cells[0];
- do {
- *dst++ = params.fun.eval(ctx, param_proxy).as_double();
- } while (step_labels(&labels[0], params.result_type));
- state.stack.push_back(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells)));
-}
-
-struct MyInterpretedLambdaOp {
- template <typename CT>
- static auto invoke() { return my_interpreted_lambda_op<CT>; }
-};
-
-//-----------------------------------------------------------------------------
-
-}
-
-DenseLambdaFunction::DenseLambdaFunction(const Lambda &lambda_in)
- : Super(lambda_in.result_type()),
- _lambda(lambda_in)
-{
-}
-
-DenseLambdaFunction::~DenseLambdaFunction() = default;
-
-DenseLambdaFunction::EvalMode
-DenseLambdaFunction::eval_mode() const
-{
- if (!CompiledFunction::detect_issues(_lambda.lambda()) &&
- _lambda.types().all_types_are_double())
- {
- return EvalMode::COMPILED;
- } else {
- return EvalMode::INTERPRETED;
- }
-}
-
-Instruction
-DenseLambdaFunction::compile_self(eval::EngineOrFactory engine, Stash &stash) const
-{
- auto mode = eval_mode();
- using MyTypify = eval::TypifyCellType;
- if (mode == EvalMode::COMPILED) {
- CompiledParams &params = stash.create<CompiledParams>(_lambda);
- auto op = typify_invoke<1,MyTypify,MyCompiledLambdaOp>(result_type().cell_type());
- return Instruction(op, wrap_param<CompiledParams>(params));
- } else {
- assert(mode == EvalMode::INTERPRETED);
- InterpretedParams &params = stash.create<InterpretedParams>(_lambda, engine);
- auto op = typify_invoke<1,MyTypify,MyInterpretedLambdaOp>(result_type().cell_type());
- return Instruction(op, wrap_param<InterpretedParams>(params));
- }
-}
-
-const eval::TensorFunction &
-DenseLambdaFunction::optimize(const TensorFunction &expr, Stash &stash)
-{
- if (auto lambda = as<Lambda>(expr)) {
- return stash.create<DenseLambdaFunction>(*lambda);
- }
- return expr;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h
deleted file mode 100644
index e82c022d781..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_function.h>
-
-namespace vespalib::tensor {
-
-/**
- * Tensor function for generic tensor lambda producing dense tensor
- * views directly. This is the catch-all fall-back used by the default
- * (production) tensor engine to avoid having a TensorSpec as an
- * intermediate result.
- **/
-class DenseLambdaFunction : public eval::tensor_function::Leaf
-{
- using Super = eval::tensor_function::Leaf;
-private:
- const eval::tensor_function::Lambda &_lambda;
-public:
- enum class EvalMode : uint8_t { COMPILED, INTERPRETED };
- DenseLambdaFunction(const eval::tensor_function::Lambda &lambda_in);
- ~DenseLambdaFunction() override;
- bool result_is_mutable() const override { return true; }
- EvalMode eval_mode() const;
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp
deleted file mode 100644
index c41743200da..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_number_join_function.h"
-#include "dense_tensor_view.h"
-#include <vespa/vespalib/util/typify.h>
-#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/inline_operation.h>
-
-namespace vespalib::tensor {
-
-using vespalib::ArrayRef;
-
-using eval::CellType;
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using eval::TypifyCellType;
-using eval::as;
-
-using namespace eval::operation;
-using namespace eval::tensor_function;
-
-using Primary = DenseNumberJoinFunction::Primary;
-
-using op_function = eval::InterpretedFunction::op_function;
-using Instruction = eval::InterpretedFunction::Instruction;
-using State = eval::InterpretedFunction::State;
-
-namespace {
-
-template <typename CT, bool inplace>
-ArrayRef<CT> make_dst_cells(ConstArrayRef<CT> src_cells, Stash &stash) {
- if (inplace) {
- return unconstify(src_cells);
- } else {
- return stash.create_uninitialized_array<CT>(src_cells.size());
- }
-}
-
-template <typename CT, typename Fun, bool inplace, bool swap>
-void my_number_join_op(State &state, uint64_t param) {
- using OP = typename std::conditional<swap,SwapArgs2<Fun>,Fun>::type;
- OP my_op((join_fun_t)param);
- const Value &tensor = state.peek(swap ? 0 : 1);
- CT number = state.peek(swap ? 1 : 0).as_double();
- auto src_cells = tensor.cells().typify<CT>();
- auto dst_cells = make_dst_cells<CT, inplace>(src_cells, state.stash);
- apply_op2_vec_num(dst_cells.begin(), src_cells.begin(), number, dst_cells.size(), my_op);
- if (inplace) {
- state.pop_pop_push(tensor);
- } else {
- state.pop_pop_push(state.stash.create<DenseTensorView>(tensor.type(), TypedCells(dst_cells)));
- }
-}
-
-//-----------------------------------------------------------------------------
-
-struct MyGetFun {
- template <typename R1, typename R2, typename R3, typename R4> static auto invoke() {
- return my_number_join_op<R1, R2, R3::value, R4::value>;
- }
-};
-
-using MyTypify = TypifyValue<TypifyCellType,TypifyOp2,TypifyBool>;
-
-bool is_dense(const TensorFunction &tf) { return tf.result_type().is_dense(); }
-bool is_double(const TensorFunction &tf) { return tf.result_type().is_double(); }
-CellType cell_type(const TensorFunction &tf) { return tf.result_type().cell_type(); }
-
-} // namespace vespalib::tensor::<unnamed>
-
-//-----------------------------------------------------------------------------
-
-DenseNumberJoinFunction::DenseNumberJoinFunction(const ValueType &result_type,
- const TensorFunction &lhs,
- const TensorFunction &rhs,
- join_fun_t function_in,
- Primary primary_in)
- : Join(result_type, lhs, rhs, function_in),
- _primary(primary_in)
-{
-}
-
-DenseNumberJoinFunction::~DenseNumberJoinFunction() = default;
-
-bool
-DenseNumberJoinFunction::inplace() const
-{
- if (_primary == Primary::LHS) {
- return lhs().result_is_mutable();
- } else {
- return rhs().result_is_mutable();
- }
-}
-
-Instruction
-DenseNumberJoinFunction::compile_self(eval::EngineOrFactory, Stash &) const
-{
- auto op = typify_invoke<4,MyTypify,MyGetFun>(result_type().cell_type(), function(),
- inplace(), (_primary == Primary::RHS));
- static_assert(sizeof(uint64_t) == sizeof(function()));
- return Instruction(op, (uint64_t)(function()));
-}
-
-const TensorFunction &
-DenseNumberJoinFunction::optimize(const TensorFunction &expr, Stash &stash)
-{
- if (auto join = as<Join>(expr)) {
- const TensorFunction &lhs = join->lhs();
- const TensorFunction &rhs = join->rhs();
- if (is_dense(lhs) && is_double(rhs)) {
- assert(cell_type(expr) == cell_type(lhs));
- return stash.create<DenseNumberJoinFunction>(join->result_type(), lhs, rhs, join->function(), Primary::LHS);
- } else if (is_double(lhs) && is_dense(rhs)) {
- assert(cell_type(expr) == cell_type(rhs));
- return stash.create<DenseNumberJoinFunction>(join->result_type(), lhs, rhs, join->function(), Primary::RHS);
- }
- }
- return expr;
-}
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h
deleted file mode 100644
index c4478ce43b6..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_function.h>
-#include <vespa/eval/eval/operation.h>
-
-namespace vespalib::tensor {
-
-/**
- * Tensor function for join operations between dense tensors and
- * numbers.
- **/
-class DenseNumberJoinFunction : public eval::tensor_function::Join
-{
-public:
- enum class Primary : uint8_t { LHS, RHS };
- using join_fun_t = vespalib::eval::operation::op2_t;
-private:
- Primary _primary;
-public:
- DenseNumberJoinFunction(const eval::ValueType &result_type,
- const TensorFunction &lhs,
- const TensorFunction &rhs,
- join_fun_t function_in,
- Primary primary_in);
- ~DenseNumberJoinFunction() override;
- Primary primary() const { return _primary; }
- bool inplace() const;
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
-};
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp
deleted file mode 100644
index 004edf06d92..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_replace_type_function.h"
-#include "dense_tensor_view.h"
-#include <vespa/eval/eval/value.h>
-
-namespace vespalib::tensor {
-
-using eval::Value;
-using eval::ValueType;
-using eval::TensorFunction;
-using eval::TensorEngine;
-using eval::as;
-using namespace eval::tensor_function;
-
-namespace {
-
-void my_replace_type_op(eval::InterpretedFunction::State &state, uint64_t param) {
- const ValueType &type = unwrap_param<ValueType>(param);
- TypedCells cells = state.peek(0).cells();
- state.pop_push(state.stash.create<DenseTensorView>(type, cells));
-}
-
-} // namespace vespalib::tensor::<unnamed>
-
-DenseReplaceTypeFunction::DenseReplaceTypeFunction(const eval::ValueType &result_type,
- const eval::TensorFunction &child)
- : eval::tensor_function::Op1(result_type, child)
-{
-}
-
-DenseReplaceTypeFunction::~DenseReplaceTypeFunction()
-{
-}
-
-eval::InterpretedFunction::Instruction
-DenseReplaceTypeFunction::compile_self(eval::EngineOrFactory, Stash &) const
-{
- return eval::InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type()));
-}
-
-const DenseReplaceTypeFunction &
-DenseReplaceTypeFunction::create_compact(const eval::ValueType &result_type,
- const eval::TensorFunction &child,
- Stash &stash)
-{
- if (auto replace = as<DenseReplaceTypeFunction>(child)) {
- return stash.create<DenseReplaceTypeFunction>(result_type, replace->child());
- } else {
- return stash.create<DenseReplaceTypeFunction>(result_type, child);
- }
-}
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h
deleted file mode 100644
index ce0498c9ab7..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_function.h>
-
-namespace vespalib::tensor {
-
-/**
- * Tensor function for simple map operations on dense tensors.
- **/
-class DenseSimpleMapFunction : public eval::tensor_function::Map
-{
-public:
- using map_fun_t = vespalib::eval::operation::op1_t;
- DenseSimpleMapFunction(const eval::ValueType &result_type,
- const TensorFunction &child,
- map_fun_t function_in);
- ~DenseSimpleMapFunction() override;
- bool inplace() const { return child().result_is_mutable(); }
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
-};
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp
deleted file mode 100644
index 26f9194c8ce..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor.h"
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/util/exceptions.h>
-
-using vespalib::eval::TensorSpec;
-
-namespace vespalib::tensor {
-
-namespace {
-
-size_t
-calcCellsSize(const eval::ValueType &type)
-{
- size_t cellsSize = 1;
- for (const auto &dim : type.dimensions()) {
- cellsSize *= dim.size;
- }
- return cellsSize;
-}
-
-template<typename T>
-void
-checkCellsSize(const DenseTensor<T> &arg)
-{
- auto cellsSize = calcCellsSize(arg.fast_type());
- if (arg.cells().size != cellsSize) {
- throw IllegalStateException(make_string("Wrong cell size, "
- "expected=%zu, "
- "actual=%zu",
- cellsSize,
- arg.cells().size));
- }
- if (arg.fast_type().cell_type() != arg.cells().type) {
- throw IllegalStateException(make_string("Wrong cell type, "
- "expected=%u, "
- "actual=%u",
- (unsigned char)arg.fast_type().cell_type(),
- (unsigned char)arg.cells().type));
- }
-}
-
-}
-
-template <typename CT>
-DenseTensor<CT>::DenseTensor(eval::ValueType type_in,
- std::vector<CT> &&cells_in)
- : DenseTensorView(_type),
- _type(std::move(type_in)),
- _cells(std::move(cells_in))
-{
- initCellsRef(TypedCells(_cells));
- checkCellsSize(*this);
-}
-
-template <typename CT>
-DenseTensor<CT>::~DenseTensor() = default;
-
-template <typename CT>
-template <typename RCT>
-bool
-DenseTensor<CT>::operator==(const DenseTensor<RCT> &rhs) const
-{
- if (_type != rhs._type) return false;
- if (_cells.size != rhs._cells.size) return false;
- for (size_t i = 0; i < _cells.size; i++) {
- if (_cells[i] != rhs._cells[i]) return false;
- }
- return true;
-}
-
-template class DenseTensor<float>;
-template class DenseTensor<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor.h b/eval/src/vespa/eval/tensor/dense/dense_tensor.h
deleted file mode 100644
index f4b2b0a584f..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_tensor_view.h"
-
-namespace vespalib::tensor {
-
-/**
- * A dense tensor where all dimensions are indexed.
- * Tensor cells are stored in an underlying array according to the order of the dimensions.
- */
-template <typename CT>
-class DenseTensor : public DenseTensorView
-{
-public:
- DenseTensor() = delete;
- ~DenseTensor() override;
- DenseTensor(eval::ValueType type_in, std::vector<CT> &&cells_in);
-
- // for unit tests
- template <typename RCT>
- bool operator==(const DenseTensor<RCT> &rhs) const;
-
- MemoryUsage get_memory_usage() const override {
- size_t alloc = sizeof(DenseTensor) + (sizeof(CT) * _cells.capacity());
- size_t used = sizeof(DenseTensor) + (sizeof(CT) * _cells.size());
- // missing: extra memory used by _type
- return MemoryUsage(alloc, used, 0, 0);
- }
-
-private:
- eval::ValueType _type;
- std::vector<CT> _cells;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp
deleted file mode 100644
index f32af0d097b..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_address_mapper.h"
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/tensor/tensor_address.h>
-#include <vespa/eval/tensor/tensor_address_element_iterator.h>
-
-namespace vespalib::tensor {
-
-uint32_t
-DenseTensorAddressMapper::mapLabelToNumber(stringref label)
-{
- uint32_t result = 0;
- for (char c : label) {
- if (c < '0' || c > '9') {
- return BAD_LABEL; // bad char
- }
- result = result * 10 + (c - '0');
- if (result > 100000000) {
- return BAD_LABEL; // overflow
- }
- }
- return result;
-}
-
-uint32_t
-DenseTensorAddressMapper::mapAddressToIndex(const TensorAddress &address, const eval::ValueType &type)
-{
- uint32_t idx = 0;
- TensorAddressElementIterator<TensorAddress> addressIterator(address);
- for (const auto &dimension : type.dimensions()) {
- if (addressIterator.skipToDimension(dimension.name)) {
- uint32_t label = mapLabelToNumber(addressIterator.label());
- if (label == BAD_LABEL || label >= dimension.size) {
- return BAD_ADDRESS;
- }
- idx = idx * dimension.size + label;
- addressIterator.next();
- } else {
- // output dimension not in input
- idx = idx * dimension.size;
- }
- }
- return idx;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h
deleted file mode 100644
index 7cd776a260c..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <limits>
-#include <cstdint>
-
-namespace vespalib::eval { class ValueType; }
-namespace vespalib { class stringref; }
-
-namespace vespalib::tensor {
-
-class TensorAddress;
-
-/**
- * Utility class for mapping of tensor adress to index
- */
-class DenseTensorAddressMapper
-{
-public:
- static constexpr uint32_t BAD_LABEL = std::numeric_limits<uint32_t>::max();
- static constexpr uint32_t BAD_ADDRESS = std::numeric_limits<uint32_t>::max();
- static uint32_t mapLabelToNumber(stringref label);
- static uint32_t mapAddressToIndex(const TensorAddress &address, const eval::ValueType &type);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp
deleted file mode 100644
index 55d0e29bc35..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_cells_iterator.h"
-
-namespace vespalib::tensor {
-
-DenseTensorCellsIterator::DenseTensorCellsIterator(const eval::ValueType &type_in, TypedCells cells)
- : _type(type_in),
- _cells(cells),
- _cellIdx(0),
- _lastDimension(type_in.dimensions().size() - 1),
- _address(type_in.dimensions().size(), 0)
-{}
-DenseTensorCellsIterator::~DenseTensorCellsIterator() = default;
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h
deleted file mode 100644
index 4611ffaf1d1..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/vespalib/util/arrayref.h>
-#include "typed_cells_dispatch.h"
-
-namespace vespalib::tensor {
-
-/**
- * Utility class to iterate over cells in a dense tensor.
- */
-class DenseTensorCellsIterator
-{
-public:
- using size_type = eval::ValueType::Dimension::size_type;
- using Address = std::vector<size_type>;
-private:
-
- const eval::ValueType &_type;
- TypedCells _cells;
- size_t _cellIdx;
- const int32_t _lastDimension;
- Address _address;
-public:
- DenseTensorCellsIterator(const eval::ValueType &type_in, TypedCells cells);
- ~DenseTensorCellsIterator();
- void next() {
- ++_cellIdx;
- for (int32_t i = _lastDimension; i >= 0; --i) {
- _address[i]++;
- if (__builtin_expect((_address[i] != _type.dimensions()[i].size), true)) {
- // Outer dimension labels can only be increased when this label wraps around.
- break;
- } else {
- _address[i] = 0;
- }
- }
- }
- bool valid() const { return _cellIdx < _cells.size; }
- double cell() const { return GetCell::from(_cells, _cellIdx); }
- const Address &address() const { return _address; }
- const eval::ValueType &fast_type() const { return _type; }
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h
deleted file mode 100644
index a2ca71ce894..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_function.h>
-
-namespace vespalib::tensor {
-
-/**
- * Tensor function for creating a dense tensor from double values.
- */
-class DenseTensorCreateFunction : public eval::TensorFunction
-{
-public:
- struct Self {
- eval::ValueType result_type;
- size_t result_size;
- Self(const eval::ValueType &r, size_t n) : result_type(r), result_size(n) {}
- };
-private:
- Self _self;
- std::vector<Child> _children;
-public:
- DenseTensorCreateFunction(const eval::ValueType &res_type, std::vector<Child> children);
- ~DenseTensorCreateFunction();
- const eval::ValueType &result_type() const override { return _self.result_type; }
- void push_children(std::vector<Child::CREF> &children) const override;
- eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override;
- bool result_is_mutable() const override { return true; }
- static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash);
-};
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp
deleted file mode 100644
index 4777abcbdef..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_modify.h"
-#include "dense_tensor_address_mapper.h"
-#include "dense_tensor.h"
-
-namespace vespalib::tensor {
-
-template <class CT>
-DenseTensorModify<CT>::DenseTensorModify(join_fun_t op, const eval::ValueType &type, std::vector<CT> &&cells)
- : _op(op),
- _type(type),
- _cells(std::move(cells))
-{
- assert(vespalib::eval::check_cell_type<CT>(type.cell_type()));
-}
-
-template <class CT>
-DenseTensorModify<CT>::~DenseTensorModify() = default;
-
-template <class CT>
-void
-DenseTensorModify<CT>::visit(const TensorAddress &address, double value)
-{
- uint32_t idx = DenseTensorAddressMapper::mapAddressToIndex(address, _type);
- if (idx != DenseTensorAddressMapper::BAD_ADDRESS) {
- double nv = _op(_cells[idx], value);
- _cells[idx] = (CT) nv;
- }
-}
-
-template <class CT>
-std::unique_ptr<Tensor>
-DenseTensorModify<CT>::build()
-{
- return std::make_unique<DenseTensor<CT>>(_type, std::move(_cells));
-}
-
-template class DenseTensorModify<float>;
-template class DenseTensorModify<double>;
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h
deleted file mode 100644
index 13ed735eb6a..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include "dense_tensor_view.h"
-
-namespace vespalib::tensor {
-
-/*
- * This class handles tensor modify update on a dense tensor.
- * For all cells visited, a join function is applied to determine
- * the new cell value.
- */
-template <class CT>
-class DenseTensorModify : public TensorVisitor
-{
- using join_fun_t = vespalib::eval::operation::op2_t;
- join_fun_t _op;
- const eval::ValueType &_type;
- std::vector<CT> _cells;
-
-public:
- DenseTensorModify(join_fun_t op, const eval::ValueType &type, std::vector<CT> &&cells);
- ~DenseTensorModify();
- void visit(const TensorAddress &address, double value) override;
- std::unique_ptr<Tensor> build();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp
deleted file mode 100644
index d44fe88bb10..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_reduce.hpp"
-
-namespace vespalib::tensor::dense {
-
-size_t
-DimensionReducer::calcCellsSize(const eval::ValueType &type)
-{
- size_t cellsSize = 1;
- for (const auto &dim : type.dimensions()) {
- cellsSize *= dim.size;
- }
- return cellsSize;
-}
-
-DimensionReducer::DimensionReducer(const eval::ValueType &oldType, const string &dimensionToRemove)
- : _type(oldType.reduce({ dimensionToRemove })),
- _innerDimSize(1),
- _sumDimSize(1),
- _outerDimSize(1)
-{
- setup(oldType, dimensionToRemove);
-}
-
-DimensionReducer::~DimensionReducer() = default;
-
-void
-DimensionReducer::setup(const eval::ValueType &oldType, const vespalib::string &dimensionToRemove)
-{
- auto itr = std::lower_bound(oldType.dimensions().cbegin(),
- oldType.dimensions().cend(),
- dimensionToRemove,
- [](const auto &dim, const auto &dimension)
- { return dim.name < dimension; });
- if ((itr != oldType.dimensions().end()) && (itr->name == dimensionToRemove)) {
- for (auto outerItr = oldType.dimensions().cbegin(); outerItr != itr; ++outerItr) {
- _outerDimSize *= outerItr->size;
- }
- _sumDimSize = itr->size;
- for (++itr; itr != oldType.dimensions().cend(); ++itr) {
- _innerDimSize *= itr->size;
- }
- } else {
- _outerDimSize = calcCellsSize(oldType);
- }
-}
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.h
deleted file mode 100644
index fb054318985..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_tensor.h"
-
-namespace vespalib::tensor::dense {
-
-/**
- * Returns a tensor with the given dimension(s) removed and the cell values in that dimension(s)
- * combined using the given func.
- */
-template<typename Function>
-std::unique_ptr<Tensor>
-reduce(const DenseTensorView &tensor, const std::vector<vespalib::string> &dimensions, Function &&func);
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp
deleted file mode 100644
index cbdf7e0a3ca..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_reduce.h"
-#include <cassert>
-#include <algorithm>
-
-namespace vespalib::tensor::dense {
-
-class DimensionReducer
-{
-private:
- eval::ValueType _type;
- size_t _innerDimSize;
- size_t _sumDimSize;
- size_t _outerDimSize;
-
- static size_t calcCellsSize(const eval::ValueType &type);
- void setup(const eval::ValueType &oldType, const vespalib::string &dimensionToRemove);
-public:
- DimensionReducer(const eval::ValueType &oldType, const string &dimensionToRemove);
- ~DimensionReducer();
-
- template <typename T, typename Function>
- std::unique_ptr<DenseTensorView>
- reduceCells(ConstArrayRef<T> cellsIn, Function &&func) {
- size_t resultSize = calcCellsSize(_type);
- std::vector<T> cellsOut(resultSize);
- auto itr_in = cellsIn.cbegin();
- auto itr_out = cellsOut.begin();
- for (size_t outerDim = 0; outerDim < _outerDimSize; ++outerDim) {
- auto saved_itr = itr_out;
- for (size_t innerDim = 0; innerDim < _innerDimSize; ++innerDim) {
- *itr_out = *itr_in;
- ++itr_out;
- ++itr_in;
- }
- for (size_t sumDim = 1; sumDim < _sumDimSize; ++sumDim) {
- itr_out = saved_itr;
- for (size_t innerDim = 0; innerDim < _innerDimSize; ++innerDim) {
- *itr_out = func(*itr_out, *itr_in);
- ++itr_out;
- ++itr_in;
- }
- }
- }
- assert(itr_out == cellsOut.end());
- assert(itr_in == cellsIn.cend());
- return std::make_unique<DenseTensor<T>>(std::move(_type), std::move(cellsOut));
- }
-};
-
-namespace {
-
-struct CallReduceCells {
- template <typename CT, typename Function>
- static std::unique_ptr<DenseTensorView>
- call(const ConstArrayRef<CT> &oldCells, DimensionReducer &reducer, Function &&func) {
- return reducer.reduceCells(oldCells, func);
- }
-
- template <typename CT, typename Function>
- static double
- call(const ConstArrayRef<CT> &oldCells, Function &&func) {
- assert(oldCells.size() > 0);
- double result = oldCells[0];
- for (size_t i = 1; i < oldCells.size(); ++i) {
- result = func(result, oldCells[i]);
- }
- return result;
- }
-};
-
-template <typename Function>
-std::unique_ptr<DenseTensorView>
-reduce(const DenseTensorView &tensor, const vespalib::string &dimensionToRemove, Function &&func)
-{
- DimensionReducer reducer(tensor.fast_type(), dimensionToRemove);
- TypedCells oldCells = tensor.cells();
- return dispatch_1<CallReduceCells>(oldCells, reducer, func);
-}
-
-template <typename Function>
-double
-reduce_all_dimensions(TypedCells oldCells, Function &&func)
-{
- return dispatch_1<CallReduceCells>(oldCells, func);
-}
-
-}
-
-template <typename Function>
-std::unique_ptr<Tensor>
-reduce(const DenseTensorView &tensor, const std::vector<vespalib::string> &dimensions, Function &&func)
-{
- if ((dimensions.size() == 0) ||
- (dimensions.size() == tensor.fast_type().dimensions().size()))
- {
- eval::ValueType newType = tensor.fast_type().reduce(dimensions);
- assert(newType.is_double());
- double result = reduce_all_dimensions(tensor.cells(), func);
- std::vector<double> newCells({result});
- return std::make_unique<DenseTensor<double>>(std::move(newType), std::move(newCells));
- }
- std::unique_ptr<DenseTensorView> result = reduce(tensor, dimensions[0], func);
- for (size_t i = 1; i < dimensions.size(); ++i) {
- std::unique_ptr<DenseTensorView> tmpResult = reduce(*result, dimensions[i], func);
- result = std::move(tmpResult);
- }
- return result;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.cpp
deleted file mode 100644
index 6a5bb33ca06..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_value_builder.h"
-
-namespace vespalib::tensor {
-
-template<typename T>
-DenseTensorValueBuilder<T>::DenseTensorValueBuilder(const eval::ValueType &type,
- size_t subspace_size_in)
- : _type(type),
- _cells(subspace_size_in)
-{
-}
-
-template<typename T>
-DenseTensorValueBuilder<T>::~DenseTensorValueBuilder() = default;
-
-template class DenseTensorValueBuilder<float>;
-template class DenseTensorValueBuilder<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.h
deleted file mode 100644
index 49a660553ee..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_value_builder.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_tensor.h"
-
-namespace vespalib::tensor {
-
-/**
- * A builder for DenseTensor objects
- **/
-template<typename T>
-class DenseTensorValueBuilder : public eval::ValueBuilder<T>
-{
-private:
- eval::ValueType _type;
- std::vector<T> _cells;
-public:
- DenseTensorValueBuilder(const eval::ValueType &type, size_t subspace_size_in);
- ~DenseTensorValueBuilder() override;
- ArrayRef<T>
- add_subspace(ConstArrayRef<vespalib::stringref>) override {
- return _cells;
- }
- std::unique_ptr<eval::Value>
- build(std::unique_ptr<eval::ValueBuilder<T>>) override {
- return std::make_unique<DenseTensor<T>>(std::move(_type), std::move(_cells));
- }
-};
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp
deleted file mode 100644
index 757072e74c4..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp
+++ /dev/null
@@ -1,324 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_tensor_view.h"
-#include "dense_generic_join.hpp"
-#include "dense_tensor_reduce.hpp"
-#include "dense_tensor_modify.h"
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/vespalib/stllike/asciistream.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/tensor_address_builder.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include <vespa/eval/eval/operation.h>
-#include <sstream>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.dense.dense_tensor_view");
-
-using vespalib::eval::TensorSpec;
-
-namespace vespalib::tensor {
-
-namespace {
-
-string
-dimensionsAsString(const eval::ValueType &type)
-{
- std::ostringstream oss;
- bool first = true;
- oss << "[";
- for (const auto &dim : type.dimensions()) {
- if (!first) {
- oss << ",";
- }
- first = false;
- oss << dim.name << ":" << dim.size;
- }
- oss << "]";
- return oss.str();
-}
-
-void
-checkCellsSize(const eval::ValueType &type, TypedCells cells)
-{
- auto cellsSize = type.dense_subspace_size();
- if (cells.size != cellsSize) {
- throw IllegalStateException(make_string("wrong cell size, "
- "expected=%zu, "
- "actual=%zu",
- cellsSize,
- cells.size));
- }
-}
-
-void
-checkDimensions(const eval::ValueType &lhs, const eval::ValueType &rhs,
- vespalib::stringref operation)
-{
- if (lhs.dimensions() != rhs.dimensions()) {
- throw IllegalStateException(make_string("mismatching dimensions for "
- "dense tensor %s, "
- "lhs dimensions = '%s', "
- "rhs dimensions = '%s'",
- operation.data(),
- dimensionsAsString(lhs).c_str(),
- dimensionsAsString(rhs).c_str()));
- }
-}
-
-/*
- * Join the cells of two tensors.
- *
- * The given function is used to calculate the resulting cell value
- * for overlapping cells.
- */
-template <typename LCT, typename RCT, typename Function>
-static Tensor::UP
-sameShapeJoin(const ConstArrayRef<LCT> &lhs, const ConstArrayRef<RCT> &rhs,
- const std::vector<eval::ValueType::Dimension> &lhs_dims,
- Function &&func)
-{
- size_t sz = lhs.size();
- assert(sz == rhs.size());
- using OCT = typename eval::UnifyCellTypes<LCT,RCT>::type;
- std::vector<OCT> newCells;
- newCells.reserve(sz);
- auto rhsCellItr = rhs.cbegin();
- for (const auto &lhsCell : lhs) {
- OCT v = func(lhsCell, *rhsCellItr);
- newCells.push_back(v);
- ++rhsCellItr;
- }
- assert(rhsCellItr == rhs.cend());
- assert(newCells.size() == sz);
- auto newType = eval::ValueType::tensor_type(lhs_dims, eval::get_cell_type<OCT>());
- return std::make_unique<DenseTensor<OCT>>(std::move(newType), std::move(newCells));
-}
-
-struct CallJoin
-{
- template <typename LCT, typename RCT, typename Function>
- static Tensor::UP
- call(const ConstArrayRef<LCT> &lhs, const ConstArrayRef<RCT> &rhs,
- const std::vector<eval::ValueType::Dimension> &lhs_dims,
- Function &&func)
- {
- return sameShapeJoin(lhs, rhs, lhs_dims, std::move(func));
- }
-};
-
-template <typename Function>
-Tensor::UP
-joinDenseTensors(const DenseTensorView &lhs, const Tensor &rhs,
- vespalib::stringref operation,
- Function &&func)
-{
- const auto & lhs_type = lhs.fast_type();
- const auto & rhs_type = rhs.type();
- TypedCells lhs_cells = lhs.cells();
- TypedCells rhs_cells = rhs.cells();
- checkDimensions(lhs_type, rhs_type, operation);
- checkCellsSize(lhs_type, lhs_cells);
- checkCellsSize(rhs_type, rhs_cells);
- return dispatch_2<CallJoin>(lhs_cells, rhs_cells, lhs_type.dimensions(), std::move(func));
-}
-
-bool sameCells(TypedCells lhs, TypedCells rhs)
-{
- if (lhs.size != rhs.size) {
- return false;
- }
- for (size_t i = 0; i < lhs.size; ++i) {
- if (GetCell::from(lhs, i) != GetCell::from(rhs, i)) {
- return false;
- }
- }
- return true;
-}
-
-}
-
-bool
-DenseTensorView::operator==(const DenseTensorView &rhs) const
-{
- return (_typeRef == rhs._typeRef) && sameCells(_cellsRef, rhs._cellsRef);
-}
-
-const eval::ValueType &
-DenseTensorView::type() const
-{
- return _typeRef;
-}
-
-struct CallSum {
- template <typename CT>
- static double
- call(const ConstArrayRef<CT> &arr) {
- double res = 0.0;
- for (CT val : arr) {
- res += val;
- }
- return res;
- }
-};
-
-double
-DenseTensorView::as_double() const
-{
- return dispatch_1<CallSum>(_cellsRef);
-}
-
-struct CallApply {
- template <typename CT>
- static Tensor::UP
- call(const ConstArrayRef<CT> &oldCells, const eval::ValueType &newType, const CellFunction &func)
- {
- std::vector<CT> newCells;
- newCells.reserve(oldCells.size());
- for (const auto &cell : oldCells) {
- CT nv = func.apply(cell);
- newCells.push_back(nv);
- }
- return std::make_unique<DenseTensor<CT>>(newType, std::move(newCells));
- }
-};
-
-Tensor::UP
-DenseTensorView::apply(const CellFunction &func) const
-{
- return dispatch_1<CallApply>(_cellsRef, _typeRef, func);
-}
-
-namespace {
-
-void
-buildAddress(const DenseTensorCellsIterator &itr, TensorSpec::Address &address)
-{
- auto addressItr = itr.address().begin();
- for (const auto &dim : itr.fast_type().dimensions()) {
- address.emplace(std::make_pair(dim.name, TensorSpec::Label(*addressItr++)));
- }
- assert(addressItr == itr.address().end());
-}
-
-}
-
-TensorSpec
-DenseTensorView::toSpec() const
-{
- TensorSpec result(type().to_spec());
- TensorSpec::Address address;
- for (CellsIterator itr(_typeRef, _cellsRef); itr.valid(); itr.next()) {
- buildAddress(itr, address);
- result.add(address, itr.cell());
- address.clear();
- }
- return result;
-}
-
-void
-DenseTensorView::accept(TensorVisitor &visitor) const
-{
- CellsIterator iterator(_typeRef, _cellsRef);
- TensorAddressBuilder addressBuilder;
- TensorAddress address;
- vespalib::string label;
- while (iterator.valid()) {
- addressBuilder.clear();
- auto rawIndex = iterator.address().begin();
- for (const auto &dimension : _typeRef.dimensions()) {
- label = vespalib::make_string("%u", *rawIndex);
- addressBuilder.add(dimension.name, label);
- ++rawIndex;
- }
- address = addressBuilder.build();
- visitor.visit(address, iterator.cell());
- iterator.next();
- }
-}
-
-Tensor::UP
-DenseTensorView::join(join_fun_t function, const Tensor &arg) const
-{
- if (fast_type().dimensions() == arg.type().dimensions()) {
- if (function == eval::operation::Mul::f) {
- return joinDenseTensors(*this, arg, "mul",
- [](double a, double b) { return (a * b); });
- }
- if (function == eval::operation::Add::f) {
- return joinDenseTensors(*this, arg, "add",
- [](double a, double b) { return (a + b); });
- }
- return joinDenseTensors(*this, arg, "join", function);
- }
- if (function == eval::operation::Mul::f) {
- return dense::generic_join(*this, arg, [](auto a, auto b) { return (a * b); });
- }
- if (function == eval::operation::Add::f) {
- return dense::generic_join(*this, arg, [](double a, double b) { return (a + b); });
- }
- return dense::generic_join(*this, arg, function);
-}
-
-Tensor::UP
-DenseTensorView::merge(join_fun_t function, const Tensor &arg) const
-{
- assert(fast_type().dimensions() == arg.type().dimensions());
- return join(function, arg);
-}
-
-Tensor::UP
-DenseTensorView::reduce_all(join_fun_t op, const std::vector<vespalib::string> &dims) const
-{
- if (op == eval::operation::Mul::f) {
- return dense::reduce(*this, dims, [](double a, double b) { return (a * b);});
- }
- if (op == eval::operation::Add::f) {
- return dense::reduce(*this, dims, [](auto a, auto b) { return (a + b);});
- }
- return dense::reduce(*this, dims, op);
-}
-
-Tensor::UP
-DenseTensorView::reduce(join_fun_t op, const std::vector<vespalib::string> &dimensions) const
-{
- return dimensions.empty()
- ? reduce_all(op, _typeRef.dimension_names())
- : reduce_all(op, dimensions);
-}
-
-struct CallModify
-{
- using join_fun_t = vespalib::eval::operation::op2_t;
-
- template <typename CT>
- static std::unique_ptr<Tensor>
- call(const ConstArrayRef<CT> &arr, join_fun_t op, const eval::ValueType &typeRef, const CellValues &cellValues)
- {
- std::vector newCells(arr.begin(), arr.end());
- DenseTensorModify<CT> modifier(op, typeRef, std::move(newCells));
- cellValues.accept(modifier);
- return modifier.build();
- }
-};
-
-std::unique_ptr<Tensor>
-DenseTensorView::modify(join_fun_t op, const CellValues &cellValues) const
-{
- return dispatch_1<CallModify>(_cellsRef, op, _typeRef, cellValues);
-}
-
-std::unique_ptr<Tensor>
-DenseTensorView::add(const Tensor &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-std::unique_ptr<Tensor>
-DenseTensorView::remove(const CellValues &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h
deleted file mode 100644
index 3ebd62208c3..00000000000
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "typed_cells_dispatch.h"
-#include "dense_tensor_cells_iterator.h"
-#include <vespa/eval/tensor/tensor.h>
-
-namespace vespalib::tensor {
-
-/**
- * A view to a dense tensor where all dimensions are indexed.
- * Tensor cells are stored in an underlying array according to the order of the dimensions.
- */
-class DenseTensorView : public Tensor
-{
-public:
- using CellsIterator = DenseTensorCellsIterator;
- using Address = std::vector<eval::ValueType::Dimension::size_type>;
-
- DenseTensorView(const DenseTensorView &rhs) : DenseTensorView(rhs._typeRef, rhs._cellsRef) {}
- DenseTensorView(const eval::ValueType &type_in, TypedCells cells_in)
- : _typeRef(type_in),
- _cellsRef(cells_in)
- {
- assert(_typeRef.cell_type() == cells_in.type);
- }
-
- const eval::ValueType &fast_type() const { return _typeRef; }
- TypedCells cells() const final override { return _cellsRef; }
- const Index &index() const override { return eval::TrivialIndex::get(); }
- bool operator==(const DenseTensorView &rhs) const;
- CellsIterator cellsIterator() const { return CellsIterator(_typeRef, _cellsRef); }
-
- const eval::ValueType &type() const override;
- double as_double() const override;
- Tensor::UP apply(const CellFunction &func) const override;
- Tensor::UP join(join_fun_t function, const Tensor &arg) const override;
- Tensor::UP merge(join_fun_t function, const Tensor &arg) const override;
- Tensor::UP reduce(join_fun_t op, const std::vector<vespalib::string> &dimensions) const override;
- std::unique_ptr<Tensor> modify(join_fun_t op, const CellValues &cellValues) const override;
- std::unique_ptr<Tensor> add(const Tensor &arg) const override;
- std::unique_ptr<Tensor> remove(const CellValues &) const override;
- eval::TensorSpec toSpec() const override;
- void accept(TensorVisitor &visitor) const override;
- MemoryUsage get_memory_usage() const override {
- size_t sz = sizeof(DenseTensorView);
- return MemoryUsage(sz, sz, 0, 0);
- }
-
-protected:
- explicit DenseTensorView(const eval::ValueType &type_in)
- : _typeRef(type_in),
- _cellsRef()
- {}
-
- void initCellsRef(TypedCells cells_in) {
- assert(_typeRef.cell_type() == cells_in.type);
- _cellsRef = cells_in;
- }
-private:
- Tensor::UP reduce_all(join_fun_t op, const std::vector<vespalib::string> &dimensions) const;
-
- const eval::ValueType &_typeRef;
- TypedCells _cellsRef;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp
deleted file mode 100644
index ae3e8ad9023..00000000000
--- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "mutable_dense_tensor_view.h"
-
-using vespalib::eval::ValueType;
-
-namespace vespalib::tensor {
-
-MutableDenseTensorView::MutableDenseTensorView(ValueType type_in)
- : DenseTensorView(_type),
- _type(type_in)
-{
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h
deleted file mode 100644
index 5e4a48462d7..00000000000
--- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_tensor_view.h"
-#include <cassert>
-
-namespace vespalib::tensor {
-
-/**
- * A mutable view to a dense tensor where all dimensions are indexed.
- */
-class MutableDenseTensorView : public DenseTensorView
-{
-private:
- eval::ValueType _type;
-
-public:
- MutableDenseTensorView(eval::ValueType type_in);
- MutableDenseTensorView(MutableDenseTensorView &&) = default;
- void setCells(TypedCells cells_in) {
- initCellsRef(cells_in);
- }
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.cpp b/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.cpp
deleted file mode 100644
index 874a530e767..00000000000
--- a/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "typed_cells_dispatch.h"
diff --git a/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.h b/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.h
deleted file mode 100644
index 7a35966cef8..00000000000
--- a/eval/src/vespa/eval/tensor/dense/typed_cells_dispatch.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/typed_cells.h>
-
-namespace vespalib::tensor {
-
-using vespalib::eval::CellType;
-using TypedCells = vespalib::eval::TypedCells;
-
-template <typename TGT, typename... Args>
-decltype(auto) dispatch_1(const TypedCells &a, Args &&...args) {
- switch (a.type) {
- case CellType::DOUBLE: return TGT::call(a.unsafe_typify<double>(), std::forward<Args>(args)...);
- case CellType::FLOAT: return TGT::call(a.unsafe_typify<float>(), std::forward<Args>(args)...);
- }
- abort();
-}
-
-template <typename TGT, typename A1, typename... Args>
-decltype(auto) dispatch_2(A1 &&a, const TypedCells &b, Args &&...args) {
- switch (b.type) {
- case CellType::DOUBLE: return dispatch_1<TGT>(std::forward<A1>(a), b.unsafe_typify<double>(), std::forward<Args>(args)...);
- case CellType::FLOAT: return dispatch_1<TGT>(std::forward<A1>(a), b.unsafe_typify<float>(), std::forward<Args>(args)...);
- }
- abort();
-}
-
-struct GetCell {
- template<typename T>
- static double call(ConstArrayRef<T> arr, size_t idx) {
- return arr[idx];
- }
- static double from(TypedCells src, size_t idx) {
- return dispatch_1<GetCell>(src, idx);
- }
-};
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp
deleted file mode 100644
index 385da6d1fcd..00000000000
--- a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-
-#include "typed_dense_tensor_builder.h"
-
-namespace vespalib::tensor {
-
-using Address = DenseTensorView::Address;
-using eval::ValueType;
-
-namespace {
-
-size_t
-calculateCellsSize(const ValueType &type)
-{
- size_t cellsSize = 1;
- for (const auto &dim : type.dimensions()) {
- cellsSize *= dim.size;
- }
- return cellsSize;
-}
-
-} // namespace
-
-template <typename CT>
-TypedDenseTensorBuilder<CT>::~TypedDenseTensorBuilder() = default;
-
-template <typename CT>
-TypedDenseTensorBuilder<CT>::TypedDenseTensorBuilder(const ValueType &type_in)
- : _type(type_in),
- _cells(calculateCellsSize(_type))
-{
- assert(vespalib::eval::check_cell_type<CT>(_type.cell_type()));
-}
-
-template <typename CT>
-Tensor::UP
-TypedDenseTensorBuilder<CT>::build()
-{
- return std::make_unique<DenseTensor<CT>>(std::move(_type), std::move(_cells));
-}
-
-template class TypedDenseTensorBuilder<double>;
-template class TypedDenseTensorBuilder<float>;
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h
deleted file mode 100644
index 770ea4ae5ea..00000000000
--- a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "dense_tensor.h"
-
-namespace vespalib::tensor {
-
-/**
- * Class for building a dense tensor by inserting cell values directly into underlying array of cells.
- */
-template <typename CT>
-class TypedDenseTensorBuilder
-{
-public:
- using Address = DenseTensorView::Address;
-private:
- eval::ValueType _type;
- std::vector<CT> _cells;
-
- static size_t calculateCellAddress(const Address &address, const eval::ValueType &type) {
- size_t result = 0;
- for (size_t i = 0; i < address.size(); ++i) {
- result *= type.dimensions()[i].size;
- result += address[i];
- }
- return result;
- }
-public:
- TypedDenseTensorBuilder(const eval::ValueType &type_in);
- ~TypedDenseTensorBuilder();
- void insertCell(const Address &address, CT cellValue) {
- insertCell(calculateCellAddress(address, _type), cellValue);
- }
- void insertCell(size_t index, CT cellValue) {
- _cells[index] = cellValue;
- }
- Tensor::UP build();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/join_tensors.h b/eval/src/vespa/eval/tensor/join_tensors.h
deleted file mode 100644
index d66d0c1bf8e..00000000000
--- a/eval/src/vespa/eval/tensor/join_tensors.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor.h"
-#include "direct_tensor_builder.h"
-
-namespace vespalib::tensor {
-
-/*
- * Join the cells of two tensors.
- * The given function is used to calculate the resulting cell value for overlapping cells.
- */
-template <typename TensorImplType, typename Function>
-Tensor::UP
-joinTensors(const TensorImplType &lhs,
- const TensorImplType &rhs,
- Function &&func)
-{
- DirectSparseTensorBuilder
- builder(lhs.combineDimensionsWith(rhs), lhs.my_cells());
- for (const auto &rhsCell : rhs.my_cells()) {
- builder.insertCell(rhsCell.first, rhsCell.second, func);
- }
- return builder.build();
-}
-
-/*
- * Join the cells of two tensors, where the rhs values are treated as negated values.
- * The given function is used to calculate the resulting cell value for overlapping cells.
- */
-template <typename TensorImplType, typename Function>
-Tensor::UP
-joinTensorsNegated(const TensorImplType &lhs,
- const TensorImplType &rhs,
- Function &&func)
-{
- DirectSparseTensorBuilder
- builder(lhs.combineDimensionsWith(rhs), lhs.my_cells());
- for (const auto &rhsCell : rhs.my_cells()) {
- builder.insertCell(rhsCell.first, -rhsCell.second, func);
- }
- return builder.build();
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/serialization/CMakeLists.txt b/eval/src/vespa/eval/tensor/serialization/CMakeLists.txt
deleted file mode 100644
index fc9ac64ea68..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_library(eval_tensor_serialization OBJECT
- SOURCES
- sparse_binary_format.cpp
- dense_binary_format.cpp
- typed_binary_format.cpp
-)
diff --git a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp
deleted file mode 100644
index 837b135c0aa..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "dense_binary_format.h"
-#include <vespa/eval/tensor/dense/dense_tensor.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <cassert>
-
-using vespalib::nbostream;
-using vespalib::eval::ValueType;
-using vespalib::eval::CellType;
-
-namespace vespalib::tensor {
-
-using Dimension = eval::ValueType::Dimension;
-
-
-namespace {
-
-size_t encodeDimensions(nbostream &stream, const eval::ValueType & type) {
- stream.putInt1_4Bytes(type.dimensions().size());
- size_t cellsSize = 1;
- for (const auto &dimension : type.dimensions()) {
- stream.writeSmallString(dimension.name);
- stream.putInt1_4Bytes(dimension.size);
- cellsSize *= dimension.size;
- }
- return cellsSize;
-}
-
-template<typename T>
-void encodeCells(nbostream &stream, TypedCells cells) {
- auto arr = cells.typify<T>();
- for (const auto &value : arr) {
- stream << value;
- }
-}
-
-size_t decodeDimensions(nbostream & stream, std::vector<Dimension> & dimensions) {
- vespalib::string dimensionName;
- size_t dimensionsSize = stream.getInt1_4Bytes();
- size_t dimensionSize;
- size_t cellsSize = 1;
- while (dimensions.size() < dimensionsSize) {
- stream.readSmallString(dimensionName);
- dimensionSize = stream.getInt1_4Bytes();
- dimensions.emplace_back(dimensionName, dimensionSize);
- cellsSize *= dimensionSize;
- }
- return cellsSize;
-}
-
-template<typename T, typename V>
-void decodeCells(nbostream &stream, size_t cellsSize, V &cells) {
- T cellValue = 0.0;
- for (size_t i = 0; i < cellsSize; ++i) {
- stream >> cellValue;
- cells.emplace_back(cellValue);
- }
-}
-
-template <typename V>
-void decodeCells(CellType cell_type, nbostream &stream, size_t cellsSize, V &cells) {
- switch (cell_type) {
- case CellType::DOUBLE:
- decodeCells<double>(stream, cellsSize, cells);
- break;
- case CellType::FLOAT:
- decodeCells<float>(stream, cellsSize, cells);
- break;
- }
-}
-
-}
-
-void
-DenseBinaryFormat::serialize(nbostream &stream, const DenseTensorView &tensor)
-{
- size_t cellsSize = encodeDimensions(stream, tensor.fast_type());
- TypedCells cells = tensor.cells();
- assert(cells.size == cellsSize);
- switch (tensor.fast_type().cell_type()) {
- case CellType::DOUBLE:
- encodeCells<double>(stream, cells);
- break;
- case CellType::FLOAT:
- encodeCells<float>(stream, cells);
- break;
- }
-}
-
-struct CallDecodeCells {
- template <typename CT>
- static std::unique_ptr<DenseTensorView>
- invoke(nbostream &stream, size_t numCells, ValueType &&newType) {
- std::vector<CT> newCells;
- newCells.reserve(numCells);
- decodeCells<CT>(stream, numCells, newCells);
- return std::make_unique<DenseTensor<CT>>(std::move(newType), std::move(newCells));
- }
-};
-
-std::unique_ptr<DenseTensorView>
-DenseBinaryFormat::deserialize(nbostream &stream, CellType cell_type)
-{
- std::vector<Dimension> dimensions;
- size_t numCells = decodeDimensions(stream, dimensions);
- ValueType newType = ValueType::tensor_type(std::move(dimensions), cell_type);
- using MyTypify = eval::TypifyCellType;
- return typify_invoke<1,MyTypify,CallDecodeCells>(cell_type, stream, numCells, std::move(newType));
-}
-
-template <typename T>
-void
-DenseBinaryFormat::deserializeCellsOnly(nbostream &stream, std::vector<T> &cells, CellType cell_type)
-{
- std::vector<Dimension> dimensions;
- size_t cellsSize = decodeDimensions(stream, dimensions);
- cells.clear();
- cells.reserve(cellsSize);
- decodeCells(cell_type, stream, cellsSize, cells);
-}
-
-template void DenseBinaryFormat::deserializeCellsOnly(nbostream &stream, std::vector<double> &cells, CellType cell_type);
-template void DenseBinaryFormat::deserializeCellsOnly(nbostream &stream, std::vector<float> &cells, CellType cell_type);
-
-}
diff --git a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h
deleted file mode 100644
index f0516e9fcc9..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <memory>
-#include <vector>
-#include <vespa/eval/eval/value_type.h>
-
-namespace vespalib { class nbostream; }
-
-namespace vespalib::tensor {
-
-class DenseTensorView;
-
-/**
- * Class for serializing a dense tensor.
- */
-class DenseBinaryFormat
-{
-public:
- using CellType = vespalib::eval::CellType;
-
- static void serialize(nbostream &stream, const DenseTensorView &tensor);
- static std::unique_ptr<DenseTensorView> deserialize(nbostream &stream, CellType cell_type);
-
- // This is a temporary method untill we get full support for typed tensors
- template <typename T>
- static void deserializeCellsOnly(nbostream &stream, std::vector<T> &cells, CellType cell_type);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.cpp b/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.cpp
deleted file mode 100644
index a4022c4f60a..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_binary_format.h"
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/tensor/types.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h>
-#include <vespa/eval/tensor/sparse/sparse_tensor_address_builder.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include <vespa/vespalib/objects/nbostream.h>
-#include <sstream>
-#include <cassert>
-
-using vespalib::nbostream;
-using vespalib::eval::CellType;
-using vespalib::eval::ValueType;
-
-namespace vespalib::tensor {
-
-namespace {
-
-vespalib::string undefinedLabel("");
-
-void writeTensorAddress(nbostream &output,
- const eval::ValueType &type,
- const TensorAddress &value)
-{
- auto elemItr = value.elements().cbegin();
- auto elemItrEnd = value.elements().cend();
- for (const auto &dimension : type.dimensions()) {
- if (elemItr != elemItrEnd && dimension.name == elemItr->dimension()) {
- output.writeSmallString(elemItr->label());
- ++elemItr;
- } else {
- output.writeSmallString(undefinedLabel);
- }
- }
- assert(elemItr == elemItrEnd);
-}
-
-template <typename T>
-class SparseBinaryFormatSerializer : public TensorVisitor
-{
-private:
- uint32_t _num_cells;
- nbostream &_cells;
- const ValueType &_type;
-public:
- SparseBinaryFormatSerializer(nbostream &cells, const ValueType &type);
- size_t num_cells() const { return _num_cells; }
- virtual ~SparseBinaryFormatSerializer() override;
- virtual void visit(const TensorAddress &address, double value) override;
-};
-
-template <typename T>
-SparseBinaryFormatSerializer<T>::SparseBinaryFormatSerializer(nbostream &cells, const ValueType &type)
- : _num_cells(0),
- _cells(cells),
- _type(type)
-{
-}
-
-template <typename T>
-SparseBinaryFormatSerializer<T>::~SparseBinaryFormatSerializer() = default;
-
-template <typename T>
-void
-SparseBinaryFormatSerializer<T>::visit(const TensorAddress &address, double value)
-{
- ++_num_cells;
- writeTensorAddress(_cells, _type, address);
- _cells << static_cast<T>(value);
-}
-
-void encodeDimensions(nbostream &stream, const eval::ValueType &type) {
- stream.putInt1_4Bytes(type.dimensions().size());
- for (const auto &dimension : type.dimensions()) {
- stream.writeSmallString(dimension.name);
- }
-}
-
-template <typename T>
-size_t encodeCells(nbostream &stream, const Tensor &tensor) {
- SparseBinaryFormatSerializer<T> serializer(stream, tensor.type());
- tensor.accept(serializer);
- return serializer.num_cells();
-}
-
-size_t encodeCells(nbostream &stream, const Tensor &tensor, CellType cell_type) {
- switch (cell_type) {
- case CellType::DOUBLE:
- return encodeCells<double>(stream, tensor);
- break;
- case CellType::FLOAT:
- return encodeCells<float>(stream, tensor);
- break;
- }
- return 0;
-}
-
-template<typename T>
-void decodeCells(nbostream &stream, size_t dimensionsSize, size_t cellsSize, DirectSparseTensorBuilder<T> &builder) {
- T cellValue = 0.0;
- vespalib::string str;
- SparseTensorAddressBuilder address;
- for (size_t cellIdx = 0; cellIdx < cellsSize; ++cellIdx) {
- address.clear();
- for (size_t dimension = 0; dimension < dimensionsSize; ++dimension) {
- stream.readSmallString(str);
- if (!str.empty()) {
- address.add(str);
- } else {
- address.addUndefined();
- }
- }
- stream >> cellValue;
- builder.insertCell(address, cellValue, [](double, double v){ return v; });
- }
-}
-
-}
-
-void
-SparseBinaryFormat::serialize(nbostream &stream, const Tensor &tensor)
-{
- const auto &type = tensor.type();
- encodeDimensions(stream, type);
- nbostream cells;
- size_t numCells = encodeCells(cells, tensor, type.cell_type());
- stream.putInt1_4Bytes(numCells);
- stream.write(cells.peek(), cells.size());
-}
-
-struct BuildSparseCells {
- template<typename CT>
- static Tensor::UP invoke(ValueType type, nbostream &stream,
- size_t dimensionsSize,
- size_t cellsSize)
- {
- DirectSparseTensorBuilder<CT> builder(std::move(type));
- builder.reserve(cellsSize);
- decodeCells<CT>(stream, dimensionsSize, cellsSize, builder);
- auto retval = builder.build();
- if (retval->should_shrink()) {
- return retval->shrink();
- } else {
- return retval;
- }
- }
-};
-
-std::unique_ptr<Tensor>
-SparseBinaryFormat::deserialize(nbostream &stream, CellType cell_type)
-{
- vespalib::string str;
- size_t dimensionsSize = stream.getInt1_4Bytes();
- std::vector<ValueType::Dimension> dimensions;
- while (dimensions.size() < dimensionsSize) {
- stream.readSmallString(str);
- dimensions.emplace_back(str);
- }
- size_t cellsSize = stream.getInt1_4Bytes();
- ValueType type = ValueType::tensor_type(std::move(dimensions), cell_type);
- return typify_invoke<1,eval::TypifyCellType,BuildSparseCells>(cell_type,
- std::move(type), stream, dimensionsSize, cellsSize);
-}
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h b/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h
deleted file mode 100644
index d4c7fa4bf6f..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <memory>
-#include <vespa/eval/eval/value_type.h>
-
-namespace vespalib { class nbostream; }
-
-namespace vespalib::tensor {
-
-class Tensor;
-
-/**
- * Class for serializing a sparse tensor.
- */
-class SparseBinaryFormat
-{
-public:
- using CellType = eval::CellType;
-
- static void serialize(nbostream &stream, const Tensor &tensor);
- static std::unique_ptr<Tensor> deserialize(nbostream &stream, CellType cell_type);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.cpp b/eval/src/vespa/eval/tensor/serialization/typed_binary_format.cpp
deleted file mode 100644
index 2d3d1f4a0ea..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "typed_binary_format.h"
-#include "sparse_binary_format.h"
-#include "dense_binary_format.h"
-#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
-#include <vespa/eval/eval/simple_value.h>
-#include <vespa/eval/tensor/wrapped_simple_value.h>
-#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-
-#include <vespa/log/log.h>
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/util/exceptions.h>
-
-LOG_SETUP(".eval.tensor.serialization.typed_binary_format");
-
-using vespalib::nbostream;
-using vespalib::eval::ValueType;
-using vespalib::eval::CellType;
-
-namespace vespalib::tensor {
-
-namespace {
-
-const eval::EngineOrFactory &simple_engine() {
- static eval::EngineOrFactory engine(eval::SimpleValueBuilderFactory::get());
- return engine;
-}
-
-constexpr uint32_t SPARSE_BINARY_FORMAT_TYPE = 1u;
-constexpr uint32_t DENSE_BINARY_FORMAT_TYPE = 2u;
-constexpr uint32_t MIXED_BINARY_FORMAT_TYPE = 3u;
-constexpr uint32_t SPARSE_BINARY_FORMAT_WITH_CELLTYPE = 5u;
-constexpr uint32_t DENSE_BINARY_FORMAT_WITH_CELLTYPE = 6u;
-constexpr uint32_t MIXED_BINARY_FORMAT_WITH_CELLTYPE = 7u;
-
-constexpr uint32_t DOUBLE_VALUE_TYPE = 0;
-constexpr uint32_t FLOAT_VALUE_TYPE = 1;
-
-uint32_t cell_type_to_encoding(CellType cell_type) {
- switch (cell_type) {
- case CellType::DOUBLE:
- return DOUBLE_VALUE_TYPE;
- case CellType::FLOAT:
- return FLOAT_VALUE_TYPE;
- }
- abort();
-}
-
-CellType
-encoding_to_cell_type(uint32_t cell_encoding) {
- switch (cell_encoding) {
- case DOUBLE_VALUE_TYPE:
- return CellType::DOUBLE;
- case FLOAT_VALUE_TYPE:
- return CellType::FLOAT;
- default:
- throw IllegalArgumentException(make_string("Received unknown tensor value type = %u. Only 0(double), or 1(float) are legal.", cell_encoding));
- }
-}
-
-std::unique_ptr<Tensor>
-wrap_simple_value(std::unique_ptr<eval::Value> simple)
-{
- if (Tensor::supported({simple->type()})) {
- nbostream data;
- simple_engine().encode(*simple, data);
- // note: some danger of infinite recursion here
- return TypedBinaryFormat::deserialize(data);
- }
- return std::make_unique<WrappedSimpleValue>(std::move(simple));
-}
-
-} // namespace <unnamed>
-
-void
-TypedBinaryFormat::serialize(nbostream &stream, const Tensor &tensor)
-{
- auto cell_type = tensor.type().cell_type();
- bool default_cell_type = (cell_type == CellType::DOUBLE);
- if (auto denseTensor = dynamic_cast<const DenseTensorView *>(&tensor)) {
- if (default_cell_type) {
- stream.putInt1_4Bytes(DENSE_BINARY_FORMAT_TYPE);
- } else {
- stream.putInt1_4Bytes(DENSE_BINARY_FORMAT_WITH_CELLTYPE);
- stream.putInt1_4Bytes(cell_type_to_encoding(cell_type));
- }
- DenseBinaryFormat::serialize(stream, *denseTensor);
- } else if (dynamic_cast<const WrappedSimpleValue *>(&tensor)) {
- eval::encode_value(tensor, stream);
- } else {
- if (default_cell_type) {
- stream.putInt1_4Bytes(SPARSE_BINARY_FORMAT_TYPE);
- } else {
- stream.putInt1_4Bytes(SPARSE_BINARY_FORMAT_WITH_CELLTYPE);
- stream.putInt1_4Bytes(cell_type_to_encoding(cell_type));
- }
- SparseBinaryFormat::serialize(stream, tensor);
- }
-}
-
-
-std::unique_ptr<Tensor>
-TypedBinaryFormat::deserialize(nbostream &stream)
-{
- auto cell_type = CellType::DOUBLE;
- auto read_pos = stream.rp();
- auto formatId = stream.getInt1_4Bytes();
- switch (formatId) {
- case SPARSE_BINARY_FORMAT_WITH_CELLTYPE:
- cell_type = encoding_to_cell_type(stream.getInt1_4Bytes());
- [[fallthrough]];
- case SPARSE_BINARY_FORMAT_TYPE:
- return SparseBinaryFormat::deserialize(stream, cell_type);
- case DENSE_BINARY_FORMAT_WITH_CELLTYPE:
- cell_type = encoding_to_cell_type(stream.getInt1_4Bytes());
- [[fallthrough]];
- case DENSE_BINARY_FORMAT_TYPE:
- return DenseBinaryFormat::deserialize(stream, cell_type);
- case MIXED_BINARY_FORMAT_TYPE:
- case MIXED_BINARY_FORMAT_WITH_CELLTYPE:
- stream.adjustReadPos(read_pos - stream.rp());
- return wrap_simple_value(simple_engine().decode(stream));
- default:
- throw IllegalArgumentException(make_string("Received unknown tensor format type = %du.", formatId));
- }
-}
-
-template <typename T>
-void
-TypedBinaryFormat::deserializeCellsOnlyFromDenseTensors(nbostream &stream, std::vector<T> &cells)
-{
- auto cell_type = CellType::DOUBLE;
- auto formatId = stream.getInt1_4Bytes();
- switch (formatId) {
- case DENSE_BINARY_FORMAT_WITH_CELLTYPE:
- cell_type = encoding_to_cell_type(stream.getInt1_4Bytes());
- [[fallthrough]];
- case DENSE_BINARY_FORMAT_TYPE:
- return DenseBinaryFormat::deserializeCellsOnly(stream, cells, cell_type);
- }
- abort();
-}
-
-template void TypedBinaryFormat::deserializeCellsOnlyFromDenseTensors(nbostream &stream, std::vector<double> &cells);
-template void TypedBinaryFormat::deserializeCellsOnlyFromDenseTensors(nbostream &stream, std::vector<float> &cells);
-
-}
diff --git a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h b/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h
deleted file mode 100644
index 198b09ae336..00000000000
--- a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <memory>
-#include <vector>
-
-namespace vespalib { class nbostream; }
-
-namespace vespalib::tensor {
-
-class Tensor;
-
-/**
- * Class for serializing a tensor.
- */
-class TypedBinaryFormat
-{
-public:
- static void serialize(nbostream &stream, const Tensor &tensor);
- static std::unique_ptr<Tensor> deserialize(nbostream &stream);
-
- // This is a temporary method until we get full support for typed tensors
- template <typename T>
- static void deserializeCellsOnlyFromDenseTensors(nbostream &stream, std::vector<T> &cells);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt b/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt
deleted file mode 100644
index 45baefe24c3..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_library(eval_tensor_sparse OBJECT
- SOURCES
- direct_sparse_tensor_builder.cpp
- sparse_tensor.cpp
- sparse_tensor_t.cpp
- sparse_tensor_add.cpp
- sparse_tensor_address_builder.cpp
- sparse_tensor_address_combiner.cpp
- sparse_tensor_address_reducer.cpp
- sparse_tensor_address_ref.cpp
- sparse_tensor_index.cpp
- sparse_tensor_match.cpp
- sparse_tensor_modify.cpp
- sparse_tensor_remove.cpp
- sparse_tensor_value_builder.cpp
-)
diff --git a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp
deleted file mode 100644
index d6471f07191..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "direct_sparse_tensor_builder.h"
-#include "sparse_tensor_t.h"
-#include <type_traits>
-
-namespace vespalib::tensor {
-
-template<typename T>
-DirectSparseTensorBuilder<T>::DirectSparseTensorBuilder()
- : _type(eval::ValueType::double_type()),
- _index(0),
- _values()
-{
- assert((std::is_same_v<T,double>));
-}
-
-template<typename T>
-DirectSparseTensorBuilder<T>::DirectSparseTensorBuilder(const eval::ValueType &type_in)
- : _type(type_in),
- _index(_type.count_mapped_dimensions()),
- _values()
-{
-}
-
-template<typename T>
-DirectSparseTensorBuilder<T>::~DirectSparseTensorBuilder() = default;
-
-template<typename T>
-std::unique_ptr<SparseTensorT<T>>
-DirectSparseTensorBuilder<T>::build() {
- using tt = SparseTensorT<T>;
- return std::make_unique<tt>(std::move(_type), std::move(_index), std::move(_values));
-}
-
-template<typename T>
-void
-DirectSparseTensorBuilder<T>::reserve(uint32_t estimatedCells) {
- _index.reserve(estimatedCells);
- _values.reserve(estimatedCells);
-}
-
-template class DirectSparseTensorBuilder<float>;
-template class DirectSparseTensorBuilder<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h b/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h
deleted file mode 100644
index 9570f744ae0..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/util/hdr_abort.h>
-#include "sparse_tensor.h"
-#include "sparse_tensor_t.h"
-#include "sparse_tensor_address_builder.h"
-
-namespace vespalib::tensor {
-
-/**
- * Utility class to build tensors of type SparseTensor, to be used by
- * tensor operations.
- */
-template<typename T>
-class DirectSparseTensorBuilder
-{
-public:
- using AddressBuilderType = SparseTensorAddressBuilder;
- using AddressRefType = SparseTensorAddressRef;
-
-private:
- eval::ValueType _type;
- SparseTensorIndex _index;
- std::vector<T> _values;
-
-public:
- DirectSparseTensorBuilder();
- DirectSparseTensorBuilder(const eval::ValueType &type_in);
- ~DirectSparseTensorBuilder();
-
- std::unique_ptr<SparseTensorT<T>> build();
-
- template <class Function>
- void insertCell(SparseTensorAddressRef address, T value, Function &&func)
- {
- size_t idx;
- if (_index.lookup_address(address, idx)) {
- _values[idx] = func(_values[idx], value);
- } else {
- idx = _index.lookup_or_add(address);
- assert(idx == _values.size());
- _values.push_back(value);
- }
- }
-
- void insertCell(SparseTensorAddressRef address, T value) {
- // This address should not already exist and a new cell should be inserted.
- _index.add_address(address);
- _values.push_back(value);
- }
-
- template <class Function>
- void insertCell(SparseTensorAddressBuilder &address, T value, Function &&func) {
- insertCell(address.getAddressRef(), value, func);
- }
-
- void insertCell(SparseTensorAddressBuilder &address, T value) {
- // This address should not already exist and a new cell should be inserted.
- insertCell(address.getAddressRef(), value);
- }
-
- eval::ValueType &fast_type() { return _type; }
-
- void reserve(uint32_t estimatedCells);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp
deleted file mode 100644
index 5149b5bfb86..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_add.h"
-#include "sparse_tensor_address_builder.h"
-#include "sparse_tensor_join.hpp"
-#include "sparse_tensor_match.h"
-#include "direct_sparse_tensor_builder.h"
-#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/tensor_address_builder.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <vespa/vespalib/stllike/hash_map_equal.hpp>
-#include <vespa/vespalib/util/array_equal.hpp>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.sparse.sparse_tensor");
-
-using vespalib::eval::TensorSpec;
-
-namespace vespalib::tensor {
-
-SparseTensor::SparseTensor(eval::ValueType type_in, SparseTensorIndex index_in)
- : _type(std::move(type_in)),
- _index(std::move(index_in))
-{}
-
-SparseTensor::~SparseTensor() = default;
-
-struct CompareValues {
- template <typename T>
- static bool invoke(const SparseTensor &lhs_in,
- const SparseTensor &rhs_in)
- {
- auto & lhs = static_cast<const SparseTensorT<T> &>(lhs_in);
- auto & rhs = static_cast<const SparseTensorT<T> &>(rhs_in);
- auto lhs_cells = lhs.cells().template typify<T>();
- auto rhs_cells = rhs.cells().template typify<T>();
- size_t rhs_idx;
- for (const auto & kv : lhs.index().get_map()) {
- if (rhs.index().lookup_address(kv.first, rhs_idx)) {
- size_t lhs_idx = kv.second;
- if (lhs_cells[lhs_idx] != rhs_cells[rhs_idx]) {
- return false;
- }
- } else {
- return false;
- }
- }
- return true;
- }
-};
-
-bool
-SparseTensor::operator==(const SparseTensor &rhs) const
-{
- if (fast_type() == rhs.fast_type() && my_size() == rhs.my_size()) {
- return typify_invoke<1,eval::TypifyCellType,CompareValues>(_type.cell_type(), *this, rhs);
- }
- return false;
-}
-
-eval::ValueType
-SparseTensor::combineDimensionsWith(const SparseTensor &rhs) const
-{
- return eval::ValueType::join(_type, rhs._type);
-}
-
-const eval::ValueType &
-SparseTensor::type() const
-{
- return _type;
-}
-
-TensorSpec
-SparseTensor::toSpec() const
-{
- return vespalib::eval::spec_from_value(*this);
-}
-
-
-
-}
-
-VESPALIB_HASH_MAP_INSTANTIATE(vespalib::tensor::SparseTensorAddressRef, double);
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h
deleted file mode 100644
index 5fdd466d15f..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_index.h"
-#include <vespa/eval/tensor/cell_function.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/tensor_address.h>
-#include <vespa/eval/tensor/types.h>
-#include <vespa/vespalib/stllike/string.h>
-
-namespace vespalib::tensor {
-
-/**
- * A tensor implementation using serialized tensor addresses to
- * improve CPU cache and TLB hit ratio, relative to SimpleTensor
- * implementation.
- */
-class SparseTensor : public Tensor
-{
-private:
- eval::ValueType _type;
- SparseTensorIndex _index;
-
-public:
- SparseTensor(eval::ValueType type_in, SparseTensorIndex index_in);
- ~SparseTensor() override;
- size_t my_size() const { return _index.get_map().size(); }
- const SparseTensorIndex &index() const final override { return _index; }
- const eval::ValueType &fast_type() const { return _type; }
- bool operator==(const SparseTensor &rhs) const;
- eval::ValueType combineDimensionsWith(const SparseTensor &rhs) const;
-
- const eval::ValueType &type() const override;
- eval::TensorSpec toSpec() const override;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp
deleted file mode 100644
index bb44826db9c..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_add.h"
-#include "sparse_tensor_t.h"
-
-namespace vespalib::tensor {
-
-template<typename T>
-SparseTensorAdd<T>::SparseTensorAdd(eval::ValueType type, SparseTensorIndex index, std::vector<T> values)
- : _type(std::move(type)),
- _index(std::move(index)),
- _values(std::move(values)),
- _addressBuilder()
-{
-}
-
-template<typename T>
-SparseTensorAdd<T>::~SparseTensorAdd() = default;
-
-template<typename T>
-void
-SparseTensorAdd<T>::visit(const TensorAddress &address, double value)
-{
- _addressBuilder.populate(_type, address);
- auto addressRef = _addressBuilder.getAddressRef();
- size_t idx = _index.lookup_or_add(addressRef);
- if (idx < _values.size()) {
- _values[idx] = value;
- } else {
- assert(idx == _values.size());
- _values.push_back(value);
- }
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorAdd<T>::build()
-{
- using tt = SparseTensorT<T>;
- return std::make_unique<tt>(std::move(_type), std::move(_index), std::move(_values));
-}
-
-template class SparseTensorAdd<float>;
-template class SparseTensorAdd<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h
deleted file mode 100644
index 7baea13440a..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_address_builder.h"
-#include <vespa/eval/tensor/tensor_visitor.h>
-
-namespace vespalib::tensor {
-
-/**
- * This class handles a tensor add operation on a sparse tensor.
- *
- * Creates a new tensor by adding the cells of the argument tensor to this tensor.
- * Existing cell values are overwritten.
- */
-template<typename T>
-class SparseTensorAdd : public TensorVisitor
-{
- eval::ValueType _type;
- SparseTensorIndex _index;
- std::vector<T> _values;
- SparseTensorAddressBuilder _addressBuilder;
-public:
- SparseTensorAdd(eval::ValueType type, SparseTensorIndex index, std::vector<T> values);
- ~SparseTensorAdd();
- void visit(const TensorAddress &address, double value) override;
- std::unique_ptr<Tensor> build();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp
deleted file mode 100644
index 3eb7d64f060..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_address_builder.h"
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/tensor/tensor_address.h>
-#include <vespa/eval/tensor/tensor_address_element_iterator.h>
-
-namespace vespalib::tensor {
-
-SparseTensorAddressBuilder::SparseTensorAddressBuilder()
- : _address()
-{
-}
-
-void
-SparseTensorAddressBuilder::populate(const eval::ValueType &type, const TensorAddress &address)
-{
- clear();
- TensorAddressElementIterator itr(address);
- for (const auto &dimension : type.dimensions()) {
- if (itr.skipToDimension(dimension.name)) {
- add(itr.label());
- } else {
- addUndefined();
- }
- }
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h
deleted file mode 100644
index 32b9b57fb26..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_address_ref.h"
-#include <vespa/vespalib/stllike/string.h>
-
-namespace vespalib::eval { class ValueType; }
-
-namespace vespalib::tensor {
-
-class TensorAddress;
-
-
-/**
- * A writer to serialize tensor addresses into a compact representation.
- * All dimensions in the tensors are present, empty label is the "undefined"
- * value.
- *
- * Format: (labelStr NUL)*
- */
-class SparseTensorAddressBuilder
-{
-private:
- vespalib::Array<char> _address;
-
-protected:
- void append(vespalib::stringref str) {
- for (size_t i(0); i < str.size(); i++) {
- _address.push_back_fast(str[i]);
- }
- _address.push_back_fast('\0');
- }
- void ensure_room(size_t additional) {
- if (_address.capacity() < (_address.size() + additional)) {
- _address.reserve(_address.size() + additional);
- }
- }
-public:
- SparseTensorAddressBuilder();
- void add(vespalib::stringref label) {
- ensure_room(label.size()+1);
- append(label);
- }
- void addUndefined() { _address.push_back('\0'); }
- void clear() { _address.clear(); }
- void set(std::initializer_list<vespalib::stringref> labels) {
- clear();
- for (const auto &label: labels) {
- add(label);
- }
- }
- SparseTensorAddressRef getAddressRef() const {
- return SparseTensorAddressRef(&_address[0], _address.size());
- }
- bool empty() const { return _address.empty(); }
- void populate(const eval::ValueType &type, const TensorAddress &address);
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.cpp
deleted file mode 100644
index 95b004a9bd2..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_address_combiner.h"
-#include "sparse_tensor_address_decoder.h"
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/vespalib/util/overload.h>
-#include <vespa/vespalib/util/visit_ranges.h>
-
-namespace vespalib::tensor::sparse {
-
-TensorAddressCombiner::TensorAddressCombiner(const eval::ValueType &lhs, const eval::ValueType &rhs)
-{
- auto visitor = overload{
- [this](visit_ranges_first, const auto &) { _ops.push_back(AddressOp::LHS); },
- [this](visit_ranges_second, const auto &) { _ops.push_back(AddressOp::RHS); },
- [this](visit_ranges_both, const auto &, const auto &) { _ops.push_back(AddressOp::BOTH); }
- };
- visit_ranges(visitor,
- lhs.dimensions().cbegin(), lhs.dimensions().cend(),
- rhs.dimensions().cbegin(), rhs.dimensions().cend(),
- [](const auto & li, const auto & ri) { return li.name < ri.name; });
-}
-
-TensorAddressCombiner::~TensorAddressCombiner() = default;
-
-size_t
-TensorAddressCombiner::numOverlappingDimensions() const {
- size_t count = 0;
- for (AddressOp op : _ops) {
- if (op == AddressOp::BOTH) {
- count++;
- }
- }
- return count;
-}
-
-bool
-TensorAddressCombiner::combine(SparseTensorAddressRef lhsRef,
- SparseTensorAddressRef rhsRef)
-{
- clear();
- ensure_room(lhsRef.size() + rhsRef.size());
- SparseTensorAddressDecoder lhs(lhsRef);
- SparseTensorAddressDecoder rhs(rhsRef);
- for (auto op : _ops) {
- switch (op) {
- case AddressOp::LHS:
- append(lhs.decodeLabel());
- break;
- case AddressOp::RHS:
- append(rhs.decodeLabel());
- break;
- case AddressOp::BOTH:
- auto lhsLabel(lhs.decodeLabel());
- auto rhsLabel(rhs.decodeLabel());
- if (lhsLabel != rhsLabel) {
- return false;
- }
- append(lhsLabel);
- }
- }
- return true;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h
deleted file mode 100644
index 1a7f2fd8d3c..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_address_builder.h"
-
-#define VESPA_DLL_LOCAL __attribute__ ((visibility("hidden")))
-
-namespace vespalib::eval { class ValueType; }
-namespace vespalib::tensor::sparse {
-
-/**
- * Combine two tensor addresses to a new tensor address. Common dimensions
- * must have matching labels.
- */
-class TensorAddressCombiner : public SparseTensorAddressBuilder
-{
- enum class AddressOp { LHS, RHS, BOTH };
-
- std::vector<AddressOp> _ops;
-public:
- TensorAddressCombiner(const eval::ValueType &lhs, const eval::ValueType &rhs);
- ~TensorAddressCombiner();
-
- VESPA_DLL_LOCAL bool combine(SparseTensorAddressRef lhsRef, SparseTensorAddressRef rhsRef);
- size_t numOverlappingDimensions() const;
- size_t numDimensions() const { return _ops.size(); }
-};
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_decoder.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_decoder.h
deleted file mode 100644
index 2fbd9932009..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_decoder.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-#include "sparse_tensor_address_ref.h"
-
-namespace vespalib::tensor {
-
-/**
- * A decoder for a serialized tensor address, with only labels present.
- */
-class SparseTensorAddressDecoder
-{
- const char *_cur;
- const char *_end;
-public:
- SparseTensorAddressDecoder(SparseTensorAddressRef ref)
- : _cur(static_cast<const char *>(ref.start())),
- _end(_cur + ref.size())
- {
- }
-
- bool valid() const { return _cur != _end; }
-
- void skipLabel() {
- while (*_cur != '\0') {
- ++_cur;
- }
- ++_cur;
- }
- vespalib::stringref decodeLabel() {
- const char *base = _cur;
- skipLabel();
- return vespalib::stringref(base, _cur - base - 1);
- }
-
-};
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.cpp
deleted file mode 100644
index fbd0034bc14..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_address_reducer.h"
-#include <vespa/eval/eval/value_type.h>
-#include <vespa/vespalib/stllike/hash_set.hpp>
-
-namespace vespalib::tensor::sparse {
-
-TensorAddressReducer::TensorAddressReducer(const eval::ValueType &type,
- const std::vector<vespalib::string> & removeDimensions)
- : SparseTensorAddressBuilder(),
- _ops()
-{
- TensorDimensionsSet removeSet(removeDimensions.cbegin(), removeDimensions.cend());
- _ops.reserve(type.dimensions().size());
- for (const auto &dim : type.dimensions()) {
- if (removeSet.find(dim.name) != removeSet.end()) {
- _ops.push_back(AddressOp::REMOVE);
- } else {
- _ops.push_back(AddressOp::COPY);
- }
- }
-}
-
-TensorAddressReducer::~TensorAddressReducer() = default;
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.h
deleted file mode 100644
index a2034d3be49..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_reducer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_address_builder.h"
-#include <vespa/eval/tensor/types.h>
-#include "sparse_tensor_address_decoder.h"
-#include <cassert>
-
-namespace vespalib::eval { class ValueType; }
-namespace vespalib::tensor::sparse {
-
-/**
- * Reduce sparse tensor address by removing one or more dimensions.
- */
-class TensorAddressReducer : public SparseTensorAddressBuilder
-{
- enum AddressOp { REMOVE, COPY };
-
- using AddressOps = std::vector<AddressOp>;
-
- AddressOps _ops;
-
-public:
- TensorAddressReducer(const eval::ValueType &type,
- const std::vector<vespalib::string> &removeDimensions);
-
- ~TensorAddressReducer();
-
- void reduce(SparseTensorAddressRef ref)
- {
- clear();
- SparseTensorAddressDecoder decoder(ref);
- for (auto op : _ops) {
- switch (op) {
- case AddressOp::REMOVE:
- decoder.skipLabel();
- break;
- case AddressOp::COPY:
- add(decoder.decodeLabel());
- }
- }
- assert(!decoder.valid());
- }
-};
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.cpp
deleted file mode 100644
index e2929269ce6..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_address_ref.h"
-#include <xxhash.h>
-
-namespace vespalib::tensor {
-
-uint32_t
-SparseTensorAddressRef::calcHash() const noexcept {
- return XXH32(_start, _size, 0);
-}
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.h
deleted file mode 100644
index e8838b1acdb..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_ref.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/util/stash.h>
-#include <cstring>
-
-namespace vespalib::tensor {
-
-/**
- * A reference to a compact sparse immutable address to a tensor cell.
- */
-class SparseTensorAddressRef
-{
- const void *_start;
- uint32_t _size;
- uint32_t _hash;
- static void * copy(const SparseTensorAddressRef rhs, Stash &stash) {
- void *res = stash.alloc(rhs._size);
- memcpy(res, rhs._start, rhs._size);
- return res;
- }
-public:
- SparseTensorAddressRef() noexcept
- : _start(nullptr), _size(0u), _hash(0u)
- {
- }
-
- SparseTensorAddressRef(const void *start_in, uint32_t size_in) noexcept
- : _start(start_in), _size(size_in),
- _hash(calcHash())
- {
- }
-
- SparseTensorAddressRef(const SparseTensorAddressRef rhs, Stash &stash)
- : _start(copy(rhs, stash)),
- _size(rhs._size),
- _hash(rhs._hash)
- {}
-
- uint32_t hash() const noexcept { return _hash; }
-
- uint32_t calcHash() const noexcept;
-
- bool operator<(const SparseTensorAddressRef &rhs) const noexcept {
- size_t minSize = std::min(_size, rhs._size);
- int res = memcmp(_start, rhs._start, minSize);
- if (res != 0) {
- return res < 0;
- }
- return _size < rhs._size;
- }
-
- bool operator==(const SparseTensorAddressRef &rhs) const noexcept
- {
- if (_size != rhs._size || _hash != rhs._hash) {
- return false;
- }
- return memcmp(_start, rhs._start, _size) == 0;
- }
-
- const void *start() const { return _start; }
- uint32_t size() const { return _size; }
-};
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.cpp
deleted file mode 100644
index 4d03a9673dd..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_index.h"
-#include "sparse_tensor_address_builder.h"
-#include "sparse_tensor_address_decoder.h"
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <vespa/vespalib/stllike/hash_map_equal.hpp>
-
-namespace vespalib::tensor {
-
-using IndexMap = SparseTensorIndex::IndexMap;
-using View = vespalib::eval::Value::Index::View;
-
-namespace {
-
-void copyMap(IndexMap &map, const IndexMap &map_in, Stash &to_stash) {
- // copy the exact hashtable structure:
- map = map_in;
- // copy the actual contents of the addresses,
- // and update the pointers inside the hashtable
- // keys so they point to our copy:
- for (auto & kv : map) {
- SparseTensorAddressRef oldRef = kv.first;
- SparseTensorAddressRef newRef(oldRef, to_stash);
- kv.first = newRef;
- }
-}
-
-//-----------------------------------------------------------------------------
-
-class SparseTensorValueView : public View
-{
-private:
- const IndexMap &map;
- IndexMap::const_iterator iter;
- const std::vector<size_t> lookup_dims;
- std::vector<vespalib::stringref> lookup_refs;
-public:
- SparseTensorValueView(const IndexMap & map_in,
- const std::vector<size_t> &dims)
- : map(map_in), iter(map.end()), lookup_dims(dims), lookup_refs() {}
- ~SparseTensorValueView();
- void lookup(ConstArrayRef<const vespalib::stringref*> addr) override;
- bool next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out) override;
-};
-
-SparseTensorValueView::~SparseTensorValueView() = default;
-
-void
-SparseTensorValueView::lookup(ConstArrayRef<const vespalib::stringref*> addr)
-{
- lookup_refs.clear();
- for (auto ptr : addr) {
- lookup_refs.push_back(*ptr);
- }
- iter = map.begin();
-
-}
-
-bool
-SparseTensorValueView::next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out)
-{
- size_t total_dims = lookup_refs.size() + addr_out.size();
- while (iter != map.end()) {
- const auto & ref = iter->first;
- SparseTensorAddressDecoder decoder(ref);
- idx_out = iter->second;
- ++iter;
- bool couldmatch = true;
- size_t vd_idx = 0;
- size_t ao_idx = 0;
- for (size_t i = 0; i < total_dims; ++i) {
- const auto label = decoder.decodeLabel();
- if (vd_idx < lookup_dims.size()) {
- size_t next_view_dim = lookup_dims[vd_idx];
- if (i == next_view_dim) {
- if (label == lookup_refs[vd_idx]) {
- // match in this dimension
- ++vd_idx;
- continue;
- } else {
- // does not match
- couldmatch = false;
- break;
- }
- }
- }
- // not a view dimension:
- *addr_out[ao_idx] = label;
- ++ao_idx;
- }
- if (couldmatch) {
- assert(vd_idx == lookup_dims.size());
- assert(ao_idx == addr_out.size());
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-class SparseTensorValueLookup : public View
-{
-private:
- const IndexMap &map;
- IndexMap::const_iterator iter;
-public:
- SparseTensorValueLookup(const IndexMap & map_in) : map(map_in), iter(map.end()) {}
- ~SparseTensorValueLookup();
- void lookup(ConstArrayRef<const vespalib::stringref*> addr) override;
- bool next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out) override;
-};
-
-SparseTensorValueLookup::~SparseTensorValueLookup() = default;
-
-void
-SparseTensorValueLookup::lookup(ConstArrayRef<const vespalib::stringref*> addr)
-{
- SparseTensorAddressBuilder builder;
- for (const auto & label : addr) {
- builder.add(*label);
- }
- auto ref = builder.getAddressRef();
- iter = map.find(ref);
-}
-
-bool
-SparseTensorValueLookup::next_result(ConstArrayRef<vespalib::stringref*>, size_t &idx_out)
-{
- if (iter != map.end()) {
- idx_out = iter->second;
- iter = map.end();
- return true;
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-class SparseTensorValueAllMappings : public View
-{
-private:
- const IndexMap &map;
- IndexMap::const_iterator iter;
-public:
- SparseTensorValueAllMappings(const IndexMap & map_in) : map(map_in), iter(map.end()) {}
- ~SparseTensorValueAllMappings();
- void lookup(ConstArrayRef<const vespalib::stringref*> addr) override;
- bool next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out) override;
-};
-
-SparseTensorValueAllMappings::~SparseTensorValueAllMappings() = default;
-
-void
-SparseTensorValueAllMappings::lookup(ConstArrayRef<const vespalib::stringref*>)
-{
- iter = map.begin();
-}
-
-bool
-SparseTensorValueAllMappings::next_result(ConstArrayRef<vespalib::stringref*> addr_out, size_t &idx_out)
-{
- if (iter != map.end()) {
- const auto & ref = iter->first;
- idx_out = iter->second;
- ++iter;
- SparseTensorAddressDecoder decoder(ref);
- for (const auto ptr : addr_out) {
- const auto label = decoder.decodeLabel();
- *ptr = label;
- }
- return true;
- }
- return false;
-}
-
-} // namespace <unnamed>
-
-//-----------------------------------------------------------------------------
-
-size_t
-SparseTensorIndex::wanted_chunk_size_for(const SparseTensorIndex &other) {
- auto mem = other._stash.get_memory_usage();
- size_t mem_use = mem.usedBytes();
- if (mem_use == 0) {
- return STASH_CHUNK_SIZE;
- }
- if (mem_use < (STASH_CHUNK_SIZE / 4)) {
- size_t avg_per_addr = mem_use / other.size();
- mem_use = std::max(mem_use, (7 * avg_per_addr));
- size_t aligned_size = (mem_use + 63) & ~(sizeof(char *) - 1);
- return aligned_size;
- }
- return STASH_CHUNK_SIZE;
-}
-
-SparseTensorIndex::SparseTensorIndex(size_t num_mapped_in)
- : _stash(STASH_CHUNK_SIZE), _map(), _num_mapped_dims(num_mapped_in)
-{}
-
-SparseTensorIndex::SparseTensorIndex(size_t stash_size, const SparseTensorIndex &index_in)
- : _stash(stash_size), _map(), _num_mapped_dims(index_in._num_mapped_dims)
-{
- copyMap(_map, index_in._map, _stash);
-}
-
-SparseTensorIndex
-SparseTensorIndex::shrunk_copy() const
-{
- size_t want_mem = wanted_chunk_size_for(*this);
- return SparseTensorIndex(want_mem, *this);
-}
-
-SparseTensorIndex
-SparseTensorIndex::copy() const
-{
- size_t want_mem = _stash.get_chunk_size();
- return SparseTensorIndex(want_mem, *this);
-}
-
-void
-SparseTensorIndex::reserve(size_t estimate) {
- _map.resize(2*estimate);
-}
-
-SparseTensorIndex::~SparseTensorIndex() = default;
-
-size_t SparseTensorIndex::size() const {
- return _map.size();
-}
-
-std::unique_ptr<View>
-SparseTensorIndex::create_view(const std::vector<size_t> &dims) const
-{
- if (dims.size() == _num_mapped_dims) {
- return std::make_unique<SparseTensorValueLookup>(_map);
- }
- if (dims.size() == 0) {
- return std::make_unique<SparseTensorValueAllMappings>(_map);
- }
- return std::make_unique<SparseTensorValueView>(_map, dims);
-}
-
-void
-SparseTensorIndex::add_address(SparseTensorAddressRef tmp_ref)
-{
- SparseTensorAddressRef ref(tmp_ref, _stash);
- size_t idx = _map.size();
- auto insert_result = _map.insert({ref, idx});
- assert(insert_result.second);
-}
-
-size_t
-SparseTensorIndex::lookup_or_add(SparseTensorAddressRef tmp_ref)
-{
- auto [map_iter, was_inserted] = _map.insert({tmp_ref, _map.size()});
- if (was_inserted) {
- // we must copy the memory tmp_ref refers to into our own stash:
- SparseTensorAddressRef ref(tmp_ref, _stash);
- // and update the key in the map, just like copyMap() does.
- map_iter->first = ref;
- }
- return map_iter->second;
-}
-
-bool
-SparseTensorIndex::lookup_address(SparseTensorAddressRef ref, size_t &idx) const
-{
- auto iter = _map.find(ref);
- if (iter != _map.end()) {
- idx = iter->second;
- return true;
- }
- idx = size_t(-1);
- return false;
-}
-
-MemoryUsage
-SparseTensorIndex::get_memory_usage() const
-{
- MemoryUsage mem = _stash.get_memory_usage();
- size_t plus = _map.getMemoryConsumption();
- mem.incUsedBytes(plus);
- mem.incAllocatedBytes(plus);
- return mem;
-}
-
-
-//-----------------------------------------------------------------------------
-
-} // namespace
-
-VESPALIB_HASH_MAP_INSTANTIATE(vespalib::tensor::SparseTensorAddressRef, uint32_t);
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.h
deleted file mode 100644
index 089759452b5..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_index.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_address_ref.h"
-#include <vespa/eval/eval/value.h>
-#include <vespa/vespalib/stllike/hash_map.h>
-#include <vespa/vespalib/util/stash.h>
-
-namespace vespalib::tensor {
-
-class SparseTensorIndex : public vespalib::eval::Value::Index
-{
-public:
- static constexpr size_t STASH_CHUNK_SIZE = 16384u;
- //
- using View = vespalib::eval::Value::Index::View;
- using IndexMap = hash_map<SparseTensorAddressRef, uint32_t, hash<SparseTensorAddressRef>,
- std::equal_to<>, hashtable_base::and_modulator>;
- // construct
- explicit SparseTensorIndex(size_t num_mapped_dims_in);
- SparseTensorIndex copy() const;
- SparseTensorIndex shrunk_copy() const;
- SparseTensorIndex(const SparseTensorIndex &) = delete;
- SparseTensorIndex(SparseTensorIndex && index_in) = default;
- ~SparseTensorIndex();
- // Index API
- size_t size() const override;
- std::unique_ptr<View> create_view(const std::vector<size_t> &dims) const override;
- // build API
- void reserve(size_t estimate);
- void add_address(SparseTensorAddressRef tmp_ref);
- size_t lookup_or_add(SparseTensorAddressRef tmp_ref);
- // lookup API
- bool lookup_address(SparseTensorAddressRef ref, size_t &idx) const;
- // traversal API
- const IndexMap &get_map() const { return _map; }
- // stats
- MemoryUsage get_memory_usage() const;
-private:
- Stash _stash;
- IndexMap _map;
- size_t _num_mapped_dims;
- static size_t wanted_chunk_size_for(const SparseTensorIndex &other);
- SparseTensorIndex(size_t stash_size, const SparseTensorIndex &other);
-};
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.h
deleted file mode 100644
index 07695b66ccb..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-namespace vespalib::tensor {
- class Tensor;
- class SparseTensor;
-}
-
-namespace vespalib::tensor::sparse {
-
-/**
- * Create new tensor using all combinations of input tensor cells with matching
- * labels for common dimensions, using func to calculate new cell value
- * based on the cell values in the input tensors.
- */
-template <typename LCT, typename RCT, typename OCT, typename Function>
-std::unique_ptr<Tensor>
-join(const SparseTensor &lhs, const SparseTensor &rhs, eval::ValueType res_type, Function &&func);
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.hpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.hpp
deleted file mode 100644
index ae54e42f5c2..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_join.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_join.h"
-#include "sparse_tensor_t.h"
-#include "sparse_tensor_address_combiner.h"
-#include "direct_sparse_tensor_builder.h"
-
-namespace vespalib::tensor::sparse {
-
-template <typename LCT, typename RCT, typename OCT, typename Function>
-std::unique_ptr<Tensor>
-join(const SparseTensor &lhs_in, const SparseTensor &rhs_in, eval::ValueType res_type, Function &&func)
-{
- auto & lhs = static_cast<const SparseTensorT<LCT> &>(lhs_in);
- auto & rhs = static_cast<const SparseTensorT<RCT> &>(rhs_in);
- DirectSparseTensorBuilder<OCT> builder(std::move(res_type));
- TensorAddressCombiner addressCombiner(lhs.fast_type(), rhs.fast_type());
- if (addressCombiner.numOverlappingDimensions() != 0) {
- size_t estimatedCells = std::min(lhs.my_size(), rhs.my_size());
- builder.reserve(estimatedCells*2);
- } else {
- size_t estimatedCells = (lhs.my_size() * rhs.my_size());
- builder.reserve(estimatedCells);
- }
- for (const auto & lhs_kv : lhs.index().get_map()) {
- for (const auto & rhs_kv : rhs.index().get_map()) {
- bool combineSuccess = addressCombiner.combine(lhs_kv.first, rhs_kv.first);
- if (combineSuccess) {
- auto a = lhs.get_value(lhs_kv.second);
- auto b = rhs.get_value(rhs_kv.second);
- builder.insertCell(addressCombiner.getAddressRef(), func(a, b));
- }
- }
- }
- return builder.build();
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.cpp
deleted file mode 100644
index 74aa557d92b..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_match.h"
-#include "sparse_tensor_address_decoder.h"
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <vespa/vespalib/util/overload.h>
-#include <vespa/vespalib/util/visit_ranges.h>
-#include <assert.h>
-
-namespace vespalib::tensor {
-
-template<typename LCT, typename RCT>
-void
-SparseTensorMatch<LCT,RCT>::fastMatch(const SparseTensorT<LCT> &lhs, const SparseTensorT<RCT> &rhs)
-{
- const auto & lhs_map = lhs.index().get_map();
- const auto & rhs_map = rhs.index().get_map();
- _builder.reserve(lhs_map.size());
- const auto rhs_map_end = rhs_map.end();
- for (const auto & kv : lhs_map) {
- auto rhsItr = rhs_map.find(kv.first);
- if (rhsItr != rhs_map_end) {
- LCT a = lhs.get_value(kv.second);
- RCT b = rhs.get_value(rhsItr->second);
- _builder.insertCell(kv.first, a * b);
- }
- }
-}
-
-template<typename LCT, typename RCT>
-SparseTensorMatch<LCT,RCT>::SparseTensorMatch(const SparseTensorT<LCT> &lhs,
- const SparseTensorT<RCT> &rhs,
- eval::ValueType res_type)
- : _builder(std::move(res_type))
-{
- fastMatch(lhs, rhs);
-}
-
-template class SparseTensorMatch<float,float>;
-template class SparseTensorMatch<float,double>;
-template class SparseTensorMatch<double,float>;
-template class SparseTensorMatch<double,double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.h
deleted file mode 100644
index 21223112329..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_match.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_t.h"
-#include "direct_sparse_tensor_builder.h"
-
-namespace vespalib::tensor {
-
-/**
- * Returns the match product of two tensors.
- * This returns a tensor which contains the matching cells in the two tensors,
- * with their values multiplied.
- *
- * Only used when two tensors have exactly the same dimensions,
- * this is the Hadamard product.
- */
-template<typename LCT, typename RCT>
-class SparseTensorMatch
-{
-public:
- using OCT = typename eval::UnifyCellTypes<LCT,RCT>::type;
- DirectSparseTensorBuilder<OCT> _builder;
-private:
- void fastMatch(const SparseTensorT<LCT> &lhs, const SparseTensorT<RCT> &rhs);
-public:
- SparseTensorMatch(const SparseTensorT<LCT> &lhs, const SparseTensorT<RCT> &rhs, eval::ValueType res_type);
- Tensor::UP result() {
- return _builder.build();
- }
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp
deleted file mode 100644
index f36e1c71c16..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_modify.h"
-#include "sparse_tensor_t.h"
-#include <vespa/eval/tensor/tensor_address_element_iterator.h>
-
-namespace vespalib::tensor {
-
-template<typename T>
-SparseTensorModify<T>::SparseTensorModify(join_fun_t op, const SparseTensorT<T> &input)
- : _op(op),
- _type(input.fast_type()),
- _index(input.index()),
- _values(input.my_values()),
- _addressBuilder()
-{
-}
-
-template<typename T>
-SparseTensorModify<T>::~SparseTensorModify() = default;
-
-template<typename T>
-void
-SparseTensorModify<T>::visit(const TensorAddress &address, double value)
-{
- _addressBuilder.populate(_type, address);
- auto addressRef = _addressBuilder.getAddressRef();
- size_t idx;
- if (_index.lookup_address(addressRef, idx)) {
- _values[idx] = _op(_values[idx], value);
- }
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorModify<T>::build()
-{
- using tt = SparseTensorT<T>;
- return std::make_unique<tt>(std::move(_type), _index.copy(), std::move(_values));
-}
-
-template class SparseTensorModify<float>;
-template class SparseTensorModify<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.h
deleted file mode 100644
index 86f0c0a5c48..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include "sparse_tensor.h"
-#include "sparse_tensor_t.h"
-#include "sparse_tensor_address_builder.h"
-
-namespace vespalib::tensor {
-
-/*
- * This class handles tensor modify update on a sparse tensor.
- * For all cells visited, a join function is applied to determine
- * the new cell value.
- */
-template<typename T>
-class SparseTensorModify : public TensorVisitor
-{
- using join_fun_t = vespalib::eval::operation::op2_t;
- join_fun_t _op;
- eval::ValueType _type;
- const SparseTensorIndex & _index;
- std::vector<T> _values;
- SparseTensorAddressBuilder _addressBuilder;
-
-public:
- SparseTensorModify(join_fun_t op, const SparseTensorT<T> & input);
- ~SparseTensorModify();
- void visit(const TensorAddress &address, double value) override;
- std::unique_ptr<Tensor> build();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_reduce.hpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_reduce.hpp
deleted file mode 100644
index 1ee13a2d8e1..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_reduce.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_address_reducer.h"
-#include "direct_sparse_tensor_builder.h"
-
-namespace vespalib::tensor::sparse {
-
-template <typename T, typename Function>
-std::unique_ptr<Tensor>
-reduceAll(const SparseTensorT<T> &tensor, Function &&func)
-{
- DirectSparseTensorBuilder<double> builder;
- size_t sz = tensor.my_size();
- double result = 0.0;
- if (sz != 0) {
- result = tensor.get_value(0);
- }
- for (size_t i = 1; i < sz; ++i) {
- result = func(result, tensor.get_value(i));
- }
- builder.insertCell(SparseTensorAddressRef(), result);
- return builder.build();
-}
-
-template <typename T, typename Function>
-std::unique_ptr<Tensor>
-reduce(const SparseTensorT<T> &tensor,
- const std::vector<vespalib::string> &dimensions, Function &&func)
-{
- auto tt = tensor.fast_type().reduce(dimensions);
- if (tt.is_double()) {
- return reduceAll(tensor, func);
- }
- DirectSparseTensorBuilder<T> builder(std::move(tt));
- builder.reserve(tensor.my_size());
- TensorAddressReducer addressReducer(tensor.fast_type(), dimensions);
- for (const auto & kv : tensor.index().get_map()) {
- addressReducer.reduce(kv.first);
- auto v = tensor.get_value(kv.second);
- builder.insertCell(addressReducer.getAddressRef(), v, func);
- }
- return builder.build();
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.cpp
deleted file mode 100644
index eae09c0cb83..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_remove.h"
-#include "sparse_tensor_t.h"
-#include <vespa/eval/tensor/tensor_address_element_iterator.h>
-
-namespace vespalib::tensor {
-
-template<typename T>
-SparseTensorRemove<T>::SparseTensorRemove(const SparseTensorT<T> &input)
- : _input(input),
- _map(input.index().get_map()),
- _addressBuilder()
-{
-}
-
-template<typename T>
-SparseTensorRemove<T>::~SparseTensorRemove() = default;
-
-template<typename T>
-void
-SparseTensorRemove<T>::visit(const TensorAddress &address, double)
-{
- _addressBuilder.populate(_input.fast_type(), address);
- auto addressRef = _addressBuilder.getAddressRef();
- _map.erase(addressRef);
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorRemove<T>::build()
-{
- SparseTensorIndex new_index(_input.fast_type().count_mapped_dimensions());
- std::vector<T> new_values;
- new_index.reserve(_map.size());
- new_values.reserve(_map.size());
- for (const auto & kv : _map) {
- size_t idx = new_index.lookup_or_add(kv.first);
- assert(idx == new_values.size());
- double v = _input.get_value(kv.second);
- new_values.push_back(v);
- }
- using tt = SparseTensorT<T>;
- return std::make_unique<tt>(_input.fast_type(), std::move(new_index), std::move(new_values));
-}
-
-template class SparseTensorRemove<float>;
-template class SparseTensorRemove<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.h
deleted file mode 100644
index c52c38a9b0e..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_remove.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_t.h"
-#include "sparse_tensor_address_builder.h"
-#include <vespa/eval/tensor/tensor_visitor.h>
-
-namespace vespalib::tensor {
-
-/**
- * This class handles a tensor remove operation on a sparse tensor.
- *
- * Creates a new tensor by removing the cells matching the cell addresses visited.
- * The value associated with the address is ignored.
- */
-template<typename T>
-class SparseTensorRemove : public TensorVisitor {
-private:
- const SparseTensorT<T> & _input;
- SparseTensorIndex::IndexMap _map;
- SparseTensorAddressBuilder _addressBuilder;
-public:
- explicit SparseTensorRemove(const SparseTensorT<T> &input);
- ~SparseTensorRemove();
- void visit(const TensorAddress &address, double value) override;
- std::unique_ptr<Tensor> build();
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.cpp
deleted file mode 100644
index 164d9bc957f..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_add.h"
-#include "sparse_tensor_address_builder.h"
-#include "sparse_tensor_join.h"
-#include "sparse_tensor_join.hpp"
-#include "sparse_tensor_match.h"
-#include "sparse_tensor_modify.h"
-#include "sparse_tensor_reduce.hpp"
-#include "sparse_tensor_remove.h"
-#include "direct_sparse_tensor_builder.h"
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/tensor/cell_values.h>
-#include <vespa/eval/tensor/tensor_address_builder.h>
-#include <vespa/eval/tensor/tensor_visitor.h>
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <vespa/vespalib/stllike/hash_map_equal.hpp>
-#include <vespa/vespalib/util/array_equal.hpp>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.sparse.sparse_tensor");
-
-namespace vespalib::tensor {
-
-namespace {
-
-template<typename LCT>
-struct GenericSparseJoin {
- template<typename RCT, typename OCT>
- static Tensor::UP invoke(const SparseTensor & lhs_in,
- const SparseTensor & rhs_in,
- eval::ValueType res_type,
- SparseTensor::join_fun_t func)
- {
- auto & lhs = static_cast<const SparseTensorT<LCT> &>(lhs_in);
- auto & rhs = static_cast<const SparseTensorT<RCT> &>(rhs_in);
- return sparse::join<LCT, RCT, OCT>(lhs, rhs, std::move(res_type), func);
- }
-};
-
-template<typename LCT>
-struct FastSparseJoin {
- template<typename RCT>
- static Tensor::UP invoke(const SparseTensor & lhs_in,
- const SparseTensor & rhs_in,
- eval::ValueType res_type)
- {
- auto & lhs = static_cast<const SparseTensorT<LCT> &>(lhs_in);
- auto & rhs = static_cast<const SparseTensorT<RCT> &>(rhs_in);
- // Ensure that first tensor to fastMatch has fewest cells.
- if (rhs.my_size() < lhs.my_size()) {
- return SparseTensorMatch<RCT,LCT>(rhs, lhs, std::move(res_type)).result();
- } else {
- return SparseTensorMatch<LCT,RCT>(lhs, rhs, std::move(res_type)).result();
- }
- }
-};
-
-struct GenericSparseMerge {
- template<typename LCT, typename RCT>
- static Tensor::UP invoke(const SparseTensor &lhs_in,
- const SparseTensor &rhs_in,
- SparseTensor::join_fun_t function)
- {
- using OCT = typename eval::UnifyCellTypes<LCT,RCT>::type;
- auto & lhs= static_cast<const SparseTensorT<LCT> &>(lhs_in);
- auto & rhs= static_cast<const SparseTensorT<RCT> &>(rhs_in);
- DirectSparseTensorBuilder<OCT> builder(eval::ValueType::merge(lhs.fast_type(), rhs.fast_type()));
- builder.reserve(lhs.my_size() + rhs.my_size());
- const auto &lhs_map = lhs.index().get_map();
- const auto &rhs_map = rhs.index().get_map();
- for (const auto & kv : lhs_map) {
- auto pos = rhs_map.find(kv.first);
- if (pos == rhs_map.end()) {
- builder.insertCell(kv.first, lhs.get_value(kv.second));
- } else {
- double a = lhs.get_value(kv.second);
- double b = rhs.get_value(pos->second);
- builder.insertCell(kv.first, function(a, b));
- }
- }
- for (const auto & kv : rhs_map) {
- auto pos = lhs_map.find(kv.first);
- if (pos == lhs_map.end()) {
- double b = rhs.get_value(kv.second);
- builder.insertCell(kv.first, b);
- }
- }
- return builder.build();
- }
-};
-
-} // namespace <unnamed>
-
-template<typename T>
-SparseTensorT<T>::SparseTensorT(eval::ValueType type_in, SparseTensorIndex index_in, std::vector<T> values_in)
- : SparseTensor(std::move(type_in), std::move(index_in)),
- _values(std::move(values_in))
-{
-}
-
-template<typename T>
-SparseTensorT<T>::~SparseTensorT() = default;
-
-template<typename T>
-eval::TypedCells
-SparseTensorT<T>::cells() const
-{
- return eval::TypedCells(_values);
-}
-
-template<typename T>
-double
-SparseTensorT<T>::as_double() const
-{
- double result = 0.0;
- for (double v : _values) {
- result += v;
- }
- return result;
-}
-
-template<typename T>
-void
-SparseTensorT<T>::accept(TensorVisitor &visitor) const
-{
- TensorAddressBuilder addrBuilder;
- TensorAddress addr;
- for (const auto & kv : index().get_map()) {
- SparseTensorAddressDecoder decoder(kv.first);
- addrBuilder.clear();
- for (const auto &dimension : fast_type().dimensions()) {
- auto label = decoder.decodeLabel();
- if (label.size() != 0u) {
- addrBuilder.add(dimension.name, label);
- }
- }
- assert(!decoder.valid());
- addr = addrBuilder.build();
- visitor.visit(addr, get_value(kv.second));
- }
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorT<T>::add(const Tensor &arg) const
-{
- const SparseTensor *rhs = dynamic_cast<const SparseTensor *>(&arg);
- if (!rhs) {
- return Tensor::UP();
- }
- SparseTensorAdd<T> adder(fast_type(), index().copy(), _values);
- rhs->accept(adder);
- return adder.build();
-}
-
-template<typename T>
-Tensor::UP
-SparseTensorT<T>::apply(const CellFunction &func) const
-{
- std::vector<T> new_values;
- new_values.reserve(_values.size());
- for (T v : _values) {
- new_values.push_back(func.apply(v));
- }
- return std::make_unique<SparseTensorT<T>>(fast_type(), index().copy(), std::move(new_values));
-}
-
-template<typename T>
-Tensor::UP
-SparseTensorT<T>::join(join_fun_t function, const Tensor &arg) const
-{
- const SparseTensor *rhs = dynamic_cast<const SparseTensor *>(&arg);
- if (!rhs) {
- return Tensor::UP();
- }
- const auto & lhs_type = fast_type();
- const auto & rhs_type = rhs->fast_type();
- auto rhs_ct = rhs_type.cell_type();
- auto res_type = eval::ValueType::join(lhs_type, rhs_type);
- if (function == eval::operation::Mul::f) {
- if (lhs_type.dimensions() == rhs_type.dimensions()) {
- return typify_invoke<1,eval::TypifyCellType,FastSparseJoin<T>>(rhs_ct,
- *this, *rhs, std::move(res_type));
- }
- }
- auto res_ct = res_type.cell_type();
- return typify_invoke<2,eval::TypifyCellType,GenericSparseJoin<T>>(rhs_ct, res_ct,
- *this, *rhs, std::move(res_type), function);
-}
-
-template<typename T>
-Tensor::UP
-SparseTensorT<T>::merge(join_fun_t function, const Tensor &arg) const
-{
- const SparseTensor *rhs = dynamic_cast<const SparseTensor *>(&arg);
- assert(rhs && (fast_type().dimensions() == rhs->fast_type().dimensions()));
- return typify_invoke<2,eval::TypifyCellType,GenericSparseMerge>(
- fast_type().cell_type(), rhs->fast_type().cell_type(),
- *this, *rhs, function);
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorT<T>::modify(join_fun_t op, const CellValues &cellValues) const
-{
- SparseTensorModify modifier(op, *this);;
- cellValues.accept(modifier);
- return modifier.build();
-}
-
-template<typename T>
-Tensor::UP
-SparseTensorT<T>::reduce(join_fun_t op, const std::vector<vespalib::string> &dimensions) const
-{
- return sparse::reduce(*this, dimensions, op);
-}
-
-template<typename T>
-std::unique_ptr<Tensor>
-SparseTensorT<T>::remove(const CellValues &cellAddresses) const
-{
- SparseTensorRemove<T> remover(*this);
- cellAddresses.accept(remover);
- return remover.build();
-}
-
-template<typename T>
-MemoryUsage
-SparseTensorT<T>::get_memory_usage() const
-{
- MemoryUsage result = index().get_memory_usage();
- result.incUsedBytes(sizeof(SparseTensor));
- result.incUsedBytes(_values.size() * sizeof(T));
- result.incAllocatedBytes(sizeof(SparseTensor));
- result.incAllocatedBytes(_values.capacity() * sizeof(T));
- return result;
-}
-
-template<typename T>
-bool
-SparseTensorT<T>::should_shrink() const
-{
- auto mem_use = get_memory_usage();
- return (mem_use.usedBytes() * 3 < mem_use.allocatedBytes());
-}
-
-template<typename T>
-Tensor::UP
-SparseTensorT<T>::shrink() const
-{
- return std::make_unique<SparseTensorT<T>>(fast_type(), index().shrunk_copy(), _values);
-}
-
-template class SparseTensorT<float>;
-template class SparseTensorT<double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.h
deleted file mode 100644
index ed8c1f427f9..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_t.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor_index.h"
-#include <vespa/eval/tensor/cell_function.h>
-#include <vespa/eval/tensor/tensor.h>
-#include <vespa/eval/tensor/tensor_address.h>
-#include <vespa/eval/tensor/types.h>
-#include <vespa/vespalib/stllike/hash_map.h>
-#include <vespa/vespalib/stllike/string.h>
-#include <vespa/vespalib/util/stash.h>
-
-namespace vespalib::tensor {
-
-template<typename T>
-class SparseTensorT : public SparseTensor
-{
-private:
- std::vector<T> _values;
-public:
- SparseTensorT(eval::ValueType type_in, SparseTensorIndex index_in, std::vector<T> cells_in);
- ~SparseTensorT() override;
- eval::TypedCells cells() const override;
- T get_value(size_t idx) const { return _values[idx]; }
- size_t my_size() const { return _values.size(); }
- const std::vector<T> &my_values() const { return _values; }
- double as_double() const override;
- void accept(TensorVisitor &visitor) const override;
- Tensor::UP add(const Tensor &arg) const override;
- Tensor::UP apply(const CellFunction &func) const override;
- Tensor::UP join(join_fun_t function, const Tensor &arg) const override;
- Tensor::UP merge(join_fun_t function, const Tensor &arg) const override;
- Tensor::UP modify(join_fun_t op, const CellValues &cellValues) const override;
- Tensor::UP reduce(join_fun_t op, const std::vector<vespalib::string> &dimensions) const override;
- Tensor::UP remove(const CellValues &cellAddresses) const override;
- MemoryUsage get_memory_usage() const override;
- bool should_shrink() const;
- Tensor::UP shrink() const;
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.cpp
deleted file mode 100644
index 2152a2c3b6e..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "sparse_tensor_value_builder.h"
-#include "sparse_tensor_t.h"
-
-namespace vespalib::tensor {
-
-template <typename T>
-ArrayRef<T>
-SparseTensorValueBuilder<T>::add_subspace(ConstArrayRef<vespalib::stringref> addr)
-{
- uint32_t idx = _cells.size();
- _addr_builder.clear();
- for (const auto & label : addr) {
- _addr_builder.add(label);
- }
- auto tmp_ref = _addr_builder.getAddressRef();
- _index.add_address(tmp_ref);
- _cells.push_back(0.0);
- return ArrayRef<T>(&_cells[idx], 1);
-}
-
-template <typename T>
-std::unique_ptr<eval::Value>
-SparseTensorValueBuilder<T>::build(std::unique_ptr<eval::ValueBuilder<T>>)
-{
- return std::make_unique<SparseTensorT<T>>(std::move(_type),
- std::move(_index),
- std::move(_cells));
-
-}
-
-template class SparseTensorValueBuilder<float>;
-template class SparseTensorValueBuilder<double>;
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.h
deleted file mode 100644
index a48af150b15..00000000000
--- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_value_builder.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "sparse_tensor.h"
-#include "sparse_tensor_address_builder.h"
-
-namespace vespalib::tensor {
-
-/**
- * A builder for SparseTensorValue objects
- * appropriate for cell type T.
- **/
-template <typename T>
-class SparseTensorValueBuilder : public eval::ValueBuilder<T>
-{
-private:
- eval::ValueType _type;
- SparseTensorIndex _index;
- std::vector<T> _cells;
- SparseTensorAddressBuilder _addr_builder;
-public:
- SparseTensorValueBuilder(const eval::ValueType &type,
- size_t num_mapped_in,
- size_t expected_subspaces)
- : _type(type),
- _index(num_mapped_in),
- _cells()
- {
- assert(num_mapped_in > 0);
- _index.reserve(expected_subspaces);
- _cells.reserve(expected_subspaces);
- }
-
- ~SparseTensorValueBuilder() override = default;
-
- ArrayRef<T> add_subspace(ConstArrayRef<vespalib::stringref> addr) override;
- std::unique_ptr<eval::Value> build(std::unique_ptr<eval::ValueBuilder<T>> self) override;
-};
-
-} // namespace
diff --git a/eval/src/vespa/eval/tensor/tensor.cpp b/eval/src/vespa/eval/tensor/tensor.cpp
deleted file mode 100644
index 51c94aab5b0..00000000000
--- a/eval/src/vespa/eval/tensor/tensor.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor.h"
-#include "default_tensor_engine.h"
-#include <sstream>
-
-namespace vespalib::tensor {
-
-Tensor::Tensor()
- : eval::Tensor(DefaultTensorEngine::ref())
-{
-}
-
-bool
-Tensor::supported(TypeList types)
-{
- bool sparse = false;
- bool dense = false;
- for (const eval::ValueType &type: types) {
- dense = (dense || type.is_double());
- for (const auto &dim: type.dimensions()) {
- dense = (dense || dim.is_indexed());
- sparse = (sparse || dim.is_mapped());
- }
- }
- return (dense != sparse);
-}
-
-std::ostream &
-operator<<(std::ostream &out, const Tensor &value)
-{
- out << value.toSpec().to_string();
- return out;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor.h b/eval/src/vespa/eval/tensor/tensor.h
deleted file mode 100644
index 01cf6e8e61d..00000000000
--- a/eval/src/vespa/eval/tensor/tensor.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "cell_function.h"
-#include "tensor_address.h"
-#include <vespa/vespalib/stllike/string.h>
-#include <vespa/eval/eval/operation.h>
-#include <vespa/eval/eval/tensor.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/value_type.h>
-
-namespace vespalib::eval { struct BinaryOperation; }
-namespace vespalib::tensor {
-
-class TensorVisitor;
-class CellValues;
-
-/**
- * Interface for operations on a tensor (sparse multi-dimensional array).
- *
- * A sparse tensor is a set of cells containing scalar values.
- * Each cell is identified by its address, which consists of a set of dimension -> label pairs,
- * where both dimension and label is a string on the form of an identifier or integer.
- */
-class Tensor : public eval::Tensor
-{
-public:
- typedef std::unique_ptr<Tensor> UP;
- typedef std::reference_wrapper<const Tensor> CREF;
- using join_fun_t = vespalib::eval::operation::op2_t;
-
- Tensor();
- virtual ~Tensor() {}
- virtual Tensor::UP apply(const CellFunction &func) const = 0;
- virtual Tensor::UP join(join_fun_t function, const Tensor &arg) const = 0;
- virtual Tensor::UP merge(join_fun_t function, const Tensor &arg) const = 0;
- virtual Tensor::UP reduce(join_fun_t op, const std::vector<vespalib::string> &dimensions) const = 0;
-
- /*
- * Creates a new tensor by modifying the underlying cells matching
- * the given cells applying a join function to determine the new
- * cell value.
- */
- virtual std::unique_ptr<Tensor> modify(join_fun_t op, const CellValues &cellValues) const = 0;
-
- /**
- * Creates a new tensor by adding the cells of the argument tensor to this tensor.
- * Existing cell values are overwritten.
- */
- virtual std::unique_ptr<Tensor> add(const Tensor &arg) const = 0;
-
- /**
- * Creates a new tensor by removing the cells matching the given cell addresses.
- * The value associated with the address is ignored.
- */
- virtual std::unique_ptr<Tensor> remove(const CellValues &cellAddresses) const = 0;
-
- virtual eval::TensorSpec toSpec() const = 0;
- virtual void accept(TensorVisitor &visitor) const = 0;
-
- using TypeList = std::initializer_list<std::reference_wrapper<const eval::ValueType>>;
- static bool supported(TypeList types);
-};
-
-std::ostream &operator<<(std::ostream &out, const Tensor &value);
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_address.cpp b/eval/src/vespa/eval/tensor/tensor_address.cpp
deleted file mode 100644
index a68fc5d3353..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_address.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor_address.h"
-#include <algorithm>
-#include <ostream>
-
-namespace vespalib::tensor {
-
-const vespalib::string TensorAddress::Element::UNDEFINED_LABEL = "(undefined)";
-
-TensorAddress::Element::~Element() = default;
-
-TensorAddress::TensorAddress()
- : _elements()
-{
-}
-
-TensorAddress::~TensorAddress() = default;
-
-TensorAddress::TensorAddress(const Elements &elements_in)
- : _elements(elements_in)
-{
- std::sort(_elements.begin(), _elements.end());
-}
-
-bool
-TensorAddress::hasDimension(const vespalib::string &dimension) const
-{
- for (const auto &elem : _elements) {
- if (elem.dimension() == dimension) {
- return true;
- }
- }
- return false;
-}
-
-bool
-TensorAddress::operator<(const TensorAddress &rhs) const
-{
- if (_elements.size() == rhs._elements.size()) {
- for (size_t i = 0; i < _elements.size(); ++i) {
- if (_elements[i] != rhs._elements[i]) {
- return _elements[i] < rhs._elements[i];
- }
- }
- }
- return _elements.size() < rhs._elements.size();
-}
-
-bool
-TensorAddress::operator==(const TensorAddress &rhs) const
-{
- return _elements == rhs._elements;
-}
-
-size_t
-TensorAddress::hash() const
-{
- size_t hashCode = 1;
- for (const auto &elem : _elements) {
- hashCode = 31 * hashCode + elem.hash();
- }
- return hashCode;
-}
-
-std::ostream &
-operator<<(std::ostream &out, const TensorAddress::Elements &elements)
-{
- out << "{";
- bool first = true;
- for (const auto &elem : elements) {
- if (!first) {
- out << ",";
- }
- out << elem.dimension() << ":" << elem.label();
- first = false;
- }
- out << "}";
- return out;
-}
-
-std::ostream &
-operator<<(std::ostream &out, const TensorAddress &value)
-{
- out << value.elements();
- return out;
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_address.h b/eval/src/vespa/eval/tensor/tensor_address.h
deleted file mode 100644
index b12a5ca2dbb..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_address.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/stllike/hash_fun.h>
-#include <vespa/vespalib/stllike/string.h>
-#include <iosfwd>
-#include <map>
-#include <vector>
-
-namespace vespalib::tensor {
-
-/**
- * A sparse immutable address to a tensor cell.
- *
- * Only dimensions which have a different label than "undefined" are explicitly included.
- * Tensor addresses are ordered by increasing size primarily,
- * and by the natural order of the elements in sorted order secondarily.
- */
-class TensorAddress
-{
-public:
- typedef std::unique_ptr<TensorAddress> UP;
-
- class Element
- {
- private:
- vespalib::string _dimension;
- vespalib::string _label;
-
- public:
- static const vespalib::string UNDEFINED_LABEL;
- Element(const vespalib::string &dimension_in, const vespalib::string &label_in) noexcept
- : _dimension(dimension_in), _label(label_in)
- {}
- Element(const Element &) noexcept = default;
- Element & operator = (const Element &) noexcept = default;
- Element(Element &&) noexcept = default;
- Element & operator = (Element &&) noexcept = default;
- ~Element();
- const vespalib::string &dimension() const { return _dimension; }
- const vespalib::string &label() const { return _label; }
- bool operator<(const Element &rhs) const {
- if (_dimension == rhs._dimension) {
- // Define sort order when dimension is the same to be able
- // to do set operations over element vectors.
- return _label < rhs._label;
- }
- return _dimension < rhs._dimension;
- }
- bool operator==(const Element &rhs) const {
- return (_dimension == rhs._dimension) && (_label == rhs._label);
- }
- bool operator!=(const Element &rhs) const {
- return !(*this == rhs);
- }
- size_t hash() const {
- return hashValue(_dimension.c_str()) + hashValue(_label.c_str());
- }
- };
-
- typedef std::vector<Element> Elements;
-
-private:
- Elements _elements;
-
-public:
- TensorAddress();
- explicit TensorAddress(const Elements &elements_in);
- explicit TensorAddress(Elements &&elements_in)
- : _elements(std::move(elements_in))
- {}
- TensorAddress(const TensorAddress &) = default;
- TensorAddress & operator = (const TensorAddress &) = default;
- TensorAddress(TensorAddress &&) = default;
- TensorAddress & operator = (TensorAddress &&) = default;
-
- ~TensorAddress();
- const Elements &elements() const { return _elements; }
- bool hasDimension(const vespalib::string &dimension) const;
- bool operator<(const TensorAddress &rhs) const;
- bool operator==(const TensorAddress &rhs) const;
- size_t hash() const;
-};
-
-std::ostream &operator<<(std::ostream &out, const TensorAddress::Elements &elements);
-std::ostream &operator<<(std::ostream &out, const TensorAddress &value);
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_address_builder.h b/eval/src/vespa/eval/tensor/tensor_address_builder.h
deleted file mode 100644
index 47ea79fd985..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_address_builder.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor_address.h"
-
-namespace vespalib::tensor {
-
-
-/**
- * A builder for tensor addresses.
- */
-class TensorAddressBuilder
-{
- TensorAddress::Elements _elements;
-public:
- TensorAddressBuilder()
- : _elements()
- {
- }
- void add(vespalib::stringref dimension, vespalib::stringref label) {
- _elements.emplace_back(dimension, label);
- }
- TensorAddress build() { return TensorAddress(_elements); }
- void clear(void) { _elements.clear(); }
-};
-
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h b/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h
deleted file mode 100644
index 01710105840..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-
-namespace vespalib::tensor {
-
-
-/**
- * An iterator for tensor address elements used to simplify 3-way merge
- * between two tensor addresses and a dimension vector.
- */
-template <class Address>
-class TensorAddressElementIterator {
- using InnerIterator = typename Address::Elements::const_iterator;
- InnerIterator _itr;
- InnerIterator _itrEnd;
-public:
- TensorAddressElementIterator(const Address &address)
- : _itr(address.elements().cbegin()),
- _itrEnd(address.elements().cend())
- {
- }
- bool valid() const { return (_itr != _itrEnd); }
- vespalib::stringref dimension() const { return _itr->dimension(); }
- vespalib::stringref label() const { return _itr->label(); }
- void next() { ++_itr; }
- bool skipToDimension(vespalib::stringref rhsDimension) {
- for (;;) {
- if (!valid()) {
- return false;
- }
- if (dimension() < rhsDimension) {
- next();
- } else {
- return (dimension() == rhsDimension);
- }
- }
- }
-};
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_visitor.h b/eval/src/vespa/eval/tensor/tensor_visitor.h
deleted file mode 100644
index 4cd9792afbd..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_visitor.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor_address.h"
-#include <vespa/vespalib/stllike/string.h>
-#include "types.h"
-
-namespace vespalib::tensor {
-
-/**
- * Class for visiting a tensor. First visit must specify dimensions,
- * remaining visits must specify tensor addresses and values.
- */
-class TensorVisitor
-{
-public:
- virtual ~TensorVisitor() {}
- virtual void visit(const TensorAddress &address, double value) = 0;
-};
-
-} \ No newline at end of file
diff --git a/eval/src/vespa/eval/tensor/test/test_utils.h b/eval/src/vespa/eval/tensor/test/test_utils.h
deleted file mode 100644
index 5daae74284b..00000000000
--- a/eval/src/vespa/eval/tensor/test/test_utils.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/vespalib/testkit/test_kit.h>
-
-namespace vespalib::tensor::test {
-
-template <typename T>
-std::unique_ptr<T>
-makeTensor(const vespalib::eval::TensorSpec &spec)
-{
- auto value = DefaultTensorEngine::ref().from_spec(spec);
- T *tensor = dynamic_cast<T *>(value.get());
- ASSERT_TRUE(tensor);
- value.release();
- return std::unique_ptr<T>(tensor);
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/types.h b/eval/src/vespa/eval/tensor/types.h
deleted file mode 100644
index d969bc0a2fb..00000000000
--- a/eval/src/vespa/eval/tensor/types.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-#include <vespa/vespalib/stllike/hash_set.h>
-#include <vector>
-#include <map>
-
-namespace vespalib::tensor {
-
-using TensorCells = std::map<std::map<vespalib::string, vespalib::string>, double>;
-using TensorDimensions = std::vector<vespalib::string>;
-using TensorDimensionsSet = vespalib::hash_set<vespalib::string>;
-using DenseTensorCells = std::map<std::map<vespalib::string, size_t>, double>;
-
-}
diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp
deleted file mode 100644
index fd49d1d83bc..00000000000
--- a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "cell_values.h"
-#include "tensor_address_builder.h"
-#include "tensor_visitor.h"
-#include "wrapped_simple_tensor.h"
-#include <vespa/eval/eval/simple_tensor_engine.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/vespalib/util/stringfmt.h>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.wrapped_simple_tensor");
-
-namespace vespalib::tensor {
-
-using eval::SimpleTensor;
-using eval::TensorSpec;
-
-eval::TensorSpec
-WrappedSimpleTensor::toSpec() const
-{
- return eval::SimpleTensorEngine::ref().to_spec(_tensor);
-}
-
-double
-WrappedSimpleTensor::as_double() const
-{
- return _tensor.as_double();
-}
-
-void
-WrappedSimpleTensor::accept(TensorVisitor &visitor) const
-{
- TensorAddressBuilder addr;
- const auto &dimensions = _tensor.type().dimensions();
- for (const auto &cell: _tensor.my_cells()) {
- addr.clear();
- for (size_t i = 0; i < dimensions.size(); ++i) {
- if (dimensions[i].is_indexed()) {
- addr.add(dimensions[i].name, make_string("%zu", cell.address[i].index));
- } else {
- addr.add(dimensions[i].name, cell.address[i].name);
- }
- }
- visitor.visit(addr.build(), cell.value);
- }
-}
-
-MemoryUsage
-WrappedSimpleTensor::get_memory_usage() const
-{
- size_t used = sizeof(WrappedSimpleTensor);
- if (_space) {
- auto plus = _space->get_memory_usage();
- plus.incUsedBytes(used);
- plus.incAllocatedBytes(used);
- return plus;
- }
- return MemoryUsage(used, used, 0, 0);
-}
-
-//-----------------------------------------------------------------------------
-
-Tensor::UP
-WrappedSimpleTensor::apply(const CellFunction &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleTensor::join(join_fun_t, const Tensor &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleTensor::merge(join_fun_t, const Tensor &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleTensor::reduce(join_fun_t, const std::vector<vespalib::string> &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-namespace {
-
-TensorSpec::Address
-convertToOnlyMappedDimensions(const TensorSpec::Address &address)
-{
- TensorSpec::Address result;
- for (const auto &elem : address) {
- if (elem.second.is_indexed()) {
- result.emplace(std::make_pair(elem.first,
- TensorSpec::Label(vespalib::make_string("%zu", elem.second.index))));
- } else {
- result.emplace(elem);
- }
- }
- return result;
-}
-
-}
-
-std::unique_ptr<Tensor>
-WrappedSimpleTensor::modify(join_fun_t op, const CellValues &cellValues) const
-{
- TensorSpec oldTensor = toSpec();
- TensorSpec toModify = cellValues.toSpec();
- TensorSpec result(type().to_spec());
-
- for (const auto &cell : oldTensor.cells()) {
- TensorSpec::Address mappedAddress = convertToOnlyMappedDimensions(cell.first);
- auto itr = toModify.cells().find(mappedAddress);
- if (itr != toModify.cells().end()) {
- result.add(cell.first, op(cell.second, itr->second));
- } else {
- result.add(cell.first, cell.second);
- }
- }
- return std::make_unique<WrappedSimpleTensor>(SimpleTensor::create(result));
-}
-
-std::unique_ptr<Tensor>
-WrappedSimpleTensor::add(const Tensor &arg) const
-{
- const auto *rhs = dynamic_cast<const WrappedSimpleTensor *>(&arg);
- if (!rhs || type() != rhs->type()) {
- return Tensor::UP();
- }
- TensorSpec oldTensor = toSpec();
- TensorSpec argTensor = rhs->toSpec();
- TensorSpec result(type().to_spec());
- for (const auto &cell : oldTensor.cells()) {
- auto argItr = argTensor.cells().find(cell.first);
- if (argItr != argTensor.cells().end()) {
- result.add(argItr->first, argItr->second);
- } else {
- result.add(cell.first, cell.second);
- }
- }
- for (const auto &cell : argTensor.cells()) {
- auto resultItr = result.cells().find(cell.first);
- if (resultItr == result.cells().end()) {
- result.add(cell.first, cell.second);
- }
- }
- return std::make_unique<WrappedSimpleTensor>(SimpleTensor::create(result));
-}
-
-namespace {
-
-TensorSpec::Address
-extractMappedDimensions(const TensorSpec::Address &address)
-{
- TensorSpec::Address result;
- for (const auto &elem : address) {
- if (elem.second.is_mapped()) {
- result.emplace(elem);
- }
- }
- return result;
-}
-
-}
-
-std::unique_ptr<Tensor>
-WrappedSimpleTensor::remove(const CellValues &cellAddresses) const
-{
- TensorSpec oldTensor = toSpec();
- TensorSpec toRemove = cellAddresses.toSpec();
- TensorSpec result(type().to_spec());
-
- for (const auto &cell : oldTensor.cells()) {
- TensorSpec::Address mappedAddress = extractMappedDimensions(cell.first);
- auto itr = toRemove.cells().find(mappedAddress);
- if (itr == toRemove.cells().end()) {
- result.add(cell.first, cell.second);
- }
- }
- return std::make_unique<WrappedSimpleTensor>(SimpleTensor::create(result));
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h
deleted file mode 100644
index c2199ccb49d..00000000000
--- a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor.h"
-#include <vespa/eval/eval/simple_tensor.h>
-
-namespace vespalib::tensor {
-
-/**
- * A thin wrapper around a SimpleTensor (tensor reference
- * implementation) to be used as fallback for tensors with data
- * layouts not supported by the default tensor implementation.
- *
- * Tensor implementation class is currently inferred from its value
- * type. Consider adding explicit tagging to the tensor::Tensor
- * default implementation top-level class in the future.
- **/
-class WrappedSimpleTensor : public Tensor
-{
-private:
- std::unique_ptr<eval::SimpleTensor> _space;
- const eval::SimpleTensor &_tensor;
-public:
- explicit WrappedSimpleTensor(const eval::SimpleTensor &tensor)
- : _space(), _tensor(tensor) {}
- explicit WrappedSimpleTensor(std::unique_ptr<eval::SimpleTensor> tensor)
- : _space(std::move(tensor)), _tensor(*_space) {}
- eval::TypedCells cells() const override { abort(); }
- const Index &index() const override { abort(); }
- ~WrappedSimpleTensor() {}
- const eval::SimpleTensor &get() const { return _tensor; }
- const eval::ValueType &type() const override { return _tensor.type(); }
- eval::TensorSpec toSpec() const override;
- double as_double() const override;
- void accept(TensorVisitor &visitor) const override;
- MemoryUsage get_memory_usage() const override;
- // functions below should not be used for this implementation
- Tensor::UP apply(const CellFunction &) const override;
- Tensor::UP join(join_fun_t, const Tensor &) const override;
- Tensor::UP merge(join_fun_t, const Tensor &) const override;
- Tensor::UP reduce(join_fun_t, const std::vector<vespalib::string> &) const override;
- std::unique_ptr<Tensor> modify(join_fun_t, const CellValues &) const override;
- std::unique_ptr<Tensor> add(const Tensor &arg) const override;
- std::unique_ptr<Tensor> remove(const CellValues &) const override;
-};
-
-} // namespace vespalib::tensor
diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_value.cpp b/eval/src/vespa/eval/tensor/wrapped_simple_value.cpp
deleted file mode 100644
index eb552c21aa0..00000000000
--- a/eval/src/vespa/eval/tensor/wrapped_simple_value.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "wrapped_simple_value.h"
-#include "cell_values.h"
-#include "tensor_address_builder.h"
-#include "tensor_visitor.h"
-#include <vespa/eval/eval/memory_usage_stuff.h>
-#include <vespa/eval/eval/simple_value.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/value_codec.h>
-#include <vespa/vespalib/util/stringfmt.h>
-
-#include <vespa/log/log.h>
-LOG_SETUP(".eval.tensor.wrapped_simple_value");
-
-using vespalib::eval::TensorSpec;
-using vespalib::eval::SimpleValueBuilderFactory;
-
-namespace vespalib::tensor {
-
-namespace {
-
-TensorSpec::Address
-sparsify_address(const TensorSpec::Address &address)
-{
- TensorSpec::Address result;
- for (const auto &elem : address) {
- if (elem.second.is_indexed()) {
- auto val = vespalib::make_string("%zu", elem.second.index);
- result.emplace(elem.first, TensorSpec::Label(val));
- } else {
- result.emplace(elem);
- }
- }
- return result;
-}
-
-TensorSpec::Address
-extract_sparse_address(const TensorSpec::Address &address)
-{
- TensorSpec::Address result;
- for (const auto &elem : address) {
- if (elem.second.is_mapped()) {
- result.emplace(elem);
- }
- }
- return result;
-}
-
-Tensor::UP wrap(eval::Value::UP value) {
- return std::make_unique<WrappedSimpleValue>(std::move(value));
-}
-
-} // namespace <unnamed>
-
-
-eval::TensorSpec
-WrappedSimpleValue::toSpec() const
-{
- return spec_from_value(_tensor);
-}
-
-void
-WrappedSimpleValue::accept(TensorVisitor &visitor) const
-{
- TensorSpec myspec = toSpec();
- TensorAddressBuilder addr;
- for (const auto & cell : myspec.cells()) {
- auto sparse_addr = sparsify_address(cell.first);
- addr.clear();
- for (const auto & dim_and_label : sparse_addr) {
- addr.add(dim_and_label.first, dim_and_label.second.name);
- }
- visitor.visit(addr.build(), cell.second);
- }
-}
-
-MemoryUsage
-WrappedSimpleValue::get_memory_usage() const
-{
- MemoryUsage rv = eval::self_memory_usage<WrappedSimpleValue>();
- if (_space) {
- rv.merge(_space->get_memory_usage());
- }
- return rv;
-}
-
-//-----------------------------------------------------------------------------
-
-Tensor::UP
-WrappedSimpleValue::apply(const CellFunction &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleValue::join(join_fun_t, const Tensor &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleValue::merge(join_fun_t, const Tensor &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleValue::reduce(join_fun_t, const std::vector<vespalib::string> &) const
-{
- LOG_ABORT("should not be reached");
-}
-
-Tensor::UP
-WrappedSimpleValue::modify(join_fun_t fun, const CellValues &cellValues) const
-{
- TensorSpec a = toSpec();
- TensorSpec b = cellValues.toSpec();
- TensorSpec result(a.type());
- auto end_iter = b.cells().end();
- for (const auto &cell: a.cells()) {
- double v = cell.second;
- auto sparse_addr = sparsify_address(cell.first);
- auto iter = b.cells().find(sparse_addr);
- if (iter == end_iter) {
- result.add(cell.first, v);
- } else {
- result.add(cell.first, fun(v, iter->second));
- }
- }
- return wrap(value_from_spec(result, SimpleValueBuilderFactory::get()));
-}
-
-Tensor::UP
-WrappedSimpleValue::add(const Tensor &rhs) const
-{
- TensorSpec a = toSpec();
- TensorSpec b = rhs.toSpec();
- if (a.type() != b.type()) {
- return {};
- }
- TensorSpec result(a.type());
- for (const auto &cell: b.cells()) {
- result.add(cell.first, cell.second);
- }
- auto end_iter = b.cells().end();
- for (const auto &cell: a.cells()) {
- auto iter = b.cells().find(cell.first);
- if (iter == end_iter) {
- result.add(cell.first, cell.second);
- }
- }
- return wrap(value_from_spec(result, SimpleValueBuilderFactory::get()));
-}
-
-
-Tensor::UP
-WrappedSimpleValue::remove(const CellValues &rhs) const
-{
- TensorSpec a = toSpec();
- TensorSpec b = rhs.toSpec();
- TensorSpec result(a.type());
- auto end_iter = b.cells().end();
- for (const auto &cell: a.cells()) {
- TensorSpec::Address mappedAddress = extract_sparse_address(cell.first);
- auto iter = b.cells().find(mappedAddress);
- if (iter == end_iter) {
- result.add(cell.first, cell.second);
- }
- }
- return wrap(value_from_spec(result, SimpleValueBuilderFactory::get()));
-}
-
-}
diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_value.h b/eval/src/vespa/eval/tensor/wrapped_simple_value.h
deleted file mode 100644
index 3d8c3e43757..00000000000
--- a/eval/src/vespa/eval/tensor/wrapped_simple_value.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "tensor.h"
-#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/aggr.h>
-
-namespace vespalib::tensor {
-
-/**
- * A thin wrapper around a SimpleValue to be used as fallback for tensors with data
- * layouts not supported by the default tensor implementation.
- *
- * Tensor implementation class is currently inferred from its value
- * type. Consider adding explicit tagging to the tensor::Tensor
- * default implementation top-level class in the future.
- **/
-class WrappedSimpleValue : public Tensor
-{
-private:
- std::unique_ptr<eval::Value> _space;
- const eval::Value &_tensor;
-public:
- explicit WrappedSimpleValue(const eval::Value &tensor)
- : _space(), _tensor(tensor) {}
- explicit WrappedSimpleValue(std::unique_ptr<eval::Value> tensor)
- : _space(std::move(tensor)), _tensor(*_space) {}
- ~WrappedSimpleValue() {}
- const eval::Value &unwrap() const { return _tensor; }
-
- // Value API
- const eval::ValueType &type() const override { return _tensor.type(); }
- eval::TypedCells cells() const override { return _tensor.cells(); }
- const Index &index() const override { return _tensor.index(); }
- double as_double() const override { return _tensor.as_double(); }
-
- // tensor API
- eval::TensorSpec toSpec() const override;
- void accept(TensorVisitor &visitor) const override;
- MemoryUsage get_memory_usage() const override;
-
- Tensor::UP join(join_fun_t fun, const Tensor &rhs) const override;
- Tensor::UP merge(join_fun_t fun, const Tensor &rhs) const override;
- Tensor::UP reduce(join_fun_t fun, const std::vector<vespalib::string> &dims) const override;
-
- Tensor::UP apply(const CellFunction & func) const override;
- Tensor::UP modify(join_fun_t fun, const CellValues &cellValues) const override;
- Tensor::UP add(const Tensor &rhs) const override;
- Tensor::UP remove(const CellValues &rhs) const override;
-};
-
-} // namespace vespalib::tensor
diff --git a/fbench/src/fbench/fbench.cpp b/fbench/src/fbench/fbench.cpp
index efac34409cc..b2bdc69eca4 100644
--- a/fbench/src/fbench/fbench.cpp
+++ b/fbench/src/fbench/fbench.cpp
@@ -291,7 +291,7 @@ FBench::Usage()
printf(" [-s seconds] [-q queryFilePattern] [-o outputFilePattern]\n");
printf(" [-r restartLimit] [-m maxLineSize] [-k] <hostname> <port>\n\n");
printf(" -H <str> : append extra header to each get request.\n");
- printf(" -A <str> : assign autority. <str> should be hostname:port format. Overrides Host: header sent.\n");
+ printf(" -A <str> : assign authority. <str> should be hostname:port format. Overrides Host: header sent.\n");
printf(" -P : use POST for requests instead of GET.\n");
printf(" -a <str> : append string to each query\n");
printf(" -n <num> : run with <num> parallel clients [10]\n");
diff --git a/flags/pom.xml b/flags/pom.xml
index ba0e4a94692..4f1bdcb61e3 100644
--- a/flags/pom.xml
+++ b/flags/pom.xml
@@ -88,6 +88,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java b/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java
index 0dce61cf0bb..d01ca64cb9f 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/FlagDefinition.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.flags;
import javax.annotation.concurrent.Immutable;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -12,13 +13,26 @@ import java.util.List;
@Immutable
public class FlagDefinition {
private final UnboundFlag<?, ?, ?> unboundFlag;
+ private final List<String> owners;
+ private final Instant createdAt;
+ private final Instant expiresAt;
private final String description;
private final String modificationEffect;
private final List<FetchVector.Dimension> dimensions;
- public FlagDefinition(UnboundFlag<?, ?, ?> unboundFlag, String description, String modificationEffect,
- FetchVector.Dimension... dimensions) {
+ public FlagDefinition(
+ UnboundFlag<?, ?, ?> unboundFlag,
+ List<String> owners,
+ Instant createdAt,
+ Instant expiresAt,
+ String description,
+ String modificationEffect,
+ FetchVector.Dimension... dimensions) {
+ validate(owners, createdAt, expiresAt);
this.unboundFlag = unboundFlag;
+ this.owners = owners;
+ this.createdAt = createdAt;
+ this.expiresAt = expiresAt;
this.description = description;
this.modificationEffect = modificationEffect;
this.dimensions = Collections.unmodifiableList(Arrays.asList(dimensions));
@@ -39,4 +53,26 @@ public class FlagDefinition {
public String getModificationEffect() {
return modificationEffect;
}
+
+ public List<String> getOwners() { return owners; }
+
+ public Instant getCreatedAt() { return createdAt; }
+
+ public Instant getExpiresAt() { return expiresAt; }
+
+ private static void validate(List<String> owners, Instant createdAt, Instant expiresAt) {
+ if (expiresAt.isBefore(createdAt)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Flag cannot expire before its creation date (createdAt='%s', expiresAt='%s')",
+ createdAt, expiresAt));
+ }
+ if (owners == PermanentFlags.OWNERS) {
+ if (!createdAt.equals(PermanentFlags.CREATED_AT) || !expiresAt.equals(PermanentFlags.EXPIRES_AT)) {
+ throw new IllegalArgumentException("Invalid creation or expiration date for permanent flag");
+ }
+ } else if (owners.isEmpty()) {
+ throw new IllegalArgumentException("Owner(s) must be specified");
+ }
+ }
}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 0ecf957d1d9..f1eaf522308 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -1,20 +1,20 @@
-// Copyright 2019 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.flags;
import com.yahoo.component.Vtag;
import com.yahoo.vespa.defaults.Defaults;
-import com.yahoo.vespa.flags.custom.HostCapacity;
-import com.yahoo.vespa.flags.custom.SharedHost;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.TreeMap;
import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID;
-import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL;
import static com.yahoo.vespa.flags.FetchVector.Dimension.HOSTNAME;
import static com.yahoo.vespa.flags.FetchVector.Dimension.NODE_TYPE;
-import static com.yahoo.vespa.flags.FetchVector.Dimension.TENANT_ID;
import static com.yahoo.vespa.flags.FetchVector.Dimension.VESPA_VERSION;
import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
@@ -42,214 +42,166 @@ import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
public class Flags {
private static volatile TreeMap<FlagId, FlagDefinition> flags = new TreeMap<>();
- public static final UnboundBooleanFlag FLEET_CANARY = defineFeatureFlag(
- "fleet-canary", false,
- "Whether the host is a fleet canary.",
- "Takes effect on next host admin tick.",
- HOSTNAME);
-
- public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag(
- "disabled-host-admin-tasks", List.of(), String.class,
- "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask), or some node-agent " +
- "functionality (see NodeAgentTask), that should be skipped",
- "Takes effect on next host admin tick",
- HOSTNAME, NODE_TYPE);
-
- public static final UnboundStringFlag DOCKER_VERSION = defineStringFlag(
- "docker-version", "1.13.1-102.git7f2769b",
- "The version of the docker to use of the format VERSION-REL: The YUM package to be installed will be " +
- "2:docker-VERSION-REL.el7.centos.x86_64 in AWS (and without '.centos' otherwise). " +
- "If docker-version is not of this format, it must be parseable by YumPackageName::fromString.",
- "Takes effect on next tick.",
- HOSTNAME);
-
- public static final UnboundDoubleFlag CONTAINER_CPU_CAP = defineDoubleFlag(
- "container-cpu-cap", 0,
- "Hard limit on how many CPUs a container may use. This value is multiplied by CPU allocated to node, so " +
- "to cap CPU at 200%, set this to 2, etc.",
- "Takes effect on next node agent tick. Change is orchestrated, but does NOT require container restart",
- HOSTNAME, APPLICATION_ID);
-
- public static final UnboundIntFlag REBOOT_INTERVAL_IN_DAYS = defineIntFlag(
- "reboot-interval-in-days", 30,
- "No reboots are scheduled 0x-1x reboot intervals after the previous reboot, while reboot is " +
- "scheduled evenly distributed in the 1x-2x range (and naturally guaranteed at the 2x boundary).",
- "Takes effect on next run of NodeRebooter");
-
public static final UnboundBooleanFlag RETIRE_WITH_PERMANENTLY_DOWN = defineFeatureFlag(
"retire-with-permanently-down", false,
+ List.of("hakonhall"), "2020-12-02", "2021-02-01",
"If enabled, retirement will end with setting the host status to PERMANENTLY_DOWN, " +
"instead of ALLOWED_TO_BE_DOWN (old behavior).",
"Takes effect on the next run of RetiredExpirer.",
HOSTNAME);
- public static final UnboundListFlag<HostCapacity> TARGET_CAPACITY = defineListFlag(
- "preprovision-capacity", List.of(), HostCapacity.class,
- "List of node resources and their count that should be provisioned." +
- "In a dynamically provisioned zone this specifies the unallocated (i.e. pre-provisioned) capacity. " +
- "Otherwise it specifies the total (unallocated or not) capacity.",
- "Takes effect on next iteration of DynamicProvisioningMaintainer.");
-
- public static final UnboundJacksonFlag<SharedHost> SHARED_HOST = defineJacksonFlag(
- "shared-host", SharedHost.createDisabled(), SharedHost.class,
- "Specifies whether shared hosts can be provisioned, and if so, the advertised " +
- "node resources of the host, the maximum number of containers, etc.",
- "Takes effect on next iteration of DynamicProvisioningMaintainer.");
-
- public static final UnboundListFlag<String> INACTIVE_MAINTENANCE_JOBS = defineListFlag(
- "inactive-maintenance-jobs", List.of(), String.class,
- "The list of maintenance jobs that are inactive.",
- "Takes effect immediately, but any currently running jobs will run until completion.");
-
public static final UnboundDoubleFlag DEFAULT_TERM_WISE_LIMIT = defineDoubleFlag(
"default-term-wise-limit", 1.0,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Default limit for when to apply termwise query evaluation",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
- public static final UnboundStringFlag JVM_GC_OPTIONS = defineStringFlag(
- "jvm-gc-options", "",
- "Sets deafult jvm gc options",
- "Takes effect at redeployment",
- ZONE_ID, APPLICATION_ID);
-
public static final UnboundStringFlag FEED_SEQUENCER_TYPE = defineStringFlag(
"feed-sequencer-type", "LATENCY",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Selects type of sequenced executor used for feeding, valid values are LATENCY, ADAPTIVE, THROUGHPUT",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundStringFlag RESPONSE_SEQUENCER_TYPE = defineStringFlag(
"response-sequencer-type", "ADAPTIVE",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Selects type of sequenced executor used for mbus responses, valid values are LATENCY, ADAPTIVE, THROUGHPUT",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundIntFlag RESPONSE_NUM_THREADS = defineIntFlag(
"response-num-threads", 2,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Number of threads used for mbus responses, default is 2, negative number = numcores/4",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_COMMUNICATIONMANAGER_THREAD = defineFeatureFlag(
"skip-communicatiomanager-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the communicationmanager thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_MBUS_REQUEST_THREAD = defineFeatureFlag(
"skip-mbus-request-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the mbus request thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag SKIP_MBUS_REPLY_THREAD = defineFeatureFlag(
"skip-mbus-reply-thread", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Should we skip the mbus reply thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_THREE_PHASE_UPDATES = defineFeatureFlag(
"use-three-phase-updates", false,
+ List.of("vekterli"), "2020-12-02", "2021-02-01",
"Whether to enable the use of three-phase updates when bucket replicas are out of sync.",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_DIRECT_STORAGE_API_RPC = defineFeatureFlag(
"use-direct-storage-api-rpc", false,
+ List.of("geirst"), "2020-12-02", "2021-02-01",
"Whether to use direct RPC for Storage API communication between content cluster nodes.",
"Takes effect at restart of distributor and content node process",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag USE_FAST_VALUE_TENSOR_IMPLEMENTATION = defineFeatureFlag(
"use-fast-value-tensor-implementation", false,
+ List.of("geirst"), "2020-12-02", "2021-02-01",
"Whether to use FastValueBuilderFactory as the tensor implementation on all content nodes.",
"Takes effect at restart of content node process",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag HOST_HARDENING = defineFeatureFlag(
"host-hardening", false,
+ List.of("hakonhall"), "2020-12-02", "2021-02-01",
"Whether to enable host hardening Linux baseline.",
"Takes effect on next tick or on host-admin restart (may vary where used).",
HOSTNAME);
public static final UnboundBooleanFlag TCP_ABORT_ON_OVERFLOW = defineFeatureFlag(
"tcp-abort-on-overflow", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to set /proc/sys/net/ipv4/tcp_abort_on_overflow to 0 (false) or 1 (true)",
"Takes effect on next host-admin tick.",
HOSTNAME);
- public static final UnboundStringFlag ZOOKEEPER_SERVER_VERSION = defineStringFlag(
- "zookeeper-server-version", "3.5.6",
- "ZooKeeper server version, a jar file zookeeper-server-<ZOOKEEPER_SERVER_VERSION>-jar-with-dependencies.jar must exist",
- "Takes effect on restart of Docker container",
- NODE_TYPE, APPLICATION_ID, HOSTNAME);
-
public static final UnboundStringFlag TLS_FOR_ZOOKEEPER_CLIENT_SERVER_COMMUNICATION = defineStringFlag(
"tls-for-zookeeper-client-server-communication", "OFF",
+ List.of("hmusum"), "2020-12-02", "2021-02-01",
"How to setup TLS for ZooKeeper client/server communication. Valid values are OFF, PORT_UNIFICATION, TLS_WITH_PORT_UNIFICATION, TLS_ONLY",
"Takes effect on restart of config server",
NODE_TYPE, HOSTNAME);
public static final UnboundBooleanFlag USE_TLS_FOR_ZOOKEEPER_CLIENT = defineFeatureFlag(
"use-tls-for-zookeeper-client", false,
+ List.of("hmusum"), "2020-12-02", "2021-02-01",
"Whether to use TLS for ZooKeeper clients",
"Takes effect on restart of process",
NODE_TYPE, HOSTNAME);
public static final UnboundBooleanFlag VALIDATE_ENDPOINT_CERTIFICATES = defineFeatureFlag(
"validate-endpoint-certificates", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether endpoint certificates should be validated before use",
"Takes effect on the next deployment of the application");
public static final UnboundStringFlag DELETE_UNUSED_ENDPOINT_CERTIFICATES = defineStringFlag(
"delete-unused-endpoint-certificates", "disable",
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether the endpoint certificate maintainer should delete unused certificates in cameo/zk",
"Takes effect on next scheduled run of maintainer - set to \"disable\", \"dryrun\" or \"enable\"");
public static final UnboundBooleanFlag USE_ALTERNATIVE_ENDPOINT_CERTIFICATE_PROVIDER = defineFeatureFlag(
"use-alternative-endpoint-certificate-provider", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to use an alternative CA when provisioning new certificates",
"Takes effect only on initial application deployment - not on later certificate refreshes!");
- public static final UnboundStringFlag DOCKER_IMAGE_REPO = defineStringFlag(
- "docker-image-repo", "",
- "Override default docker image repo. Docker image version will be Vespa version.",
- "Takes effect on next deployment from controller",
- ZONE_ID, APPLICATION_ID);
+ public static final UnboundStringFlag YUM_DIST_HOST = defineStringFlag(
+ "yum-dist-host", "",
+ List.of("aressem"), "2020-12-02", "2021-02-01",
+ "Override the default dist host for yum.",
+ "Takes effect on next tick or on host-admin restart (may vary where used).");
public static final UnboundBooleanFlag ENDPOINT_CERT_IN_SHARED_ROUTING = defineFeatureFlag(
"endpoint-cert-in-shared-routing", false,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"Whether to provision and use endpoint certs for apps in shared routing zones",
"Takes effect on next deployment of the application", APPLICATION_ID);
- public static final UnboundBooleanFlag USE_CLOUD_INIT_FORMAT = defineFeatureFlag(
- "use-cloud-init", false,
- "Use the cloud-init format when provisioning hosts",
- "Takes effect immediately",
- ZONE_ID);
-
public static final UnboundBooleanFlag PROVISION_APPLICATION_ROLES = defineFeatureFlag(
"provision-application-roles", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether application roles should be provisioned",
"Takes effect on next deployment (controller)",
ZONE_ID);
public static final UnboundBooleanFlag APPLICATION_IAM_ROLE = defineFeatureFlag(
"application-iam-roles", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Allow separate iam roles when provisioning/assigning hosts",
"Takes effect immediately on new hosts, on next redeploy for applications",
APPLICATION_ID);
- public static final UnboundBooleanFlag ENABLE_PUBLIC_SIGNUP_FLOW = defineFeatureFlag(
- "enable-public-signup-flow", false,
- "Show the public signup flow for a user in the console",
- "takes effect on browser reload of api/user/v1/user",
- CONSOLE_USER_EMAIL
+ public static final UnboundIntFlag MAX_TRIAL_TENANTS = defineIntFlag(
+ "max-trial-tenants", -1,
+ List.of("ogronnesby"), "2020-12-03", "2021-04-01",
+ "The maximum nr. of tenants with trial plan, -1 is unlimited",
+ "Takes effect immediately"
);
public static final UnboundBooleanFlag CONTROLLER_PROVISION_LB = defineFeatureFlag(
"controller-provision-lb", false,
+ List.of("mpolden"), "2020-12-02", "2021-02-01",
"Provision load balancer for controller cluster",
"Takes effect when controller application is redeployed",
ZONE_ID
@@ -257,142 +209,139 @@ public class Flags {
public static final UnboundIntFlag TENANT_NODE_QUOTA = defineIntFlag(
"tenant-node-quota", 5,
+ List.of("andreer"), "2020-12-02", "2021-02-01",
"The number of nodes a tenant is allowed to request per cluster",
"Only takes effect on next deployment, if set to a value other than the default for flag!",
APPLICATION_ID
);
- public static final UnboundIntFlag TENANT_BUDGET_QUOTA = defineIntFlag(
- "tenant-budget-quota", -1,
- "The budget in cents/hr a tenant is allowed spend per instance, as calculated by NodeResources",
- "Only takes effect on next deployment, if set to a value other than the default for flag!",
- TENANT_ID
- );
-
public static final UnboundBooleanFlag ONLY_PUBLIC_ACCESS = defineFeatureFlag(
"enable-public-only", false,
+ List.of("ogronnesby"), "2020-12-02", "2021-02-01",
"Only access public hosts from container",
"Takes effect on next tick"
);
- public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV4 = defineListFlag(
- "container-outbound-blocked-ipv4", List.of(), String.class,
- "List of IPs or CIDRs that are blocked for outbound connections",
- "Takes effect on next tick"
- );
-
- public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV6 = defineListFlag(
- "container-outbound-blocked-ipv6", List.of(), String.class,
- "List of IPs or CIDRs that are blocked for outbound connections",
- "Takes effect on next tick"
- );
-
public static final UnboundBooleanFlag HIDE_SHARED_ROUTING_ENDPOINT = defineFeatureFlag(
- "hide-shared-routing-endpoint",
- false,
+ "hide-shared-routing-endpoint", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether the controller should hide shared routing layer endpoint",
"Takes effect immediately",
APPLICATION_ID
);
- public static final UnboundBooleanFlag SKIP_MAINTENANCE_DEPLOYMENT = defineFeatureFlag(
- "node-repository-skip-maintenance-deployment",
- false,
- "Whether PeriodicApplicationMaintainer should skip deployment for an application",
- "Takes effect at next run of maintainer",
- APPLICATION_ID);
-
public static final UnboundBooleanFlag USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION = defineFeatureFlag(
- "use-access-control-client-authentication",
- false,
+ "use-access-control-client-authentication", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether application container should set up client authentication on default port based on access control element",
"Takes effect on next internal redeployment",
APPLICATION_ID);
public static final UnboundBooleanFlag USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE = defineFeatureFlag(
"async-message-handling-on-schedule", false,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Optionally deliver async messages in own thread",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundIntFlag CONTENT_NODE_BUCKET_DB_STRIPE_BITS = defineIntFlag(
"content-node-bucket-db-stripe-bits", 0,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"Number of bits used for striping the bucket DB in service layer",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundIntFlag MERGE_CHUNK_SIZE = defineIntFlag(
"merge-chunk-size", 0x400000,
- "Size of merge buffer in service layer",
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
+ "Size of baldersheim buffer in service layer",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
+
public static final UnboundDoubleFlag FEED_CONCURRENCY = defineDoubleFlag(
"feed-concurrency", 0.5,
+ List.of("baldersheim"), "2020-12-02", "2021-02-01",
"How much concurrency should be allowed for feed",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
public static final UnboundBooleanFlag ENABLE_AUTOMATIC_REINDEXING = defineFeatureFlag(
- "enable-automatic-reindexing",
- false,
+ "enable-automatic-reindexing", true,
+ List.of("bjorncs", "jonmv"), "2020-12-02", "2021-02-01",
"Whether to automatically trigger reindexing from config change",
"Takes effect on next internal redeployment",
APPLICATION_ID);
+ public static final UnboundDoubleFlag REINDEXER_WINDOW_SIZE_INCREMENT = defineDoubleFlag(
+ "reindexer-window-size-increment", 0.2,
+ List.of("jonmv"), "2020-12-09", "2021-02-07",
+ "Window size increment for dynamic throttle policy used by reindexer visitor session — more means more aggressive reindexing",
+ "Takes effect on (re)deployment",
+ APPLICATION_ID);
+
public static final UnboundBooleanFlag USE_POWER_OF_TWO_CHOICES_LOAD_BALANCING = defineFeatureFlag(
- "use-power-of-two-choices-load-balancing",
- false,
+ "use-power-of-two-choices-load-balancing", false,
+ List.of("tokle"), "2020-12-02", "2021-02-01",
"Whether to use Power of two load balancing algorithm for application",
"Takes effect on next internal redeployment",
APPLICATION_ID);
- public static final UnboundBooleanFlag DYNAMIC_RECONFIGURATION_OF_ZOOKEEPER_CLUSTER = defineFeatureFlag(
- "dynamic-reconfiguration-of-zookeeper-cluster",
- false,
- "Whether to allow dynamic reconfiguration of zookeeper cluster",
- "Takes effect on next deployment",
+ public static final UnboundBooleanFlag RECONFIGURABLE_ZOOKEEPER_SERVER_FOR_CLUSTER_CONTROLLER = defineFeatureFlag(
+ "reconfigurable-zookeeper-server-for-cluster-controller", false,
+ List.of("musum", "mpolden"), "2020-12-16", "2021-02-16",
+ "Whether to use reconfigurable zookeeper server for cluster controller",
+ "Takes effect on (re)redeployment",
APPLICATION_ID);
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, String description,
+ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundBooleanFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundBooleanFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundStringFlag defineStringFlag(String flagId, String defaultValue, String description,
+ public static UnboundStringFlag defineStringFlag(String flagId, String defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundStringFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundStringFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundIntFlag defineIntFlag(String flagId, int defaultValue, String description,
+ public static UnboundIntFlag defineIntFlag(String flagId, int defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundIntFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundIntFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundLongFlag defineLongFlag(String flagId, long defaultValue, String description,
+ public static UnboundLongFlag defineLongFlag(String flagId, long defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundLongFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundLongFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static UnboundDoubleFlag defineDoubleFlag(String flagId, double defaultValue, String description,
+ public static UnboundDoubleFlag defineDoubleFlag(String flagId, double defaultValue, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
- return define(UnboundDoubleFlag::new, flagId, defaultValue, description, modificationEffect, dimensions);
+ return define(UnboundDoubleFlag::new, flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
- public static <T> UnboundJacksonFlag<T> defineJacksonFlag(String flagId, T defaultValue, Class<T> jacksonClass, String description,
+ public static <T> UnboundJacksonFlag<T> defineJacksonFlag(String flagId, T defaultValue, Class<T> jacksonClass, List<String> owners,
+ String createdAt, String expiresAt, String description,
String modificationEffect, FetchVector.Dimension... dimensions) {
return define((id2, defaultValue2, vector2) -> new UnboundJacksonFlag<>(id2, defaultValue2, vector2, jacksonClass),
- flagId, defaultValue, description, modificationEffect, dimensions);
+ flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
public static <T> UnboundListFlag<T> defineListFlag(String flagId, List<T> defaultValue, Class<T> elementClass,
+ List<String> owners, String createdAt, String expiresAt,
String description, String modificationEffect, FetchVector.Dimension... dimensions) {
return define((fid, dval, fvec) -> new UnboundListFlag<>(fid, dval, elementClass, fvec),
- flagId, defaultValue, description, modificationEffect, dimensions);
+ flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions);
}
@FunctionalInterface
@@ -423,6 +372,9 @@ public class Flags {
private static <T, U extends UnboundFlag<?, ?, ?>> U define(TypedUnboundFlagFactory<T, U> factory,
String flagId,
T defaultValue,
+ List<String> owners,
+ String createdAt,
+ String expiresAt,
String description,
String modificationEffect,
FetchVector.Dimension[] dimensions) {
@@ -433,11 +385,16 @@ public class Flags {
// (determined by the current major version). Consider not setting VESPA_VERSION if minor = micro = 0.
.with(VESPA_VERSION, Vtag.currentVersion.toFullString());
U unboundFlag = factory.create(id, defaultValue, vector);
- FlagDefinition definition = new FlagDefinition(unboundFlag, description, modificationEffect, dimensions);
+ FlagDefinition definition = new FlagDefinition(
+ unboundFlag, owners, parseDate(createdAt), parseDate(expiresAt), description, modificationEffect, dimensions);
flags.put(id, definition);
return unboundFlag;
}
+ private static Instant parseDate(String rawDate) {
+ return DateTimeFormatter.ISO_DATE.parse(rawDate, LocalDate::from).atStartOfDay().toInstant(ZoneOffset.UTC);
+ }
+
public static List<FlagDefinition> getAllFlags() {
return List.copyOf(flags.values());
}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
new file mode 100644
index 00000000000..a3e2a11a79c
--- /dev/null
+++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java
@@ -0,0 +1,172 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags;
+
+import com.yahoo.vespa.flags.custom.ClusterCapacity;
+import com.yahoo.vespa.flags.custom.SharedHost;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+import static com.yahoo.vespa.flags.FetchVector.Dimension.APPLICATION_ID;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.CONSOLE_USER_EMAIL;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.HOSTNAME;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.NODE_TYPE;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.TENANT_ID;
+import static com.yahoo.vespa.flags.FetchVector.Dimension.ZONE_ID;
+
+/**
+ * Definition for permanent feature flags
+ *
+ * @author bjorncs
+ */
+public class PermanentFlags {
+
+ static final List<String> OWNERS = List.of();
+ static final Instant CREATED_AT = Instant.EPOCH;
+ static final Instant EXPIRES_AT = ZonedDateTime.of(2100, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant();
+
+ public static final UnboundBooleanFlag USE_ALTERNATIVE_ENDPOINT_CERTIFICATE_PROVIDER = defineFeatureFlag(
+ "use-alternative-endpoint-certificate-provider", false,
+ "Whether to use an alternative CA when provisioning new certificates",
+ "Takes effect only on initial application deployment - not on later certificate refreshes!");
+
+ public static final UnboundStringFlag JVM_GC_OPTIONS = defineStringFlag(
+ "jvm-gc-options", "",
+ "Sets deafult jvm gc options",
+ "Takes effect at redeployment",
+ ZONE_ID, APPLICATION_ID);
+
+ public static final UnboundStringFlag DOCKER_VERSION = defineStringFlag(
+ "docker-version", "1.13.1-102.git7f2769b",
+ "The version of the docker to use of the format VERSION-REL: The YUM package to be installed will be " +
+ "2:docker-VERSION-REL.el7.centos.x86_64 in AWS (and without '.centos' otherwise). " +
+ "If docker-version is not of this format, it must be parseable by YumPackageName::fromString.",
+ "Takes effect on next tick.",
+ HOSTNAME);
+
+ public static final UnboundBooleanFlag FLEET_CANARY = defineFeatureFlag(
+ "fleet-canary", false,
+ "Whether the host is a fleet canary.",
+ "Takes effect on next host admin tick.",
+ HOSTNAME);
+
+ public static final UnboundListFlag<ClusterCapacity> PREPROVISION_CAPACITY = defineListFlag(
+ "preprovision-capacity", List.of(), ClusterCapacity.class,
+ "Specifies the resources that ought to be immediately available for additional cluster " +
+ "allocations. If the resources are not available, additional hosts will be provisioned. " +
+ "Only applies to dynamically provisioned zones.",
+ "Takes effect on next iteration of DynamicProvisioningMaintainer.");
+
+ public static final UnboundIntFlag REBOOT_INTERVAL_IN_DAYS = defineIntFlag(
+ "reboot-interval-in-days", 30,
+ "No reboots are scheduled 0x-1x reboot intervals after the previous reboot, while reboot is " +
+ "scheduled evenly distributed in the 1x-2x range (and naturally guaranteed at the 2x boundary).",
+ "Takes effect on next run of NodeRebooter");
+
+ public static final UnboundJacksonFlag<SharedHost> SHARED_HOST = defineJacksonFlag(
+ "shared-host", SharedHost.createDisabled(), SharedHost.class,
+ "Specifies whether shared hosts can be provisioned, and if so, the advertised " +
+ "node resources of the host, the maximum number of containers, etc.",
+ "Takes effect on next iteration of DynamicProvisioningMaintainer.");
+
+ public static final UnboundBooleanFlag SKIP_MAINTENANCE_DEPLOYMENT = defineFeatureFlag(
+ "node-repository-skip-maintenance-deployment", false,
+ "Whether PeriodicApplicationMaintainer should skip deployment for an application",
+ "Takes effect at next run of maintainer",
+ APPLICATION_ID);
+
+ public static final UnboundListFlag<String> INACTIVE_MAINTENANCE_JOBS = defineListFlag(
+ "inactive-maintenance-jobs", List.of(), String.class,
+ "The list of maintenance jobs that are inactive.",
+ "Takes effect immediately, but any currently running jobs will run until completion.");
+
+ public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV4 = defineListFlag(
+ "container-outbound-blocked-ipv4", List.of(), String.class,
+ "List of IPs or CIDRs that are blocked for outbound connections",
+ "Takes effect on next tick");
+
+ public static final UnboundListFlag<String> OUTBOUND_BLOCKED_IPV6 = defineListFlag(
+ "container-outbound-blocked-ipv6", List.of(), String.class,
+ "List of IPs or CIDRs that are blocked for outbound connections",
+ "Takes effect on next tick");
+
+ public static final UnboundIntFlag TENANT_BUDGET_QUOTA = defineIntFlag(
+ "tenant-budget-quota", -1,
+ "The budget in cents/hr a tenant is allowed spend per instance, as calculated by NodeResources",
+ "Only takes effect on next deployment, if set to a value other than the default for flag!",
+ TENANT_ID);
+
+ public static final UnboundDoubleFlag CONTAINER_CPU_CAP = defineDoubleFlag(
+ "container-cpu-cap", 0,
+ "Hard limit on how many CPUs a container may use. This value is multiplied by CPU allocated to node, so " +
+ "to cap CPU at 200%, set this to 2, etc.",
+ "Takes effect on next node agent tick. Change is orchestrated, but does NOT require container restart",
+ HOSTNAME, APPLICATION_ID);
+
+ public static final UnboundListFlag<String> DISABLED_HOST_ADMIN_TASKS = defineListFlag(
+ "disabled-host-admin-tasks", List.of(), String.class,
+ "List of host-admin task names (as they appear in the log, e.g. root>main>UpgradeTask), or some node-agent " +
+ "functionality (see NodeAgentTask), that should be skipped",
+ "Takes effect on next host admin tick",
+ HOSTNAME, NODE_TYPE);
+
+ public static final UnboundStringFlag DOCKER_IMAGE_REPO = defineStringFlag(
+ "docker-image-repo", "",
+ "Override default docker image repo. Docker image version will be Vespa version.",
+ "Takes effect on next deployment from controller",
+ ZONE_ID, APPLICATION_ID);
+
+ public static final UnboundStringFlag ZOOKEEPER_SERVER_VERSION = defineStringFlag(
+ "zookeeper-server-version", "3.5.6",
+ "ZooKeeper server version, a jar file zookeeper-server-<ZOOKEEPER_SERVER_VERSION>-jar-with-dependencies.jar must exist",
+ "Takes effect on restart of Docker container",
+ NODE_TYPE, APPLICATION_ID, HOSTNAME);
+
+ public static final UnboundBooleanFlag ENABLE_PUBLIC_SIGNUP_FLOW = defineFeatureFlag(
+ "enable-public-signup-flow", false,
+ "Show the public signup flow for a user in the console",
+ "takes effect on browser reload of api/user/v1/user",
+ CONSOLE_USER_EMAIL);
+
+ private PermanentFlags() {}
+
+ private static UnboundBooleanFlag defineFeatureFlag(
+ String flagId, boolean defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineFeatureFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundStringFlag defineStringFlag(
+ String flagId, String defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineStringFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundIntFlag defineIntFlag(
+ String flagId, int defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineIntFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundLongFlag defineLongFlag(
+ String flagId, long defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineLongFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static UnboundDoubleFlag defineDoubleFlag(
+ String flagId, double defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineDoubleFlag(flagId, defaultValue, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static <T> UnboundJacksonFlag<T> defineJacksonFlag(
+ String flagId, T defaultValue, Class<T> jacksonClass, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineJacksonFlag(flagId, defaultValue, jacksonClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static <T> UnboundListFlag<T> defineListFlag(
+ String flagId, List<T> defaultValue, Class<T> elementClass, String description, String modificationEffect, FetchVector.Dimension... dimensions) {
+ return Flags.defineListFlag(flagId, defaultValue, elementClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions);
+ }
+
+ private static String toString(Instant instant) { return DateTimeFormatter.ISO_DATE.withZone(ZoneOffset.UTC).format(instant); }
+}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/ClusterCapacity.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/ClusterCapacity.java
new file mode 100644
index 00000000000..9992d1f9a53
--- /dev/null
+++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/ClusterCapacity.java
@@ -0,0 +1,89 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags.custom;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Objects;
+import java.util.OptionalDouble;
+
+/**
+ * @author freva
+ */
+// @Immutable
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(value = JsonInclude.Include.NON_NULL)
+public class ClusterCapacity {
+ private final int count;
+ private final double vcpu;
+ private final double memoryGb;
+ private final double diskGb;
+ private final OptionalDouble bandwidthGbps;
+
+ @JsonCreator
+ public ClusterCapacity(@JsonProperty("count") int count,
+ @JsonProperty("vcpu") double vcpu,
+ @JsonProperty("memoryGb") double memoryGb,
+ @JsonProperty("diskGb") double diskGb,
+ @JsonProperty("bandwidthGbps") Double bandwidthGbps) {
+ this.count = (int) requireNonNegative("count", count);
+ this.vcpu = requireNonNegative("vcpu", vcpu);
+ this.memoryGb = requireNonNegative("memoryGb", memoryGb);
+ this.diskGb = requireNonNegative("diskGb", diskGb);
+ this.bandwidthGbps = bandwidthGbps == null ? OptionalDouble.empty() : OptionalDouble.of(bandwidthGbps);
+ }
+
+ /** Returns a new ClusterCapacity equal to {@code this}, but with the given count. */
+ public ClusterCapacity withCount(int count) {
+ return new ClusterCapacity(count, vcpu, memoryGb, diskGb, bandwidthGbpsOrNull());
+ }
+
+ @JsonGetter("count") public int count() { return count; }
+ @JsonGetter("vcpu") public double vcpu() { return vcpu; }
+ @JsonGetter("memoryGb") public double memoryGb() { return memoryGb; }
+ @JsonGetter("diskGb") public double diskGb() { return diskGb; }
+ @JsonGetter("bandwidthGbps") public Double bandwidthGbpsOrNull() {
+ return bandwidthGbps.isPresent() ? bandwidthGbps.getAsDouble() : null;
+ }
+
+ @JsonIgnore
+ public double bandwidthGbps() { return bandwidthGbps.orElse(1.0); }
+
+ @Override
+ public String toString() {
+ return "ClusterCapacity{" +
+ "count=" + count +
+ ", vcpu=" + vcpu +
+ ", memoryGb=" + memoryGb +
+ ", diskGb=" + diskGb +
+ ", bandwidthGbps=" + bandwidthGbps +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ClusterCapacity that = (ClusterCapacity) o;
+ return count == that.count &&
+ Double.compare(that.vcpu, vcpu) == 0 &&
+ Double.compare(that.memoryGb, memoryGb) == 0 &&
+ Double.compare(that.diskGb, diskGb) == 0 &&
+ bandwidthGbps.equals(that.bandwidthGbps);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(count, vcpu, memoryGb, diskGb, bandwidthGbps);
+ }
+
+ private static double requireNonNegative(String name, double value) {
+ if (value < 0)
+ throw new IllegalArgumentException("'" + name + "' must be positive, was " + value);
+ return value;
+ }
+}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostCapacity.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/HostCapacity.java
deleted file mode 100644
index 947520ca2d7..00000000000
--- a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostCapacity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.flags.custom;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.Objects;
-
-/**
- * @author freva
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class HostCapacity {
- @JsonProperty("vcpu")
- private final double vcpu;
-
- @JsonProperty("memoryGb")
- private final double memoryGb;
-
- @JsonProperty("diskGb")
- private final double diskGb;
-
- @JsonProperty("count")
- private final int count;
-
- public HostCapacity(@JsonProperty("vcpu") double vcpu,
- @JsonProperty("memoryGb") double memoryGb,
- @JsonProperty("diskGb") double diskGb,
- @JsonProperty("count") int count) {
- this.vcpu = requirePositive("vcpu", vcpu);
- this.memoryGb = requirePositive("memoryGb", memoryGb);
- this.diskGb = requirePositive("diskGb", diskGb);
- this.count = (int) requirePositive("count", count);
- }
-
- public double getVcpu() {
- return vcpu;
- }
-
- public double getMemoryGb() {
- return memoryGb;
- }
-
- public double getDiskGb() {
- return diskGb;
- }
-
- public int getCount() {
- return count;
- }
-
- private static double requirePositive(String name, double value) {
- if (value <= 0)
- throw new IllegalArgumentException("'" + name + "' must be positive, was " + value);
- return value;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- HostCapacity that = (HostCapacity) o;
- return Double.compare(that.vcpu, vcpu) == 0 &&
- Double.compare(that.memoryGb, memoryGb) == 0 &&
- Double.compare(that.diskGb, diskGb) == 0 &&
- count == that.count;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(vcpu, memoryGb, diskGb, count);
- }
-}
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
index c0b5d7a523c..129e1020b04 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/HostResources.java
@@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
/**
@@ -45,7 +44,7 @@ public class HostResources {
this.vcpu = requirePositive("vcpu", vcpu);
this.memoryGb = requirePositive("memoryGb", memoryGb);
this.diskGb = requirePositive("diskGb", diskGb);
- this.bandwidthGbps = requirePositive("bandwidthGbps", Optional.ofNullable(bandwidthGbps).orElse(0.3));
+ this.bandwidthGbps = requirePositive("bandwidthGbps", bandwidthGbps);
this.diskSpeed = validateEnum("diskSpeed", validDiskSpeeds, diskSpeed);
this.storageType = validateEnum("storageType", validStorageTypes, storageType);
this.containers = requirePositive("containers", containers);
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
index e463159eb8f..c952161cf72 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/custom/SharedHost.java
@@ -2,46 +2,68 @@
package com.yahoo.vespa.flags.custom;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import java.util.List;
import java.util.Objects;
/**
- * Defines properties related to shared hosts, see {@link Flags#SHARED_HOST}.
+ * Defines properties related to shared hosts, see {@link PermanentFlags#SHARED_HOST}.
*
* @author hakon
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class SharedHost {
+ private final int DEFAULT_MIN_COUNT = 0;
+
private final List<HostResources> resources;
+ private final int minCount;
public static SharedHost createDisabled() {
- return new SharedHost(null);
+ return new SharedHost(null, null);
}
+ /**
+ * @param resourcesOrNull the resources of the shared host (or several to support e.g. tiers or
+ * fast/slow disks separately)
+ * @param minCountOrNull the minimum number of shared hosts
+ */
@JsonCreator
- public SharedHost(@JsonProperty("resources") List<HostResources> resources) {
- this.resources = resources == null ? List.of() : List.copyOf(resources);
+ public SharedHost(@JsonProperty("resources") List<HostResources> resourcesOrNull,
+ @JsonProperty("min-count") Integer minCountOrNull) {
+ this.resources = resourcesOrNull == null ? List.of() : List.copyOf(resourcesOrNull);
+ this.minCount = requireNonNegative(minCountOrNull, DEFAULT_MIN_COUNT, "min-count");
}
- @JsonProperty("resources")
+ @JsonGetter("resources")
public List<HostResources> getResourcesOrNull() {
return resources.isEmpty() ? null : resources;
}
+ @JsonGetter("min-count")
+ public Integer getMinCountOrNull() {
+ return minCount == DEFAULT_MIN_COUNT ? null : minCount;
+ }
+
+ @JsonIgnore
+ public boolean isEnabled() {
+ return resources.size() > 0;
+ }
+
@JsonIgnore
public List<HostResources> getHostResources() {
return resources;
}
- public boolean isEnabled() {
- return resources.size() > 0;
+ @JsonIgnore
+ public int getMinCount() {
+ return minCount;
}
@Override
@@ -61,4 +83,16 @@ public class SharedHost {
public int hashCode() {
return Objects.hash(resources);
}
+
+ private int requireNonNegative(Integer integerOrNull, int defaultValue, String fieldName) {
+ if (integerOrNull == null) {
+ return defaultValue;
+ }
+
+ if (integerOrNull < 0) {
+ throw new IllegalArgumentException(fieldName + " cannot be negative");
+ }
+
+ return integerOrNull;
+ }
}
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java b/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java
index 28e84bcf3e5..48ed318af41 100644
--- a/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java
+++ b/flags/src/test/java/com/yahoo/vespa/flags/FlagsTest.java
@@ -4,8 +4,6 @@ package com.yahoo.vespa.flags;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.node.BooleanNode;
-import com.yahoo.vespa.flags.custom.HostResources;
-import com.yahoo.vespa.flags.custom.SharedHost;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -34,7 +32,7 @@ public class FlagsTest {
public void testBoolean() {
final boolean defaultValue = false;
FlagSource source = mock(FlagSource.class);
- BooleanFlag booleanFlag = Flags.defineFeatureFlag("id", defaultValue, "description",
+ BooleanFlag booleanFlag = Flags.defineFeatureFlag("id", defaultValue, List.of("owner"), "1970-01-01", "2100-01-01", "description",
"modification effect", FetchVector.Dimension.ZONE_ID, FetchVector.Dimension.HOSTNAME)
.with(FetchVector.Dimension.ZONE_ID, "a-zone")
.bindTo(source);
@@ -69,29 +67,29 @@ public class FlagsTest {
@Test
public void testString() {
- testGeneric(Flags.defineStringFlag("string-id", "default value", "description",
+ testGeneric(Flags.defineStringFlag("string-id", "default value", List.of("owner"), "1970-01-01", "2100-01-01", "description",
"modification effect", FetchVector.Dimension.ZONE_ID, FetchVector.Dimension.HOSTNAME),
"other value");
}
@Test
public void testInt() {
- testGeneric(Flags.defineIntFlag("int-id", 2, "desc", "mod"), 3);
+ testGeneric(Flags.defineIntFlag("int-id", 2, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 3);
}
@Test
public void testLong() {
- testGeneric(Flags.defineLongFlag("long-id", 1L, "desc", "mod"), 2L);
+ testGeneric(Flags.defineLongFlag("long-id", 1L, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 2L);
}
@Test
public void testDouble() {
- testGeneric(Flags.defineDoubleFlag("double-id", 3.142, "desc", "mod"), 2.718);
+ testGeneric(Flags.defineDoubleFlag("double-id", 3.142, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), 2.718);
}
@Test
public void testList() {
- testGeneric(Flags.defineListFlag("list-id", List.of("a"), String.class, "desc", "mod"), List.of("a", "b", "c"));
+ testGeneric(Flags.defineListFlag("list-id", List.of("a"), String.class, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"), List.of("a", "b", "c"));
}
@Test
@@ -102,23 +100,14 @@ public class FlagsTest {
instance.string = "foo";
testGeneric(Flags.defineJacksonFlag("jackson-id", defaultInstance, ExampleJacksonClass.class,
- "description", "modification effect", FetchVector.Dimension.HOSTNAME),
+ List.of("owner"), "1970-01-01", "2100-01-01", "description", "modification effect", FetchVector.Dimension.HOSTNAME),
instance);
- testGeneric(Flags.defineListFlag("jackson-list-id", List.of(defaultInstance), ExampleJacksonClass.class, "desc", "mod"),
+ testGeneric(Flags.defineListFlag("jackson-list-id", List.of(defaultInstance), ExampleJacksonClass.class, List.of("owner"), "1970-01-01", "2100-01-01", "desc", "mod"),
List.of(instance));
}
- @Test
- public void testSharedHostFlag() {
- SharedHost sharedHost = new SharedHost(List.of(new HostResources(
- 4.0, 16.0, 50.0, null,
- "fast", "local",
- 10)));
- testGeneric(Flags.SHARED_HOST, sharedHost);
- }
-
- private <T> void testGeneric(UnboundFlag<T, ?, ?> unboundFlag, T value) {
+ static <T> void testGeneric(UnboundFlag<T, ?, ?> unboundFlag, T value) {
FlagSource source = mock(FlagSource.class);
Flag<T, ?> flag = unboundFlag.bindTo(source);
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java b/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java
new file mode 100644
index 00000000000..3f43682cfb9
--- /dev/null
+++ b/flags/src/test/java/com/yahoo/vespa/flags/PermanentFlagsTest.java
@@ -0,0 +1,25 @@
+package com.yahoo.vespa.flags;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.yahoo.vespa.flags.custom.HostResources;
+import com.yahoo.vespa.flags.custom.SharedHost;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static com.yahoo.vespa.flags.FlagsTest.testGeneric;
+
+/**
+ * @author bjorncs
+ */
+class PermanentFlagsTest {
+ @Test
+ public void testSharedHostFlag() {
+ SharedHost sharedHost = new SharedHost(List.of(new HostResources(
+ 4.0, 16.0, 50.0, 0.3,
+ "fast", "local",
+ 10)),
+ null);
+ testGeneric(PermanentFlags.SHARED_HOST, sharedHost);
+ }
+
+} \ No newline at end of file
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/custom/ClusterCapacityTest.java b/flags/src/test/java/com/yahoo/vespa/flags/custom/ClusterCapacityTest.java
new file mode 100644
index 00000000000..0258b562897
--- /dev/null
+++ b/flags/src/test/java/com/yahoo/vespa/flags/custom/ClusterCapacityTest.java
@@ -0,0 +1,41 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags.custom;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+public class ClusterCapacityTest {
+ @Test
+ public void serialization() throws IOException {
+ ClusterCapacity clusterCapacity = new ClusterCapacity(7, 1.2, 3.4, 5.6, null);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(clusterCapacity);
+ assertEquals("{\"count\":7,\"vcpu\":1.2,\"memoryGb\":3.4,\"diskGb\":5.6}", json);
+
+ ClusterCapacity deserialized = mapper.readValue(json, ClusterCapacity.class);
+ assertEquals(1.2, deserialized.vcpu(), 0.0001);
+ assertEquals(3.4, deserialized.memoryGb(), 0.0001);
+ assertEquals(5.6, deserialized.diskGb(), 0.0001);
+ assertEquals(1.0, deserialized.bandwidthGbps(), 0.0001);
+ assertEquals(7, deserialized.count());
+ }
+
+ @Test
+ public void serialization2() throws IOException {
+ ClusterCapacity clusterCapacity = new ClusterCapacity(7, 1.2, 3.4, 5.6, 2.3);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(clusterCapacity);
+ assertEquals("{\"count\":7,\"vcpu\":1.2,\"memoryGb\":3.4,\"diskGb\":5.6,\"bandwidthGbps\":2.3}", json);
+
+ ClusterCapacity deserialized = mapper.readValue(json, ClusterCapacity.class);
+ assertEquals(1.2, deserialized.vcpu(), 0.0001);
+ assertEquals(3.4, deserialized.memoryGb(), 0.0001);
+ assertEquals(5.6, deserialized.diskGb(), 0.0001);
+ assertEquals(2.3, deserialized.bandwidthGbps(), 0.0001);
+ assertEquals(7, deserialized.count());
+ }
+} \ No newline at end of file
diff --git a/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java b/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java
new file mode 100644
index 00000000000..f0a11f244a4
--- /dev/null
+++ b/flags/src/test/java/com/yahoo/vespa/flags/custom/SharedHostTest.java
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.flags.custom;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class SharedHostTest {
+ @Test
+ public void serialization() throws IOException {
+ verifySerialization(new SharedHost(List.of(new HostResources(1.0, 2.0, 3.0, 4.0, "fast", "remote", 5)), 6));
+ verifySerialization(new SharedHost(List.of(new HostResources(1.0, 2.0, 3.0, 4.0, "fast", "remote", 5)), null));
+ }
+
+ private void verifySerialization(SharedHost sharedHost) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(sharedHost);
+ SharedHost deserialized = mapper.readValue(json, SharedHost.class);
+ assertEquals(sharedHost, deserialized);
+ }
+} \ No newline at end of file
diff --git a/fnet/src/examples/frt/rpc/echo_client.cpp b/fnet/src/examples/frt/rpc/echo_client.cpp
index 06f4ef0ee5b..bb2ef66c6fa 100644
--- a/fnet/src/examples/frt/rpc/echo_client.cpp
+++ b/fnet/src/examples/frt/rpc/echo_client.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
diff --git a/fnet/src/examples/frt/rpc/rpc_callback_client.cpp b/fnet/src/examples/frt/rpc/rpc_callback_client.cpp
index 726a500cc55..c63352d8f24 100644
--- a/fnet/src/examples/frt/rpc/rpc_callback_client.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_callback_client.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
diff --git a/fnet/src/examples/frt/rpc/rpc_callback_server.cpp b/fnet/src/examples/frt/rpc/rpc_callback_server.cpp
index 872894b190d..9832a59abad 100644
--- a/fnet/src/examples/frt/rpc/rpc_callback_server.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_callback_server.cpp
@@ -1,6 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/signalshutdown.h>
+#include <vespa/fnet/transport.h>
+
#include <vespa/fastos/app.h>
#include <thread>
diff --git a/fnet/src/examples/frt/rpc/rpc_client.cpp b/fnet/src/examples/frt/rpc/rpc_client.cpp
index fc1d54d3440..1c634f4b704 100644
--- a/fnet/src/examples/frt/rpc/rpc_client.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_client.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
diff --git a/fnet/src/examples/frt/rpc/rpc_info.cpp b/fnet/src/examples/frt/rpc/rpc_info.cpp
index d90d22d1986..0f8b8422241 100644
--- a/fnet/src/examples/frt/rpc/rpc_info.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_info.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
diff --git a/fnet/src/examples/frt/rpc/rpc_invoke.cpp b/fnet/src/examples/frt/rpc/rpc_invoke.cpp
index fb82622a537..d1f35429352 100644
--- a/fnet/src/examples/frt/rpc/rpc_invoke.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_invoke.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/fastos/app.h>
#include <vespa/vespalib/locale/c.h>
diff --git a/fnet/src/examples/frt/rpc/rpc_proxy.cpp b/fnet/src/examples/frt/rpc/rpc_proxy.cpp
index a61e2d37197..93076344ce2 100644
--- a/fnet/src/examples/frt/rpc/rpc_proxy.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_proxy.cpp
@@ -1,6 +1,14 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/invoker.h>
+#include <vespa/fnet/channel.h>
+#include <vespa/fnet/transport_thread.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/signalshutdown.h>
+
#include <vespa/fastos/app.h>
#include <chrono>
@@ -15,12 +23,10 @@ struct Session
uint32_t id;
uint32_t finiCnt;
- Session(uint32_t xid) : client(nullptr), server(nullptr), id(xid), finiCnt(0) {}
+ explicit Session(uint32_t xid) : client(nullptr), server(nullptr), id(xid), finiCnt(0) {}
~Session() { assert(client == nullptr && server == nullptr && finiCnt == 2); }
-
-private:
- Session(const Session &);
- Session &operator=(const Session &);
+ Session(const Session &) = delete;
+ Session &operator=(const Session &) = delete;
};
//-----------------------------------------------------------------------------
@@ -34,10 +40,9 @@ private:
uint32_t _currID;
char _prefixStr[256];
- RPCProxy(const RPCProxy &);
- RPCProxy &operator=(const RPCProxy &);
-
public:
+ RPCProxy(const RPCProxy &) = delete;
+ RPCProxy &operator=(const RPCProxy &) = delete;
RPCProxy(FRT_Supervisor &supervisor,
const char *spec,
bool verbose)
@@ -69,7 +74,7 @@ private:
RPCProxy &_proxy;
public:
- ReqDone(RPCProxy &proxy) : _proxy(proxy) {}
+ explicit ReqDone(RPCProxy &proxy) : _proxy(proxy) {}
void RequestDone(FRT_RPCRequest *req) override;
};
diff --git a/fnet/src/examples/frt/rpc/rpc_server.cpp b/fnet/src/examples/frt/rpc/rpc_server.cpp
index aa521080538..4333f182cc0 100644
--- a/fnet/src/examples/frt/rpc/rpc_server.cpp
+++ b/fnet/src/examples/frt/rpc/rpc_server.cpp
@@ -1,6 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/signalshutdown.h>
+#include <vespa/fnet/transport.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
diff --git a/fnet/src/examples/ping/packets.cpp b/fnet/src/examples/ping/packets.cpp
index e5e9f645c9a..6aa54838c8b 100644
--- a/fnet/src/examples/ping/packets.cpp
+++ b/fnet/src/examples/ping/packets.cpp
@@ -1,7 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
#include "packets.h"
+#include <vespa/fnet/databuffer.h>
uint32_t
PingRequest::GetPCODE()
diff --git a/fnet/src/examples/ping/pingclient.cpp b/fnet/src/examples/ping/pingclient.cpp
index 1d65ef3b69c..6a7bd21e715 100644
--- a/fnet/src/examples/ping/pingclient.cpp
+++ b/fnet/src/examples/ping/pingclient.cpp
@@ -1,8 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/simplepacketstreamer.h>
+#include <vespa/fnet/channel.h>
+#include <vespa/fnet/connection.h>
#include <examples/ping/packets.h>
#include <vespa/fastos/app.h>
+#include <vespa/fastos/thread.h>
#include <vespa/log/log.h>
LOG_SETUP("pingclient");
diff --git a/fnet/src/examples/ping/pingserver.cpp b/fnet/src/examples/ping/pingserver.cpp
index c4543134912..cb0ab02aa0d 100644
--- a/fnet/src/examples/ping/pingserver.cpp
+++ b/fnet/src/examples/ping/pingserver.cpp
@@ -1,6 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/signalshutdown.h>
+#include <vespa/fnet/simplepacketstreamer.h>
+#include <vespa/fnet/channel.h>
+#include <vespa/fnet/iserveradapter.h>
+#include <vespa/fnet/connector.h>
#include <examples/ping/packets.h>
#include <vespa/fastos/app.h>
diff --git a/fnet/src/examples/proxy/proxy.cpp b/fnet/src/examples/proxy/proxy.cpp
index a01a16ead9c..062a0d52627 100644
--- a/fnet/src/examples/proxy/proxy.cpp
+++ b/fnet/src/examples/proxy/proxy.cpp
@@ -1,6 +1,14 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/transport_thread.h>
+#include <vespa/fnet/connection.h>
+#include <vespa/fnet/signalshutdown.h>
+#include <vespa/fnet/packet.h>
+#include <vespa/fnet/iserveradapter.h>
+#include <vespa/fnet/ipacketstreamer.h>
+#include <vespa/fnet/channel.h>
+#include <vespa/fnet/connector.h>
#include <vespa/fastos/app.h>
#include <vespa/log/log.h>
@@ -140,7 +148,7 @@ private:
public:
Proxy() : _transport() {}
- ~Proxy() { }
+ ~Proxy() override { }
bool GetPacketInfo(FNET_DataBuffer *src, uint32_t *plen, uint32_t *pcode, uint32_t *chid, bool *) override;
FNET_Packet *Decode(FNET_DataBuffer *src, uint32_t plen, uint32_t pcode, FNET_Context) override;
void Encode(FNET_Packet *packet, uint32_t chid, FNET_DataBuffer *dst) override;
diff --git a/fnet/src/examples/timeout/timeout.cpp b/fnet/src/examples/timeout/timeout.cpp
index 23dfbeb9070..9f363ccd864 100644
--- a/fnet/src/examples/timeout/timeout.cpp
+++ b/fnet/src/examples/timeout/timeout.cpp
@@ -1,7 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/signalshutdown.h>
+#include <vespa/fnet/packetqueue.h>
+#include <vespa/fnet/controlpacket.h>
#include <vespa/fastos/app.h>
+#include <vespa/fastos/thread.h>
#include <vespa/vespalib/util/time.h>
#include <thread>
diff --git a/fnet/src/tests/connect/connect_test.cpp b/fnet/src/tests/connect/connect_test.cpp
index 3fe7b5b7614..2b4a2bbe9f0 100644
--- a/fnet/src/tests/connect/connect_test.cpp
+++ b/fnet/src/tests/connect/connect_test.cpp
@@ -1,7 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/transport_thread.h>
+#include <vespa/fnet/simplepacketstreamer.h>
+#include <vespa/fnet/ipackethandler.h>
+#include <vespa/fnet/connection.h>
+#include <vespa/fnet/controlpacket.h>
#include <vespa/vespalib/net/server_socket.h>
#include <vespa/vespalib/net/crypto_engine.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -90,13 +95,13 @@ struct TransportFixture : FNET_IPacketHandler, FNET_IConnectionCleanupHandler {
transport.Start(&pool);
}
TransportFixture(AsyncResolver::HostResolver::SP host_resolver)
- : streamer(nullptr), pool(128 * 1024), transport(make_resolver(std::move(host_resolver)), 1),
+ : streamer(nullptr), pool(128 * 1024), transport(TransportConfig().resolver(make_resolver(std::move(host_resolver)))),
conn_lost(), conn_deleted()
{
transport.Start(&pool);
}
TransportFixture(CryptoEngine::SP crypto)
- : streamer(nullptr), pool(128 * 1024), transport(crypto, 1),
+ : streamer(nullptr), pool(128 * 1024), transport(TransportConfig().crypto(std::move(crypto))),
conn_lost(), conn_deleted()
{
transport.Start(&pool);
@@ -114,7 +119,7 @@ struct TransportFixture : FNET_IPacketHandler, FNET_IConnectionCleanupHandler {
conn->SetCleanupHandler(this);
return conn;
}
- ~TransportFixture() {
+ ~TransportFixture() override {
transport.ShutDown(true);
pool.Close();
}
diff --git a/fnet/src/tests/connection_spread/connection_spread_test.cpp b/fnet/src/tests/connection_spread/connection_spread_test.cpp
index 11120ebc3dc..caeb4211ab2 100644
--- a/fnet/src/tests/connection_spread/connection_spread_test.cpp
+++ b/fnet/src/tests/connection_spread/connection_spread_test.cpp
@@ -1,6 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fnet/transport_thread.h>
+#include <vespa/fnet/iserveradapter.h>
+#include <vespa/fnet/ipacketstreamer.h>
+#include <vespa/fnet/connector.h>
+#include <vespa/fnet/connection.h>
+#include <vespa/fastos/thread.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <thread>
#include <chrono>
diff --git a/fnet/src/tests/frt/method_pt/method_pt.cpp b/fnet/src/tests/frt/method_pt/method_pt.cpp
index 53960d73466..450731fe1aa 100644
--- a/fnet/src/tests/frt/method_pt/method_pt.cpp
+++ b/fnet/src/tests/frt/method_pt/method_pt.cpp
@@ -1,8 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/fnet/frt/frt.h>
-
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
class Test;
class SimpleHandler;
diff --git a/fnet/src/tests/frt/parallel_rpc/parallel_rpc_test.cpp b/fnet/src/tests/frt/parallel_rpc/parallel_rpc_test.cpp
index ed4911175a0..2577b4e6155 100644
--- a/fnet/src/tests/frt/parallel_rpc/parallel_rpc_test.cpp
+++ b/fnet/src/tests/frt/parallel_rpc/parallel_rpc_test.cpp
@@ -1,7 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/transport.h>
+#include <vespa/fastos/thread.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/vespalib/net/crypto_engine.h>
#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
@@ -15,7 +18,7 @@ struct Rpc : FRT_Invokable {
FNET_Transport transport;
FRT_Supervisor orb;
Rpc(CryptoEngine::SP crypto, size_t num_threads)
- : thread_pool(128 * 1024), transport(crypto, num_threads), orb(&transport) {}
+ : thread_pool(128 * 1024), transport(TransportConfig(num_threads).crypto(std::move(crypto))), orb(&transport) {}
void start() {
ASSERT_TRUE(transport.Start(&thread_pool));
}
@@ -26,7 +29,7 @@ struct Rpc : FRT_Invokable {
FRT_Target *connect(uint32_t port) {
return orb.GetTarget(port);
}
- ~Rpc() {
+ ~Rpc() override {
transport.ShutDown(true);
thread_pool.Close();
}
@@ -34,7 +37,7 @@ struct Rpc : FRT_Invokable {
struct Server : Rpc {
uint32_t port;
- Server(CryptoEngine::SP crypto, size_t num_threads) : Rpc(crypto, num_threads), port(listen()) {
+ Server(CryptoEngine::SP crypto, size_t num_threads) : Rpc(std::move(crypto), num_threads), port(listen()) {
init_rpc();
start();
}
@@ -54,7 +57,7 @@ struct Server : Rpc {
struct Client : Rpc {
uint32_t port;
- Client(CryptoEngine::SP crypto, size_t num_threads, const Server &server) : Rpc(crypto, num_threads), port(server.port) {
+ Client(CryptoEngine::SP crypto, size_t num_threads, const Server &server) : Rpc(std::move(crypto), num_threads), port(server.port) {
start();
}
FRT_Target *connect() { return Rpc::connect(port); }
@@ -62,7 +65,7 @@ struct Client : Rpc {
struct Result {
std::vector<double> req_per_sec;
- Result(size_t num_threads) : req_per_sec(num_threads, 0.0) {}
+ explicit Result(size_t num_threads) : req_per_sec(num_threads, 0.0) {}
double throughput() const {
double sum = 0.0;
for (double sample: req_per_sec) {
diff --git a/fnet/src/tests/frt/parallel_rpc/tls_rpc_bench.cpp b/fnet/src/tests/frt/parallel_rpc/tls_rpc_bench.cpp
index cdb2636a8c1..8a954db26e0 100644
--- a/fnet/src/tests/frt/parallel_rpc/tls_rpc_bench.cpp
+++ b/fnet/src/tests/frt/parallel_rpc/tls_rpc_bench.cpp
@@ -6,7 +6,9 @@
#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
#include <vespa/vespalib/test/make_tls_options_for_testing.h>
#include <vespa/vespalib/test/time_tracer.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <thread>
#include <chrono>
diff --git a/fnet/src/tests/frt/rpc/detach_return_invoke.cpp b/fnet/src/tests/frt/rpc/detach_return_invoke.cpp
index 95dbe672909..68bd58d2f82 100644
--- a/fnet/src/tests/frt/rpc/detach_return_invoke.cpp
+++ b/fnet/src/tests/frt/rpc/detach_return_invoke.cpp
@@ -1,6 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/invoker.h>
#include <vespa/vespalib/util/stringfmt.h>
struct Receptor : public FRT_IRequestWait
diff --git a/fnet/src/tests/frt/rpc/invoke.cpp b/fnet/src/tests/frt/rpc/invoke.cpp
index 410a60fa08a..bd2f6fa9e1d 100644
--- a/fnet/src/tests/frt/rpc/invoke.cpp
+++ b/fnet/src/tests/frt/rpc/invoke.cpp
@@ -3,7 +3,10 @@
#include <vespa/vespalib/net/socket_spec.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/vespalib/util/latch.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/invoker.h>
#include <mutex>
#include <condition_variable>
@@ -25,7 +28,7 @@ private:
vespalib::Latch<FRT_RPCRequest*> _latch;
public:
RequestLatch() : _latch() {}
- ~RequestLatch() { ASSERT_TRUE(!has_req()); }
+ ~RequestLatch() override { ASSERT_TRUE(!has_req()); }
bool has_req() { return _latch.has_value(); }
FRT_RPCRequest *read() { return _latch.read(); }
void write(FRT_RPCRequest *req) { _latch.write(req); }
@@ -38,8 +41,8 @@ class MyReq {
private:
FRT_RPCRequest *_req;
public:
- MyReq(FRT_RPCRequest *req) : _req(req) {}
- MyReq(const char *method_name)
+ explicit MyReq(FRT_RPCRequest *req) : _req(req) {}
+ explicit MyReq(const char *method_name)
: _req(new FRT_RPCRequest())
{
_req->SetMethodName(method_name);
@@ -270,8 +273,6 @@ public:
_testRPC(&_server.supervisor()),
_echoTest(&_server.supervisor())
{
- _client.supervisor().GetTransport()->SetTCPNoDelay(true);
- _server.supervisor().GetTransport()->SetTCPNoDelay(true);
ASSERT_TRUE(_server.supervisor().Listen("tcp/0"));
_peerSpec = SocketSpec::from_host_port("localhost", _server.supervisor().GetListenPort()).spec();
_target = _client.supervisor().GetTarget(_peerSpec.c_str());
diff --git a/fnet/src/tests/frt/rpc/session.cpp b/fnet/src/tests/frt/rpc/session.cpp
index 24cbedb3ff7..b96c881ba27 100644
--- a/fnet/src/tests/frt/rpc/session.cpp
+++ b/fnet/src/tests/frt/rpc/session.cpp
@@ -1,7 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <mutex>
//-------------------------------------------------------------
diff --git a/fnet/src/tests/frt/rpc/sharedblob.cpp b/fnet/src/tests/frt/rpc/sharedblob.cpp
index 1c0503454c7..09297bbf1c3 100644
--- a/fnet/src/tests/frt/rpc/sharedblob.cpp
+++ b/fnet/src/tests/frt/rpc/sharedblob.cpp
@@ -1,7 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vector>
constexpr size_t ALLOC_LIMIT=1024;
diff --git a/fnet/src/tests/info/info.cpp b/fnet/src/tests/info/info.cpp
index 1d26f2b0fa1..3422efe1da6 100644
--- a/fnet/src/tests/info/info.cpp
+++ b/fnet/src/tests/info/info.cpp
@@ -1,6 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/channel.h>
+#include <vespa/fnet/info.h>
#include <mutex>
#include <condition_variable>
diff --git a/fnet/src/tests/locking/castspeed.cpp b/fnet/src/tests/locking/castspeed.cpp
index dc82073ea57..2f784e625be 100644
--- a/fnet/src/tests/locking/castspeed.cpp
+++ b/fnet/src/tests/locking/castspeed.cpp
@@ -1,6 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
#include <chrono>
class B;
diff --git a/fnet/src/tests/locking/drainpackets.cpp b/fnet/src/tests/locking/drainpackets.cpp
index 9db43a5eb52..2d0ab6e2808 100644
--- a/fnet/src/tests/locking/drainpackets.cpp
+++ b/fnet/src/tests/locking/drainpackets.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/packetqueue.h>
+#include <vespa/fnet/packet.h>
#include <mutex>
#include <chrono>
diff --git a/fnet/src/tests/locking/lockspeed.cpp b/fnet/src/tests/locking/lockspeed.cpp
index ae6b983d724..a3ab48edd22 100644
--- a/fnet/src/tests/locking/lockspeed.cpp
+++ b/fnet/src/tests/locking/lockspeed.cpp
@@ -1,6 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
#include "dummy.h"
#include <chrono>
diff --git a/fnet/src/tests/scheduling/schedule.cpp b/fnet/src/tests/scheduling/schedule.cpp
index a1b02a688bf..55fe4c16398 100644
--- a/fnet/src/tests/scheduling/schedule.cpp
+++ b/fnet/src/tests/scheduling/schedule.cpp
@@ -1,12 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/scheduler.h>
+#include <vespa/fnet/task.h>
-using my_clock = FNET_Scheduler::clock;
-using time_point = my_clock::time_point;
+using vespalib::steady_clock;
+using vespalib::steady_time;
using ms_double = std::chrono::duration<double, std::milli>;
-time_point _time;
+steady_time _time;
FNET_Scheduler *_scheduler;
template <class Rep, class Period>
@@ -22,11 +23,11 @@ int as_ms(std::chrono::time_point<Clock,Duration> time) {
class MyTask : public FNET_Task
{
public:
- time_point _time;
+ steady_time _time;
int _target;
bool _done;
- MyTask(int target)
+ explicit MyTask(int target)
: FNET_Task(::_scheduler),
_time(),
_target(target),
@@ -79,7 +80,7 @@ public:
TEST("schedule") {
- _time = time_point(std::chrono::milliseconds(0));
+ _time = steady_time(vespalib::duration::zero());
_scheduler = new FNET_Scheduler(&_time, &_time);
RealTimeTask rt_task1;
@@ -97,25 +98,25 @@ TEST("schedule") {
assert(tasks[i] != nullptr);
}
- time_point start;
+ steady_time start;
ms_double ms;
- start = my_clock::now();
+ start = steady_clock::now();
for (uint32_t j = 0; j < taskCnt; j++) {
tasks[j]->Schedule(tasks[j]->GetTarget() / 1000.0);
}
- ms = (my_clock::now() - start);
+ ms = (steady_clock::now() - start);
double scheduleTime = ms.count() / (double)taskCnt;
fprintf(stderr, "scheduling cost: %1.2f microseconds\n", scheduleTime * 1000.0);
- start = my_clock::now();
+ start = steady_clock::now();
uint32_t tickCnt = 0;
while (as_ms(_time) < 135000.0) {
_time += FNET_Scheduler::tick_ms;
_scheduler->CheckTasks();
tickCnt++;
}
- ms = (my_clock::now() - start);
+ ms = (steady_clock::now() - start);
fprintf(stderr, "3 RT tasks + %d one-shot tasks over 135s\n", taskCnt);
fprintf(stderr, "%1.2f seconds actual run time\n", ms.count() / 1000.0);
fprintf(stderr, "%1.2f tasks per simulated second\n", (double)taskCnt / (double)135);
diff --git a/fnet/src/tests/scheduling/sloweventloop.cpp b/fnet/src/tests/scheduling/sloweventloop.cpp
index 5ddc9b1502c..33070aa29e9 100644
--- a/fnet/src/tests/scheduling/sloweventloop.cpp
+++ b/fnet/src/tests/scheduling/sloweventloop.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/scheduler.h>
+#include <vespa/fnet/task.h>
class MyTask : public FNET_Task
{
@@ -17,14 +18,14 @@ public:
TEST("slow event loop") {
- FNET_Scheduler::time_point t(std::chrono::milliseconds(0));
+ vespalib::steady_time t(vespalib::duration::zero());
FNET_Scheduler scheduler(&t, &t);
MyTask task(scheduler);
MyTask task2(scheduler);
scheduler.CheckTasks();
- t += std::chrono::milliseconds(10000);
+ t += 10s;
task.Schedule(5.0);
uint32_t cnt = 0;
@@ -34,7 +35,7 @@ TEST("slow event loop") {
break;
}
++cnt;
- t += std::chrono::milliseconds(1);
+ t += 1ms;
}
if (!EXPECT_TRUE(cnt > 4700 && cnt < 4800)) {
@@ -42,7 +43,7 @@ TEST("slow event loop") {
}
scheduler.CheckTasks();
- t += std::chrono::milliseconds(10000);
+ t += 10s;
task2.Schedule(5.0);
uint32_t cnt2 = 0;
@@ -52,7 +53,7 @@ TEST("slow event loop") {
break;
}
++cnt2;
- t += std::chrono::milliseconds(10000);
+ t += 10s;
}
if (!EXPECT_TRUE(cnt2 > 15 && cnt2 < 25)) {
diff --git a/fnet/src/tests/thread_selection/thread_selection_test.cpp b/fnet/src/tests/thread_selection/thread_selection_test.cpp
index ecfe0c57d5c..35df07221a2 100644
--- a/fnet/src/tests/thread_selection/thread_selection_test.cpp
+++ b/fnet/src/tests/thread_selection/thread_selection_test.cpp
@@ -1,6 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
+#include <vespa/fnet/transport.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <thread>
#include <chrono>
diff --git a/fnet/src/tests/time/timespeed.cpp b/fnet/src/tests/time/timespeed.cpp
index e6d2af5a278..eda367f1990 100644
--- a/fnet/src/tests/time/timespeed.cpp
+++ b/fnet/src/tests/time/timespeed.cpp
@@ -1,6 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/fnet/fnet.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <chrono>
diff --git a/fnet/src/vespa/fnet/config.cpp b/fnet/src/vespa/fnet/config.cpp
index a546d38f78b..856d0ab4c1c 100644
--- a/fnet/src/vespa/fnet/config.cpp
+++ b/fnet/src/vespa/fnet/config.cpp
@@ -3,7 +3,8 @@
#include "config.h"
FNET_Config::FNET_Config()
- : _iocTimeOut(0),
+ : _iocTimeOut(vespalib::duration::zero()),
+ _events_before_wakeup(1),
_maxInputBufferSize(0x10000),
_maxOutputBufferSize(0x10000),
_tcpNoDelay(true)
diff --git a/fnet/src/vespa/fnet/config.h b/fnet/src/vespa/fnet/config.h
index 3f34c1511b6..fd6f9f8557d 100644
--- a/fnet/src/vespa/fnet/config.h
+++ b/fnet/src/vespa/fnet/config.h
@@ -2,7 +2,7 @@
#pragma once
-#include <cstdint>
+#include <vespa/vespalib/util/time.h>
/**
* This class is used internally by the @ref FNET_Transport to keep
@@ -11,7 +11,8 @@
class FNET_Config
{
public:
- uint32_t _iocTimeOut;
+ vespalib::duration _iocTimeOut;
+ uint32_t _events_before_wakeup;
uint32_t _maxInputBufferSize;
uint32_t _maxOutputBufferSize;
bool _tcpNoDelay;
diff --git a/fnet/src/vespa/fnet/connection.cpp b/fnet/src/vespa/fnet/connection.cpp
index c5afd627a5a..a2e6fe25edc 100644
--- a/fnet/src/vespa/fnet/connection.cpp
+++ b/fnet/src/vespa/fnet/connection.cpp
@@ -347,7 +347,7 @@ done_read:
}
UpdateTimeOut();
- uint32_t maxSize = GetConfig()->_maxInputBufferSize;
+ uint32_t maxSize = getConfig()._maxInputBufferSize;
if (maxSize > 0 && _input.GetBufSize() > maxSize)
{
if (!_flags._gotheader || _packetLength < maxSize) {
@@ -430,7 +430,7 @@ FNET_Connection::Write()
}
}
- uint32_t maxSize = GetConfig()->_maxOutputBufferSize;
+ uint32_t maxSize = getConfig()._maxOutputBufferSize;
if (maxSize > 0 && _output.GetBufSize() > maxSize) {
_output.Shrink(maxSize);
}
diff --git a/fnet/src/vespa/fnet/fnet.h b/fnet/src/vespa/fnet/fnet.h
deleted file mode 100644
index c7570e025ec..00000000000
--- a/fnet/src/vespa/fnet/fnet.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/component/vtag.h>
-
-// DEPRECATED
-
-#define DEPRECATED __attribute__((deprecated))
-
-// FORWARD DECLARATIONS
-
-class FNET_IPacketFactory;
-class FNET_IPacketHandler;
-class FNET_IPacketStreamer;
-class FNET_IServerAdapter;
-class FNET_IExecutable;
-
-class FNET_Channel;
-class FNET_ChannelLookup;
-class FNET_ChannelPool;
-class FNET_Config;
-class FNET_Connection;
-class FNET_Connector;
-class FNET_Context;
-class FNET_ControlPacket;
-class FNET_DataBuffer;
-class FNET_DummyPacket;
-class FNET_Info;
-class FNET_IOComponent;
-class FNET_Packet;
-class FNET_PacketQueue;
-class FNET_Scheduler;
-class FNET_SimplePacketStreamer;
-class FNET_Task;
-class FNET_Transport;
-class FNET_TransportThread;
-
-// CONTEXT CLASS (union of types)
-#include "context.h"
-
-// INTERFACES
-#include "ipacketfactory.h"
-#include "ipackethandler.h"
-#include "ipacketstreamer.h"
-#include "iserveradapter.h"
-#include "iexecutable.h"
-
-// CLASSES
-#include "task.h"
-#include "scheduler.h"
-#include "config.h"
-#include "databuffer.h"
-#include "packet.h"
-#include "dummypacket.h"
-#include "controlpacket.h"
-#include "packetqueue.h"
-#include "channel.h"
-#include "channellookup.h"
-#include "simplepacketstreamer.h"
-#include "transport_thread.h"
-#include "iocomponent.h"
-#include "transport.h"
-#include "connection.h"
-#include "connector.h"
-#include "info.h"
-#include "signalshutdown.h"
-
diff --git a/fnet/src/vespa/fnet/frt/frt.h b/fnet/src/vespa/fnet/frt/frt.h
deleted file mode 100644
index 490b9b0a2b1..00000000000
--- a/fnet/src/vespa/fnet/frt/frt.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-class FRT_Invokable;
-class FRT_IAbortHandler;
-class FRT_IReturnHandler;
-class FRT_ICleanupHandler;
-class FRT_ISharedBlob;
-
-class FRT_Method;
-class FRT_PacketFactory;
-class FRT_ReflectionBuilder;
-class FRT_ReflectionManager;
-class FRT_RPCErrorPacket;
-class FRT_RPCInvoker;
-class FRT_RPCReplyPacket;
-class FRT_RPCRequest;
-class FRT_RPCRequestPacket;
-class FRT_Supervisor;
-class FRT_Target;
-class FRT_Values;
-
-#include <vespa/fnet/fnet.h>
-#include "error.h"
-#include "isharedblob.h"
-#include "invokable.h"
-#include "values.h"
-#include "reflection.h"
-#include "rpcrequest.h"
-#include "packets.h"
-#include "invoker.h"
-#include "supervisor.h"
-#include "target.h"
-
diff --git a/fnet/src/vespa/fnet/frt/supervisor.cpp b/fnet/src/vespa/fnet/frt/supervisor.cpp
index 7e92855583e..388d754ece4 100644
--- a/fnet/src/vespa/fnet/frt/supervisor.cpp
+++ b/fnet/src/vespa/fnet/frt/supervisor.cpp
@@ -419,7 +419,7 @@ StandaloneFRT::StandaloneFRT()
StandaloneFRT::StandaloneFRT(vespalib::CryptoEngine::SP crypto)
: _threadPool(std::make_unique<FastOS_ThreadPool>(1024*128)),
- _transport(std::make_unique<FNET_Transport>(std::move(crypto), 1)),
+ _transport(std::make_unique<FNET_Transport>(TransportConfig().crypto(std::move(crypto)))),
_supervisor(std::make_unique<FRT_Supervisor>(_transport.get()))
{
_transport->Start(_threadPool.get());
diff --git a/fnet/src/vespa/fnet/iocomponent.cpp b/fnet/src/vespa/fnet/iocomponent.cpp
index 81d1bf47567..471156f53ea 100644
--- a/fnet/src/vespa/fnet/iocomponent.cpp
+++ b/fnet/src/vespa/fnet/iocomponent.cpp
@@ -16,7 +16,7 @@ FNET_IOComponent::FNET_IOComponent(FNET_TransportThread *owner,
_ioc_selector(nullptr),
_ioc_spec(nullptr),
_flags(shouldTimeOut),
- _ioc_timestamp(clock::now()),
+ _ioc_timestamp(vespalib::steady_clock::now()),
_ioc_lock(),
_ioc_cond(),
_ioc_refcnt(1)
@@ -32,9 +32,9 @@ FNET_IOComponent::~FNET_IOComponent()
assert(_ioc_selector == nullptr);
}
-FNET_Config *
-FNET_IOComponent::GetConfig() {
- return _ioc_owner->GetConfig();
+const FNET_Config &
+FNET_IOComponent::getConfig() const {
+ return _ioc_owner->getConfig();
}
void
diff --git a/fnet/src/vespa/fnet/iocomponent.h b/fnet/src/vespa/fnet/iocomponent.h
index 84e3c8bd412..ee228e0126d 100644
--- a/fnet/src/vespa/fnet/iocomponent.h
+++ b/fnet/src/vespa/fnet/iocomponent.h
@@ -25,8 +25,6 @@ class FNET_IOComponent
FNET_IOComponent &operator=(const FNET_IOComponent &);
using Selector = vespalib::Selector<FNET_IOComponent>;
- using clock = FNET_Scheduler::clock;
- using time_point = clock::time_point;
struct Flags {
Flags(bool shouldTimeout) :
@@ -50,7 +48,7 @@ protected:
Selector *_ioc_selector; // attached event selector
char *_ioc_spec; // connect/listen spec
Flags _flags; // Compressed representation of boolean flags;
- time_point _ioc_timestamp; // last I/O activity
+ vespalib::steady_time _ioc_timestamp; // last I/O activity
std::mutex _ioc_lock; // synchronization
std::condition_variable _ioc_cond; // synchronization
uint32_t _ioc_refcnt; // reference counter
@@ -138,7 +136,7 @@ public:
*
* @return config object.
**/
- FNET_Config *GetConfig();
+ const FNET_Config & getConfig() const;
/**
diff --git a/fnet/src/vespa/fnet/scheduler.cpp b/fnet/src/vespa/fnet/scheduler.cpp
index a4d504db752..f54d3d6a9bb 100644
--- a/fnet/src/vespa/fnet/scheduler.cpp
+++ b/fnet/src/vespa/fnet/scheduler.cpp
@@ -9,8 +9,8 @@
LOG_SETUP(".fnet.scheduler");
-FNET_Scheduler::FNET_Scheduler(time_point *sampler,
- time_point *now)
+FNET_Scheduler::FNET_Scheduler(vespalib::steady_time *sampler,
+ vespalib::steady_time *now)
: _cond(),
_next(),
_now(),
@@ -29,7 +29,7 @@ FNET_Scheduler::FNET_Scheduler(time_point *sampler,
if (now != nullptr) {
_next = *now;
} else {
- _next = clock::now();
+ _next = vespalib::steady_clock::now();
}
_next += tick_ms;
}
@@ -146,7 +146,7 @@ FNET_Scheduler::CheckTasks()
if (_sampler != nullptr) {
_now = *_sampler;
} else {
- _now = clock::now();
+ _now = vespalib::steady_clock::now();
}
// assume timely value propagation
diff --git a/fnet/src/vespa/fnet/scheduler.h b/fnet/src/vespa/fnet/scheduler.h
index 81ff8977f89..98a9442799e 100644
--- a/fnet/src/vespa/fnet/scheduler.h
+++ b/fnet/src/vespa/fnet/scheduler.h
@@ -2,9 +2,9 @@
#pragma once
+#include <vespa/vespalib/util/time.h>
#include <mutex>
#include <condition_variable>
-#include <chrono>
class FNET_Task;
@@ -19,9 +19,8 @@ class FNET_Task;
class FNET_Scheduler
{
public:
- using clock = std::chrono::steady_clock;
- using time_point = clock::time_point;
- static constexpr auto tick_ms = std::chrono::milliseconds(10);
+ using clock = vespalib::steady_clock;
+ static constexpr auto tick_ms = 10ms;
enum scheduler_constants {
NUM_SLOTS = 4096,
@@ -32,16 +31,16 @@ public:
private:
std::mutex _lock;
std::condition_variable _cond;
- FNET_Task *_slots[NUM_SLOTS + 1];
- time_point _next;
- time_point _now;
- time_point *_sampler;
- uint32_t _currIter;
- uint32_t _currSlot;
- FNET_Task *_currPt;
- FNET_Task *_tailPt;
- FNET_Task *_performing;
- bool _waitTask;
+ FNET_Task *_slots[NUM_SLOTS + 1];
+ vespalib::steady_time _next;
+ vespalib::steady_time _now;
+ vespalib::steady_time *_sampler;
+ uint32_t _currIter;
+ uint32_t _currSlot;
+ FNET_Task *_currPt;
+ FNET_Task *_tailPt;
+ FNET_Task *_performing;
+ bool _waitTask;
FNET_Scheduler(const FNET_Scheduler &);
FNET_Scheduler &operator=(const FNET_Scheduler &);
@@ -73,8 +72,8 @@ public:
* @param now if given, indicates the current time. This value is
* used by the constructor to init internal variables.
**/
- FNET_Scheduler(time_point *sampler = nullptr,
- time_point *now = nullptr);
+ FNET_Scheduler(vespalib::steady_time *sampler = nullptr,
+ vespalib::steady_time *now = nullptr);
virtual ~FNET_Scheduler();
diff --git a/fnet/src/vespa/fnet/transport.cpp b/fnet/src/vespa/fnet/transport.cpp
index d3b52969c8c..ce5f44efb7c 100644
--- a/fnet/src/vespa/fnet/transport.cpp
+++ b/fnet/src/vespa/fnet/transport.cpp
@@ -3,6 +3,7 @@
#include "transport.h"
#include "transport_thread.h"
#include "iocomponent.h"
+#include <vespa/vespalib/util/threadstackexecutor.h>
#include <chrono>
#include <xxhash.h>
@@ -24,15 +25,34 @@ VESPA_THREAD_STACK_TAG(fnet_work_pool);
} // namespace <unnamed>
-FNET_Transport::FNET_Transport(vespalib::AsyncResolver::SP resolver, vespalib::CryptoEngine::SP crypto, size_t num_threads)
- : _async_resolver(std::move(resolver)),
- _crypto_engine(std::move(crypto)),
- _work_pool(1, 128 * 1024, fnet_work_pool, 1024),
- _threads()
+TransportConfig::TransportConfig(int num_threads)
+ : _config(),
+ _resolver(),
+ _crypto(),
+ _num_threads(num_threads)
+{}
+
+TransportConfig::~TransportConfig() = default;
+
+vespalib::AsyncResolver::SP
+TransportConfig::resolver() const {
+ return _resolver ? _resolver : vespalib::AsyncResolver::get_shared();
+}
+vespalib::CryptoEngine::SP
+TransportConfig::crypto() const {
+ return _crypto ? _crypto : vespalib::CryptoEngine::get_default();
+}
+
+FNET_Transport::FNET_Transport(TransportConfig cfg)
+ : _async_resolver(cfg.resolver()),
+ _crypto_engine(cfg.crypto()),
+ _work_pool(std::make_unique<vespalib::ThreadStackExecutor>(1, 128 * 1024, fnet_work_pool, 1024)),
+ _threads(),
+ _config(cfg.config())
{
- assert(num_threads >= 1);
- for (size_t i = 0; i < num_threads; ++i) {
- _threads.emplace_back(new FNET_TransportThread(*this));
+ assert(cfg.num_threads() >= 1);
+ for (size_t i = 0; i < cfg.num_threads(); ++i) {
+ _threads.emplace_back(std::make_unique<FNET_TransportThread>(*this));
}
}
@@ -41,7 +61,7 @@ FNET_Transport::~FNET_Transport() = default;
void
FNET_Transport::post_or_perform(vespalib::Executor::Task::UP task)
{
- if (auto rejected = _work_pool.execute(std::move(task))) {
+ if (auto rejected = _work_pool->execute(std::move(task))) {
rejected->run();
}
}
@@ -102,38 +122,6 @@ FNET_Transport::GetNumIOComponents()
}
void
-FNET_Transport::SetIOCTimeOut(uint32_t ms)
-{
- for (const auto &thread: _threads) {
- thread->SetIOCTimeOut(ms);
- }
-}
-
-void
-FNET_Transport::SetMaxInputBufferSize(uint32_t bytes)
-{
- for (const auto &thread: _threads) {
- thread->SetMaxInputBufferSize(bytes);
- }
-}
-
-void
-FNET_Transport::SetMaxOutputBufferSize(uint32_t bytes)
-{
- for (const auto &thread: _threads) {
- thread->SetMaxOutputBufferSize(bytes);
- }
-}
-
-void
-FNET_Transport::SetTCPNoDelay(bool noDelay)
-{
- for (const auto &thread: _threads) {
- thread->SetTCPNoDelay(noDelay);
- }
-}
-
-void
FNET_Transport::sync()
{
for (const auto &thread: _threads) {
@@ -161,7 +149,7 @@ FNET_Transport::ShutDown(bool waitFinished)
}
if (waitFinished) {
_async_resolver->wait_for_pending_resolves();
- _work_pool.shutdown().sync();
+ _work_pool->shutdown().sync();
}
}
@@ -172,7 +160,7 @@ FNET_Transport::WaitFinished()
thread->WaitFinished();
}
_async_resolver->wait_for_pending_resolves();
- _work_pool.shutdown().sync();
+ _work_pool->shutdown().sync();
}
bool
diff --git a/fnet/src/vespa/fnet/transport.h b/fnet/src/vespa/fnet/transport.h
index 02ef22c7fb6..766eaa3ccaa 100644
--- a/fnet/src/vespa/fnet/transport.h
+++ b/fnet/src/vespa/fnet/transport.h
@@ -3,11 +3,11 @@
#pragma once
#include "context.h"
+#include "config.h"
#include <memory>
#include <vector>
#include <vespa/vespalib/net/async_resolver.h>
#include <vespa/vespalib/net/crypto_engine.h>
-#include <vespa/vespalib/util/threadstackexecutor.h>
class FNET_TransportThread;
class FastOS_ThreadPool;
@@ -17,6 +17,48 @@ class FNET_IServerAdapter;
class FNET_IPacketHandler;
class FNET_Scheduler;
+class TransportConfig {
+public:
+ TransportConfig() : TransportConfig(1) {}
+ explicit TransportConfig(int num_threads);
+ ~TransportConfig();
+ vespalib::AsyncResolver::SP resolver() const;
+ vespalib::CryptoEngine::SP crypto() const;
+ TransportConfig & resolver(vespalib::AsyncResolver::SP resolver_in) {
+ _resolver = std::move(resolver_in);
+ return *this;
+ }
+ TransportConfig & crypto(vespalib::CryptoEngine::SP crypto_in) {
+ _crypto = std::move(crypto_in);
+ return *this;
+ }
+ const FNET_Config & config() const { return _config; }
+ uint32_t num_threads() const { return _num_threads; }
+
+ TransportConfig & events_before_wakeup(uint32_t v) {
+ if (v > 1) {
+ _config._events_before_wakeup = v;
+ }
+ return *this;
+ }
+ TransportConfig & maxInputBufferSize(uint32_t v) {
+ _config._maxInputBufferSize = v;
+ return *this;
+ }
+ TransportConfig & maxOutputBufferSize(uint32_t v) {
+ _config._maxOutputBufferSize = v;
+ return *this;
+ }
+ TransportConfig & tcpNoDelay(bool v) {
+ _config._tcpNoDelay = v;
+ return *this;
+ }
+private:
+ FNET_Config _config;
+ vespalib::AsyncResolver::SP _resolver;
+ vespalib::CryptoEngine::SP _crypto;
+ uint32_t _num_threads;
+};
/**
* This class represents the transport layer and handles a collection
* of transport threads. Note: remember to shut down your transport
@@ -29,11 +71,14 @@ private:
using Threads = std::vector<Thread>;
vespalib::AsyncResolver::SP _async_resolver;
- vespalib::CryptoEngine::SP _crypto_engine;
- vespalib::ThreadStackExecutor _work_pool;
- Threads _threads;
+ vespalib::CryptoEngine::SP _crypto_engine;
+ std::unique_ptr<vespalib::SyncableThreadExecutor> _work_pool;
+ Threads _threads;
+ const FNET_Config _config;
public:
+ FNET_Transport(const FNET_Transport &) = delete;
+ FNET_Transport & operator = (const FNET_Transport &) = delete;
/**
* Construct a transport layer. To activate your newly created
* transport object you need to call either the Start method to
@@ -41,18 +86,16 @@ public:
* the current thread become the transport thread. Main may only
* be called for single-threaded transports.
**/
- FNET_Transport(vespalib::AsyncResolver::SP resolver, vespalib::CryptoEngine::SP crypto, size_t num_threads);
+ explicit FNET_Transport(TransportConfig config);
- FNET_Transport(vespalib::AsyncResolver::SP resolver, size_t num_threads)
- : FNET_Transport(std::move(resolver), vespalib::CryptoEngine::get_default(), num_threads) {}
- FNET_Transport(vespalib::CryptoEngine::SP crypto, size_t num_threads)
- : FNET_Transport(vespalib::AsyncResolver::get_shared(), std::move(crypto), num_threads) {}
- FNET_Transport(size_t num_threads)
- : FNET_Transport(vespalib::AsyncResolver::get_shared(), vespalib::CryptoEngine::get_default(), num_threads) {}
+ explicit FNET_Transport(uint32_t num_threads)
+ : FNET_Transport(TransportConfig(num_threads)) {}
FNET_Transport()
- : FNET_Transport(vespalib::AsyncResolver::get_shared(), vespalib::CryptoEngine::get_default(), 1) {}
+ : FNET_Transport(TransportConfig()) {}
~FNET_Transport();
+ const FNET_Config & getConfig() const { return _config; }
+
/**
* Try to execute the given task on the internal work pool
* executor (post). If the executor has been closed or there is
@@ -168,54 +211,6 @@ public:
uint32_t GetNumIOComponents();
/**
- * Set the I/O Component timeout. Idle I/O Components with timeout
- * enabled (determined by calling the ShouldTimeOut method) will
- * time out if idle for the given number of milliseconds. An I/O
- * component reports its un-idle-ness by calling the UpdateTimeOut
- * method in the owning transport object. Calling this method with 0
- * as parameter will disable I/O Component timeouts. Note that newly
- * created transport objects begin their lives with I/O Component
- * timeouts disabled. An I/O Component timeout has the same effect
- * as calling the Close method in the transport object with the
- * target I/O Component as parameter.
- *
- * @param ms number of milliseconds before IOC idle timeout occurs.
- **/
- void SetIOCTimeOut(uint32_t ms);
-
- /**
- * Set maximum input buffer size. This value will only affect
- * connections that use a common input buffer when decoding
- * incoming packets. Note that this value is not an absolute
- * max. The buffer will still grow larger than this value if
- * needed to decode big packets. However, when the buffer becomes
- * larger than this value, it will be shrunk back when possible.
- *
- * @param bytes buffer size in bytes. 0 means unlimited.
- **/
- void SetMaxInputBufferSize(uint32_t bytes);
-
- /**
- * Set maximum output buffer size. This value will only affect
- * connections that use a common output buffer when encoding
- * outgoing packets. Note that this value is not an absolute
- * max. The buffer will still grow larger than this value if needed
- * to encode big packets. However, when the buffer becomes larger
- * than this value, it will be shrunk back when possible.
- *
- * @param bytes buffer size in bytes. 0 means unlimited.
- **/
- void SetMaxOutputBufferSize(uint32_t bytes);
-
- /**
- * Enable or disable use of the TCP_NODELAY flag with sockets
- * created by this transport object.
- *
- * @param noDelay true if TCP_NODELAY flag should be used.
- **/
- void SetTCPNoDelay(bool noDelay);
-
- /**
* Synchronize with all transport threads. This method will block
* until all events posted before this method was invoked has been
* processed. If a transport thread has been shut down (or is in
diff --git a/fnet/src/vespa/fnet/transport_thread.cpp b/fnet/src/vespa/fnet/transport_thread.cpp
index a20de880f15..5e1a9759a60 100644
--- a/fnet/src/vespa/fnet/transport_thread.cpp
+++ b/fnet/src/vespa/fnet/transport_thread.cpp
@@ -9,6 +9,7 @@
#include "transport.h"
#include <vespa/vespalib/net/socket_spec.h>
#include <vespa/vespalib/net/server_socket.h>
+#include <vespa/vespalib/util/gate.h>
#include <csignal>
#include <vespa/log/log.h>
@@ -17,6 +18,7 @@ LOG_SETUP(".fnet");
using vespalib::ServerSocket;
using vespalib::SocketHandle;
using vespalib::SocketSpec;
+using vespalib::steady_clock;
namespace {
@@ -112,7 +114,7 @@ bool
FNET_TransportThread::PostEvent(FNET_ControlPacket *cpacket,
FNET_Context context)
{
- bool wasEmpty;
+ size_t qLen;
{
std::unique_lock<std::mutex> guard(_lock);
if (IsShutDown()) {
@@ -120,10 +122,10 @@ FNET_TransportThread::PostEvent(FNET_ControlPacket *cpacket,
SafeDiscardEvent(cpacket, context);
return false;
}
- wasEmpty = _queue.IsEmpty_NoLock();
_queue.QueuePacket_NoLock(cpacket, context);
+ qLen = _queue.GetPacketCnt_NoLock();
}
- if (wasEmpty) {
+ if (qLen == getConfig()._events_before_wakeup) {
_selector.wakeup();
}
return true;
@@ -205,9 +207,8 @@ extern "C" {
FNET_TransportThread::FNET_TransportThread(FNET_Transport &owner_in)
: _owner(owner_in),
- _now(clock::now()),
+ _now(steady_clock ::now()),
_scheduler(&_now),
- _config(),
_componentsHead(nullptr),
_timeOutHead(nullptr),
_componentsTail(nullptr),
@@ -217,12 +218,12 @@ FNET_TransportThread::FNET_TransportThread(FNET_Transport &owner_in)
_queue(),
_myQueue(),
_lock(),
- _cond(),
+ _shutdownLock(),
+ _shutdownCond(),
_pseudo_thread(),
_started(false),
_shutdown(false),
- _finished(false),
- _waitFinished(false)
+ _finished(false)
{
trapsigpipe();
}
@@ -231,22 +232,26 @@ FNET_TransportThread::FNET_TransportThread(FNET_Transport &owner_in)
FNET_TransportThread::~FNET_TransportThread()
{
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard<std::mutex> guard(_shutdownLock);
}
- if (_started && !_finished) {
+ if (_started.load() && !_finished) {
LOG(error, "Transport: delete called on active object!");
} else {
std::lock_guard guard(_pseudo_thread);
}
}
+const FNET_Config &
+FNET_TransportThread::getConfig() const {
+ return _owner.getConfig();
+}
bool
FNET_TransportThread::tune(SocketHandle &handle) const
{
handle.set_keepalive(true);
handle.set_linger(true, 0);
- handle.set_nodelay(_config._tcpNoDelay);
+ handle.set_nodelay(getConfig()._tcpNoDelay);
return handle.set_blocking(false);
}
@@ -370,33 +375,23 @@ FNET_TransportThread::WaitFinished()
if (_finished)
return;
- std::unique_lock<std::mutex> guard(_lock);
- _waitFinished = true;
+ std::unique_lock<std::mutex> guard(_shutdownLock);
while (!_finished)
- _cond.wait(guard);
+ _shutdownCond.wait(guard);
}
bool
FNET_TransportThread::InitEventLoop()
{
- bool wasStarted;
- {
- std::lock_guard<std::mutex> guard(_lock);
- wasStarted = _started;
- if (!_started) {
- _started = true;
- }
- }
- if (wasStarted) {
+ if (_started.exchange(true)) {
LOG(error, "Transport: InitEventLoop: object already active!");
return false;
}
- _now = clock::now();
+ _now = steady_clock::now();
return true;
}
-
void
FNET_TransportThread::handle_wakeup()
{
@@ -467,32 +462,26 @@ FNET_TransportThread::handle_event(FNET_IOComponent &ctx, bool read, bool write)
bool
-FNET_TransportThread::EventLoopIteration()
-{
- FNET_IOComponent *component = nullptr;
- int msTimeout = FNET_Scheduler::tick_ms.count();
+FNET_TransportThread::EventLoopIteration() {
if (!IsShutDown()) {
+ int msTimeout = FNET_Scheduler::tick_ms.count();
// obtain I/O events
_selector.poll(msTimeout);
// sample current time (performed once per event loop iteration)
- _now = clock::now();
+ _now = steady_clock::now();
- // handle wakeup and io-events
- _selector.dispatch(*this);
+ // handle io-events
+ auto dispatchResult = _selector.dispatch(*this);
+
+ if ((dispatchResult == vespalib::SelectorDispatchResult::NO_WAKEUP) && (getConfig()._events_before_wakeup > 1)) {
+ handle_wakeup();
+ }
// handle IOC time-outs
- if (_config._iocTimeOut > 0) {
- time_point oldest = (_now - std::chrono::milliseconds(_config._iocTimeOut));
- while (_timeOutHead != nullptr &&
- oldest > _timeOutHead->_ioc_timestamp) {
-
- component = _timeOutHead;
- RemoveComponent(component);
- component->Close();
- AddDeleteComponent(component);
- }
+ if (getConfig()._iocTimeOut > vespalib::duration::zero()) {
+ checkTimedoutComponents(getConfig()._iocTimeOut);
}
// perform pending tasks
@@ -507,6 +496,23 @@ FNET_TransportThread::EventLoopIteration()
if (_finished)
return false;
+ endEventLoop();
+ return false;
+}
+
+void
+FNET_TransportThread::checkTimedoutComponents(vespalib::duration timeout) {
+ vespalib::steady_time oldest = (_now - timeout);
+ while (_timeOutHead != nullptr && oldest > _timeOutHead->_ioc_timestamp) {
+ FNET_IOComponent *component = _timeOutHead;
+ RemoveComponent(component);
+ component->Close();
+ AddDeleteComponent(component);
+ }
+}
+
+void
+FNET_TransportThread::endEventLoop() {
// flush event queue
{
std::lock_guard<std::mutex> guard(_lock);
@@ -525,7 +531,7 @@ FNET_TransportThread::EventLoopIteration()
}
// close and remove all I/O Components
- component = _componentsHead;
+ FNET_IOComponent *component = _componentsHead;
while (component != nullptr) {
assert(component == _componentsHead);
FNET_IOComponent *tmp = component;
@@ -542,16 +548,13 @@ FNET_TransportThread::EventLoopIteration()
_myQueue.IsEmpty_NoLock());
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard<std::mutex> guard(_shutdownLock);
_finished = true;
- if (_waitFinished) {
- _cond.notify_all();
- }
+ _shutdownCond.notify_all();
}
LOG(spam, "Transport: event loop finished.");
- return false;
}
diff --git a/fnet/src/vespa/fnet/transport_thread.h b/fnet/src/vespa/fnet/transport_thread.h
index 8bced290962..371544f9c8a 100644
--- a/fnet/src/vespa/fnet/transport_thread.h
+++ b/fnet/src/vespa/fnet/transport_thread.h
@@ -30,14 +30,11 @@ class FNET_TransportThread : public FastOS_Runnable
public:
using Selector = vespalib::Selector<FNET_IOComponent>;
- using clock = FNET_Scheduler::clock;
- using time_point = clock::time_point;
private:
FNET_Transport &_owner; // owning transport layer
- time_point _now; // current time sampler
+ vespalib::steady_time _now; // current time sampler
FNET_Scheduler _scheduler; // transport thread scheduler
- FNET_Config _config; // FNET configuration [static]
FNET_IOComponent *_componentsHead; // I/O component list head
FNET_IOComponent *_timeOutHead; // first IOC in list to time out
FNET_IOComponent *_componentsTail; // I/O component list tail
@@ -46,17 +43,13 @@ private:
Selector _selector; // I/O event generator
FNET_PacketQueue_NoLock _queue; // outer event queue
FNET_PacketQueue_NoLock _myQueue; // inner event queue
- std::mutex _lock; // used for synchronization
- std::condition_variable _cond; // used for synchronization
+ std::mutex _lock; // protects the Q
+ std::mutex _shutdownLock; // used for synchronization during shutdown
+ std::condition_variable _shutdownCond; // used for synchronization during shutdown
std::recursive_mutex _pseudo_thread; // used after transport thread has shut down
- bool _started; // event loop started ?
+ std::atomic<bool> _started; // event loop started ?
std::atomic<bool> _shutdown; // should stop event loop ?
bool _finished; // event loop stopped ?
- bool _waitFinished; // someone is waiting for _finished
-
- FNET_TransportThread(const FNET_TransportThread &);
- FNET_TransportThread &operator=(const FNET_TransportThread &);
-
/**
* Add an IOComponent to the list of components. This operation is
@@ -144,7 +137,7 @@ private:
*
* @return config object.
**/
- FNET_Config *GetConfig() { return &_config; }
+ const FNET_Config & getConfig() const;
void handle_add_cmd(FNET_IOComponent *ioc);
@@ -161,6 +154,9 @@ private:
**/
bool InitEventLoop();
+ void endEventLoop();
+ void checkTimedoutComponents(vespalib::duration timeout);
+
/**
* Perform a single transport thread event loop iteration. This
* method is called by the FRT_Transport::Run method. If you want to
@@ -177,6 +173,8 @@ private:
}
public:
+ FNET_TransportThread(const FNET_TransportThread &) = delete;
+ FNET_TransportThread &operator=(const FNET_TransportThread &) = delete;
/**
* Construct a transport object. To activate your newly created
* transport object you need to call either the Start method to
@@ -185,14 +183,14 @@ public:
*
* @param owner owning transport layer
**/
- FNET_TransportThread(FNET_Transport &owner_in);
+ explicit FNET_TransportThread(FNET_Transport &owner_in);
/**
* Destruct object. This should NOT be done before the transport
* thread has completed it's work and raised the finished flag.
**/
- ~FNET_TransportThread();
+ ~FNET_TransportThread() override;
/**
@@ -269,60 +267,6 @@ public:
**/
uint32_t GetNumIOComponents() { return _componentCnt; }
-
- /**
- * Set the I/O Component timeout. Idle I/O Components with timeout
- * enabled (determined by calling the ShouldTimeOut method) will
- * time out if idle for the given number of milliseconds. An I/O
- * component reports its un-idle-ness by calling the UpdateTimeOut
- * method in the owning transport object. Calling this method with 0
- * as parameter will disable I/O Component timeouts. Note that newly
- * created transport objects begin their lives with I/O Component
- * timeouts disabled. An I/O Component timeout has the same effect
- * as calling the Close method in the transport object with the
- * target I/O Component as parameter.
- *
- * @param ms number of milliseconds before IOC idle timeout occurs.
- **/
- void SetIOCTimeOut(uint32_t ms) { _config._iocTimeOut = ms; }
-
-
- /**
- * Set maximum input buffer size. This value will only affect
- * connections that use a common input buffer when decoding
- * incoming packets. Note that this value is not an absolute
- * max. The buffer will still grow larger than this value if
- * needed to decode big packets. However, when the buffer becomes
- * larger than this value, it will be shrunk back when possible.
- *
- * @param bytes buffer size in bytes. 0 means unlimited.
- **/
- void SetMaxInputBufferSize(uint32_t bytes)
- { _config._maxInputBufferSize = bytes; }
-
-
- /**
- * Set maximum output buffer size. This value will only affect
- * connections that use a common output buffer when encoding
- * outgoing packets. Note that this value is not an absolute
- * max. The buffer will still grow larger than this value if needed
- * to encode big packets. However, when the buffer becomes larger
- * than this value, it will be shrunk back when possible.
- *
- * @param bytes buffer size in bytes. 0 means unlimited.
- **/
- void SetMaxOutputBufferSize(uint32_t bytes)
- { _config._maxOutputBufferSize = bytes; }
-
- /**
- * Enable or disable use of the TCP_NODELAY flag with sockets
- * created by this transport object.
- *
- * @param noDelay true if TCP_NODELAY flag should be used.
- **/
- void SetTCPNoDelay(bool noDelay) { _config._tcpNoDelay = noDelay; }
-
-
/**
* Add an I/O component to the working set of this transport
* object. Note that the actual work is performed by the transport
@@ -458,7 +402,7 @@ public:
void WaitFinished();
- // selector call-back for selector wakeup
+ // selector call-back for wakeup events
void handle_wakeup();
// selector call-back for io-events
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSet.java b/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSet.java
index eea932b6a27..c71390dbc1c 100644
--- a/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSet.java
+++ b/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSet.java
@@ -1,17 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.application;
-import com.google.common.collect.ImmutableList;
-
import java.net.URI;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
+import static java.util.stream.Collectors.toUnmodifiableList;
+
/**
* <p>This is an immutable set of ordered bindings from {@link UriPattern}s to some target type T. To create an instance
* of this class, you must 1) create a {@link BindingRepository}, 2) configure it using the {@link
@@ -22,10 +18,11 @@ import java.util.Map;
public class BindingSet<T> implements Iterable<Map.Entry<UriPattern, T>> {
public static final String DEFAULT = "default";
+
private final Collection<Map.Entry<UriPattern, T>> bindings;
BindingSet(Collection<Map.Entry<UriPattern, T>> bindings) {
- this.bindings = sort(bindings);
+ this.bindings = sorted(bindings);
}
/**
@@ -71,15 +68,8 @@ public class BindingSet<T> implements Iterable<Map.Entry<UriPattern, T>> {
return bindings.iterator();
}
- private static <T> Collection<Map.Entry<UriPattern, T>> sort(Collection<Map.Entry<UriPattern, T>> unsorted) {
- List<Map.Entry<UriPattern, T>> ret = new LinkedList<>(unsorted);
- Collections.sort(ret, new Comparator<Map.Entry<UriPattern, ?>>() {
-
- @Override
- public int compare(Map.Entry<UriPattern, ?> lhs, Map.Entry<UriPattern, ?> rhs) {
- return lhs.getKey().compareTo(rhs.getKey());
- }
- });
- return ImmutableList.copyOf(ret);
+ private static <T> Collection<Map.Entry<UriPattern, T>> sorted(Collection<Map.Entry<UriPattern, T>> unsorted) {
+ return unsorted.stream().sorted(Map.Entry.comparingByKey()).collect(toUnmodifiableList());
}
+
}
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSetSelector.java b/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSetSelector.java
index 25d13c6a4e3..5acddbabfe1 100644
--- a/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSetSelector.java
+++ b/jdisc_core/src/main/java/com/yahoo/jdisc/application/BindingSetSelector.java
@@ -29,5 +29,6 @@ public interface BindingSetSelector {
* @param uri The URI to select on.
* @return The name of selected BindingSet.
*/
- public String select(URI uri);
+ String select(URI uri);
+
}
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/application/UriPattern.java b/jdisc_core/src/main/java/com/yahoo/jdisc/application/UriPattern.java
index 350d8170987..642fd062b94 100644
--- a/jdisc_core/src/main/java/com/yahoo/jdisc/application/UriPattern.java
+++ b/jdisc_core/src/main/java/com/yahoo/jdisc/application/UriPattern.java
@@ -37,6 +37,8 @@ public class UriPattern implements Comparable<UriPattern> {
private final GlobPattern host;
private final int port;
private final GlobPattern path;
+
+ // TODO Vespa 8 jonmv remove
private final int priority;
/**
@@ -48,7 +50,16 @@ public class UriPattern implements Comparable<UriPattern> {
* @throws IllegalArgumentException If the pattern could not be parsed.
*/
public UriPattern(String uri) {
- this(uri, DEFAULT_PRIORITY);
+ Matcher matcher = PATTERN.matcher(uri);
+ if ( ! matcher.find())
+ throw new IllegalArgumentException(uri);
+
+ scheme = GlobPattern.compile(normalizeScheme(nonNullOrWildcard(matcher.group(1))));
+ host = GlobPattern.compile(nonNullOrWildcard(matcher.group(2)));
+ port = parseOrZero(matcher.group(4));
+ path = GlobPattern.compile(nonNullOrWildcard(matcher.group(7)));
+ pattern = scheme + "://" + host + ":" + (port > 0 ? port : "*") + "/" + path;
+ this.priority = DEFAULT_PRIORITY;
}
/**
@@ -56,49 +67,53 @@ public class UriPattern implements Comparable<UriPattern> {
* input string must be on the form <code>&lt;scheme&gt;://&lt;host&gt;[:&lt;port&gt;]&lt;path&gt;</code>, where
* '*' can be used as a wildcard character at any position.</p>
*
+ * @deprecated Use {@link #UriPattern(String)} and let's avoid another complication here.
* @param uri The pattern to parse.
* @param priority The priority of this pattern.
* @throws IllegalArgumentException If the pattern could not be parsed.
*/
+ @Deprecated(forRemoval = true, since = "7")
public UriPattern(String uri, int priority) {
Matcher matcher = PATTERN.matcher(uri);
if (!matcher.find()) {
throw new IllegalArgumentException(uri);
}
- scheme = GlobPattern.compile(normalizeScheme(resolvePatternComponent(matcher.group(1))));
- host = GlobPattern.compile(resolvePatternComponent(matcher.group(2)));
- port = resolvePortPattern(matcher.group(4));
- path = GlobPattern.compile(resolvePatternComponent(matcher.group(7)));
+ scheme = GlobPattern.compile(normalizeScheme(nonNullOrWildcard(matcher.group(1))));
+ host = GlobPattern.compile(nonNullOrWildcard(matcher.group(2)));
+ port = parseOrZero(matcher.group(4));
+ path = GlobPattern.compile(nonNullOrWildcard(matcher.group(7)));
pattern = scheme + "://" + host + ":" + (port > 0 ? port : "*") + "/" + path;
this.priority = priority;
}
/**
* <p>Attempts to match the given {@link URI} to this pattern. Note that only the scheme, host, port, and path
- * components of the URI are used. Any query or fragment part is simply ignored.</p>
+ * components of the URI are used, <em>and these must all be defined</em>. Only <em>absolute</em> URIs are supported.
+ * Any user info, query or fragment part is ignored.</p>
*
* @param uri The URI to match.
* @return A {@link Match} object describing the match found, or null if not found.
*/
public Match match(URI uri) {
- // Performance optimization: Match path first since scheme and host are often the same in a given binding repository.
- String uriPath = resolveUriComponent(uri.getPath());
- GlobPattern.Match pathMatch = path.match(uriPath, uriPath.startsWith("/") ? 1 : 0);
- if (pathMatch == null) {
+ if ( ! uri.isAbsolute() || uri.getHost() == null) // URI must have scheme, host and absolute (or empty) path.
return null;
- }
- if (port > 0 && port != resolvePortComponent(uri)) {
+
+ // Performance optimization: match in order of increasing cost and decreasing discriminating power.
+ if (port > 0 && port != uri.getPort())
return null;
- }
- // Match scheme before host because it has a higher chance of differing (e.g. http versus https)
- GlobPattern.Match schemeMatch = scheme.match(normalizeScheme(resolveUriComponent(uri.getScheme())));
- if (schemeMatch == null) {
+
+ GlobPattern.Match pathMatch = path.match(uri.getRawPath(), uri.getRawPath().isEmpty() ? 0 : 1); // Strip leading '/'.
+ if (pathMatch == null)
return null;
- }
- GlobPattern.Match hostMatch = host.match(resolveUriComponent(uri.getHost()));
- if (hostMatch == null) {
+
+ GlobPattern.Match hostMatch = host.match(uri.getHost());
+ if (hostMatch == null)
return null;
- }
+
+ GlobPattern.Match schemeMatch = scheme.match(normalizeScheme(uri.getScheme()));
+ if (schemeMatch == null)
+ return null;
+
return new Match(schemeMatch, hostMatch, port > 0 ? 0 : uri.getPort(), pathMatch);
}
@@ -109,7 +124,7 @@ public class UriPattern implements Comparable<UriPattern> {
@Override
public boolean equals(Object obj) {
- return obj instanceof UriPattern && pattern.equals(((UriPattern)obj).pattern);
+ return obj instanceof UriPattern && pattern.equals(((UriPattern) obj).pattern);
}
@Override
@@ -143,35 +158,21 @@ public class UriPattern implements Comparable<UriPattern> {
return 0;
}
- private static String resolveUriComponent(String str) {
+ private static String nonNullOrBlank(String str) {
return str != null ? str : "";
}
- private static String resolvePatternComponent(String val) {
+ private static String nonNullOrWildcard(String val) {
return val != null ? val : "*";
}
- private static int resolvePortPattern(String str) {
+ private static int parseOrZero(String str) {
if (str == null || str.equals("*")) {
return 0;
}
return Integer.parseInt(str);
}
- private static int resolvePortComponent(URI uri) {
- int rawPort = uri.getPort();
- return rawPort != -1 ? rawPort : resolvePortFromScheme(uri.getScheme());
- }
-
- private static int resolvePortFromScheme(String scheme) {
- if (scheme == null) return -1;
- switch (scheme) {
- case "http": return 80;
- case "https": return 443;
- default: return -1;
- }
- }
-
private static String normalizeScheme(String scheme) {
if (scheme.equals("https")) return "http"; // handle 'https' in bindings and uris as 'http'
return scheme;
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/DefaultBindingSelector.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/DefaultBindingSelector.java
index 83fe5e25cdb..374964c7e65 100644
--- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/DefaultBindingSelector.java
+++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/DefaultBindingSelector.java
@@ -15,4 +15,5 @@ public class DefaultBindingSelector implements BindingSetSelector {
public String select(URI uri) {
return BindingSet.DEFAULT;
}
+
}
diff --git a/jdisc_core/src/test/java/com/yahoo/jdisc/application/UriPatternTestCase.java b/jdisc_core/src/test/java/com/yahoo/jdisc/application/UriPatternTestCase.java
index d2499bbf369..0ea82508f06 100644
--- a/jdisc_core/src/test/java/com/yahoo/jdisc/application/UriPatternTestCase.java
+++ b/jdisc_core/src/test/java/com/yahoo/jdisc/application/UriPatternTestCase.java
@@ -124,32 +124,6 @@ public class UriPatternTestCase {
}
@Test
- public void requireThatUriWithoutHostDoesNotThrowException() {
- String schemeOnly = "scheme:schemeSpecificPart";
- String schemeAndPath = "scheme:/path";
- String pathOnly = "path";
- String pathOnlyWithSlash = "/path";
-
- UriPattern pattern = new UriPattern("scheme://host/path");
- assertNotMatch(pattern, schemeOnly);
- assertNotMatch(pattern, schemeAndPath);
- assertNotMatch(pattern, pathOnly);
- assertNotMatch(pattern, pathOnlyWithSlash);
-
- pattern = new UriPattern("scheme*://host*/path*");
- assertNotMatch(pattern, schemeOnly);
- assertNotMatch(pattern, schemeAndPath);
- assertNotMatch(pattern, pathOnly);
- assertNotMatch(pattern, pathOnlyWithSlash);
-
- pattern = new UriPattern("*://*/*");
- assertMatch(pattern, schemeOnly, Arrays.asList("scheme", "", ""));
- assertMatch(pattern, schemeAndPath, Arrays.asList("scheme", "", "path"));
- assertMatch(pattern, pathOnly, Arrays.asList("", "", "path"));
- assertMatch(pattern, pathOnlyWithSlash, Arrays.asList("", "", "path"));
- }
-
- @Test
public void requireThatUriWithoutPathDoesNotThrowException() {
UriPattern pattern = new UriPattern("scheme://host/path");
assertNotMatch(pattern, "scheme://host");
@@ -173,12 +147,14 @@ public class UriPatternTestCase {
}
@Test
+ @SuppressWarnings("removal")
public void requireThatPrioritiesAreOrderedDescending() {
assertCompareLt(new UriPattern("scheme://host:69/path", 1),
new UriPattern("scheme://host:69/path", 0));
}
@Test
+ @SuppressWarnings("removal")
public void requireThatPriorityOrdersBeforeScheme() {
assertCompareLt(new UriPattern("*://host:69/path", 1),
new UriPattern("scheme://host:69/path", 0));
@@ -287,15 +263,6 @@ public class UriPatternTestCase {
}
@Test
- public void requireThatUrisWithImplicitPortFromSchemeMatchesBindingWithExplicitPort() {
- UriPattern httpPattern = new UriPattern("http://host:80/path");
- assertMatch(httpPattern, "http://host/path", NO_GROUPS);
-
- UriPattern httpsPattern = new UriPattern("https://host:443/path");
- assertMatch(httpsPattern, "https://host/path", NO_GROUPS);
- }
-
- @Test
public void requireThatHttpsSchemeIsHandledAsHttp() {
UriPattern httpPattern = new UriPattern("http://host:80/path");
assertMatch(httpPattern, "https://host:80/path", NO_GROUPS);
@@ -304,6 +271,17 @@ public class UriPatternTestCase {
assertMatch(httpsPattern, "http://host:443/path", NO_GROUPS);
}
+ @Test
+ public void requireThatUrlEncodingIsNotDoneForPath() {
+ UriPattern encodedSlashPattern = new UriPattern("http://host:80/one%2Fpath");
+ assertMatch(encodedSlashPattern, "http://host:80/one%2Fpath", NO_GROUPS);
+ assertNotMatch(encodedSlashPattern, "http://host:80/one/path");
+
+ UriPattern actualSlashPattern = new UriPattern("http://host:80/two/paths");
+ assertNotMatch(actualSlashPattern, "http://host:80/two%2Fpaths");
+ assertMatch(actualSlashPattern, "http://host:80/two/paths", NO_GROUPS);
+ }
+
private static void assertIllegalPattern(String uri) {
try {
new UriPattern(uri);
@@ -314,7 +292,7 @@ public class UriPatternTestCase {
}
private static void assertCompareLt(String lhs, String rhs) {
- assertCompareLt(new UriPattern(lhs, 0), new UriPattern(rhs, 0));
+ assertCompareLt(new UriPattern(lhs), new UriPattern(rhs));
}
private static void assertCompareLt(UriPattern lhs, UriPattern rhs) {
@@ -322,7 +300,7 @@ public class UriPatternTestCase {
}
private static void assertCompareEq(String lhs, String rhs) {
- assertCompareEq(new UriPattern(lhs, 0), new UriPattern(rhs, 0));
+ assertCompareEq(new UriPattern(lhs), new UriPattern(rhs));
}
private static void assertCompareEq(UriPattern lhs, UriPattern rhs) {
diff --git a/jdisc_http_service/abi-spec.json b/jdisc_http_service/abi-spec.json
index 8b48631d4aa..6e2836cad6e 100644
--- a/jdisc_http_service/abi-spec.json
+++ b/jdisc_http_service/abi-spec.json
@@ -50,6 +50,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.jdisc.http.ConnectorConfig build()"
],
"fields": [
@@ -753,6 +755,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.jdisc.http.ServerConfig build()"
],
"fields": [
@@ -964,6 +968,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.jdisc.http.ServletPathsConfig build()"
],
"fields": [
diff --git a/jdisc_http_service/pom.xml b/jdisc_http_service/pom.xml
index 7333db96b91..094ca7baa25 100644
--- a/jdisc_http_service/pom.xml
+++ b/jdisc_http_service/pom.xml
@@ -78,6 +78,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>yolean</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
<!-- TEST SCOPE -->
<dependency>
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/Exceptions.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/Exceptions.java
deleted file mode 100644
index 0806f352ae9..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/Exceptions.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-/**
- * Utility methods for exceptions
- *
- * @author Tony Vaagenes
- */
-public class Exceptions {
-
- /**
- * Allows treating checked exceptions as unchecked.
- * Usage:
- * throw throwUnchecked(e);
- * The reason for the return type is to allow writing throw at the call site
- * instead of just calling throwUnchecked. Just calling throwUnchecked
- * means that the java compiler won't know that the statement will throw an exception,
- * and will therefore complain on things such e.g. missing return value.
- */
- public static RuntimeException throwUnchecked(Throwable e) {
- throwUncheckedImpl(e);
- return null;
- }
-
- @SuppressWarnings("unchecked")
- private static <T extends Throwable> void throwUncheckedImpl(Throwable t) throws T {
- throw (T)t;
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
index 940009e7520..84c47f5a342 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
@@ -35,8 +35,8 @@ import java.util.logging.Logger;
import static com.yahoo.jdisc.http.HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED;
import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnection;
-import static com.yahoo.jdisc.http.server.jetty.Exceptions.throwUnchecked;
import static com.yahoo.jdisc.http.server.jetty.JDiscHttpServlet.getConnector;
+import static com.yahoo.yolean.Exceptions.throwUnchecked;
/**
* @author Simon Thoresen Hult
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
index 86aa9b994f9..c565025e9ba 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
@@ -1,11 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.http.server.jetty;
-import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.servlet.ServletRequest;
import com.yahoo.jdisc.service.CurrentContainer;
-import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.Utf8Appendable;
import javax.servlet.http.HttpServletRequest;
@@ -14,6 +12,7 @@ import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
+import static com.yahoo.jdisc.Response.Status.BAD_REQUEST;
import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnection;
import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnectorLocalPort;
@@ -48,16 +47,15 @@ class HttpRequestFactory {
String path = servletRequest.getRequestURI();
String query = servletRequest.getQueryString();
- StringBuffer builder = new StringBuffer(128);
- URIUtil.appendSchemeHostPort(builder, scheme, host, port);
- builder.append(path);
- if (query != null) {
- builder.append('?').append(query);
- }
- URI uri = URI.create(builder.toString());
+ URI uri = URI.create(scheme + "://" +
+ host + ":" + port +
+ (path != null ? path : "") +
+ (query != null ? "?" + query : ""));
+
validateSchemeHostPort(scheme, host, port, uri);
return uri;
- } catch (IllegalArgumentException e) {
+ }
+ catch (IllegalArgumentException e) {
throw createBadQueryException(e);
}
}
@@ -66,15 +64,12 @@ class HttpRequestFactory {
if ( ! scheme.equals(uri.getScheme()))
throw new IllegalArgumentException("Bad scheme: " + scheme);
- if ( ! host.equals(uri.getHost()))
- throw new IllegalArgumentException("Bad host: " + host);
-
- if (port != uri.getPort() && ! (port == 80 && scheme.equals("http")) && ! (port == 443 && scheme.equals("https")))
- throw new IllegalArgumentException("Bad port: " + port);
+ if ( ! host.equals(uri.getHost()) || port != uri.getPort())
+ throw new IllegalArgumentException("Bad authority: " + uri.getRawAuthority() + " != " + host + ":" + port);
}
private static RequestException createBadQueryException(IllegalArgumentException e) {
- return new RequestException(Response.Status.BAD_REQUEST, "Query violates RFC 2396: " + e.getMessage(), e);
+ return new RequestException(BAD_REQUEST, "URL violates RFC 2396: " + e.getMessage(), e);
}
public static void copyHeaders(HttpServletRequest from, HttpRequest to) {
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java
index e4dbccf1bcb..a89c115a1c2 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java
@@ -26,8 +26,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
-import static com.yahoo.jdisc.http.server.jetty.Exceptions.throwUnchecked;
import static com.yahoo.jdisc.http.server.jetty.JDiscHttpServlet.getConnector;
+import static com.yahoo.yolean.Exceptions.throwUnchecked;
/**
* Runs JDisc security filters for Servlets
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
index 588bbaf73fb..984d93042ab 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
@@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -33,7 +34,46 @@ public class HttpRequestFactoryTest {
private static final int LOCAL_PORT = 80;
@Test
- public final void testIllegalQuery() {
+ public void testLegalURIs() {
+ {
+ URI uri = HttpRequestFactory.getUri(createMockRequest("https", "host", null, null));
+ assertEquals("https", uri.getScheme());
+ assertEquals("host", uri.getHost());
+ assertEquals("", uri.getRawPath());
+ assertNull(uri.getRawQuery());
+ }
+ {
+ URI uri = HttpRequestFactory.getUri(createMockRequest("https", "host", "", ""));
+ assertEquals("https", uri.getScheme());
+ assertEquals("host", uri.getHost());
+ assertEquals("", uri.getRawPath());
+ assertEquals("", uri.getRawQuery());
+ }
+ {
+ URI uri = HttpRequestFactory.getUri(createMockRequest("http", "host.a1-2-3", "", ""));
+ assertEquals("http", uri.getScheme());
+ assertEquals("host.a1-2-3", uri.getHost());
+ assertEquals("", uri.getRawPath());
+ assertEquals("", uri.getRawQuery());
+ }
+ {
+ URI uri = HttpRequestFactory.getUri(createMockRequest("https", "host", "/:1/../1=.", ""));
+ assertEquals("https", uri.getScheme());
+ assertEquals("host", uri.getHost());
+ assertEquals("/:1/../1=.", uri.getRawPath());
+ assertEquals("", uri.getRawQuery());
+ }
+ {
+ URI uri = HttpRequestFactory.getUri(createMockRequest("https", "host", "", "a=/../&?="));
+ assertEquals("https", uri.getScheme());
+ assertEquals("host", uri.getHost());
+ assertEquals("", uri.getRawPath());
+ assertEquals("a=/../&?=", uri.getRawQuery());
+ }
+ }
+
+ @Test
+ public void testIllegalQuery() {
try {
HttpRequestFactory.newJDiscRequest(
new MockContainer(),
@@ -89,7 +129,7 @@ public class HttpRequestFactoryTest {
fail("Above statement should throw");
} catch (RequestException e) {
assertThat(e.getResponseStatus(), is(Response.Status.BAD_REQUEST));
- assertThat(e.getMessage(), equalTo("Query violates RFC 2396: Not valid UTF8! byte C0 in state 0"));
+ assertThat(e.getMessage(), equalTo("URL violates RFC 2396: Not valid UTF8! byte C0 in state 0"));
}
}
diff --git a/jrt/src/com/yahoo/jrt/Transport.java b/jrt/src/com/yahoo/jrt/Transport.java
index 003e40b8aa9..2d2e653956d 100644
--- a/jrt/src/com/yahoo/jrt/Transport.java
+++ b/jrt/src/com/yahoo/jrt/Transport.java
@@ -27,6 +27,7 @@ public class Transport {
private final Worker worker;
private final AtomicInteger runCnt;
private final boolean tcpNoDelay;
+ private final int eventsBeforeWakeup;
private final TransportMetrics metrics = TransportMetrics.getInstance();
private final ArrayList<TransportThread> threads = new ArrayList<>();
@@ -42,12 +43,14 @@ public class Transport {
* @param fatalHandler fatal error handler
* @param cryptoEngine crypto engine to use
* @param numThreads number of {@link TransportThread}s.
+ * @param eventsBeforeWakeup number write events in Q before waking thread up
**/
- public Transport(String name, FatalErrorHandler fatalHandler, CryptoEngine cryptoEngine, int numThreads, boolean tcpNoDelay) {
+ public Transport(String name, FatalErrorHandler fatalHandler, CryptoEngine cryptoEngine, int numThreads, boolean tcpNoDelay, int eventsBeforeWakeup) {
this.name = name;
this.fatalHandler = fatalHandler; // NB: this must be set first
this.cryptoEngine = cryptoEngine;
this.tcpNoDelay = tcpNoDelay;
+ this.eventsBeforeWakeup = Math.max(1, eventsBeforeWakeup);
connector = new Connector();
worker = new Worker(this);
runCnt = new AtomicInteger(numThreads);
@@ -55,10 +58,23 @@ public class Transport {
threads.add(new TransportThread(this, i));
}
}
- public Transport(String name, CryptoEngine cryptoEngine, int numThreads) { this(name, null, cryptoEngine, numThreads, true); }
- public Transport(String name, int numThreads) { this(name, null, CryptoEngine.createDefault(), numThreads, true); }
- public Transport(String name, int numThreads, boolean tcpNoDelay) { this(name, null, CryptoEngine.createDefault(), numThreads, tcpNoDelay); }
- public Transport(String name) { this(name, null, CryptoEngine.createDefault(), 1, true); }
+ public Transport(String name, CryptoEngine cryptoEngine, int numThreads, int eventsBeforeWakeup) {
+ this(name, null, cryptoEngine, numThreads, true, eventsBeforeWakeup);
+ }
+ public Transport(String name, CryptoEngine cryptoEngine, int numThreads) {
+ this(name, null, cryptoEngine, numThreads, true, 1);
+ }
+ public Transport(String name, int numThreads, int eventsBeforeWakeup) {
+ this(name, null, CryptoEngine.createDefault(), numThreads, true, eventsBeforeWakeup);
+ }
+ public Transport(String name, int numThreads, boolean tcpNoDelay, int eventsBeforeWakeup) {
+ this(name, null, CryptoEngine.createDefault(), numThreads, tcpNoDelay, eventsBeforeWakeup); }
+ public Transport(String name, int numThreads) {
+ this(name, null, CryptoEngine.createDefault(), numThreads, true, 1);
+ }
+ public Transport(String name) {
+ this(name, null, CryptoEngine.createDefault(), 1, true, 1);
+ }
// Only for testing
public Transport() { this("default"); }
@@ -72,6 +88,7 @@ public class Transport {
}
boolean getTcpNoDelay() { return tcpNoDelay; }
+ int getEventsBeforeWakeup() { return eventsBeforeWakeup; }
String getName() { return name; }
diff --git a/jrt/src/com/yahoo/jrt/TransportThread.java b/jrt/src/com/yahoo/jrt/TransportThread.java
index 8f158161888..107e0490405 100644
--- a/jrt/src/com/yahoo/jrt/TransportThread.java
+++ b/jrt/src/com/yahoo/jrt/TransportThread.java
@@ -5,7 +5,6 @@ package com.yahoo.jrt;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -32,30 +31,30 @@ public class TransportThread {
}
private class AddConnectionCmd implements Runnable {
- private Connection conn;
+ private final Connection conn;
AddConnectionCmd(Connection conn) { this.conn = conn; }
public void run() { handleAddConnection(conn); }
}
private class CloseConnectionCmd implements Runnable {
- private Connection conn;
+ private final Connection conn;
CloseConnectionCmd(Connection conn) { this.conn = conn; }
public void run() { handleCloseConnection(conn); }
}
private class EnableWriteCmd implements Runnable {
- private Connection conn;
+ private final Connection conn;
EnableWriteCmd(Connection conn) { this.conn = conn; }
public void run() { handleEnableWrite(conn); }
}
private class HandshakeWorkDoneCmd implements Runnable {
- private Connection conn;
+ private final Connection conn;
HandshakeWorkDoneCmd(Connection conn) { this.conn = conn; }
public void run() { handleHandshakeWorkDone(conn); }
}
- private class SyncCmd implements Runnable {
+ private static class SyncCmd implements Runnable {
boolean done = false;
public synchronized void waitDone() {
while (!done) {
@@ -68,7 +67,7 @@ public class TransportThread {
}
}
- private static Logger log = Logger.getLogger(TransportThread.class.getName());
+ private static final Logger log = Logger.getLogger(TransportThread.class.getName());
private final Transport parent;
private final Thread thread;
@@ -120,15 +119,15 @@ public class TransportThread {
}
private boolean postCommand(Runnable cmd) {
- boolean wakeup;
+ int qlen;
synchronized (this) {
if (state == CLOSED) {
return false;
}
- wakeup = queue.isEmpty();
queue.enqueue(cmd);
+ qlen = queue.size();
}
- if (wakeup) {
+ if (qlen == parent.getEventsBeforeWakeup()) {
selector.wakeup();
}
return true;
diff --git a/jrt/tests/com/yahoo/jrt/CryptoUtils.java b/jrt/tests/com/yahoo/jrt/CryptoUtils.java
index 95ea581cb90..06f7fbb1704 100644
--- a/jrt/tests/com/yahoo/jrt/CryptoUtils.java
+++ b/jrt/tests/com/yahoo/jrt/CryptoUtils.java
@@ -9,7 +9,6 @@ import com.yahoo.security.tls.HostnameVerification;
import com.yahoo.security.tls.PeerAuthentication;
import com.yahoo.security.tls.TlsContext;
import com.yahoo.security.tls.policy.AuthorizedPeers;
-import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.RequiredPeerCredential.Field;
@@ -46,8 +45,7 @@ class CryptoUtils {
singleton(
new Role("localhost-role")),
singletonList(
- new RequiredPeerCredential(
- Field.CN, new HostGlobPattern("localhost"))))));
+ RequiredPeerCredential.of(Field.CN, "localhost")))));
static TlsContext createTestTlsContext() {
return new DefaultTlsContext(
diff --git a/jrt_test/src/jrt-test/simpleserver/simpleserver.cpp b/jrt_test/src/jrt-test/simpleserver/simpleserver.cpp
index ff6c84b5b18..cf23a027905 100644
--- a/jrt_test/src/jrt-test/simpleserver/simpleserver.cpp
+++ b/jrt_test/src/jrt-test/simpleserver/simpleserver.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/transport.h>
#include <vespa/fastos/app.h>
class Server : public FRT_Invokable
diff --git a/jrt_test/src/tests/echo/echo-client.cpp b/jrt_test/src/tests/echo/echo-client.cpp
index 3a87e38e6e0..4bc9ac743e4 100644
--- a/jrt_test/src/tests/echo/echo-client.cpp
+++ b/jrt_test/src/tests/echo/echo-client.cpp
@@ -1,6 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+
#include <vespa/fastos/app.h>
class EchoClient : public FastOS_Application
diff --git a/jrt_test/src/tests/mandatory-methods/extract-reflection.cpp b/jrt_test/src/tests/mandatory-methods/extract-reflection.cpp
index cd1ad7e6eed..af9f60f84d3 100644
--- a/jrt_test/src/tests/mandatory-methods/extract-reflection.cpp
+++ b/jrt_test/src/tests/mandatory-methods/extract-reflection.cpp
@@ -1,7 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/app.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/vespalib/util/time.h>
#include <thread>
diff --git a/jrt_test/src/tests/mockup-invoke/mockup-server.cpp b/jrt_test/src/tests/mockup-invoke/mockup-server.cpp
index 4101bb8e9aa..1abe27407b3 100644
--- a/jrt_test/src/tests/mockup-invoke/mockup-server.cpp
+++ b/jrt_test/src/tests/mockup-invoke/mockup-server.cpp
@@ -1,15 +1,15 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/transport.h>
#include <vespa/fastos/app.h>
class MockupServer : public FRT_Invokable
{
-private:
- MockupServer(const MockupServer &);
- MockupServer &operator=(const MockupServer &);
-
public:
+ MockupServer(const MockupServer &) = delete;
+ MockupServer &operator=(const MockupServer &) = delete;
MockupServer(FRT_Supervisor *s)
{
FRT_ReflectionBuilder rb(s);
diff --git a/jrt_test/src/tests/rpc-error/test-errors.cpp b/jrt_test/src/tests/rpc-error/test-errors.cpp
index c30af8ea579..1c0c057e433 100644
--- a/jrt_test/src/tests/rpc-error/test-errors.cpp
+++ b/jrt_test/src/tests/rpc-error/test-errors.cpp
@@ -1,6 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/testapp.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
class TestErrors : public vespalib::TestApp
{
diff --git a/juniper/src/test/auxTest.cpp b/juniper/src/test/auxTest.cpp
index 7a0856dfabb..74b3469f2c0 100644
--- a/juniper/src/test/auxTest.cpp
+++ b/juniper/src/test/auxTest.cpp
@@ -318,10 +318,25 @@ void test_dump(const char* s, unsigned int len)
}
}
+namespace {
+
+#if defined(__cpp_char8_t)
+const char *
+char_from_u8(const char8_t * p) {
+ return reinterpret_cast<const char *>(p);
+}
+#else
+const char *
+char_from_u8(const char * p) {
+ return p;
+}
+#endif
+
+}
void AuxTest::TestUTF8(unsigned int size)
{
- const char* s = u8"\u00e5pent s\u00f8k\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5";
+ const char* s = char_from_u8(u8"\u00e5pent s\u00f8k\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5");
const unsigned char* p = (const unsigned char*)s;
int moved = 0;
@@ -378,20 +393,20 @@ void AuxTest::TestUTF8(unsigned int size)
void AuxTest::TestUTF8context()
{
- const char* iso_cont = u8"AND(m\u00b5ss,fast,s\u00f8kemotor,\u00e5relang)";
+ const char* iso_cont = char_from_u8(u8"AND(m\u00b5ss,fast,s\u00f8kemotor,\u00e5relang)");
juniper::QueryParser q(iso_cont);
juniper::QueryHandle qh(q, NULL, juniper::_Juniper->getModifier());
// some content
- std::string s(u8"Fast leverer s\u00d8kemotorer og andre nyttige ting for \u00e5 finne frem p\u00e5 ");
- s.append(u8"internett. Teknologien er basert p\u00e5 \u00c5relang");
+ std::string s(char_from_u8(u8"Fast leverer s\u00d8kemotorer og andre nyttige ting for \u00e5 finne frem p\u00e5 "));
+ s.append(char_from_u8(u8"internett. Teknologien er basert p\u00e5 \u00c5relang"));
s += UNIT_SEPARATOR;
- s.append(u8"norsk innsats og forskning i");
+ s.append(char_from_u8(u8"norsk innsats og forskning i"));
s += GROUP_SEPARATOR;
- s.append(u8"trondheimsmilj\u00f8et. M\u00b5ss med denne nye funksjonaliteten for \u00e5 vise frem");
+ s.append(char_from_u8(u8"trondheimsmilj\u00f8et. M\u00b5ss med denne nye funksjonaliteten for \u00e5 vise frem"));
s += UNIT_SEPARATOR;
- s.append(u8" beste forekomst av s\u00f8ket med s\u00f8kemotor til brukeren blir det enda bedre. ");
- s.append(u8"Hvis bare UTF8-kodingen virker som den skal for tegn som tar mer enn \u00e9n byte.");
+ s.append(char_from_u8(u8" beste forekomst av s\u00f8ket med s\u00f8kemotor til brukeren blir det enda bedre. "));
+ s.append(char_from_u8(u8"Hvis bare UTF8-kodingen virker som den skal for tegn som tar mer enn \u00e9n byte."));
juniper::Result* res = juniper::Analyse(juniper::TestConfig, &qh, s.c_str(), s.size(), 0, 0, 0);
_test(res != NULL);
diff --git a/juniper/src/test/mcandTest.cpp b/juniper/src/test/mcandTest.cpp
index 549397c90f4..085c98b63e8 100644
--- a/juniper/src/test/mcandTest.cpp
+++ b/juniper/src/test/mcandTest.cpp
@@ -391,6 +391,7 @@ struct MyTokenProcessor : public ITokenProcessor
Matcher &_m;
std::vector<size_t> _cands;
MyTokenProcessor(Matcher &m) : _m(m), _cands() {}
+ ~MyTokenProcessor() override;
void handle_token(Token &token) override {
_m.handle_token(token);
const match_sequence *ms = _m.GetWorkSet();
@@ -402,6 +403,7 @@ struct MyTokenProcessor : public ITokenProcessor
}
};
+MyTokenProcessor::~MyTokenProcessor() = default;
/**
* Test that max number of match candidates can be controlled.
diff --git a/juniper/src/vespa/juniper/Matcher.cpp b/juniper/src/vespa/juniper/Matcher.cpp
index 9b91166fa29..bb5bc0bdcae 100644
--- a/juniper/src/vespa/juniper/Matcher.cpp
+++ b/juniper/src/vespa/juniper/Matcher.cpp
@@ -375,8 +375,8 @@ void Matcher::log_matches(int printcount)
_log_text.append("<table>");
if (m.size() > 0) {
_log_text.append("<tr class=shade>");
- sprintf(buf, "<td colspan=%d align=center><b>Topmost %d matches out of %d",
- nterms+2, std::min(printcount, m.size()),m.size());
+ sprintf(buf, "<td colspan=%d align=center><b>Topmost %zu matches out of %zu",
+ nterms+2, std::min(static_cast<size_t>(printcount), m.size()),m.size());
_log_text.append(buf);
_log_text.append("</b></td></tr>");
}
diff --git a/juniper/src/vespa/juniper/Matcher.h b/juniper/src/vespa/juniper/Matcher.h
index 6bbb307b74c..db90a5a3091 100644
--- a/juniper/src/vespa/juniper/Matcher.h
+++ b/juniper/src/vespa/juniper/Matcher.h
@@ -16,7 +16,6 @@
#include <vector>
#include <list>
-#include "multiset.h"
#include <map>
#include <string>
#include "ITokenProcessor.h"
diff --git a/juniper/src/vespa/juniper/keyocc.h b/juniper/src/vespa/juniper/keyocc.h
index fae4861d1ef..c957909ac90 100644
--- a/juniper/src/vespa/juniper/keyocc.h
+++ b/juniper/src/vespa/juniper/keyocc.h
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include "multiset.h"
#include "matchelem.h"
#include "querynode.h"
diff --git a/juniper/src/vespa/juniper/matchelem.h b/juniper/src/vespa/juniper/matchelem.h
index 5da6b1b0e03..b0af8f3364f 100644
--- a/juniper/src/vespa/juniper/matchelem.h
+++ b/juniper/src/vespa/juniper/matchelem.h
@@ -4,7 +4,7 @@
#pragma once
#include <string>
-#include "multiset.h"
+#include <set>
#include "querynode.h"
class Matcher;
@@ -15,12 +15,12 @@ class MatchCandidate;
template <typename _Elem>
struct sequential_elem
{
- inline bool operator()(_Elem m1, _Elem m2)
+ inline bool operator()(_Elem m1, _Elem m2) const
{
return m1->starttoken() < m2->starttoken();
}
};
-typedef JUNIPER_SET<key_occ*, sequential_elem<key_occ*> > keylist;
+typedef std::set<key_occ*, sequential_elem<key_occ*> > keylist;
class MatchElement
{
diff --git a/juniper/src/vespa/juniper/mcand.h b/juniper/src/vespa/juniper/mcand.h
index 0928c55ddea..fee86fd83af 100644
--- a/juniper/src/vespa/juniper/mcand.h
+++ b/juniper/src/vespa/juniper/mcand.h
@@ -18,7 +18,7 @@ struct gtematch_cand {
bool operator()(const MatchCandidate* m1, const MatchCandidate* m2) const;
bool gtDistance(const MatchCandidate* m1, const MatchCandidate* m2) const;
};
-typedef JUNIPER_MULTISET<MatchCandidate*, gtematch_cand> match_candidate_set;
+typedef std::multiset<MatchCandidate*, gtematch_cand> match_candidate_set;
class MatchCandidate : public MatchElement
{
diff --git a/juniper/src/vespa/juniper/multiset.h b/juniper/src/vespa/juniper/multiset.h
deleted file mode 100644
index 5c4495080fe..00000000000
--- a/juniper/src/vespa/juniper/multiset.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#pragma once
-#include <algorithm>
-#include <vector>
-#include <cstddef>
-
-#ifdef __GNUC__
-#define USE_STL_WORKAROUNDS 1
-#endif
-
-#ifdef USE_STL_WORKAROUNDS
-
-namespace fast {
-
-// STL like wrapper around Fast_Array providing multiset functionality
-
-
-template <class ValueType, class Comparator>
-class multiset
-{
-public:
-
- class iterator
- : public std::iterator<std::bidirectional_iterator_tag, ValueType,
- ptrdiff_t, ValueType*, ValueType&>
- {
- public:
- iterator(multiset<ValueType, Comparator>& mset, int pos) : _myset(mset), _pos(pos) {}
- inline ValueType operator*() { return _myset._values[_pos]; }
- inline iterator& operator++() { _pos++; return *this; }
- inline iterator& operator--() { _pos--; return *this; }
- inline bool operator!=(const iterator& i2) { return i2._pos != _pos; }
- inline bool operator==(const iterator& i2) { return i2._pos == _pos; }
- protected:
- friend class multiset;
- const multiset<ValueType, Comparator>& _myset;
- int _pos;
- };
-
- inline multiset() : _values(), _sorted(true) {}
-
- inline bool insert(ValueType& v)
- {
- _sorted = false;
- _values.push_back(v);
- return true;
- }
-
- inline void clear() { _values.clear(); _sorted = true; }
-
- inline int size() const { return _values.size(); }
-
- iterator begin() { sort(); return iterator(*this, 0); }
- iterator end() { return iterator(*this, size()); }
-
-protected:
- inline void sort()
- {
- if (!_sorted) {
- std::stable_sort(_values.begin(), _values.end(), Comparator());
- _sorted = true;
- }
- }
-
-private:
- friend class iterator;
- std::vector<ValueType> _values;
- bool _sorted;
-}; // end class multiset
-
-} // end namespace fast
-
-#define JUNIPER_MULTISET fast::multiset
-#define JUNIPER_SET fast::multiset
-
-#else
-#include <set>
-#define JUNIPER_MULTISET std::multiset
-#define JUNIPER_SET std::set
-#endif
-
diff --git a/juniper/src/vespa/juniper/sumdesc.h b/juniper/src/vespa/juniper/sumdesc.h
index 0af1f2d3cd2..e80bf9ba9f2 100644
--- a/juniper/src/vespa/juniper/sumdesc.h
+++ b/juniper/src/vespa/juniper/sumdesc.h
@@ -61,7 +61,7 @@ protected:
void add_desc(off_t pos, ssize_t len, bool highlight);
- typedef JUNIPER_SET<MatchCandidate*,sequential_elem<MatchCandidate*> > cand_list;
+ typedef std::set<MatchCandidate*,sequential_elem<MatchCandidate*> > cand_list;
typedef std::list<highlight_desc> print_list;
/** Helper function to build a simple query highlight of the complete document */
diff --git a/logd/src/logd/rpc_forwarder.cpp b/logd/src/logd/rpc_forwarder.cpp
index ffc43bce0bb..90adf7c0b66 100644
--- a/logd/src/logd/rpc_forwarder.cpp
+++ b/logd/src/logd/rpc_forwarder.cpp
@@ -7,6 +7,10 @@
#include <vespa/log/exceptions.h>
#include <vespa/vespalib/util/buffer.h>
#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/supervisor.h>
+
+
#include <vespa/log/log.h>
LOG_SETUP(".logd.rpc_forwarder");
diff --git a/logd/src/logd/rpc_forwarder.h b/logd/src/logd/rpc_forwarder.h
index 37729db088f..fbc3ecbc09a 100644
--- a/logd/src/logd/rpc_forwarder.h
+++ b/logd/src/logd/rpc_forwarder.h
@@ -5,10 +5,12 @@
#include "forwarder.h"
#include "proto_converter.h"
#include <vespa/log/log_message.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/target.h>
#include <memory>
#include <vector>
+class FRT_Supervisor;
+
namespace logdemon {
struct Metrics;
diff --git a/logd/src/tests/rpc_forwarder/rpc_forwarder_test.cpp b/logd/src/tests/rpc_forwarder/rpc_forwarder_test.cpp
index d39a9ade0a8..370ca7f458e 100644
--- a/logd/src/tests/rpc_forwarder/rpc_forwarder_test.cpp
+++ b/logd/src/tests/rpc_forwarder/rpc_forwarder_test.cpp
@@ -5,6 +5,10 @@
#include <logd/rpc_forwarder.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/metrics/dummy_metrics_manager.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+
+
using namespace logdemon;
using vespalib::metrics::DummyMetricsManager;
diff --git a/messagebus/abi-spec.json b/messagebus/abi-spec.json
index 4bec4bd91fe..f3e7c5664d6 100644
--- a/messagebus/abi-spec.json
+++ b/messagebus/abi-spec.json
@@ -398,6 +398,8 @@
"public final java.lang.String getDefMd5()",
"public final java.lang.String getDefName()",
"public final java.lang.String getDefNamespace()",
+ "public final boolean getApplyOnRestart()",
+ "public final void setApplyOnRestart(boolean)",
"public com.yahoo.messagebus.MessagebusConfig build()"
],
"fields": [
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/DynamicThrottlePolicy.java b/messagebus/src/main/java/com/yahoo/messagebus/DynamicThrottlePolicy.java
index 1281bd0b544..ab09c9f5720 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/DynamicThrottlePolicy.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/DynamicThrottlePolicy.java
@@ -8,11 +8,43 @@ import java.util.logging.Logger;
/**
* This is an implementation of the {@link ThrottlePolicy} that offers dynamic limits to the number of pending messages a
- * {@link SourceSession} is allowed to have.
- *
- * <b>NOTE:</b> By context, "pending" is refering to the number of sent messages that have not been replied to yet.
+ * {@link SourceSession} is allowed to have. Pending means the number of sent messages that have not been replied to yet.
+ * <p>
+ * The algorithm works by increasing the number of messages allowed to be pending, the <em>window size</em>, until
+ * this no longer increases throughput. At this point, the algorithm is driven by synthetic attraction towards latencies
+ * which satisfy <code>log10(1 / latency) % 1 = e</code>, for some constant <code>0 &lt; e &lt; 1</code>. Weird? Most certainly!
+ * </p><p>
+ * The effect is that the window size the algorithm produces, for a saturated ideal server, has a level for each power
+ * of ten with an attractor the window size tends towards while on this level, determined by the <code>e</code> above.
+ * The {@link #setEfficiencyThreshold} determines the <code>e</code> constant. When <code>e</code> is set so the
+ * attractor is close to the start of the interval, this has an inhibiting effect on the algorithm, and it is basically
+ * reduced to "increase window size until this no longer increases throughput enough that it defeats the random noise".
+ * As the attractor moves towards the end of the intervals, the algorithm becomes increasingly eager in increasing
+ * its window size past what it measures as effective — if moved to the very end of the interval, the algorithm explodes.
+ * The default setting has the attractor at <code>log10(2)</code> of the way from start to end of these levels.
+ * </p><p>
+ * Because the algorithm stops increasing the window size when increases in throughput drown in random variations, the
+ * {@link #setWindowSizeIncrement} directly influences the efficient work domain of the algorithm. With the default
+ * setting of <code>20</code>, it seems to struggle to increase past window sizes of a couple thousand. Using a static
+ * increment (and a backoff factor) seems to be necessary to effectively balance the load different, competing policies
+ * are allowed to produce.
+ * </p><p>
+ * When there are multiple policies that compete against each other, they will increase load until saturating the server.
+ * If keeping all other policies but one fixed, this one policy would still see an increase in throughput with increased
+ * window size, even with a saturated server, as it would be given a greater share of the server's resources. However,
+ * since all algorithms adjust their windows concurrently, they will all reduce the throughput of the other algorithms.
+ * The result is that the commonly see the server as saturated, and commonly reach the behaviour where some increases in
+ * window size lead to measurable throughput gains, while others don't.
+ * </p><p>
+ * Now the weighting ({@link #setWeight} comes into play: with equals weights, two algorithms would have a break-even
+ * between being governed by the attractors (above), which eventually limits window size, and increases due to positive
+ * measurements, at the same point along the window size axis. With smaller weights, i.e., smaller increases to window
+ * size, this break-even occurs where the curve is steeper, i.e., where the client has a smaller share of the server.
+ * Thus, competing algorithms with different weights end up with a resource distribution roughly proportional to weight.
+ * </p>
*
* @author Simon Thoresen Hult
+ * @author jonmv
*/
public class DynamicThrottlePolicy extends StaticThrottlePolicy {
@@ -23,7 +55,7 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
private double resizeRate = 3;
private long resizeTime = 0;
private long timeOfLastMessage;
- private double efficiencyThreshold = 1.0;
+ private double efficiencyThreshold = 1;
private double windowSizeIncrement = 20;
private double windowSize = windowSizeIncrement;
private double minWindowSize = windowSizeIncrement;
@@ -76,7 +108,10 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
windowSize = Math.min(windowSize, pendingCount + windowSizeIncrement);
}
timeOfLastMessage = time;
- return pendingCount < windowSize;
+ int windowSizeFloored = (int) windowSize;
+ // Use floating point window sizes, so the algorithm sees the different in 1.1 and 1.9 window size.
+ boolean carry = numSent < (windowSize * resizeRate) * (windowSize - windowSizeFloored);
+ return pendingCount < windowSizeFloored + (carry ? 1 : 0);
}
@Override
@@ -94,30 +129,30 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
numSent = 0;
numOk = 0;
-
if (maxThroughput > 0 && throughput > maxThroughput * 0.95) {
// No need to increase window when we're this close to max.
- } else if (throughput > localMaxThroughput * 1.01) {
+ // TODO jonmv: Not so sure — what if we're too high, and should back off?
+ } else if (throughput > localMaxThroughput) {
localMaxThroughput = throughput;
- windowSize += weight*windowSizeIncrement;
+ windowSize += weight * windowSizeIncrement;
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, "windowSize " + windowSize + " throughput " + throughput + " local max " + localMaxThroughput);
}
} else {
// scale up/down throughput for comparing to window size
double period = 1;
- while(throughput * period/windowSize < 2) {
+ while(throughput * period / windowSize < 2) {
period *= 10;
}
- while(throughput * period/windowSize > 2) {
+ while(throughput * period / windowSize > 2) {
period *= 0.1;
}
- double efficiency = throughput*period/windowSize;
+ double efficiency = throughput * period / windowSize; // "efficiency" is a strange name. This is where on the level it is.
if (efficiency < efficiencyThreshold) {
windowSize = Math.min(windowSize * windowSizeBackOff, windowSize - decrementFactor * windowSizeIncrement);
localMaxThroughput = 0;
} else {
- windowSize += weight*windowSizeIncrement;
+ windowSize += weight * windowSizeIncrement;
}
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, "windowSize " + windowSize + " throughput " + throughput + " local max " + localMaxThroughput + " efficiency " + efficiency);
@@ -136,6 +171,11 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
}
/**
+ * Determines where on each latency level the attractor sits. 2 is at the very end, and makes this to *boom*.
+ * 0.2 is at the very start, and makes the algorithm more conservative. Probably fine to stay away from this.
+ */
+ // Original javadoc is non-sense, but kept for historical reasons.
+ /*
* Sets the lower efficiency threshold at which the algorithm should perform window size back off. Efficiency is
* the correlation between throughput and window size. The algorithm will increase the window size until efficiency
* drops below the efficiency of the local maxima times this value.
@@ -157,11 +197,12 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
*/
public DynamicThrottlePolicy setWindowSizeIncrement(double windowSizeIncrement) {
this.windowSizeIncrement = windowSizeIncrement;
+ this.windowSize = Math.max(this.minWindowSize, this.windowSizeIncrement);
return this;
}
/**
- * Sets the relative stepsize when decreasing window size.
+ * Sets the relative step size when decreasing window size.
*
* @param decrementFactor the step size to set
* @return this, to allow chaining
@@ -173,8 +214,7 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
/**
* Sets the factor of window size to back off to when the algorithm determines that efficiency is not increasing.
- * A value of 1 means that there is no back off from the local maxima, and means that the algorithm will fail to
- * reduce window size to something lower than a previous maxima. This value is capped to the [0, 1] range.
+ * Capped to [0, 1]
*
* @param windowSizeBackOff the back off to set
* @return this, to allow chaining
@@ -186,31 +226,31 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
/**
* Sets the rate at which the window size is updated. The larger the value, the less responsive the resizing
- * becomes. However, the smaller the value, the less accurate the measurements become.
+ * becomes. However, the smaller the value, the less accurate the measurements become. Capped to [2, )
*
* @param resizeRate the rate to set
* @return this, to allow chaining
*/
public DynamicThrottlePolicy setResizeRate(double resizeRate) {
- this.resizeRate = resizeRate;
+ this.resizeRate = Math.max(2, resizeRate);
return this;
}
/**
* Sets the weight for this client. The larger the value, the more resources
- * will be allocated to this clients. Resources are shared between clients
- * proportiannally to their weights.
+ * will be allocated to this clients. Resources are shared between clients roughly
+ * proportionally to the set weights. Must be a positive number.
*
* @param weight the weight to set
* @return this, to allow chaining
*/
public DynamicThrottlePolicy setWeight(double weight) {
- this.weight = weight;
+ this.weight = Math.pow(weight, 0.5);
return this;
}
/**
- * Sets the maximium number of pending operations allowed at any time, in
+ * Sets the maximum number of pending operations allowed at any time, in
* order to avoid using too much resources.
*
* @param max the max to set
@@ -232,7 +272,7 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
/**
- * Sets the minimium number of pending operations allowed at any time, in
+ * Sets the minimum number of pending operations allowed at any time, in
* order to keep a level of performance.
*
* @param min the min to set
@@ -240,6 +280,7 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
*/
public DynamicThrottlePolicy setMinWindowSize(double min) {
this.minWindowSize = min;
+ this.windowSize = Math.max(this.minWindowSize, this.windowSizeIncrement);
return this;
}
@@ -265,7 +306,9 @@ public class DynamicThrottlePolicy extends StaticThrottlePolicy {
* @return the max limit
*/
public int getMaxPendingCount() {
- return (int)windowSize;
+ return (int) windowSize;
}
+ double getWindowSize() { return windowSize; }
+
}
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/IntermediateSession.java b/messagebus/src/main/java/com/yahoo/messagebus/IntermediateSession.java
index 309316b450a..ca772ce6c3a 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/IntermediateSession.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/IntermediateSession.java
@@ -4,7 +4,7 @@ package com.yahoo.messagebus;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * A session which supports receiving, forwarding and acknowledgement of messages. An intermediate session is expacted
+ * A session which supports receiving, forwarding and acknowledging messages. An intermediate session is expected
* to either forward or acknowledge every message received.
*
* @author Simon Thoresen Hult
@@ -49,7 +49,7 @@ public final class IntermediateSession implements MessageHandler, ReplyHandler {
/**
* This method unregisters this session from message bus, effectively disabling any more messages from being
* delivered to the message handler. After unregistering, this method calls {@link com.yahoo.messagebus.MessageBus#sync()}
- * as to ensure that there are no threads currently entangled in the handler.
+ * to ensure that there are no threads currently entangled in the handler.
*
* This method will deadlock if you call it from the message or reply handler.
*/
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/ProtocolRepository.java b/messagebus/src/main/java/com/yahoo/messagebus/ProtocolRepository.java
index d3ab41331ae..4ca4887221a 100755
--- a/messagebus/src/main/java/com/yahoo/messagebus/ProtocolRepository.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/ProtocolRepository.java
@@ -84,10 +84,7 @@ public class ProtocolRepository {
try {
ret = protocol.createPolicy(policyName, policyParam);
} catch (RuntimeException e) {
- log.log(Level.SEVERE, "Protcol '" + protocolName + "' threw an exception: " + e.getMessage(), e);
- if (ret != null) {
- ret.destroy();
- }
+ log.log(Level.SEVERE, "Protocol '" + protocolName + "' threw an exception: " + e.getMessage(), e);
return null;
}
if (ret == null) {
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/SourceSession.java b/messagebus/src/main/java/com/yahoo/messagebus/SourceSession.java
index 0b731a4c6fb..204bf2f7906 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/SourceSession.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/SourceSession.java
@@ -186,7 +186,7 @@ public final class SourceSession implements ReplyHandler, MessageBus.SendBlocked
if (msg.isExpired()) {
Error error = new Error(ErrorCode.TIMEOUT, "Timed out in sendQ");
notifyComplete(new Result(error));
- replyHandler.handleReply(createSendTimedoutReply(msg, error));
+ replyHandler.handleReply(createSendTimedOutReply(msg, error));
return true;
}
return false;
@@ -214,7 +214,7 @@ public final class SourceSession implements ReplyHandler, MessageBus.SendBlocked
}
}
- private Reply createSendTimedoutReply(Message msg, Error error) {
+ private Reply createSendTimedOutReply(Message msg, Error error) {
Reply reply = new EmptyReply();
reply.setMessage(msg);
reply.addError(error);
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/network/NetworkOwner.java b/messagebus/src/main/java/com/yahoo/messagebus/network/NetworkOwner.java
index 4b60facef45..2b55bf5b901 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/network/NetworkOwner.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/network/NetworkOwner.java
@@ -13,7 +13,7 @@ import com.yahoo.text.Utf8String;
* across the network is part of the Network interface, whereas this interface exposes the required
* functionality of a network owner to be able to decode and deliver incoming messages.
*
- * @author <a href="mailto:havardpe@yahoo-inc.com">Haavard Pettersen</a>
+ * @author havardpe
*/
public interface NetworkOwner {
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetwork.java b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetwork.java
index b0724ad6029..1c41f87d1ee 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetwork.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetwork.java
@@ -87,7 +87,8 @@ public class RPCNetwork implements Network, MethodHandler {
public RPCNetwork(RPCNetworkParams params, SlobrokConfigSubscriber slobrokConfig) {
this.slobroksConfig = slobrokConfig;
identity = params.getIdentity();
- orb = new Supervisor(new Transport("mbus-rpc-" + identity.getServicePrefix(), params.getNumNetworkThreads(), shouldEnableTcpNodelay(params.getOptimization())));
+ orb = new Supervisor(new Transport("mbus-rpc-" + identity.getServicePrefix(), params.getNumNetworkThreads(),
+ shouldEnableTcpNodelay(params.getOptimization()), params.getTransportEventsBeforeWakeup()));
orb.setMaxInputBufferSize(params.getMaxInputBufferSize());
orb.setMaxOutputBufferSize(params.getMaxOutputBufferSize());
targetPool = new RPCTargetPool(params.getConnectionExpireSecs(), params.getNumTargetsPerSpec());
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetworkParams.java b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetworkParams.java
index e77cddd8b06..db22363785d 100755
--- a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetworkParams.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCNetworkParams.java
@@ -21,6 +21,8 @@ public class RPCNetworkParams {
private double connectionExpireSecs = 30;
private int numTargetsPerSpec = 1;
private int numNetworkThreads = 2;
+
+ private int transportEventsBeforeWakeup = 1;
public enum Optimization {LATENCY, THROUGHPUT}
Optimization optimization = Optimization.LATENCY;
@@ -216,4 +218,13 @@ public class RPCNetworkParams {
this.maxOutputBufferSize = maxOutputBufferSize;
return this;
}
+
+ public int getTransportEventsBeforeWakeup() {
+ return transportEventsBeforeWakeup;
+ }
+
+ public RPCNetworkParams setTransportEventsBeforeWakeup(int transportEventsBeforeWakeup) {
+ this.transportEventsBeforeWakeup = transportEventsBeforeWakeup;
+ return this;
+ }
}
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/routing/PolicyDirective.java b/messagebus/src/main/java/com/yahoo/messagebus/routing/PolicyDirective.java
index bf793238b3b..2391381ffed 100755
--- a/messagebus/src/main/java/com/yahoo/messagebus/routing/PolicyDirective.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/routing/PolicyDirective.java
@@ -3,7 +3,7 @@ package com.yahoo.messagebus.routing;
/**
* This class represents a policy directive within a {@link Hop}'s selector. This means to create the named protocol
- * using the given parameter string, and the running that protocol within the context of this directive.
+ * using the given parameter string, and then running that protocol within the context of this directive.
*
* @author Simon Thoresen Hult
*/
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/routing/RoutingNode.java b/messagebus/src/main/java/com/yahoo/messagebus/routing/RoutingNode.java
index d4a62bb179f..05fc6f62236 100755
--- a/messagebus/src/main/java/com/yahoo/messagebus/routing/RoutingNode.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/routing/RoutingNode.java
@@ -473,7 +473,7 @@ public class RoutingNode implements ReplyHandler {
}
/**
- * This method traverses the current hop looking for an isntance of {@link ErrorDirective}. If one is found, this
+ * This method traverses the current hop looking for an instance of {@link ErrorDirective}. If one is found, this
* method assigns a corresponding error reply to this node.
*
* @return True if an error was found.
diff --git a/messagebus/src/test/java/com/yahoo/messagebus/ConfigAgentTestCase.java b/messagebus/src/test/java/com/yahoo/messagebus/ConfigAgentTestCase.java
index 3fbc5d25cd9..02fe407b3de 100755
--- a/messagebus/src/test/java/com/yahoo/messagebus/ConfigAgentTestCase.java
+++ b/messagebus/src/test/java/com/yahoo/messagebus/ConfigAgentTestCase.java
@@ -3,21 +3,16 @@ package com.yahoo.messagebus;
import com.yahoo.config.subscription.ConfigSet;
import com.yahoo.config.subscription.ConfigURI;
-import com.yahoo.messagebus.routing.HopSpec;
-import com.yahoo.messagebus.routing.RouteSpec;
import com.yahoo.messagebus.routing.RoutingSpec;
-import com.yahoo.messagebus.routing.RoutingTableSpec;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
/**
* @author Simon Thoresen Hult
@@ -28,7 +23,7 @@ public class ConfigAgentTestCase {
public TemporaryFolder tmpFolder = new TemporaryFolder();
@Test
- public void testRoutingConfig() throws InterruptedException, IOException {
+ public void testRoutingConfig() throws InterruptedException {
LocalHandler handler = new LocalHandler();
assertFalse(testHalf(handler.spec));
assertFalse(testFull(handler.spec));
@@ -174,26 +169,23 @@ public class ConfigAgentTestCase {
private static class LocalHandler implements ConfigHandler {
- volatile RoutingSpec spec = new RoutingSpec();
+ RoutingSpec spec = new RoutingSpec();
- public void setupRouting(RoutingSpec spec) {
+ public synchronized void setupRouting(RoutingSpec spec) {
this.spec = spec;
+ notify();
}
- public void reset() {
+ public synchronized void reset() {
spec = null;
}
- public boolean await(int timeout, TimeUnit unit) throws InterruptedException {
- long millis = System.currentTimeMillis() + unit.toMillis(timeout);
- while (spec == null) {
- long now = System.currentTimeMillis();
- if (now >= millis) {
- return false;
- }
- Thread.sleep(1000);
- }
- return true;
+ public synchronized boolean await(int timeout, TimeUnit unit) throws InterruptedException {
+ long remaining, doom = System.currentTimeMillis() + unit.toMillis(timeout);
+ while (spec == null && (remaining = doom - System.currentTimeMillis()) > 0)
+ wait(remaining);
+
+ return spec != null;
}
}
}
diff --git a/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java b/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java
new file mode 100644
index 00000000000..7f48edfd48c
--- /dev/null
+++ b/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java
@@ -0,0 +1,353 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.messagebus;
+
+import com.yahoo.messagebus.test.SimpleMessage;
+import com.yahoo.messagebus.test.SimpleReply;
+import org.junit.Test;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+import java.util.stream.IntStream;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toUnmodifiableList;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * These tests are based on a simulated server, the {@link MockServer} below.
+ * The purpose is to both verify the behaviour of the algorithm, while also providing a playground
+ * for development, tuning, etc..
+ *
+ * @author jonmv
+ */
+public class DynamicThrottlePolicyTest {
+
+ static final Message message = new SimpleMessage("message");
+ static final Reply success = new SimpleReply("success");
+ static final Reply error = new SimpleReply("error");
+ static {
+ success.setContext(message.getApproxSize());
+ error.setContext(message.getApproxSize());
+ error.addError(new Error(0, "overload"));
+ }
+
+ @Test
+ public void singlePolicyWithSmallWindows() {
+ long operations = 1_000_000;
+ int numberOfWorkers = 1;
+ int maximumTasksPerWorker = 16;
+ int workerParallelism = 12;
+
+ { // This setup is lucky with the artificial local maxima for latency, and gives good results. See below for counter-examples.
+ int workPerSuccess = 8;
+
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer).setMinWindowSize(1)
+ .setWindowSizeIncrement(0.1)
+ .setResizeRate(100);
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ System.err.println(operations / (double) timer.milliTime());
+ assertInRange(minMaxPending, summary.averagePending, maxMaxPending);
+ assertInRange(minMaxPending, summary.averageWindows[0], maxMaxPending);
+ assertInRange(1, summary.inefficiency, 1.1);
+ assertInRange(0, summary.waste, 0.01);
+ }
+
+ { // This setup is not so lucky, and the artificial behaviour pushes it into overload.
+ int workPerSuccess = 5;
+
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer).setMinWindowSize(1)
+ .setWindowSizeIncrement(0.1)
+ .setResizeRate(100);
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy);
+
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ assertInRange(maxMaxPending, summary.averagePending, maxMaxPending * 1.1);
+ assertInRange(maxMaxPending, summary.averageWindows[0], maxMaxPending * 1.1);
+ assertInRange(1.2, summary.inefficiency, 1.5);
+ assertInRange(0.5, summary.waste, 1.5);
+ }
+
+ { // This setup is not so lucky either, and the artificial behaviour keeps it far below a good throughput.
+ int workPerSuccess = 4;
+
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer).setMinWindowSize(1)
+ .setWindowSizeIncrement(0.1)
+ .setResizeRate(100);
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ assertInRange(0.3 * minMaxPending, summary.averagePending, 0.5 * minMaxPending);
+ assertInRange(0.3 * minMaxPending, summary.averageWindows[0], 0.5 * minMaxPending);
+ assertInRange(2, summary.inefficiency, 4);
+ assertInRange(0, summary.waste, 0);
+ }
+ }
+
+ /** Sort of a dummy test, as the conditions are perfect. In a more realistic scenario, below, the algorithm needs luck to climb this high. */
+ @Test
+ public void singlePolicySingleWorkerWithIncreasingParallelism() {
+ for (int i = 0; i < 5; i++) {
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer);
+ int scaleFactor = (int) Math.pow(10, i);
+ long operations = 3_000 * scaleFactor;
+ int workPerSuccess = 6;
+ int numberOfWorkers = 1;
+ int maximumTasksPerWorker = 100000;
+ int workerParallelism = scaleFactor;
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ assertInRange(minMaxPending, summary.averagePending, maxMaxPending);
+ assertInRange(minMaxPending, summary.averageWindows[0], maxMaxPending);
+ assertInRange(1, summary.inefficiency, 1 + (5e-5 * scaleFactor)); // Slow ramp-up
+ assertInRange(0, summary.waste, 0.1);
+ }
+ }
+
+ /** A more realistic test, where throughput gradually flattens with increasing window size, and with more variance in throughput. */
+ @Test
+ public void singlePolicyIncreasingWorkersWithNoParallelism() {
+ for (int i = 0; i < 5; i++) {
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer);
+ int scaleFactor = (int) Math.pow(10, i);
+ long operations = 5_000 * scaleFactor;
+ // workPerSuccess determines the latency of the simulated server, which again determines the impact of the
+ // synthetic attractors of the algorithm, around latencies which give (close to) integer log10(1 / latency).
+ // With a value of 5, the impact is that the algorithm is pushed upwards slightly above 10k window size,
+ // which is the optimal choice for the case with 10000 clients.
+ // Change this to, e.g., 6 and the algorithm fails to climb as high, as the "ideal latency" is obtained at
+ // a lower latency than what is measured at 10k window size.
+ // On the other hand, changing it to 4 moves the attractor out of reach for the algorithm, which fails to
+ // push window size past 2k on its own.
+ int workPerSuccess = 5;
+ int numberOfWorkers = scaleFactor;
+ int maximumTasksPerWorker = 100000;
+ int workerParallelism = 1;
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ assertInRange(minMaxPending, summary.averagePending, maxMaxPending);
+ assertInRange(minMaxPending, summary.averageWindows[0], maxMaxPending);
+ assertInRange(1, summary.inefficiency, 1 + 0.2 * i); // Even slower ramp-up.
+ assertInRange(0, summary.waste, 0);
+ }
+ }
+
+ @Test
+ public void twoWeightedPoliciesWithUnboundedTaskQueue() {
+ for (int i = 0; i < 10; i++) {
+ long operations = 1_000_000;
+ int workPerSuccess = 6 + (int) (30 * Math.random());
+ int numberOfWorkers = 1 + (int) (10 * Math.random());
+ int maximumTasksPerWorker = 100_000;
+ int workerParallelism = 32;
+ CustomTimer timer = new CustomTimer();
+ DynamicThrottlePolicy policy1 = new DynamicThrottlePolicy(timer);
+ DynamicThrottlePolicy policy2 = new DynamicThrottlePolicy(timer).setWeight(0.5);
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policy1, policy2);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ assertInRange(minMaxPending, summary.averagePending, maxMaxPending);
+ // Actual shares are not distributed perfectly proportionally to weights, but close enough.
+ assertInRange(minMaxPending * 0.6, summary.averageWindows[0], maxMaxPending * 0.6);
+ assertInRange(minMaxPending * 0.4, summary.averageWindows[1], maxMaxPending * 0.4);
+ assertInRange(1, summary.inefficiency, 1.02);
+ assertInRange(0, summary.waste, 0);
+ }
+ }
+
+ @Test
+ public void tenPoliciesVeryParallelServerWithShortTaskQueue() {
+ for (int i = 0; i < 10; i++) {
+ long operations = 1_000_000;
+ int workPerSuccess = 6;
+ int numberOfWorkers = 6;
+ int maximumTasksPerWorker = 180 + (int) (120 * Math.random());
+ int workerParallelism = 60 + (int) (40 * Math.random());
+ CustomTimer timer = new CustomTimer();
+ int p = 10;
+ DynamicThrottlePolicy[] policies = IntStream.range(0, p)
+ .mapToObj(j -> new DynamicThrottlePolicy(timer)
+ .setWeight((j + 1.0) / p)
+ .setWindowSizeIncrement(5)
+ .setMinWindowSize(1))
+ .toArray(DynamicThrottlePolicy[]::new);
+ Summary summary = run(operations, workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism, timer, policies);
+
+ double minMaxPending = numberOfWorkers * workerParallelism;
+ double maxMaxPending = numberOfWorkers * maximumTasksPerWorker;
+ assertInRange(minMaxPending, summary.averagePending, maxMaxPending);
+ for (int j = 0; j < p; j++) {
+ double expectedShare = (j + 1) / (0.5 * p * (p + 1));
+ double imperfectionFactor = 1.5;
+ // Actual shares are not distributed perfectly proportionally to weights, but close enough.
+ assertInRange(minMaxPending * expectedShare / imperfectionFactor,
+ summary.averageWindows[j],
+ maxMaxPending * expectedShare * imperfectionFactor);
+ }
+ assertInRange(1.0, summary.inefficiency, 1.05);
+ assertInRange(0, summary.waste, 0.1);
+ }
+ }
+
+ static void assertInRange(double lower, double actual, double upper) {
+ System.err.printf("%10.4f <= %10.4f <= %10.4f\n", lower, actual, upper);
+ assertTrue(actual + " should be not be smaller than " + lower, lower <= actual);
+ assertTrue(actual + " should be not be greater than " + upper, upper >= actual);
+ }
+
+ private Summary run(long operations, int workPerSuccess, int numberOfWorkers, int maximumTasksPerWorker,
+ int workerParallelism, CustomTimer timer, DynamicThrottlePolicy... policies) {
+ System.err.printf("\n### Running %d operations of %d ticks each against %d workers with parallelism %d and queue size %d\n",
+ operations, workPerSuccess, numberOfWorkers, workerParallelism, maximumTasksPerWorker);
+
+ List<Integer> order = IntStream.range(0, policies.length).boxed().collect(toList());
+ MockServer resource = new MockServer(workPerSuccess, numberOfWorkers, maximumTasksPerWorker, workerParallelism);
+ AtomicLong outstanding = new AtomicLong(operations);
+ AtomicLong errors = new AtomicLong(0);
+ long ticks = 0;
+ long totalPending = 0;
+ double[] windows = new double[policies.length];
+ int[] pending = new int[policies.length];
+ while (outstanding.get() + resource.pending() > 0) {
+ Collections.shuffle(order);
+ for (int j = 0; j < policies.length; j++) {
+ int i = order.get(j);
+ DynamicThrottlePolicy policy = policies[i];
+ windows[i] += policy.getWindowSize();
+ while (policy.canSend(message, pending[i])) {
+ outstanding.decrementAndGet();
+ policy.processMessage(message);
+ ++pending[i];
+ resource.send(successful -> {
+ --pending[i];
+ if (successful)
+ policy.processReply(success);
+ else {
+ errors.incrementAndGet();
+ outstanding.incrementAndGet();
+ policy.processReply(error);
+ }
+ });
+ }
+ }
+ ++ticks;
+ totalPending += resource.pending();
+ resource.tick();
+ ++timer.millis;
+ }
+
+ for (int i = 0; i < windows.length; i++)
+ windows[i] /= ticks;
+
+ return new Summary(timer.milliTime() / (workPerSuccess * operations / (double) numberOfWorkers) * workerParallelism,
+ errors.get() / (double) operations,
+ totalPending / (double) ticks,
+ windows);
+ }
+
+ static class Summary {
+ final double inefficiency;
+ final double waste;
+ final double averagePending;
+ final double[] averageWindows;
+ Summary(double inefficiency, double waste, double averagePending, double[] averageWindows) {
+ this.inefficiency = inefficiency; // Time spent working / minimum time possible
+ this.waste = waste; // Number of error replies / number of successful replies
+ this.averagePending = averagePending; // Average number of pending operations in the server
+ this.averageWindows = averageWindows; // Average number of pending operations per policy
+ }
+ }
+
+ /**
+ * Resource shared between clients with throttle policies, with simulated throughput and efficiency.
+ *
+ * The model used for delay per request, and success/error, is derived from four basic attributes:
+ * <ul>
+ * <li>Ratio between work per successful and per failed reply</li>
+ * <li>Number of workers, each with minimum throughput equal to one failed reply per tick</li>
+ * <li>Parallelism of each worker — throughput increases linearly with queued tasks up to this number</li>
+ * <li>Maximum number of queued tasks per worker</li>
+ * </ul>
+ * <p>All messages are assumed to get a successful reply unless maximum pending replies is exceeded; when further
+ * messages arrive, the worker must immediately spend work to reject these before continuing its other work.
+ * The delay for a message is computed by assigning it to a random worker, and simulating the worker emptying its
+ * work queue. Since messages are assigned randomly, there will be some variation in delays and maximum throughput.
+ * The local correlation between max number of in-flight messages from the client, and its throughput,
+ * measured as number of successful replies per time unit, will start out at 1 and decrease gradually,
+ * eventually turning negative, as workers must spend work effort on failure replies as well.</p>
+ * <p> More specifically, a single worker yields a piecewise linear relationship between max pending and throughput —
+ * throughput first increases linearly with max pending, until saturated, and then remains constant, until overload,
+ * where it falls sharply. Several such workers together instead yield a throughput curve which gradually flattens
+ * as it approaches saturation, and also more gradually falls again, as overload is reached on some workers sometimes.</p>
+ */
+ static class MockServer {
+
+ final Random random = new Random();
+ final int workPerSuccess;
+ final int numberOfWorkers;
+ final int maximumTaskPerWorker;
+ final int workerParallelism;
+ final int[] currentTask;
+ final List<Deque<Consumer<Boolean>>> outstandingTasks;
+ int pending = 0;
+
+ MockServer(int workPerSuccess, int numberOfWorkers, int maximumTaskPerWorker, int workerParallelism) {
+ this.workPerSuccess = workPerSuccess;
+ this.numberOfWorkers = numberOfWorkers;
+ this.maximumTaskPerWorker = maximumTaskPerWorker;
+ this.workerParallelism = workerParallelism;
+ this.currentTask = new int[numberOfWorkers];
+ this.outstandingTasks = IntStream.range(0, numberOfWorkers)
+ .mapToObj(__ -> new ArrayDeque<Consumer<Boolean>>())
+ .collect(toUnmodifiableList());
+ }
+
+ /** Performs a tick, and returns whether work was done. */
+ void tick() {
+ for (int i = 0; i < numberOfWorkers; i++)
+ tick(i);
+ }
+
+ private void tick(int worker) {
+ Deque<Consumer<Boolean>> tasks = outstandingTasks.get(worker);
+ for (int i = 0; i < Math.min(workerParallelism, tasks.size()); i++) {
+ if (currentTask[worker] == 0) {
+ if (tasks.size() > maximumTaskPerWorker) {
+ tasks.pop().accept(false);
+ continue; // Spend work to signal failure to one excess task.
+ }
+ currentTask[worker] = workPerSuccess; // Start work on next task.
+ }
+ if (--currentTask[worker] == 0)
+ tasks.poll().accept(true); // Signal success to the completed task.
+ }
+ }
+
+ void send(Consumer<Boolean> replyHandler) {
+ ++pending;
+ outstandingTasks.get(random.nextInt(numberOfWorkers))
+ .addLast(outcome -> { --pending; replyHandler.accept(outcome); });
+ }
+
+ int pending() { return pending; }
+
+ }
+
+} \ No newline at end of file
diff --git a/messagebus/src/test/java/com/yahoo/messagebus/ThrottlerTestCase.java b/messagebus/src/test/java/com/yahoo/messagebus/ThrottlerTestCase.java
index f6185f1d410..f5ef5ea4f1f 100644
--- a/messagebus/src/test/java/com/yahoo/messagebus/ThrottlerTestCase.java
+++ b/messagebus/src/test/java/com/yahoo/messagebus/ThrottlerTestCase.java
@@ -137,16 +137,16 @@ public class ThrottlerTestCase {
.setResizeRate(1);
double windowSize = getWindowSize(policy, timer, 100);
- assertTrue(windowSize >= 90 && windowSize <= 110);
+ assertTrue(windowSize >= 90 && windowSize <= 105);
windowSize = getWindowSize(policy, timer, 200);
- assertTrue(windowSize >= 90 && windowSize <= 210);
+ assertTrue(windowSize >= 180 && windowSize <= 205);
windowSize = getWindowSize(policy, timer, 50);
- assertTrue(windowSize >= 9 && windowSize <= 55);
+ assertTrue(windowSize >= 45 && windowSize <= 55);
windowSize = getWindowSize(policy, timer, 500);
- assertTrue(windowSize >= 90 && windowSize <= 505);
+ assertTrue(windowSize >= 450 && windowSize <= 505);
windowSize = getWindowSize(policy, timer, 100);
assertTrue(windowSize >= 90 && windowSize <= 115);
diff --git a/messagebus/src/test/java/com/yahoo/messagebus/routing/RoutingTestCase.java b/messagebus/src/test/java/com/yahoo/messagebus/routing/RoutingTestCase.java
index 29d88afcce2..e097572415d 100644
--- a/messagebus/src/test/java/com/yahoo/messagebus/routing/RoutingTestCase.java
+++ b/messagebus/src/test/java/com/yahoo/messagebus/routing/RoutingTestCase.java
@@ -1142,4 +1142,5 @@ public class RoutingTestCase {
return new MyPolicy(Route.parse(select), null, null, null, e, true);
}
}
+
}
diff --git a/messagebus/src/vespa/messagebus/network/rpcnetwork.cpp b/messagebus/src/vespa/messagebus/network/rpcnetwork.cpp
index 5872706c443..9ecc57fd9de 100644
--- a/messagebus/src/vespa/messagebus/network/rpcnetwork.cpp
+++ b/messagebus/src/vespa/messagebus/network/rpcnetwork.cpp
@@ -14,6 +14,7 @@
#include <vespa/vespalib/component/vtag.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/fnet/scheduler.h>
#include <vespa/fnet/transport.h>
#include <vespa/fnet/frt/supervisor.h>
@@ -78,6 +79,14 @@ struct TargetPoolTask : public FNET_Task {
}
};
+TransportConfig
+toFNETConfig(const RPCNetworkParams & params) {
+ return TransportConfig()
+ .maxInputBufferSize(params.getMaxInputBufferSize())
+ .maxOutputBufferSize(params.getMaxOutputBufferSize())
+ .tcpNoDelay(params.getTcpNoDelay());
+}
+
}
RPCNetwork::SendContext::SendContext(RPCNetwork &net, const Message &msg,
@@ -116,7 +125,7 @@ RPCNetwork::RPCNetwork(const RPCNetworkParams &params) :
_owner(nullptr),
_ident(params.getIdentity()),
_threadPool(std::make_unique<FastOS_ThreadPool>(128000, 0)),
- _transport(std::make_unique<FNET_Transport>()),
+ _transport(std::make_unique<FNET_Transport>(toFNETConfig(params))),
_orb(std::make_unique<FRT_Supervisor>(_transport.get())),
_scheduler(*_transport->GetScheduler()),
_slobrokCfgFactory(std::make_unique<slobrok::ConfiguratorFactory>(params.getSlobrokConfig())),
@@ -134,9 +143,6 @@ RPCNetwork::RPCNetwork(const RPCNetworkParams &params) :
_allowDispatchForEncode(params.getDispatchOnEncode()),
_allowDispatchForDecode(params.getDispatchOnDecode())
{
- _transport->SetMaxInputBufferSize(params.getMaxInputBufferSize());
- _transport->SetMaxOutputBufferSize(params.getMaxOutputBufferSize());
- _transport->SetTCPNoDelay(params.getTcpNoDelay());
}
RPCNetwork::~RPCNetwork()
diff --git a/messagebus/src/vespa/messagebus/network/rpcnetwork.h b/messagebus/src/vespa/messagebus/network/rpcnetwork.h
index 2780c3e8770..d701358fc84 100644
--- a/messagebus/src/vespa/messagebus/network/rpcnetwork.h
+++ b/messagebus/src/vespa/messagebus/network/rpcnetwork.h
@@ -15,6 +15,7 @@
#include <vespa/fnet/frt/invokable.h>
class FNET_Transport;
+class FastOS_ThreadPool;
namespace slobrok {
namespace api { class RegisterAPI; }
@@ -52,26 +53,26 @@ private:
using SendAdapterMap = std::map<vespalib::Version, RPCSendAdapter*>;
- INetworkOwner *_owner;
- Identity _ident;
- std::unique_ptr<FastOS_ThreadPool> _threadPool;
- std::unique_ptr<FNET_Transport> _transport;
- std::unique_ptr<FRT_Supervisor> _orb;
- FNET_Scheduler &_scheduler;
- std::unique_ptr<slobrok::ConfiguratorFactory> _slobrokCfgFactory;
- std::unique_ptr<slobrok::api::IMirrorAPI> _mirror;
- std::unique_ptr<slobrok::api::RegisterAPI> _regAPI;
- int _requestedPort;
- std::unique_ptr<RPCTargetPool> _targetPool;
- std::unique_ptr<FNET_Task> _targetPoolTask;
- std::unique_ptr<RPCServicePool> _servicePool;
- std::unique_ptr<vespalib::ThreadStackExecutor> _executor;
- std::unique_ptr<RPCSendAdapter> _sendV1;
- std::unique_ptr<RPCSendAdapter> _sendV2;
- SendAdapterMap _sendAdapters;
- CompressionConfig _compressionConfig;
- bool _allowDispatchForEncode;
- bool _allowDispatchForDecode;
+ INetworkOwner *_owner;
+ Identity _ident;
+ std::unique_ptr<FastOS_ThreadPool> _threadPool;
+ std::unique_ptr<FNET_Transport> _transport;
+ std::unique_ptr<FRT_Supervisor> _orb;
+ FNET_Scheduler &_scheduler;
+ std::unique_ptr<slobrok::ConfiguratorFactory> _slobrokCfgFactory;
+ std::unique_ptr<slobrok::api::IMirrorAPI> _mirror;
+ std::unique_ptr<slobrok::api::RegisterAPI> _regAPI;
+ int _requestedPort;
+ std::unique_ptr<RPCTargetPool> _targetPool;
+ std::unique_ptr<FNET_Task> _targetPoolTask;
+ std::unique_ptr<RPCServicePool> _servicePool;
+ std::unique_ptr<vespalib::SyncableThreadExecutor> _executor;
+ std::unique_ptr<RPCSendAdapter> _sendV1;
+ std::unique_ptr<RPCSendAdapter> _sendV2;
+ SendAdapterMap _sendAdapters;
+ CompressionConfig _compressionConfig;
+ bool _allowDispatchForEncode;
+ bool _allowDispatchForDecode;
/**
diff --git a/messagebus/src/vespa/messagebus/network/rpctarget.cpp b/messagebus/src/vespa/messagebus/network/rpctarget.cpp
index b91ba43f036..159b86365c3 100644
--- a/messagebus/src/vespa/messagebus/network/rpctarget.cpp
+++ b/messagebus/src/vespa/messagebus/network/rpctarget.cpp
@@ -32,7 +32,7 @@ RPCTarget::resolveVersion(duration timeout, RPCTarget::IVersionHandler &handler)
std::unique_lock guard(_lock);
state = _state.load(std::memory_order_relaxed);
if (state == VERSION_RESOLVED || state == PROCESSING_HANDLERS) {
- while (_state.load(std::memory_order::memory_order_relaxed) == PROCESSING_HANDLERS) {
+ while (_state.load(std::memory_order_relaxed) == PROCESSING_HANDLERS) {
_cond.wait(guard);
}
hasVersion = true;
diff --git a/metrics/src/tests/CMakeLists.txt b/metrics/src/tests/CMakeLists.txt
index 1e3578e065b..2f517d0065d 100644
--- a/metrics/src/tests/CMakeLists.txt
+++ b/metrics/src/tests/CMakeLists.txt
@@ -4,7 +4,6 @@
vespa_add_executable(metrics_gtest_runner_app TEST
SOURCES
countmetrictest.cpp
- loadmetrictest.cpp
metric_timer_test.cpp
metricmanagertest.cpp
metricsettest.cpp
diff --git a/metrics/src/tests/loadmetrictest.cpp b/metrics/src/tests/loadmetrictest.cpp
deleted file mode 100644
index b89628f4476..00000000000
--- a/metrics/src/tests/loadmetrictest.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/metrics/loadmetric.h>
-#include <vespa/metrics/valuemetric.h>
-#include <vespa/metrics/loadmetric.hpp>
-#include <vespa/metrics/summetric.hpp>
-#include <vespa/vespalib/gtest/gtest.h>
-
-namespace metrics {
-
-struct LoadTypeSetImpl : public LoadTypeSet {
- LoadTypeSetImpl() {
- push_back(LoadType(0, "default"));
- }
- LoadTypeSetImpl& add(uint32_t id, const char* name) {
- push_back(LoadType(id, name));
- return *this;
- }
- const LoadType& operator[](const std::string& name) const {
- for (uint32_t i=0; i<size(); ++i) {
- const LoadType& lt(LoadTypeSet::operator[](i));
- if (lt.getName() == name) return lt;
- }
- abort();
- }
-};
-
-TEST(LoadMetricTest, test_normal_usage)
-{
- LoadTypeSetImpl loadTypes;
- loadTypes.add(32, "foo").add(1000, "bar");
- LoadMetric<LongValueMetric> metric(
- loadTypes, LongValueMetric("put", {}, "Put"));
-}
-
-namespace {
- struct MyMetricSet : public MetricSet {
- LongAverageMetric metric;
-
- MyMetricSet(MetricSet* owner = 0)
- : MetricSet("tick", {}, "", owner),
- metric("tack", {}, "", this)
- { }
-
- MetricSet* clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
- MetricSet* owner, bool includeUnused = false) const override
- {
- if (copyType != CLONE) {
- return MetricSet::clone(ownerList, copyType, owner, includeUnused);
- }
- MyMetricSet * myset = new MyMetricSet(owner);
- myset->assignValues(*this);
- std::cerr << "org:" << this->toString(true) << std::endl;
- std::cerr << "clone:" << myset->toString(true) << std::endl;
- return myset;
- }
- };
-}
-
-void
-test_clone(Metric::CopyType copyType)
-{
- LoadTypeSetImpl loadTypes;
- loadTypes.add(32, "foo").add(1000, "bar");
- MetricSet top("top", {}, "");
- MyMetricSet myset;
- LoadMetric<MyMetricSet> metric(loadTypes, myset, &top);
- metric[loadTypes["foo"]].metric.addValue(5);
-
- std::vector<Metric::UP> ownerList;
- MetricSet::UP copy(dynamic_cast<MetricSet*>(top.clone(ownerList, copyType, 0, true)));
- ASSERT_TRUE(copy.get());
-
- std::string expected =
- "top:\n"
- " tick:\n"
- " sum:\n"
- " tack average=5 last=5 min=5 max=5 count=1 total=5\n"
- " default:\n"
- " tack average=0 last=0 count=0 total=0\n"
- " foo:\n"
- " tack average=5 last=5 min=5 max=5 count=1 total=5\n"
- " bar:\n"
- " tack average=0 last=0 count=0 total=0";
-
- EXPECT_EQ(expected, std::string(top.toString(true)));
- EXPECT_EQ(expected, std::string(copy->toString(true)));
-}
-
-TEST(LoadMetricTest, test_inactive_copy)
-{
- test_clone(Metric::INACTIVE);
-}
-
-TEST(LoadMetricTest, test_active_copy)
-{
- test_clone(Metric::CLONE);
-}
-
-TEST(LoadMetricTest, test_adding)
-{
- LoadTypeSetImpl loadTypes;
- loadTypes.add(32, "foo").add(1000, "bar");
- MetricSet top("top", {}, "");
- MyMetricSet myset;
- LoadMetric<MyMetricSet> metric(loadTypes, myset, &top);
- metric[loadTypes["foo"]].metric.addValue(5);
-
- std::vector<Metric::UP> ownerList;
- MetricSet::UP copy(dynamic_cast<MetricSet*>(
- top.clone(ownerList, Metric::INACTIVE, 0, false)));
- ASSERT_TRUE(copy.get());
-
- top.reset();
-
- top.addToSnapshot(*copy, ownerList);
-
- std::string expected =
- "top:\n"
- " tick:\n"
- " sum:\n"
- " tack average=5 last=5 min=5 max=5 count=1 total=5\n"
- " foo:\n"
- " tack average=5 last=5 min=5 max=5 count=1 total=5";
-
- EXPECT_EQ(expected, std::string(copy->toString(true)));
-}
-
-}
diff --git a/metrics/src/tests/metricmanagertest.cpp b/metrics/src/tests/metricmanagertest.cpp
index 47515d1bc4c..6ebea283e93 100644
--- a/metrics/src/tests/metricmanagertest.cpp
+++ b/metrics/src/tests/metricmanagertest.cpp
@@ -2,7 +2,7 @@
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/metrics.h>
-#include <vespa/metrics/printutils.h>
+#include <vespa/metrics/metricmanager.h>
#include <vespa/metrics/state_api_adapter.h>
#include <vespa/metrics/textwriter.h>
#include <vespa/metrics/xmlwriter.h>
@@ -565,69 +565,6 @@ TEST_F(MetricManagerTest, test_snapshots)
ASSERT_VALUES(mm, 0 * 60, "0,0,0,0,0,0,0,0,0,0,0");
}
-TEST_F(MetricManagerTest, test_print_utils)
-{
- FastOS_ThreadPool pool(256 * 1024);
- FakeTimer* timer = new FakeTimer(1000);
- std::unique_ptr<MetricManager::Timer> timerImpl(timer);
- MetricManager mm(std::move(timerImpl));
- TestMetricSet mySet;
- {
- MetricLockGuard lockGuard(mm.getMetricLock());
- mm.registerMetric(lockGuard, mySet.set);
- }
- // Adding metrics to have some values in them
- mySet.val6.addValue(2);
- mySet.val9.val1.addValue(4);
- mySet.val10.count.inc();
- mySet.val10.a.val1.addValue(7);
- mySet.val10.a.val2.addValue(2);
- mySet.val10.b.val1.addValue(1);
- // Initialize metric manager to get snapshots created.
- mm.init("raw:"
- "consumer[2]\n"
- "consumer[0].name snapper\n"
- "consumer[0].tags[1]\n"
- "consumer[0].tags[0] snaptest\n"
- "consumer[1].name log\n"
- "consumer[1].tags[1]\n"
- "consumer[1].tags[0] snaptest\n",
- pool);
- using namespace printutils;
- MetricLockGuard lockGuard(mm.getMetricLock());
- MetricSource source(mm.getActiveMetrics(lockGuard),
- "temp.multisub");
- ASSERT_TRUE(source.getMetric("count") != nullptr);
- ASSERT_TRUE(source.getMetric("a.val1") != nullptr);
- ASSERT_TRUE(source.getMetric("a.valsum") != nullptr);
- ASSERT_TRUE(source.getMetric("sum.val1") != nullptr);
- ASSERT_TRUE(source.getMetric("sum.valsum") != nullptr);
-
- std::vector<Metric::String> metrics(
- source.getPathsMatchingPrefix("a.val"));
- std::vector<Metric::String> expected;
- expected.push_back("val1");
- expected.push_back("val2");
- expected.push_back("valsum");
- EXPECT_EQ(expected, metrics);
-
- HttpTable table("mytable", "stuff");
- table.colNames.push_back("values");
- table.rowNames.push_back("valsum");
- table[0][0] = getValueString(
- getLongMetric("a.val1.value", source)
- + getLongMetric("a.val2.value", source));
- std::ostringstream ost;
- table.print(ost);
- EXPECT_EQ(std::string(
- "<h3>mytable</h3>\n"
- "<table border=\"1\">\n"
- "<tr><th>stuff</th><th>values</th></tr>\n"
- "<tr><td>valsum</td><td align=\"right\">9</td></tr>\n"
- "</table>\n"
- ), ost.str());
-}
-
TEST_F(MetricManagerTest, test_xml_output)
{
FastOS_ThreadPool pool(256 * 1024);
diff --git a/metrics/src/tests/snapshottest.cpp b/metrics/src/tests/snapshottest.cpp
index 8336af41a79..21e33a1d937 100644
--- a/metrics/src/tests/snapshottest.cpp
+++ b/metrics/src/tests/snapshottest.cpp
@@ -1,6 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/metrics/loadmetric.hpp>
#include <vespa/metrics/metricmanager.h>
#include <vespa/metrics/metrics.h>
#include <vespa/metrics/summetric.hpp>
@@ -11,43 +10,35 @@ namespace metrics {
namespace {
struct SubSubMetricSet : public MetricSet {
- const LoadTypeSet& loadTypes;
int incVal;
LongCountMetric count1;
LongCountMetric count2;
- LoadMetric<LongCountMetric> loadCount;
SumMetric<LongCountMetric> countSum;
DoubleValueMetric value1;
DoubleValueMetric value2;
- LoadMetric<DoubleValueMetric> loadValue;
SumMetric<DoubleValueMetric> valueSum;
DoubleAverageMetric average1;
DoubleAverageMetric average2;
- LoadMetric<DoubleAverageMetric> loadAverage;
SumMetric<DoubleAverageMetric> averageSum;
- SubSubMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner = 0);
+ SubSubMetricSet(vespalib::stringref name, MetricSet* owner = 0);
~SubSubMetricSet();
MetricSet* clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
metrics::MetricSet* owner, bool includeUnused) const override;
void incValues();
};
-SubSubMetricSet::SubSubMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner)
+SubSubMetricSet::SubSubMetricSet(vespalib::stringref name, MetricSet* owner)
: MetricSet(name, {}, "", owner),
- loadTypes(loadTypes_),
incVal(1),
count1("count1", {}, "", this),
count2("count2", {}, "", this),
- loadCount(loadTypes, LongCountMetric("loadCount", {}, ""), this),
countSum("countSum", {}, "", this),
value1("value1", {}, "", this),
value2("value2", {}, "", this),
- loadValue(loadTypes, DoubleValueMetric("loadValue", {}, ""), this),
valueSum("valueSum", {}, "", this),
average1("average1", {}, "", this),
average2("average2", {}, "", this),
- loadAverage(loadTypes, DoubleAverageMetric("loadAverage", {}, ""), this),
averageSum("averageSum", {}, "", this)
{
countSum.addMetricToSum(count1);
@@ -68,7 +59,7 @@ SubSubMetricSet::clone(std::vector<Metric::UP> &ownerList,
return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused);
}
return (SubSubMetricSet*) (new SubSubMetricSet(
- getName(), loadTypes, owner))
+ getName(), owner))
->assignValues(*this);
}
@@ -76,30 +67,19 @@ void
SubSubMetricSet::incValues() {
count1.inc(incVal);
count2.inc(incVal);
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- loadCount[loadTypes[i]].inc(incVal);
- }
value1.set(incVal);
value2.set(incVal);
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- loadValue[loadTypes[i]].set(incVal);
- }
average1.set(incVal);
average2.set(incVal);
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- loadAverage[loadTypes[i]].set(incVal);
- }
}
struct SubMetricSet : public MetricSet {
- const LoadTypeSet& loadTypes;
SubSubMetricSet set1;
SubSubMetricSet set2;
- LoadMetric<SubSubMetricSet> loadSet;
SumMetric<SubSubMetricSet> setSum;
- SubMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner = 0);
+ SubMetricSet(vespalib::stringref name, MetricSet* owner = 0);
~SubMetricSet();
MetricSet* clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
@@ -108,12 +88,10 @@ struct SubMetricSet : public MetricSet {
void incValues();
};
-SubMetricSet::SubMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner)
+SubMetricSet::SubMetricSet(vespalib::stringref name, MetricSet* owner)
: MetricSet(name, {}, "", owner),
- loadTypes(loadTypes_),
- set1("set1", loadTypes, this),
- set2("set2", loadTypes, this),
- loadSet(loadTypes, *std::unique_ptr<SubSubMetricSet>(new SubSubMetricSet("loadSet", loadTypes)), this),
+ set1("set1", this),
+ set2("set2", this),
setSum("setSum", {}, "", this)
{
setSum.addMetricToSum(set1);
@@ -128,7 +106,7 @@ SubMetricSet::clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
if (copyType == INACTIVE) {
return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused);
}
- return (SubMetricSet*) (new SubMetricSet(getName(), loadTypes, owner))
+ return (SubMetricSet*) (new SubMetricSet(getName(), owner))
->assignValues(*this);
}
@@ -136,31 +114,24 @@ void
SubMetricSet::incValues() {
set1.incValues();
set2.incValues();
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- loadSet[loadTypes[i]].incValues();
- }
}
struct TestMetricSet : public MetricSet {
- const LoadTypeSet& loadTypes;
SubMetricSet set1;
SubMetricSet set2;
- LoadMetric<SubMetricSet> loadSet;
SumMetric<SubMetricSet> setSum;
- TestMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner = 0);
+ TestMetricSet(vespalib::stringref name, MetricSet* owner = 0);
~TestMetricSet();
void incValues();
};
-TestMetricSet::TestMetricSet(vespalib::stringref name, const LoadTypeSet& loadTypes_, MetricSet* owner)
+TestMetricSet::TestMetricSet(vespalib::stringref name, MetricSet* owner)
: MetricSet(name, {}, "", owner),
- loadTypes(loadTypes_),
- set1("set1", loadTypes, this),
- set2("set2", loadTypes, this),
- loadSet(loadTypes, *std::unique_ptr<SubMetricSet>(new SubMetricSet("loadSet", loadTypes)), this),
+ set1("set1", this),
+ set2("set2", this),
setSum("setSum", {}, "", this)
{
setSum.addMetricToSum(set1);
@@ -172,9 +143,6 @@ void
TestMetricSet::incValues() {
set1.incValues();
set2.incValues();
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- loadSet[loadTypes[i]].incValues();
- }
}
struct FakeTimer : public MetricManager::Timer {
@@ -204,12 +172,7 @@ struct SnapshotTest : public ::testing::Test {
TEST_F(SnapshotTest, test_snapshot_two_days)
{
- // Create load types
- LoadTypeSet loadTypes;
- loadTypes.push_back(LoadType(1, "foo"));
- loadTypes.push_back(LoadType(2, "bar"));
-
- TestMetricSet set("test", loadTypes);
+ TestMetricSet set("test");
FakeTimer* timer;
FastOS_ThreadPool threadPool(256 * 1024);
@@ -256,113 +219,39 @@ TEST_F(SnapshotTest, test_snapshot_two_days)
MetricLockGuard lockGuard(mm.getMetricLock());
snap = &mm.getActiveMetrics(lockGuard);
ASSERT_VALUE(0, *snap, "test.set1.set1.count1");
- ASSERT_VALUE(0, *snap, "test.set1.set1.loadCount.foo");
- ASSERT_VALUE(0, *snap, "test.set1.set1.loadCount.sum");
ASSERT_VALUE(0, *snap, "test.set1.set1.countSum");
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.foo.count1");
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.foo.countSum");
-/* Current test procedure for fetching values, don't work in active sums of sets
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.sum.count1");
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.sum.loadCount.foo");
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.sum.loadCount.sum");
- ASSERT_VALUE(0, *snap, "test.set1.loadSet.sum.countSum");
-*/
// 5 minute snapshot
snap = &mm.getMetricSnapshot(lockGuard, 5 * 60);
ASSERT_VALUE(1, *snap, "test.set1.set1.count1");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadCount.foo");
- ASSERT_VALUE(2, *snap, "test.set1.set1.loadCount.sum");
ASSERT_VALUE(2, *snap, "test.set1.set1.countSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.count1");
- ASSERT_VALUE(2, *snap, "test.set1.loadSet.foo.countSum");
- ASSERT_VALUE(2, *snap, "test.set1.loadSet.sum.count1");
- ASSERT_VALUE(2, *snap, "test.set1.loadSet.sum.loadCount.foo");
- ASSERT_VALUE(4, *snap, "test.set1.loadSet.sum.loadCount.sum");
- ASSERT_VALUE(4, *snap, "test.set1.loadSet.sum.countSum");
ASSERT_VALUE(1, *snap, "test.set1.set1.average1");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.sum");
ASSERT_VALUE(1, *snap, "test.set1.set1.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.sum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.averageSum");
// 1 hour snapshot
snap = &mm.getMetricSnapshot(lockGuard, 60 * 60);
ASSERT_VALUE(12, *snap, "test.set1.set1.count1");
- ASSERT_VALUE(12, *snap, "test.set1.set1.loadCount.foo");
- ASSERT_VALUE(24, *snap, "test.set1.set1.loadCount.sum");
ASSERT_VALUE(24, *snap, "test.set1.set1.countSum");
- ASSERT_VALUE(12, *snap, "test.set1.loadSet.foo.count1");
- ASSERT_VALUE(24, *snap, "test.set1.loadSet.foo.countSum");
- ASSERT_VALUE(24, *snap, "test.set1.loadSet.sum.count1");
- ASSERT_VALUE(24, *snap, "test.set1.loadSet.sum.loadCount.foo");
- ASSERT_VALUE(48, *snap, "test.set1.loadSet.sum.loadCount.sum");
- ASSERT_VALUE(48, *snap, "test.set1.loadSet.sum.countSum");
ASSERT_VALUE(1, *snap, "test.set1.set1.average1");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.sum");
ASSERT_VALUE(1, *snap, "test.set1.set1.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.sum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.averageSum");
// 1 day snapshot
snap = &mm.getMetricSnapshot(lockGuard, 24 * 60 * 60);
ASSERT_VALUE(288, *snap, "test.set1.set1.count1");
- ASSERT_VALUE(288, *snap, "test.set1.set1.loadCount.foo");
- ASSERT_VALUE(576, *snap, "test.set1.set1.loadCount.sum");
ASSERT_VALUE(576, *snap, "test.set1.set1.countSum");
- ASSERT_VALUE(288, *snap, "test.set1.loadSet.foo.count1");
- ASSERT_VALUE(576, *snap, "test.set1.loadSet.foo.countSum");
- ASSERT_VALUE(576, *snap, "test.set1.loadSet.sum.count1");
- ASSERT_VALUE(576, *snap, "test.set1.loadSet.sum.loadCount.foo");
- ASSERT_VALUE(1152, *snap, "test.set1.loadSet.sum.loadCount.sum");
- ASSERT_VALUE(1152, *snap, "test.set1.loadSet.sum.countSum");
ASSERT_VALUE(1, *snap, "test.set1.set1.average1");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.sum");
ASSERT_VALUE(1, *snap, "test.set1.set1.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.sum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.averageSum");
// total snapshot (2 days currently, not testing weeks)
snap = &mm.getTotalMetricSnapshot(lockGuard);
ASSERT_VALUE(576, *snap, "test.set1.set1.count1");
- ASSERT_VALUE(576, *snap, "test.set1.set1.loadCount.foo");
- ASSERT_VALUE(1152, *snap, "test.set1.set1.loadCount.sum");
ASSERT_VALUE(1152, *snap, "test.set1.set1.countSum");
- ASSERT_VALUE(576, *snap, "test.set1.loadSet.foo.count1");
- ASSERT_VALUE(1152, *snap, "test.set1.loadSet.foo.countSum");
- ASSERT_VALUE(1152, *snap, "test.set1.loadSet.sum.count1");
- ASSERT_VALUE(1152, *snap, "test.set1.loadSet.sum.loadCount.foo");
- ASSERT_VALUE(2304, *snap, "test.set1.loadSet.sum.loadCount.sum");
- ASSERT_VALUE(2304, *snap, "test.set1.loadSet.sum.countSum");
ASSERT_VALUE(1, *snap, "test.set1.set1.average1");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.set1.loadAverage.sum");
ASSERT_VALUE(1, *snap, "test.set1.set1.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.foo.averageSum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.average1");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.foo");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.loadAverage.sum");
- ASSERT_VALUE(1, *snap, "test.set1.loadSet.sum.averageSum");
}
}
diff --git a/metrics/src/tests/stresstest.cpp b/metrics/src/tests/stresstest.cpp
index f3e709b4b04..df6641c9798 100644
--- a/metrics/src/tests/stresstest.cpp
+++ b/metrics/src/tests/stresstest.cpp
@@ -1,6 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/metrics/loadmetric.hpp>
#include <vespa/metrics/metricmanager.h>
#include <vespa/metrics/metrics.h>
#include <vespa/metrics/summetric.hpp>
@@ -15,42 +14,38 @@ namespace metrics {
namespace {
struct InnerMetricSet : public MetricSet {
- const LoadTypeSet& _loadTypes;
LongCountMetric _count;
LongAverageMetric _value1;
LongAverageMetric _value2;
SumMetric<LongAverageMetric> _valueSum;
- LoadMetric<LongAverageMetric> _load;
- InnerMetricSet(const char* name, const LoadTypeSet& lt, MetricSet* owner = 0);
+ InnerMetricSet(const char* name, MetricSet* owner = 0);
~InnerMetricSet();
MetricSet* clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
MetricSet* owner, bool includeUnused) const override;
};
-InnerMetricSet::InnerMetricSet(const char* name, const LoadTypeSet& lt, MetricSet* owner)
+InnerMetricSet::InnerMetricSet(const char* name, MetricSet* owner)
: MetricSet(name, {}, "", owner),
- _loadTypes(lt),
_count("count", {}, "", this),
_value1("value1", {}, "", this),
_value2("value2", {}, "", this),
- _valueSum("valuesum", {}, "", this),
- _load(lt, LongAverageMetric("load", {}, ""), this)
+ _valueSum("valuesum", {}, "", this)
{
_valueSum.addMetricToSum(_value1);
_valueSum.addMetricToSum(_value2);
}
InnerMetricSet::~InnerMetricSet() = default;
- MetricSet*
- InnerMetricSet::clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
- MetricSet* owner, bool includeUnused) const
+MetricSet*
+InnerMetricSet::clone(std::vector<Metric::UP> &ownerList, CopyType copyType,
+ MetricSet* owner, bool includeUnused) const
{
if (copyType != CLONE) {
return MetricSet::clone(ownerList, copyType, owner, includeUnused);
}
- InnerMetricSet * myset = new InnerMetricSet(getName().c_str(), _loadTypes, owner);
+ InnerMetricSet * myset = new InnerMetricSet(getName().c_str(), owner);
myset->assignValues(*this);
return myset;
}
@@ -60,37 +55,31 @@ struct OuterMetricSet : public MetricSet {
InnerMetricSet _inner2;
SumMetric<InnerMetricSet> _innerSum;
InnerMetricSet _tmp;
- LoadMetric<InnerMetricSet> _load;
- OuterMetricSet(const LoadTypeSet& lt, MetricSet* owner = 0);
+ OuterMetricSet(MetricSet* owner = 0);
~OuterMetricSet();
};
-OuterMetricSet::OuterMetricSet(const LoadTypeSet& lt, MetricSet* owner)
+OuterMetricSet::OuterMetricSet(MetricSet* owner)
: MetricSet("outer", {}, "", owner),
- _inner1("inner1", lt, this),
- _inner2("inner2", lt, this),
+ _inner1("inner1", this),
+ _inner2("inner2", this),
_innerSum("innersum", {}, "", this),
- _tmp("innertmp", lt, 0),
- _load(lt, _tmp, this)
+ _tmp("innertmp", 0)
{
_innerSum.addMetricToSum(_inner1);
_innerSum.addMetricToSum(_inner2);
}
-OuterMetricSet::~OuterMetricSet() { }
+OuterMetricSet::~OuterMetricSet() = default;
struct Hammer : public document::Runnable {
using UP = std::unique_ptr<Hammer>;
OuterMetricSet& _metrics;
- const LoadTypeSet& _loadTypes;
- LoadType _nonexistingLoadType;
- Hammer(OuterMetricSet& metrics, const LoadTypeSet& lt,
- FastOS_ThreadPool& threadPool)
- : _metrics(metrics), _loadTypes(lt),
- _nonexistingLoadType(123, "nonexisting")
+ Hammer(OuterMetricSet& metrics,FastOS_ThreadPool& threadPool)
+ : _metrics(metrics)
{
start(threadPool);
}
@@ -106,8 +95,6 @@ struct Hammer : public document::Runnable {
++i;
setMetrics(i, _metrics._inner1);
setMetrics(i + 3, _metrics._inner2);
- const LoadType& loadType(_loadTypes[i % _loadTypes.size()]);
- setMetrics(i + 5, _metrics._load[loadType]);
}
}
@@ -115,7 +102,6 @@ struct Hammer : public document::Runnable {
set._count.inc(val);
set._value1.addValue(val);
set._value2.addValue(val + 10);
- set._load[_loadTypes[val % _loadTypes.size()]].addValue(val);
}
};
@@ -124,18 +110,13 @@ struct Hammer : public document::Runnable {
TEST(StressTest, test_stress)
{
- LoadTypeSet loadTypes;
- loadTypes.push_back(LoadType(0, "default"));
- loadTypes.push_back(LoadType(2, "foo"));
- loadTypes.push_back(LoadType(1, "bar"));
-
- OuterMetricSet metrics(loadTypes);
+ OuterMetricSet metrics;
LOG(info, "Starting load givers");
FastOS_ThreadPool threadPool(256 * 1024);
std::vector<Hammer::UP> hammers;
for (uint32_t i=0; i<10; ++i) {
- hammers.push_back(std::make_unique<Hammer>(metrics, loadTypes, threadPool));
+ hammers.push_back(std::make_unique<Hammer>(metrics, threadPool));
}
LOG(info, "Waiting to let loadgivers hammer a while");
std::this_thread::sleep_for(5s);
diff --git a/metrics/src/vespa/metrics/CMakeLists.txt b/metrics/src/vespa/metrics/CMakeLists.txt
index 0d7eeba3601..13a3f09449e 100644
--- a/metrics/src/vespa/metrics/CMakeLists.txt
+++ b/metrics/src/vespa/metrics/CMakeLists.txt
@@ -4,7 +4,6 @@ vespa_add_library(metrics
countmetric.cpp
countmetricvalues.cpp
jsonwriter.cpp
- loadmetric.cpp
memoryconsumption.cpp
metric.cpp
metricmanager.cpp
@@ -12,11 +11,11 @@ vespa_add_library(metrics
metricsnapshot.cpp
metrictimer.cpp
metricvalueset.cpp
- printutils.cpp
name_repo.cpp
state_api_adapter.cpp
summetric.cpp
textwriter.cpp
+ updatehook.cpp
valuemetric.cpp
valuemetricvalues.cpp
xmlwriter.cpp
diff --git a/metrics/src/vespa/metrics/common/memory_usage_metrics.h b/metrics/src/vespa/metrics/common/memory_usage_metrics.h
index 7030db8c163..5c4c2dec403 100644
--- a/metrics/src/vespa/metrics/common/memory_usage_metrics.h
+++ b/metrics/src/vespa/metrics/common/memory_usage_metrics.h
@@ -2,7 +2,8 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/metricset.h>
namespace vespalib { class MemoryUsage; }
diff --git a/metrics/src/vespa/metrics/loadmetric.cpp b/metrics/src/vespa/metrics/loadmetric.cpp
deleted file mode 100644
index 94fc2b9db7c..00000000000
--- a/metrics/src/vespa/metrics/loadmetric.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "loadmetric.hpp"
-#include "valuemetric.h"
-#include "countmetric.h"
-#include <vespa/vespalib/util/stringfmt.h>
-
-namespace metrics {
-
-vespalib::string
-LoadType::toString() const {
- return vespalib::make_string("%s(%u)", _name.c_str(), _id);
-}
-
-template class LoadMetric<ValueMetric<int64_t, int64_t, false>>;
-template class LoadMetric<ValueMetric<int64_t, int64_t, true>>;
-template class LoadMetric<ValueMetric<double, double, false>>;
-template class LoadMetric<ValueMetric<double, double, true>>;
-template class LoadMetric<CountMetric<uint64_t, true>>;
-
-}
diff --git a/metrics/src/vespa/metrics/loadmetric.h b/metrics/src/vespa/metrics/loadmetric.h
deleted file mode 100644
index 3b0c70440c9..00000000000
--- a/metrics/src/vespa/metrics/loadmetric.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * \file loadmetric.h
- * \ingroup metrics
- *
- * \brief Utility class for creating metrics for all load types.
- *
- * To better see how different load types behave in the system we want to log
- * separate metrics for various loadtypes. To make it easy to create and use
- * such metrics, this class is a wrapper class that sets up one metric per load
- * type.
- *
- * In order to make it easy to use load metrics, they are templated on the type,
- * such that you get the correct type out of operator[]. Load metric needs to
- * clone metrics on creation though, so if you want load metrics of a metric set
- * you need to properly implement clone() for that set.
- */
-
-#pragma once
-
-#include "loadtype.h"
-#include "metricset.h"
-#include "summetric.h"
-#include <vespa/vespalib/stllike/hash_map.h>
-
-namespace metrics {
-
-template<typename MetricType>
-class LoadMetric : public MetricSet {
- std::vector<Metric::UP> _ownerList;
- using MetricTypeUP = std::unique_ptr<MetricType>;
- using MetricMap = vespalib::hash_map<uint32_t, MetricTypeUP>;
- MetricMap _metrics;
- SumMetric<MetricType> _sum;
-
-public:
- /**
- * Create a load metric using the given metric as a template to how they
- * shuold look. They will get prefix names based on load types existing.
- */
- LoadMetric(const LoadTypeSet& loadTypes, const MetricType& metric, MetricSet* owner = 0);
-
- /**
- * A load metric implements a copy constructor and a clone functions that
- * clone content, and resetting name/tags/description, just so metric
- * implementors can implement clone() by using regular construction and
- * then assign the values to the new set. (Without screwing up copying as
- * the load metric alters this data in supplied metric)
- */
- LoadMetric(const LoadMetric<MetricType>& other, MetricSet* owner);
- ~LoadMetric();
- MetricSet* clone(std::vector<Metric::UP> &ownerList,
- CopyType copyType, MetricSet* owner,
- bool includeUnused = false) const override;
-
- MetricType& operator[](const LoadType& type) { return getMetric(type); }
- const MetricType& operator[](const LoadType& type) const
- { return const_cast<LoadMetric<MetricType>*>(this)->getMetric(type); }
- MetricType& getMetric(const LoadType& type);
- const MetricMap & getMetricMap() const { return _metrics; }
-
- void addMemoryUsage(MemoryConsumption& mc) const override;
-};
-
-} // metrics
-
diff --git a/metrics/src/vespa/metrics/loadmetric.hpp b/metrics/src/vespa/metrics/loadmetric.hpp
deleted file mode 100644
index 65098662e04..00000000000
--- a/metrics/src/vespa/metrics/loadmetric.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#pragma once
-
-#include "loadmetric.h"
-#include "memoryconsumption.h"
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <cassert>
-
-namespace metrics {
-
-template<typename MetricType>
-LoadMetric<MetricType>::LoadMetric(const LoadTypeSet& loadTypes, const MetricType& metric, MetricSet* owner)
- : MetricSet(metric.getName(), {}, metric.getDescription(), owner),
- _metrics(),
- _sum("sum", {{"loadsum"},{"sum"}}, "Sum of all load metrics", this)
-{
- _metrics.resize(loadTypes.size());
- // Currently, we only set tags and description on the metric set
- // itself, to cut down on size of output when downloading metrics,
- // and since matching tags of parent is just as good as matching
- // them specifically.
- setTags(metric.getTags());
- Tags noTags;
- for (uint32_t i=0; i<loadTypes.size(); ++i) {
- MetricTypeUP copy(dynamic_cast<MetricType*>(metric.clone(_ownerList, CLONE, 0, false)));
- assert(copy.get());
- copy->setName(loadTypes[i].getName());
- copy->setTags(noTags);
- registerMetric(*copy);
- _sum.addMetricToSum(*copy);
- _metrics[loadTypes[i].getId()] = std::move(copy);
- }
- _ownerList.shrink_to_fit();
-}
-
-template<typename MetricType>
-LoadMetric<MetricType>::LoadMetric(const LoadMetric<MetricType>& other, MetricSet* owner)
- : MetricSet(other.getName(), {}, other.getDescription(), owner),
- _metrics(),
- _sum("sum", {{"loadsum"},{"sum"}}, "Sum of all load metrics", this)
-{
- _metrics.resize(2 * other._metrics.size());
- setTags(other.getTags());
- Tags noTags;
- for (const auto & metric : other._metrics) {
- MetricTypeUP copy(dynamic_cast<MetricType*>(metric.second->clone(_ownerList, CLONE, 0, false)));
- assert(copy.get());
- copy->setName(metric.second->getName());
- copy->setTags(noTags);
- registerMetric(*copy);
- _sum.addMetricToSum(*copy);
- _metrics[metric.first] = std::move(copy);
- }
- _ownerList.shrink_to_fit();
-}
-
-template<typename MetricType>
-LoadMetric<MetricType>::~LoadMetric() = default;
-
-template<typename MetricType>
-MetricSet*
-LoadMetric<MetricType>::clone(std::vector<Metric::UP> &ownerList,
- CopyType copyType, MetricSet* owner,
- bool includeUnused) const
-{
- if (copyType == INACTIVE) {
- return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused);
- }
- return new LoadMetric<MetricType>(*this, owner);
-}
-
-template<typename MetricType>
-MetricType&
-LoadMetric<MetricType>::getMetric(const LoadType& type) {
- MetricType* metric;
-
- auto it = _metrics.find(type.getId());
- if (it == _metrics.end()) {
- it = _metrics.find(0u);
- assert(it != _metrics.end()); // Default should always exist
- }
- metric = it->second.get();
- assert(metric);
-
- return *metric;
-}
-
-template<typename MetricType>
-void
-LoadMetric<MetricType>::addMemoryUsage(MemoryConsumption& mc) const {
- ++mc._loadMetricCount;
- mc._loadMetricMeta += (sizeof(Metric::UP) * _ownerList.capacity())
- + (sizeof(typename MetricMap::value_type) * _metrics.capacity());
- _sum.addMemoryUsage(mc);
- mc._loadMetricMeta += sizeof(LoadMetric<MetricType>)
- - sizeof(MetricSet)
- - sizeof(SumMetric<MetricType>);
- MetricSet::addMemoryUsage(mc);
-}
-
-}
-
diff --git a/metrics/src/vespa/metrics/loadtype.h b/metrics/src/vespa/metrics/loadtype.h
deleted file mode 100644
index 7d802ebf456..00000000000
--- a/metrics/src/vespa/metrics/loadtype.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-#include <vector>
-
-namespace metrics {
-
-class LoadType {
-public:
- using string = vespalib::string;
- LoadType(uint32_t id, const string& name) : _id(id), _name(name) {}
-
- uint32_t getId() const { return _id; }
- const string& getName() const { return _name; }
-
- string toString() const;
-private:
- uint32_t _id;
- string _name;
-};
-
-typedef std::vector<LoadType> LoadTypeSet;
-
-}
diff --git a/metrics/src/vespa/metrics/metricmanager.cpp b/metrics/src/vespa/metrics/metricmanager.cpp
index 51149cf67c3..8ca74384af0 100644
--- a/metrics/src/vespa/metrics/metricmanager.cpp
+++ b/metrics/src/vespa/metrics/metricmanager.cpp
@@ -20,7 +20,7 @@ LOG_SETUP(".metrics.manager");
namespace metrics {
-typedef MetricsmanagerConfig Config;
+using Config = MetricsmanagerConfig;
MetricManager::ConsumerSpec::ConsumerSpec() = default;
MetricManager::ConsumerSpec::~ConsumerSpec() = default;
@@ -32,7 +32,7 @@ MetricManager::Timer::getTime() const {
void
MetricManager::assertMetricLockLocked(const MetricLockGuard& g) const {
- if ((g.mutex() != &_waiter) || !g.owns_lock()) {
+ if ( ! g.owns(_waiter)) {
throw vespalib::IllegalArgumentException("Given lock does not lock the metric lock.", VESPA_STRLOC);
}
}
diff --git a/metrics/src/vespa/metrics/metricmanager.h b/metrics/src/vespa/metrics/metricmanager.h
index feedf2c1515..f5ad5c5eea3 100644
--- a/metrics/src/vespa/metrics/metricmanager.h
+++ b/metrics/src/vespa/metrics/metricmanager.h
@@ -60,8 +60,6 @@ template class vespalib::hash_set<metrics::Metric::String>;
namespace metrics {
-using MetricLockGuard = UpdateHook::MetricLockGuard;
-
class MetricManager : private document::Runnable
{
public:
diff --git a/metrics/src/vespa/metrics/metrics.h b/metrics/src/vespa/metrics/metrics.h
index 256dc9fe3b4..d22079660b3 100644
--- a/metrics/src/vespa/metrics/metrics.h
+++ b/metrics/src/vespa/metrics/metrics.h
@@ -8,9 +8,7 @@
#include <vespa/metrics/metric.h>
#include <vespa/metrics/countmetric.h>
#include <vespa/metrics/valuemetric.h>
-#include <vespa/metrics/loadmetric.h>
#include <vespa/metrics/summetric.h>
#include <vespa/metrics/metricset.h>
#include <vespa/metrics/metricsnapshot.h>
#include <vespa/metrics/metrictimer.h>
-
diff --git a/metrics/src/vespa/metrics/metricset.cpp b/metrics/src/vespa/metrics/metricset.cpp
index 5cb25cee560..2916b32eb56 100644
--- a/metrics/src/vespa/metrics/metricset.cpp
+++ b/metrics/src/vespa/metrics/metricset.cpp
@@ -40,7 +40,7 @@ MetricSet::MetricSet(const MetricSet& other,
}
}
-MetricSet::~MetricSet() { }
+MetricSet::~MetricSet() = default;
MetricSet*
MetricSet::clone(std::vector<Metric::UP> &ownerList, CopyType type,
diff --git a/metrics/src/vespa/metrics/printutils.cpp b/metrics/src/vespa/metrics/printutils.cpp
deleted file mode 100644
index 974a4523366..00000000000
--- a/metrics/src/vespa/metrics/printutils.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "printutils.h"
-#include <vespa/vespalib/util/stringfmt.h>
-
-namespace metrics {
-namespace printutils {
-
-typedef std::pair<int64_t, bool> LongValue;
-typedef std::pair<double, bool> DoubleValue;
-
-MetricSource::MetricSource(const MetricSnapshot& s,
- const String& metricsPrefix,
- std::map<String, Metric::SP>* metricsAccessed)
- : _snapshot(s),
- _metricsPrefix(metricsPrefix),
- _metricsAccessedOwner(),
- _metricsAccessed(metricsAccessed == 0 ? _metricsAccessedOwner
- : *metricsAccessed)
-{
-}
-
-MetricSource::~MetricSource() {}
-
-Metric::String
-MetricSource::createAbsoluteMetricName(const String& name) const {
- String prefix = _metricsPrefix;
- String addition = name;
- while (addition.find("../") == 0) {
- String::size_type pos1 = prefix.rfind('.');
- if (pos1 == String::npos)
- throw vespalib::IllegalArgumentException(
- "Cannot go back anymore in path " + prefix,
- VESPA_STRLOC);
- prefix = prefix.substr(0, pos1);
- addition = addition.substr(3);
- }
- return (prefix.empty() ? addition : prefix + "." + addition);
-}
-
-MetricSource::SourceMetricVisitor::SourceMetricVisitor(const String& path, bool prefixMatch)
- : _stringPath(path),
- _path(vespalib::StringTokenizer(path, ".").getTokens()),
- _pathIndex(-1),
- _resultMetric(),
- _prefixMatch(prefixMatch),
- _prefixMatches()
-{
-}
-
-MetricSource::SourceMetricVisitor::~SourceMetricVisitor() { }
-
-void
-MetricSource::SourceMetricVisitor::checkForPrefixMatch(const Metric& metric) {
- if (metric.getName().size() >= _path[_pathIndex].size()) {
- if (metric.getName().find(_path[_pathIndex]) == 0) {
- _prefixMatches.push_back(metric.getName());
- }
- }
-}
-
-bool
-MetricSource::SourceMetricVisitor::visitMetricSet(const MetricSet& set, bool) {
- if (_pathIndex == -1) {
- _pathIndex = 0;
- return true;
- }
- if (_prefixMatch
- && static_cast<size_t>(_pathIndex + 1) == _path.size())
- {
- for (const Metric * entry : set.getRegisteredMetrics()) {
- checkForPrefixMatch(*entry);
- }
- return false;
- }
- if (set.getName() != _path[_pathIndex]) return false;
- if (static_cast<size_t>(++_pathIndex) >= _path.size()) {
- throw vespalib::IllegalArgumentException(
- "Path " + _stringPath + " points to a metric set. "
- "Only primitive metrics can be retrieved.",
- VESPA_STRLOC);
- }
- return true;
-}
-bool
-MetricSource::SourceMetricVisitor::visitMetric(const Metric& metric, bool) {
- if (_prefixMatch) {
- checkForPrefixMatch(metric);
- }
- if (_path[_pathIndex] != metric.getName()) {
- return true;
- }
- if (_prefixMatch) {
- throw vespalib::IllegalArgumentException(
- "Cannot find existing entries with prefix "
- + _stringPath + " since element " + metric.getName()
- + " is not a metric set", VESPA_STRLOC);
- }
- if (static_cast<size_t>(_pathIndex + 1) < _path.size()) {
- throw vespalib::IllegalArgumentException(
- "Path " + _stringPath + " cannot exist since element "
- + _path[_pathIndex] + " is not a metric set: "
- + metric.toString(),
- VESPA_STRLOC);
- }
- std::vector<Metric::UP> ownerList;
- _resultMetric.reset(metric.clone(ownerList, Metric::INACTIVE, 0));
- if (!ownerList.empty()) {
- throw vespalib::IllegalArgumentException(
- "Metric " + metric.getName() + " added entries to "
- "owners list when cloning. This should not happen "
- "for primitive metrics.", VESPA_STRLOC);
- }
- return false;
-}
-
-const Metric*
-MetricSource::getMetric(const String& name) {
- String path = createAbsoluteMetricName(name);
- std::map<String, Metric::SP>::const_iterator it(
- _metricsAccessed.find(path));
- if (it != _metricsAccessed.end()) {
- return it->second.get();
- }
- SourceMetricVisitor visitor(path, false);
- _snapshot.getMetrics().visit(visitor);
- if (visitor._resultMetric.get() == 0) {
- throw vespalib::IllegalArgumentException(
- "Metric " + path + " was not found.", VESPA_STRLOC);
- }
- Metric::SP metric(visitor._resultMetric.release());
- _metricsAccessed[path] = metric;
- return metric.get();
-}
-
-std::vector<Metric::String>
-MetricSource::getPathsMatchingPrefix(const String& prefix) const
-{
- String path = createAbsoluteMetricName(prefix);
- SourceMetricVisitor visitor(path, true);
- _snapshot.getMetrics().visit(visitor);
- return visitor._prefixMatches;
-}
-
-// Addition functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-LongValue operator+(LongValue addend1, LongValue addend2)
-{
- return LongValue(addend1.first + addend2.first,
- addend1.second && addend2.second);
-}
-
-// Subtraction functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-LongValue operator-(LongValue minuend, LongValue subtrahend)
-{
- return LongValue(minuend.first - subtrahend.first,
- minuend.second && subtrahend.second);
-}
-
-// Multiplication functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-
-LongValue operator*(LongValue factor1, LongValue factor2)
-{
- return std::pair<int64_t, bool>(factor1.first * factor2.first,
- factor1.second && factor2.second);
-}
-
-// Division functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-
-LongValue operator/(LongValue dividend, LongValue divisor)
-{
- if (dividend.first == 0) return LongValue(
- 0, dividend.second && divisor.second);
- if (divisor.first == 0) return LongValue(
- std::numeric_limits<int64_t>().max(),
- dividend.second && divisor.second);
- return LongValue(dividend.first / divisor.first,
- dividend.second && divisor.second);
-}
-
-/** Get metric with given name from source. Set bool true if existing. */
-LongValue getLongMetric(const std::string& name, MetricSource& source)
-{
- std::string::size_type pos = name.rfind('.');
- const Metric* metric = (pos == std::string::npos
- ? 0 : source.getMetric(name.substr(0, pos)));
- try{
- return LongValue(metric == 0
- ? 0 : metric->getLongValue(name.substr(pos+1)), metric != 0);
- } catch (vespalib::IllegalArgumentException& e) {
- return LongValue(0, false);
- }
-}
-
-/** Get metric with given name from source. Set bool true if existing. */
-DoubleValue getDoubleMetric(const std::string& name, MetricSource& source)
-{
- std::string::size_type pos = name.rfind('.');
- const Metric* metric = (pos == std::string::npos
- ? 0 : source.getMetric(name.substr(0, pos)));
- try{
- return DoubleValue(metric == 0
- ? 0.0 : metric->getDoubleValue(name.substr(pos+1)), metric != 0);
- } catch (vespalib::IllegalArgumentException& e) {
- return DoubleValue(0, false);
- }
-}
-
-std::string getValueString(LongValue value, const char* format)
-{
- if (!value.second) return "na";
- std::vector<char> buffer(30);
- snprintf(&buffer[0], 30, format, value.first);
- return std::string(&buffer[0]);
-}
-
-std::string getValueString(DoubleValue value, const char* format)
-{
- if (!value.second) return "na";
- std::vector<char> buffer(30);
- snprintf(&buffer[0], 30, format, value.first);
- return std::string(&buffer[0]);
-}
-
-HttpTable::HttpTable(const std::string& title_, const std::string& topLeftText_)
- : title(title_), topLeftText(topLeftText_)
-{}
-HttpTable::~HttpTable() { }
-
-HttpTable::Row&
-HttpTable::operator[](uint32_t i) {
- if (i >= cells.size()) cells.resize(i + 1);
- return cells[i];
-}
-
-void
-HttpTable::fillInEmptyHoles() {
- if (rowNames.size() < cells.size()) rowNames.resize(cells.size());
- if (rowNames.size() > cells.size()) cells.resize(rowNames.size());
- for (uint32_t i=0; i<cells.size(); ++i) {
- if (colNames.size() < cells[i].cells.size())
- colNames.resize(cells[i].cells.size());
- if (colNames.size() > cells[i].cells.size())
- cells[i].cells.resize(colNames.size());
- }
-}
-
-void
-HttpTable::print(std::ostream& out) {
- out << "<h3>" << title << "</h3>\n";
- out << "<table border=\"1\">\n";
- fillInEmptyHoles();
- for (uint32_t i=0; i<=rowNames.size(); ++i) {
- if (i == 0) {
- out << "<tr><th>" << topLeftText << "</th>";
- for (uint32_t j=0; j<colNames.size(); ++j) {
- out << "<th>" << colNames[j] << "</th>";
- }
- out << "</tr>\n";
- } else {
- out << "<tr><td>" << rowNames[i - 1] << "</td>";
- for (uint32_t j=0; j<colNames.size(); ++j) {
- out << "<td align=\"right\">"
- << (cells[i - 1][j].set ? cells[i - 1][j].value : "-")
- << "</td>";
- }
- out << "</tr>\n";
- }
- }
- out << "</table>\n";
-}
-
-} // printutils
-} // metrics
-
diff --git a/metrics/src/vespa/metrics/printutils.h b/metrics/src/vespa/metrics/printutils.h
deleted file mode 100644
index a580ad809be..00000000000
--- a/metrics/src/vespa/metrics/printutils.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-/**
- * This file contains utility functions to help print out metric snapshots in
- * a user friendly way. It defines value types, functions for retrieving and
- * doing algorithmics with the values, and printing them in an HTML table.
- *
- * This is used by storage to print HTML metrics report for its status page.
- */
-
-#pragma once
-
-#include "metricmanager.h"
-#include <vespa/vespalib/text/stringtokenizer.h>
-#include <vespa/vespalib/util/exceptions.h>
-
-namespace metrics {
-namespace printutils {
-
-typedef std::pair<int64_t, bool> LongValue;
-typedef std::pair<double, bool> DoubleValue;
-
-struct MetricSource {
- typedef Metric::String String;
-
- const MetricSnapshot& _snapshot;
- String _metricsPrefix;
- // If no map is supplied, this map will own the data in the metrics
- // accessed map.
- std::map<String, Metric::SP> _metricsAccessedOwner;
- std::map<String, Metric::SP>& _metricsAccessed;
-
- MetricSource(const MetricSnapshot& s,
- const String& metricsPrefix,
- std::map<String, Metric::SP>* metricsAccessed = 0);
- ~MetricSource();
- String createAbsoluteMetricName(const String& name) const;
-
- struct SourceMetricVisitor : public metrics::MetricVisitor {
- String _stringPath;
- vespalib::StringTokenizer::TokenList _path;
- int32_t _pathIndex;
- Metric::UP _resultMetric;
- bool _prefixMatch;
- std::vector<String> _prefixMatches;
-
- SourceMetricVisitor(const String& path, bool prefixMatch);
- ~SourceMetricVisitor();
-
- void checkForPrefixMatch(const Metric& metric);
-
- bool visitMetricSet(const MetricSet& set, bool) override;
- void doneVisitingMetricSet(const MetricSet&) override { --_pathIndex; }
- bool visitMetric(const Metric& metric, bool) override;
- };
-
- const Metric* getMetric(const String& name);
-
- std::vector<String>
- getPathsMatchingPrefix(const String& prefix) const;
-};
-
-// Addition functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-LongValue operator+(LongValue addend1, LongValue addend2);
-
-template<typename ValueType1, typename ValueType2>
-DoubleValue operator+(std::pair<ValueType1, bool> addend1,
- std::pair<ValueType2, bool> addend2)
-{
- return DoubleValue(addend1.first + addend2.first,
- addend1.second && addend2.second);
-}
-
-// Subtraction functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-LongValue operator-(LongValue minuend, LongValue subtrahend);
-
-template<typename ValueType1, typename ValueType2>
-DoubleValue operator-(std::pair<ValueType1, bool> minuend,
- std::pair<ValueType2, bool> subtrahend)
-{
- return DoubleValue(minuend.first - subtrahend.first,
- minuend.second && subtrahend.second);
-}
-
-// Multiplication functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-
-LongValue operator*(LongValue factor1, LongValue factor2);
-
-template<typename ValueType1, typename ValueType2>
-DoubleValue operator*(std::pair<ValueType1, bool> factor1,
- std::pair<ValueType2, bool> factor2)
-{
- return std::pair<double, bool>(factor1.first * factor2.first,
- factor1.second && factor2.second);
-}
-
-// Division functions. Ensure that if floating point value is used,
-// result ends up as floating point too.
-
-LongValue operator/(LongValue dividend, LongValue divisor);
-
-template<typename ValueType1, typename ValueType2>
-DoubleValue operator/(std::pair<ValueType1, bool> dividend,
- std::pair<ValueType2, bool> divisor)
-{
- // In case divisor is integer, we will core if we attempt to divide
- // with it.
- if (dividend.first == 0) return DoubleValue(
- 0, dividend.second && divisor.second);
- if (divisor.first == 0) return DoubleValue(
- std::numeric_limits<double>().infinity(),
- dividend.second && divisor.second);
- return DoubleValue(
- dividend.first / static_cast<double>(divisor.first),
- dividend.second && divisor.second);
-}
-
-// Min/Max functions
-template<typename ValueType>
-std::pair<ValueType, bool> getMin(std::pair<ValueType, bool> val1,
- std::pair<ValueType, bool> val2)
-{
- if (!val1.second) return val2;
- if (!val2.second) return val1;
- return std::pair<ValueType, bool>(std::min(val1.first, val2.first), true);
-}
-
-template<typename ValueType>
-std::pair<ValueType, bool> getMax(std::pair<ValueType, bool> val1,
- std::pair<ValueType, bool> val2)
-{
- if (!val1.second) return val2;
- if (!val2.second) return val1;
- return std::pair<ValueType, bool>(std::max(val1.first, val2.first), true);
-}
-
-// Wrapper types for primitives. Would be nice to allow primitives directly, but
-// using a wrapper we can get by with less operator overloads above.
-
-template<typename ValueType>
-struct VW : public std::pair<ValueType, bool> {
- VW(ValueType val) : std::pair<ValueType, bool>(val, true) {}
-};
-
-typedef VW<int64_t> LVW;
-typedef VW<double> DVW;
-
-
-LongValue getLongMetric(const std::string& name, MetricSource& source);
-DoubleValue getDoubleMetric(const std::string& name, MetricSource& source);
-std::string getValueString(LongValue value, const char* format = "%'lld");
-std::string getValueString(DoubleValue value, const char* format = "%'f");
-
-template<typename ValueType>
-std::string getByteValueString(std::pair<ValueType, bool> val)
-{
- static const int64_t k = (1ul << 10);
- static const int64_t m = (1ul << 20);
- static const int64_t g = (1ul << 30);
-
- if (!val.second) return "na";
- std::pair<int64_t, bool> value(
- static_cast<int64_t>(val.first), val.second);
- if (value.first < 64 * k) {
- return getValueString(value, "%'llu B");
- }
- if (value.first < 64 * m) {
- value.first /= k;
- return getValueString(value, "%'llu kB");
- }
- if (value.first < 64 * g) {
- value.first /= m;
- return getValueString(value, "%'llu MB");
- }
- value.first /= g;
- return getValueString(value, "%'llu GB");
-}
-
-struct HttpTable {
- std::string title;
- std::string topLeftText;
- std::vector<std::string> colNames;
- std::vector<std::string> rowNames;
- struct Cell {
- bool set;
- std::string value;
-
- Cell() : set(false), value() {}
-
- void operator=(const std::string& val) { value = val; set = true; }
- };
- struct Row {
- std::vector<Cell> cells;
- Cell& operator[](uint32_t i) {
- if (i >= cells.size()) cells.resize(i + 1);
- return cells[i];
- }
- };
- std::vector<Row> cells;
-
- HttpTable(const std::string& title_, const std::string& topLeftText_);
- ~HttpTable();
-
- Row& operator[](uint32_t i);
- void fillInEmptyHoles();
- void print(std::ostream& out);
-};
-
-} // printutils
-} // metrics
-
diff --git a/metrics/src/vespa/metrics/state_api_adapter.h b/metrics/src/vespa/metrics/state_api_adapter.h
index ccf7e73471e..4e152e3ab13 100644
--- a/metrics/src/vespa/metrics/state_api_adapter.h
+++ b/metrics/src/vespa/metrics/state_api_adapter.h
@@ -25,6 +25,4 @@ public:
vespalib::string getTotalMetrics(const vespalib::string &consumer) override;
};
-
} // namespace metrics
-
diff --git a/metrics/src/vespa/metrics/updatehook.cpp b/metrics/src/vespa/metrics/updatehook.cpp
new file mode 100644
index 00000000000..b627d55b09e
--- /dev/null
+++ b/metrics/src/vespa/metrics/updatehook.cpp
@@ -0,0 +1,18 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "updatehook.h"
+
+namespace metrics {
+
+MetricLockGuard::MetricLockGuard(std::mutex & mutex)
+ : _guard(mutex)
+{}
+
+bool
+MetricLockGuard::owns(const std::mutex & mutex) const {
+ return (_guard.mutex() == &mutex) && _guard.owns_lock();
+}
+
+MetricLockGuard::~MetricLockGuard() = default;
+
+}
diff --git a/metrics/src/vespa/metrics/updatehook.h b/metrics/src/vespa/metrics/updatehook.h
index 65f34c65664..0a0f218d61a 100644
--- a/metrics/src/vespa/metrics/updatehook.h
+++ b/metrics/src/vespa/metrics/updatehook.h
@@ -5,6 +5,21 @@
namespace metrics {
+class MetricLockGuard {
+public:
+ MetricLockGuard(std::mutex & mutex);
+ MetricLockGuard(const MetricLockGuard &) = delete;
+ MetricLockGuard & operator =(const MetricLockGuard &) = delete;
+ MetricLockGuard(MetricLockGuard &&) = default;
+ MetricLockGuard & operator =(MetricLockGuard &&) = default;
+ ~MetricLockGuard();
+
+ bool owns(const std::mutex &) const;
+ operator std::unique_lock<std::mutex> & () { return _guard; }
+private:
+ std::unique_lock<std::mutex> _guard;
+};
+
class MetricManager;
class UpdateHook {
@@ -14,9 +29,7 @@ class UpdateHook {
friend class MetricManager;
public:
- using UP = std::unique_ptr<UpdateHook>;
- using MetricLockGuard = std::unique_lock<std::mutex>;
-
+ using MetricLockGuard = metrics::MetricLockGuard;
UpdateHook(const char* name) : _name(name), _nextCall(0), _period(0) {}
virtual ~UpdateHook() = default;
virtual void updateMetrics(const MetricLockGuard & guard) = 0;
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
index 20d710cbad8..5d0c7c19b5d 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java
@@ -15,6 +15,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -155,7 +156,7 @@ public class CoredumpHandler {
if (!Files.exists(metadataPath.toPath())) {
Path coredumpFilePathOnHost = findCoredumpFileInProcessingDirectory(coredumpDirectory);
Path coredumpFilePathInContainer = context.pathInNodeFromPathOnHost(coredumpFilePathOnHost);
- Map<String, Object> metadata = coreCollector.collect(context, coredumpFilePathInContainer);
+ Map<String, Object> metadata = new HashMap<>(coreCollector.collect(context, coredumpFilePathInContainer));
metadata.putAll(nodeAttributesSupplier.get());
metadata.put("coredump_path", doneCoredumpsPath.resolve(context.containerName().asString()).resolve(coredumpDirectory.getFileName()).toString());
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
index 6e4d090f830..1ff8c41ade8 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java
@@ -9,8 +9,8 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl;
import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec;
@@ -69,7 +69,7 @@ public class NodeAgentContextImpl implements NodeAgentContext {
this.vespaUserOnHost = vespaUserOnHost;
this.cpuSpeedup = cpuSpeedup;
this.disabledNodeAgentTasks = NodeAgentTask.fromString(
- Flags.DISABLED_HOST_ADMIN_TASKS.bindTo(flagSource).with(FetchVector.Dimension.HOSTNAME, node.hostname()).value());
+ PermanentFlags.DISABLED_HOST_ADMIN_TASKS.bindTo(flagSource).with(FetchVector.Dimension.HOSTNAME, node.hostname()).value());
}
@Override
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
index 95dfad4c6d7..ae118e6d541 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java
@@ -8,7 +8,7 @@ import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.vespa.flags.DoubleFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.dockerapi.Container;
import com.yahoo.vespa.hosted.dockerapi.ContainerResources;
import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials;
@@ -126,7 +126,7 @@ public class NodeAgentImpl implements NodeAgent {
this.healthChecker = healthChecker;
this.clock = clock;
this.warmUpDuration = warmUpDuration;
- this.containerCpuCap = Flags.CONTAINER_CPU_CAP.bindTo(flagSource);
+ this.containerCpuCap = PermanentFlags.CONTAINER_CPU_CAP.bindTo(flagSource);
}
@Override
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
index a37a0bad125..680d197b77d 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImplTest.java
@@ -1,8 +1,8 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.node.admin.nodeagent;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.test.file.TestFileSystem;
import org.junit.Test;
@@ -88,7 +88,7 @@ public class NodeAgentContextImplTest {
private static NodeAgentContext createContextWithDisabledTasks(String... tasks) {
InMemoryFlagSource flagSource = new InMemoryFlagSource();
- flagSource.withListFlag(Flags.DISABLED_HOST_ADMIN_TASKS.id(), List.of(tasks), String.class);
+ flagSource.withListFlag(PermanentFlags.DISABLED_HOST_ADMIN_TASKS.id(), List.of(tasks), String.class);
return new NodeAgentContextImpl.Builder("node123").flagSource(flagSource).build();
}
}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
index 6a264466569..fd587da5d71 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java
@@ -7,8 +7,8 @@ import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.dockerapi.Container;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.dockerapi.ContainerResources;
@@ -238,7 +238,7 @@ public class NodeAgentImplTest {
inOrder.verify(orchestrator, never()).resume(any());
// Set the feature flag
- flagSource.withDoubleFlag(Flags.CONTAINER_CPU_CAP.id(), 2.3);
+ flagSource.withDoubleFlag(PermanentFlags.CONTAINER_CPU_CAP.id(), 2.3);
nodeAgent.doConverge(thirdContext);
inOrder.verify(containerOperations).updateContainer(eq(thirdContext), eq(ContainerResources.from(9.2, 4, 16)));
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
index 87a0684909c..5c635551692 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
@@ -183,7 +183,28 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
.findFirst());
}
+ /**
+ * Returns the cluster spec of the nodes in this, without any group designation
+ *
+ * @throws IllegalStateException if there are no nodes in thus list or they do not all belong
+ * to the same cluster
+ */
+ public ClusterSpec clusterSpec() {
+ ensureSingleCluster();
+ if (isEmpty()) throw new IllegalStateException("No nodes");
+ return first().get().allocation().get().membership().cluster().with(Optional.empty());
+ }
+
+ /**
+ * Returns the resources of the nodes of this.
+ *
+ * NOTE: If the nodes do not all have the same values of node resources, a random pick among those node resources
+ * will be returned.
+ *
+ * @throws IllegalStateException if the nodes in this do not all belong to the same cluster
+ */
public ClusterResources toResources() {
+ ensureSingleCluster();
if (isEmpty()) return new ClusterResources(0, 0, NodeResources.unspecified());
return new ClusterResources(size(),
(int)stream().map(node -> node.allocation().get().membership().cluster().group().get())
@@ -192,6 +213,18 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
first().get().resources());
}
+ private void ensureSingleCluster() {
+ if (isEmpty()) return;
+
+ if (stream().anyMatch(node -> node.allocation().isEmpty()))
+ throw new IllegalStateException("Some nodes are not allocated to a cluster");
+
+ ClusterSpec firstNodeSpec = first().get().allocation().get().membership().cluster().with(Optional.empty());
+ if (stream().map(node -> node.allocation().get().membership().cluster().with(Optional.empty()))
+ .anyMatch(clusterSpec -> ! clusterSpec.equals(firstNodeSpec)))
+ throw new IllegalStateException("Nodes belong to multiple clusters");
+ }
+
/** Returns the nodes of this as a stream */
public Stream<Node> stream() { return asList().stream(); }
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
index 86795767710..b0e7c0bd61b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
@@ -257,6 +257,10 @@ public class NodeRepository extends AbstractComponent {
return NodeList.copyOf(getNodes(inState));
}
+ public NodeList list(ApplicationId application, State ... inState) {
+ return NodeList.copyOf(getNodes(application, inState));
+ }
+
/** Returns a filterable list of all nodes of an application */
public NodeList list(ApplicationId application) {
return NodeList.copyOf(getNodes(application));
@@ -884,11 +888,15 @@ public class NodeRepository extends AbstractComponent {
}
public boolean canAllocateTenantNodeTo(Node host) {
+ return canAllocateTenantNodeTo(host, zone.getCloud().dynamicProvisioning());
+ }
+
+ public static boolean canAllocateTenantNodeTo(Node host, boolean dynamicProvisioning) {
if ( ! host.type().canRun(NodeType.tenant)) return false;
if (host.status().wantToRetire()) return false;
if (host.allocation().map(alloc -> alloc.membership().retired()).orElse(false)) return false;
- if (zone.getCloud().dynamicProvisioning())
+ if (dynamicProvisioning)
return EnumSet.of(State.active, State.ready, State.provisioned).contains(host.state());
else
return host.state() == State.active;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Cluster.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Cluster.java
index 90133f7499e..92bc62229ed 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Cluster.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Cluster.java
@@ -3,9 +3,9 @@ package com.yahoo.vespa.hosted.provision.applications;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.NodeResources;
-import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
+import java.time.Instant;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -19,11 +19,15 @@ import java.util.Optional;
*/
public class Cluster {
+ public static final int maxScalingEvents = 15;
+
private final ClusterSpec.Id id;
private final boolean exclusive;
private final ClusterResources min, max;
private final Optional<ClusterResources> suggested;
private final Optional<ClusterResources> target;
+
+ /** The maxScalingEvents last scaling events of this, sorted by increasing time (newest last) */
private final List<ScalingEvent> scalingEvents;
private final String autoscalingStatus;
@@ -45,7 +49,7 @@ public class Cluster {
this.target = Optional.empty();
else
this.target = targetResources;
- this.scalingEvents = scalingEvents;
+ this.scalingEvents = List.copyOf(scalingEvents);
this.autoscalingStatus = autoscalingStatus;
}
@@ -96,9 +100,18 @@ public class Cluster {
return new Cluster(id, exclusive, min, max, suggested, target, scalingEvents, autoscalingStatus);
}
+ /** Add or update (based on "at" time) a scaling event */
public Cluster with(ScalingEvent scalingEvent) {
- // NOTE: We're just storing the latest scaling event so far
- return new Cluster(id, exclusive, min, max, suggested, target, List.of(scalingEvent), autoscalingStatus);
+ List<ScalingEvent> scalingEvents = new ArrayList<>(this.scalingEvents);
+
+ int existingIndex = eventIndexAt(scalingEvent.at());
+ if (existingIndex >= 0)
+ scalingEvents.set(existingIndex, scalingEvent);
+ else
+ scalingEvents.add(scalingEvent);
+
+ prune(scalingEvents);
+ return new Cluster(id, exclusive, min, max, suggested, target, scalingEvents, autoscalingStatus);
}
public Cluster withAutoscalingStatus(String autoscalingStatus) {
@@ -120,4 +133,17 @@ public class Cluster {
return "cluster '" + id + "'";
}
+ private void prune(List<ScalingEvent> scalingEvents) {
+ while (scalingEvents.size() > maxScalingEvents)
+ scalingEvents.remove(0);
+ }
+
+ private int eventIndexAt(Instant at) {
+ for (int i = 0; i < scalingEvents.size(); i++) {
+ if (scalingEvents.get(i).at().equals(at))
+ return i;
+ }
+ return -1;
+ }
+
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/ScalingEvent.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/ScalingEvent.java
index 68e65d10d69..745fdcd736d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/ScalingEvent.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/ScalingEvent.java
@@ -3,8 +3,10 @@ package com.yahoo.vespa.hosted.provision.applications;
import com.yahoo.config.provision.ClusterResources;
+import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
+import java.util.Optional;
/**
* A recording of a change in resources for an application cluster
@@ -16,12 +18,19 @@ public class ScalingEvent {
private final ClusterResources from, to;
private final long generation;
private final Instant at;
+ private final Optional<Instant> completion;
- public ScalingEvent(ClusterResources from, ClusterResources to, long generation, Instant at) {
+ /** Do not use */
+ public ScalingEvent(ClusterResources from,
+ ClusterResources to,
+ long generation,
+ Instant at,
+ Optional<Instant> completion) {
this.from = from;
this.to = to;
this.generation = generation;
this.at = at;
+ this.completion = completion;
}
/** Returns the resources we changed from */
@@ -36,6 +45,19 @@ public class ScalingEvent {
/** Returns the time of this deployment */
public Instant at() { return at; }
+ /** Returns the instant this completed, or empty if it is not yet complete as far as we know */
+ public Optional<Instant> completion() { return completion; }
+
+ /** Returns the time this event took to completion, or empty if it's not yet complete */
+ public Optional<Duration> duration() {
+ if (completion.isEmpty()) return Optional.empty();
+ return Optional.of(Duration.between(at, completion.get()));
+ }
+
+ public ScalingEvent withCompletion(Instant completion) {
+ return new ScalingEvent(from, to, generation, at, Optional.of(completion));
+ }
+
@Override
public int hashCode() { return Objects.hash(from, to, generation, at); }
@@ -48,12 +70,18 @@ public class ScalingEvent {
if ( ! other.at.equals(this.at)) return false;
if ( ! other.from.equals(this.from)) return false;
if ( ! other.to.equals(this.to)) return false;
+ if ( ! other.completion.equals(this.completion)) return false;
return true;
}
@Override
public String toString() {
- return "scaling event from " + from + " to " + to + ", generation " + generation + " at " + at;
+ return "scaling event from " + from + " to " + to + ", generation " + generation + " at " + at +
+ (completion.isPresent() ? " completed " + completion.get() : "");
+ }
+
+ public static ScalingEvent create(ClusterResources from, ClusterResources to, long generation, Instant at) {
+ return new ScalingEvent(from, to, generation, at, Optional.empty());
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
index b1213b2da41..9eb4b796970 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
@@ -26,20 +26,19 @@ public class AllocatableClusterResources {
private final NodeResources realResources;
private final NodeResources advertisedResources;
- private final ClusterSpec.Type clusterType;
+ private final ClusterSpec clusterSpec;
private final double fulfilment;
/** Fake allocatable resources from requested capacity */
public AllocatableClusterResources(ClusterResources requested,
- ClusterSpec.Type clusterType,
- boolean exclusive,
+ ClusterSpec clusterSpec,
NodeRepository nodeRepository) {
this.nodes = requested.nodes();
this.groups = requested.groups();
- this.realResources = nodeRepository.resourcesCalculator().requestToReal(requested.nodeResources(), exclusive);
+ this.realResources = nodeRepository.resourcesCalculator().requestToReal(requested.nodeResources(), clusterSpec.isExclusive());
this.advertisedResources = requested.nodeResources();
- this.clusterType = clusterType;
+ this.clusterSpec = clusterSpec;
this.fulfilment = 1;
}
@@ -48,19 +47,19 @@ public class AllocatableClusterResources {
this.groups = (int)nodes.stream().map(node -> node.allocation().get().membership().cluster().group()).distinct().count();
this.realResources = averageRealResourcesOf(nodes, nodeRepository, exclusive); // Average since we average metrics over nodes
this.advertisedResources = nodes.get(0).resources();
- this.clusterType = nodes.get(0).allocation().get().membership().cluster().type();
+ this.clusterSpec = nodes.get(0).allocation().get().membership().cluster();
this.fulfilment = 1;
}
public AllocatableClusterResources(ClusterResources realResources,
NodeResources advertisedResources,
NodeResources idealResources,
- ClusterSpec.Type clusterType) {
+ ClusterSpec clusterSpec) {
this.nodes = realResources.nodes();
this.groups = realResources.groups();
this.realResources = realResources.nodeResources();
this.advertisedResources = advertisedResources;
- this.clusterType = clusterType;
+ this.clusterSpec = clusterSpec;
this.fulfilment = fulfilment(realResources.nodeResources(), idealResources);
}
@@ -88,7 +87,7 @@ public class AllocatableClusterResources {
return (int)Math.ceil((double)nodes / groups);
}
- public ClusterSpec.Type clusterType() { return clusterType; }
+ public ClusterSpec clusterSpec() { return clusterSpec; }
public double cost() { return nodes * advertisedResources.cost(); }
@@ -133,23 +132,23 @@ public class AllocatableClusterResources {
}
public static Optional<AllocatableClusterResources> from(ClusterResources wantedResources,
- boolean exclusive,
- ClusterSpec.Type clusterType,
+ ClusterSpec clusterSpec,
Limits applicationLimits,
NodeRepository nodeRepository) {
var systemLimits = new NodeResourceLimits(nodeRepository);
- if ( !exclusive && !nodeRepository.zone().getCloud().dynamicProvisioning()) {
+ boolean exclusive = clusterSpec.isExclusive();
+ if ( !clusterSpec.isExclusive() && !nodeRepository.zone().getCloud().dynamicProvisioning()) {
// We decide resources: Add overhead to what we'll request (advertised) to make sure real becomes (at least) cappedNodeResources
NodeResources advertisedResources = nodeRepository.resourcesCalculator().realToRequest(wantedResources.nodeResources(), exclusive);
- advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterType, exclusive); // Attempt to ask for something legal
+ advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterSpec.type(), exclusive); // Attempt to ask for something legal
advertisedResources = applicationLimits.cap(advertisedResources); // Overrides other conditions, even if it will then fail
NodeResources realResources = nodeRepository.resourcesCalculator().requestToReal(advertisedResources, exclusive); // ... thus, what we really get may change
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) return Optional.empty();
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type())) return Optional.empty();
if (matchesAny(nodeRepository.flavors().getFlavors(), advertisedResources))
return Optional.of(new AllocatableClusterResources(wantedResources.with(realResources),
advertisedResources,
wantedResources.nodeResources(),
- clusterType));
+ clusterSpec));
else
return Optional.empty();
}
@@ -172,11 +171,11 @@ public class AllocatableClusterResources {
}
if ( ! between(applicationLimits.min().nodeResources(), applicationLimits.max().nodeResources(), advertisedResources)) continue;
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) continue;
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type())) continue;
var candidate = new AllocatableClusterResources(wantedResources.with(realResources),
advertisedResources,
wantedResources.nodeResources(),
- clusterType);
+ clusterSpec);
if (best.isEmpty() || candidate.preferableTo(best.get()))
best = Optional.of(candidate);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
index e57011b0e4a..fb97e803a35 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocationOptimizer.java
@@ -58,7 +58,7 @@ public class AllocationOptimizer {
groups,
nodeResourcesWith(nodesAdjustedForRedundancy, groupsAdjustedForRedundancy, limits, current, target));
- var allocatableResources = AllocatableClusterResources.from(next, exclusive, current.clusterType(), limits, nodeRepository);
+ var allocatableResources = AllocatableClusterResources.from(next, current.clusterSpec(), limits, nodeRepository);
if (allocatableResources.isEmpty()) continue;
if (bestAllocation.isEmpty() || allocatableResources.get().preferableTo(bestAllocation.get()))
bestAllocation = allocatableResources;
@@ -79,7 +79,7 @@ public class AllocationOptimizer {
int groupSize = nodes / groups;
- if (current.clusterType().isContent()) { // load scales with node share of content
+ if (current.clusterSpec().isStateful()) { // load scales with node share of content
// The fixed cost portion of cpu does not scale with changes to the node count
// TODO: Only for the portion of cpu consumed by queries
double cpuPerGroup = fixedCpuCostFraction * target.nodeCpu() +
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
index d2c943794fe..79383c056f9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
@@ -5,18 +5,18 @@ import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
+import com.yahoo.vespa.hosted.provision.applications.ScalingEvent;
import java.time.Duration;
import java.time.Instant;
-import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
- * The autoscaler makes decisions about the flavor and node count that should be allocated to a cluster
- * based on observed behavior.
+ * The autoscaler gives advice about what resources should be allocated to a cluster based on observed behavior.
*
* @author bratseth
*/
@@ -44,7 +44,7 @@ public class Autoscaler {
* @param clusterNodes the list of all the active nodes in a cluster
* @return scaling advice for this cluster
*/
- public Advice suggest(Cluster cluster, List<Node> clusterNodes) {
+ public Advice suggest(Cluster cluster, NodeList clusterNodes) {
return autoscale(cluster, clusterNodes, Limits.empty(), cluster.exclusive());
}
@@ -54,30 +54,34 @@ public class Autoscaler {
* @param clusterNodes the list of all the active nodes in a cluster
* @return scaling advice for this cluster
*/
- public Advice autoscale(Cluster cluster, List<Node> clusterNodes) {
- if (cluster.minResources().equals(cluster.maxResources())) return Advice.none("Autoscaling is disabled"); // Shortcut
+ public Advice autoscale(Cluster cluster, NodeList clusterNodes) {
+ if (cluster.minResources().equals(cluster.maxResources())) return Advice.none("Autoscaling is not enabled");
return autoscale(cluster, clusterNodes, Limits.of(cluster), cluster.exclusive());
}
- private Advice autoscale(Cluster cluster, List<Node> clusterNodes, Limits limits, boolean exclusive) {
- ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
- if (unstable(clusterNodes, nodeRepository))
+ private Advice autoscale(Cluster cluster, NodeList clusterNodes, Limits limits, boolean exclusive) {
+ if ( ! stable(clusterNodes, nodeRepository))
return Advice.none("Cluster change in progress");
- AllocatableClusterResources currentAllocation =
- new AllocatableClusterResources(clusterNodes, nodeRepository, cluster.exclusive());
+ Duration scalingWindow = scalingWindow(clusterNodes.clusterSpec(), cluster);
+ if (scaledIn(scalingWindow, cluster))
+ return Advice.dontScale("Won't autoscale now: Less than " + scalingWindow + " since last rescaling");
- ClusterTimeseries clusterTimeseries = new ClusterTimeseries(cluster, clusterNodes, metricsDb, nodeRepository);
+ ClusterTimeseries clusterTimeseries =
+ new ClusterTimeseries(nodeRepository.clock().instant().minus(scalingWindow), cluster, clusterNodes, metricsDb);
+ AllocatableClusterResources currentAllocation =
+ new AllocatableClusterResources(clusterNodes.asList(), nodeRepository, cluster.exclusive());
int measurementsPerNode = clusterTimeseries.measurementsPerNode();
- if (measurementsPerNode < minimumMeasurementsPerNode(clusterType))
- return Advice.none("Collecting more data before making new scaling decisions" +
- ": Has " + measurementsPerNode + " data points per node");
+ if (measurementsPerNode < minimumMeasurementsPerNode(scalingWindow))
+ return Advice.none("Collecting more data before making new scaling decisions: " +
+ "Have " + measurementsPerNode + " measurements per node but require " +
+ minimumMeasurementsPerNode(scalingWindow));
int nodesMeasured = clusterTimeseries.nodesMeasured();
if (nodesMeasured != clusterNodes.size())
- return Advice.none("Collecting more data before making new scaling decisions" +
- ": Has measurements from " + nodesMeasured + " but need from " + clusterNodes.size());
+ return Advice.none("Collecting more data before making new scaling decisions: " +
+ "Have measurements from " + nodesMeasured + " but require from " + clusterNodes.size());
double cpuLoad = clusterTimeseries.averageLoad(Resource.cpu);
double memoryLoad = clusterTimeseries.averageLoad(Resource.memory);
@@ -91,9 +95,10 @@ public class Autoscaler {
return Advice.dontScale("No allocation changes are possible within configured limits");
if (similar(bestAllocation.get(), currentAllocation))
- return Advice.dontScale("Cluster is ideally scaled (within configured limits)");
- if (isDownscaling(bestAllocation.get(), currentAllocation) && recentlyScaled(cluster, clusterNodes))
- return Advice.dontScale("Waiting a while before scaling down");
+ return Advice.dontScale("Cluster is ideally scaled within configured limits");
+
+ if (isDownscaling(bestAllocation.get(), currentAllocation) && scaledIn(scalingWindow.multipliedBy(3), cluster))
+ return Advice.dontScale("Waiting " + scalingWindow.multipliedBy(3) + " since last rescaling before reducing resources");
return Advice.scaleTo(bestAllocation.get().toAdvertisedClusterResources());
}
@@ -120,49 +125,64 @@ public class Autoscaler {
return ! targetTotal.justNumbers().satisfies(currentTotal.justNumbers());
}
- private boolean recentlyScaled(Cluster cluster, List<Node> clusterNodes) {
- Duration downscalingDelay = downscalingDelay(clusterNodes.get(0).allocation().get().membership().cluster().type());
+ private boolean scaledIn(Duration delay, Cluster cluster) {
return cluster.lastScalingEvent().map(event -> event.at()).orElse(Instant.MIN)
- .isAfter(nodeRepository.clock().instant().minus(downscalingDelay));
+ .isAfter(nodeRepository.clock().instant().minus(delay));
}
/** The duration of the window we need to consider to make a scaling decision. See also minimumMeasurementsPerNode */
- static Duration scalingWindow(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return Duration.ofHours(12);
- return Duration.ofMinutes(30);
- }
+ private Duration scalingWindow(ClusterSpec clusterSpec, Cluster cluster) {
+ int completedEventCount = 0;
+ Duration totalDuration = Duration.ZERO;
+ for (ScalingEvent event : cluster.scalingEvents()) {
+ if (event.duration().isEmpty()) continue;
+ completedEventCount++;
+ totalDuration = totalDuration.plus(event.duration().get());
+ }
- static Duration maxScalingWindow() {
- return Duration.ofHours(12);
+ if (completedEventCount == 0) { // Use defaults
+ if (clusterSpec.isStateful()) return Duration.ofHours(12);
+ return Duration.ofMinutes(10);
+ }
+ else {
+ Duration predictedDuration = totalDuration.dividedBy(completedEventCount);
+
+ // TODO: Remove when we have reliable completion for content clusters
+ if (clusterSpec.isStateful() && predictedDuration.minus(Duration.ofHours(12)).isNegative())
+ return Duration.ofHours(12);
+
+ if (predictedDuration.minus(Duration.ofMinutes(5)).isNegative()) return Duration.ofMinutes(5); // minimum
+ return predictedDuration;
+ }
}
- /** Measurements are currently taken once a minute. See also scalingWindow */
- static int minimumMeasurementsPerNode(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return 60;
- return 7;
+ static Duration maxScalingWindow() {
+ return Duration.ofHours(48);
}
- /**
- * We should wait a while before scaling down after a scaling event as a peak in usage
- * indicates more peaks may arrive in the near future.
- */
- static Duration downscalingDelay(ClusterSpec.Type clusterType) {
- if (clusterType.isContent()) return Duration.ofHours(12);
- return Duration.ofHours(1);
+ /** Returns the minimum measurements per node (average) we require to give autoscaling advice.*/
+ private int minimumMeasurementsPerNode(Duration scalingWindow) {
+ // Measurements are ideally taken every minute, but no guarantees
+ // (network, nodes may be down, collecting is single threaded and may take longer than 1 minute to complete).
+ // Since the metric window is 5 minutes, we won't really improve from measuring more often.
+ long minimumMeasurements = scalingWindow.toMinutes() / 5;
+ minimumMeasurements = Math.round(0.8 * minimumMeasurements); // Allow 20% metrics collection blackout
+ if (minimumMeasurements < 1) minimumMeasurements = 1;
+ return (int)minimumMeasurements;
}
- public static boolean unstable(List<Node> nodes, NodeRepository nodeRepository) {
+ public static boolean stable(NodeList nodes, NodeRepository nodeRepository) {
// The cluster is processing recent changes
if (nodes.stream().anyMatch(node -> node.status().wantToRetire() ||
node.allocation().get().membership().retired() ||
node.allocation().get().isRemovable()))
- return true;
+ return false;
// A deployment is ongoing
- if (nodeRepository.getNodes(nodes.get(0).allocation().get().owner(), Node.State.reserved).size() > 0)
- return true;
+ if (nodeRepository.getNodes(nodes.first().get().allocation().get().owner(), Node.State.reserved).size() > 0)
+ return false;
- return false;
+ return true;
}
public static class Advice {
@@ -197,6 +217,13 @@ public class Autoscaler {
private static Advice scaleTo(ClusterResources target) {
return new Advice(Optional.of(target), true, "Scaling due to load changes");
}
+
+ @Override
+ public String toString() {
+ return "autoscaling advice: " +
+ (present ? (target.isPresent() ? "Scale to " + target.get() : "Don't scale") : " None");
+ }
+
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
index e325e797ca5..e1a3ceca033 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java
@@ -1,15 +1,13 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.autoscale;
-import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
import java.time.Instant;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -19,64 +17,38 @@ import java.util.stream.Collectors;
*/
public class ClusterTimeseries {
- private final List<Node> clusterNodes;
+ private final NodeList clusterNodes;
- /** The measurements for all hosts in this snapshot */
- private final List<NodeTimeseries> nodeTimeseries;
+ /** The measurements for all nodes in this snapshot */
+ private final List<NodeTimeseries> allTimeseries;
- public ClusterTimeseries(Cluster cluster, List<Node> clusterNodes, MetricsDb db, NodeRepository nodeRepository) {
+ public ClusterTimeseries(Instant startTime, Cluster cluster, NodeList clusterNodes, MetricsDb db) {
this.clusterNodes = clusterNodes;
- ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
- var allTimeseries = db.getNodeTimeseries(nodeRepository.clock().instant().minus(Autoscaler.scalingWindow(clusterType)),
- clusterNodes.stream().map(Node::hostname).collect(Collectors.toSet()));
- Map<String, Instant> startTimePerNode = metricStartTimes(cluster, clusterNodes, allTimeseries, nodeRepository);
- nodeTimeseries = filterStale(allTimeseries, startTimePerNode);
- }
+ var timeseries = db.getNodeTimeseries(startTime, clusterNodes);
- /**
- * Returns the instant of the oldest metric to consider for each node, or an empty map if metrics from the
- * entire (max) window should be considered.
- */
- private Map<String, Instant> metricStartTimes(Cluster cluster,
- List<Node> clusterNodes,
- List<NodeTimeseries> nodeTimeseries,
- NodeRepository nodeRepository) {
- Map<String, Instant> startTimePerHost = new HashMap<>();
- if ( ! cluster.scalingEvents().isEmpty()) {
- var deployment = cluster.scalingEvents().get(cluster.scalingEvents().size() - 1);
- for (Node node : clusterNodes) {
- startTimePerHost.put(node.hostname(), nodeRepository.clock().instant()); // Discard all unless we can prove otherwise
- var nodeGenerationMeasurements =
- nodeTimeseries.stream().filter(m -> m.hostname().equals(node.hostname())).findAny();
- if (nodeGenerationMeasurements.isPresent()) {
- var firstMeasurementOfCorrectGeneration =
- nodeGenerationMeasurements.get().asList().stream()
- .filter(m -> m.generation() >= deployment.generation())
- .findFirst();
- if (firstMeasurementOfCorrectGeneration.isPresent()) {
- startTimePerHost.put(node.hostname(), firstMeasurementOfCorrectGeneration.get().at());
- }
- }
- }
- }
- return startTimePerHost;
+ if (cluster.lastScalingEvent().isPresent())
+ timeseries = filter(timeseries, snapshot -> snapshot.generation() < 0 || // Content nodes do not yet send generation
+ snapshot.generation() >= cluster.lastScalingEvent().get().generation());
+ timeseries = filter(timeseries, snapshot -> snapshot.inService() && snapshot.stable());
+
+ this.allTimeseries = timeseries;
}
/** Returns the average number of measurements per node */
public int measurementsPerNode() {
- int measurementCount = nodeTimeseries.stream().mapToInt(m -> m.size()).sum();
+ int measurementCount = allTimeseries.stream().mapToInt(m -> m.size()).sum();
return measurementCount / clusterNodes.size();
}
/** Returns the number of nodes measured in this */
public int nodesMeasured() {
- return nodeTimeseries.size();
+ return allTimeseries.size();
}
/** Returns the average load of this resource in this */
public double averageLoad(Resource resource) {
- int measurementCount = nodeTimeseries.stream().mapToInt(m -> m.size()).sum();
- double measurementSum = nodeTimeseries.stream().flatMap(m -> m.asList().stream()).mapToDouble(m -> value(resource, m)).sum();
+ int measurementCount = allTimeseries.stream().mapToInt(m -> m.size()).sum();
+ double measurementSum = allTimeseries.stream().flatMap(m -> m.asList().stream()).mapToDouble(m -> value(resource, m)).sum();
return measurementSum / measurementCount;
}
@@ -89,10 +61,8 @@ public class ClusterTimeseries {
}
}
- private List<NodeTimeseries> filterStale(List<NodeTimeseries> timeseries,
- Map<String, Instant> startTimePerHost) {
- if (startTimePerHost.isEmpty()) return timeseries; // Map is either empty or complete
- return timeseries.stream().map(m -> m.justAfter(startTimePerHost.get(m.hostname()))).collect(Collectors.toList());
+ private List<NodeTimeseries> filter(List<NodeTimeseries> timeseries, Predicate<MetricSnapshot> filter) {
+ return timeseries.stream().map(nodeTimeseries -> nodeTimeseries.filter(filter)).collect(Collectors.toList());
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java
index 6f6cd862c33..d5072475cd9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricSnapshot.java
@@ -8,9 +8,8 @@ import java.time.Instant;
*
* @author bratseth
*/
-public class MetricSnapshot {
+public class MetricSnapshot implements Comparable<MetricSnapshot> {
- // TODO: Order by timestamp
private final Instant at;
private final double cpu;
@@ -18,28 +17,43 @@ public class MetricSnapshot {
private final double disk;
private final long generation;
private final boolean inService;
+ private final boolean stable;
- public MetricSnapshot(Instant at, double cpu, double memory, double disk, long generation, boolean inService) {
+ public MetricSnapshot(Instant at, double cpu, double memory, double disk, long generation,
+ boolean inService, boolean stable) {
this.at = at;
this.cpu = cpu;
this.memory = memory;
this.disk = disk;
this.generation = generation;
this.inService = inService;
+ this.stable = stable;
}
public Instant at() { return at; }
public double cpu() { return cpu; }
public double memory() { return memory; }
public double disk() { return disk; }
+
+ /** The configuration generation at the time of this measurement, or -1 if not known */
public long generation() { return generation; }
+
public boolean inService() { return inService; }
+ public boolean stable() { return stable; }
+
+ @Override
+ public int compareTo(MetricSnapshot other) {
+ return at.compareTo(other.at);
+ }
@Override
public String toString() { return "metrics at " + at + ":" +
" cpu: " + cpu +
" memory: " + memory +
" disk: " + disk +
- " generation: " + generation; }
+ " generation: " + generation +
+ " inService: " + inService +
+ " stable: " + stable;
+ }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsDb.java
index ea4ce4b44de..68acdcc88f7 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsDb.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsDb.java
@@ -2,6 +2,8 @@
package com.yahoo.vespa.hosted.provision.autoscale;
import com.yahoo.collections.Pair;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import java.time.Clock;
@@ -9,6 +11,7 @@ import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* An in-memory time-series database of node metrics.
@@ -26,6 +29,10 @@ public interface MetricsDb {
*/
List<NodeTimeseries> getNodeTimeseries(Instant startTime, Set<String> hostnames);
+ default List<NodeTimeseries> getNodeTimeseries(Instant startTime, NodeList nodes) {
+ return getNodeTimeseries(startTime, nodes.stream().map(Node::hostname).collect(Collectors.toSet()));
+ }
+
/** Must be called intermittently (as long as add is called) to gc old data */
void gc();
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java
index 4471d267416..7c5b839edf3 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java
@@ -2,17 +2,24 @@
package com.yahoo.vespa.hosted.provision.autoscale;
import com.yahoo.collections.Pair;
+import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
+import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.applications.Application;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
/**
* Consumes a response from the metrics/v2 API and populates the fields of this with the resulting values
@@ -23,33 +30,41 @@ public class MetricsResponse {
private final Collection<Pair<String, MetricSnapshot>> nodeMetrics = new ArrayList<>();
- public MetricsResponse(String response) {
- this(SlimeUtils.jsonToSlime(response));
+ public MetricsResponse(String response, NodeList applicationNodes, NodeRepository nodeRepository) {
+ this(SlimeUtils.jsonToSlime(response), applicationNodes, nodeRepository);
}
public Collection<Pair<String, MetricSnapshot>> metrics() { return nodeMetrics; }
- private MetricsResponse(Slime response) {
+ private MetricsResponse(Slime response, NodeList applicationNodes, NodeRepository nodeRepository) {
Inspector root = response.get();
Inspector nodes = root.field("nodes");
- nodes.traverse((ArrayTraverser)(__, node) -> consumeNode(node));
+ nodes.traverse((ArrayTraverser)(__, node) -> consumeNode(node, applicationNodes, nodeRepository));
}
- private void consumeNode(Inspector node) {
+ private void consumeNode(Inspector node, NodeList applicationNodes, NodeRepository nodeRepository) {
String hostname = node.field("hostname").asString();
- consumeNodeMetrics(hostname, node.field("node"));
+ consumeNodeMetrics(hostname, node.field("node"), applicationNodes, nodeRepository);
// consumeServiceMetrics(hostname, node.field("services"));
}
- private void consumeNodeMetrics(String hostname, Inspector node) {
- long timestampSecond = node.field("timestamp").asLong();
- Map<String, Double> values = consumeMetrics(node.field("metrics"));
+ private void consumeNodeMetrics(String hostname, Inspector nodeData, NodeList applicationNodes, NodeRepository nodeRepository) {
+ Optional<Node> node = applicationNodes.stream().filter(n -> n.hostname().equals(hostname)).findAny();
+ if (node.isEmpty()) return; // Node is not part of this cluster any more
+ long timestampSecond = nodeData.field("timestamp").asLong();
+ Map<String, Double> values = consumeMetrics(nodeData.field("metrics"));
nodeMetrics.add(new Pair<>(hostname, new MetricSnapshot(Instant.ofEpochMilli(timestampSecond * 1000),
Metric.cpu.from(values),
Metric.memory.from(values),
Metric.disk.from(values),
(long)Metric.generation.from(values),
- Metric.inService.from(values) > 0)));
+ Metric.inService.from(values) > 0,
+ clusterIsStable(node.get(), applicationNodes, nodeRepository))));
+ }
+
+ private boolean clusterIsStable(Node node, NodeList applicationNodes, NodeRepository nodeRepository) {
+ ClusterSpec cluster = node.allocation().get().membership().cluster();
+ return Autoscaler.stable(applicationNodes.cluster(cluster.id()), nodeRepository);
}
private void consumeServiceMetrics(String hostname, Inspector node) {
@@ -86,6 +101,7 @@ public class MetricsResponse {
generation { // application config generation active on the node
public String metricResponseName() { return "application_generation"; }
double convertValue(double metricValue) { return (float)metricValue; } // Really a long
+ double defaultValue() { return -1.0; }
},
inService {
public String metricResponseName() { return "in_service"; }
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java
index 33bdc746678..4afc876056a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcher.java
@@ -55,9 +55,6 @@ public class MetricsV2MetricsFetcher extends AbstractComponent implements Metric
public Collection<Pair<String, MetricSnapshot>> fetchMetrics(ApplicationId application) {
NodeList applicationNodes = nodeRepository.list(application).state(Node.State.active);
- // Do not try to draw conclusions from utilization while unstable
- if (Autoscaler.unstable(applicationNodes.asList(), nodeRepository)) return Collections.emptyList();
-
Optional<Node> metricsV2Container = applicationNodes.container()
.matching(node -> expectedUp(node))
.stream()
@@ -65,8 +62,7 @@ public class MetricsV2MetricsFetcher extends AbstractComponent implements Metric
if (metricsV2Container.isEmpty()) return Collections.emptyList();
// Consumer 'autoscaling' defined in com.yahoo.vespa.model.admin.monitoring.MetricConsumer
String url = "http://" + metricsV2Container.get().hostname() + ":" + 4080 + apiPath + "?consumer=autoscaling";
- String response = httpClient.get(url);
- return new MetricsResponse(response).metrics();
+ return new MetricsResponse(httpClient.get(url), applicationNodes, nodeRepository).metrics();
}
@Override
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java
index 6cba3928b8f..24876609f58 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java
@@ -1,16 +1,15 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.autoscale;
-import com.yahoo.config.provision.ClusterSpec;
-
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
- * A list of metric snapshots from a host
+ * A list of metric snapshots from a node, sorted by increasing time (newest last).
*
* @author bratseth
*/
@@ -19,10 +18,11 @@ public class NodeTimeseries {
private final String hostname;
private final List<MetricSnapshot> snapshots;
- // Note: This transfers ownership of the snapshot list to this
NodeTimeseries(String hostname, List<MetricSnapshot> snapshots) {
this.hostname = hostname;
- this.snapshots = snapshots;
+ List<MetricSnapshot> sortedSnapshots = new ArrayList<>(snapshots);
+ Collections.sort(sortedSnapshots);
+ this.snapshots = Collections.unmodifiableList(sortedSnapshots);
}
public boolean isEmpty() { return snapshots.isEmpty(); }
@@ -31,7 +31,7 @@ public class NodeTimeseries {
public MetricSnapshot get(int index) { return snapshots.get(index); }
- public List<MetricSnapshot> asList() { return Collections.unmodifiableList(snapshots); }
+ public List<MetricSnapshot> asList() { return snapshots; }
public String hostname() { return hostname; }
@@ -41,6 +41,10 @@ public class NodeTimeseries {
return new NodeTimeseries(hostname(), list);
}
+ public NodeTimeseries filter(Predicate<MetricSnapshot> filter) {
+ return new NodeTimeseries(hostname, snapshots.stream().filter(filter).collect(Collectors.toList()));
+ }
+
public NodeTimeseries justAfter(Instant oldestTime) {
return new NodeTimeseries(hostname,
snapshots.stream()
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java
index bf013810b2f..8e90294b4a5 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java
@@ -4,10 +4,12 @@ package com.yahoo.vespa.hosted.provision.autoscale;
import com.google.inject.Inject;
import com.yahoo.collections.ListMap;
import com.yahoo.collections.Pair;
+import com.yahoo.component.AbstractComponent;
import com.yahoo.io.IOUtils;
import com.yahoo.vespa.defaults.Defaults;
import io.questdb.cairo.CairoConfiguration;
import io.questdb.cairo.CairoEngine;
+import io.questdb.cairo.CairoException;
import io.questdb.cairo.DefaultCairoConfiguration;
import io.questdb.cairo.TableWriter;
import io.questdb.cairo.sql.Record;
@@ -40,14 +42,14 @@ import java.util.stream.Collectors;
*
* @author bratseth
*/
-public class QuestMetricsDb implements MetricsDb {
+public class QuestMetricsDb extends AbstractComponent implements MetricsDb {
private static final Logger log = Logger.getLogger(QuestMetricsDb.class.getName());
- private static final String tableName = "metrics";
+ private static final String table = "metrics";
private final Clock clock;
private final String dataDir;
- private final CairoEngine engine;
+ private CairoEngine engine;
private long highestTimestampAdded = 0;
@@ -63,8 +65,11 @@ public class QuestMetricsDb implements MetricsDb {
&& ! new File(Defaults.getDefaults().vespaHome()).exists())
dataDir = "data"; // We're injected, but not on a node with Vespa installed
this.dataDir = dataDir;
+ initializeDb();
+ }
- IOUtils.createDirectory(dataDir + "/" + tableName);
+ private void initializeDb() {
+ IOUtils.createDirectory(dataDir + "/" + table);
// silence Questdb's custom logging system
IOUtils.writeFile(new File(dataDir, "quest-log.conf"), new byte[0]);
@@ -73,28 +78,43 @@ public class QuestMetricsDb implements MetricsDb {
CairoConfiguration configuration = new DefaultCairoConfiguration(dataDir);
engine = new CairoEngine(configuration);
- ensureExists(tableName);
+ ensureExists(table);
}
@Override
public void add(Collection<Pair<String, MetricSnapshot>> snapshots) {
- try (TableWriter writer = engine.getWriter(newContext().getCairoSecurityContext(), tableName)) {
- for (var snapshot : snapshots) {
- long atMillis = adjustIfRecent(snapshot.getSecond().at().toEpochMilli(), highestTimestampAdded);
- if (atMillis < highestTimestampAdded) continue; // Ignore old data
- highestTimestampAdded = atMillis;
- TableWriter.Row row = writer.newRow(atMillis * 1000); // in microseconds
- row.putStr(0, snapshot.getFirst());
- row.putFloat(2, (float)snapshot.getSecond().cpu());
- row.putFloat(3, (float)snapshot.getSecond().memory());
- row.putFloat(4, (float)snapshot.getSecond().disk());
- row.putLong(5, snapshot.getSecond().generation());
- row.append();
+ try (TableWriter writer = engine.getWriter(newContext().getCairoSecurityContext(), table)) {
+ add(snapshots, writer);
+ }
+ catch (CairoException e) {
+ if (e.getMessage().contains("Cannot read offset")) {
+ // This error seems non-recoverable
+ repair(e);
+ try (TableWriter writer = engine.getWriter(newContext().getCairoSecurityContext(), table)) {
+ add(snapshots, writer);
+ }
}
- writer.commit();
}
}
+ private void add(Collection<Pair<String, MetricSnapshot>> snapshots, TableWriter writer) {
+ for (var snapshot : snapshots) {
+ long atMillis = adjustIfRecent(snapshot.getSecond().at().toEpochMilli(), highestTimestampAdded);
+ if (atMillis < highestTimestampAdded) continue; // Ignore old data
+ highestTimestampAdded = atMillis;
+ TableWriter.Row row = writer.newRow(atMillis * 1000); // in microseconds
+ row.putStr(0, snapshot.getFirst());
+ row.putFloat(2, (float)snapshot.getSecond().cpu());
+ row.putFloat(3, (float)snapshot.getSecond().memory());
+ row.putFloat(4, (float)snapshot.getSecond().disk());
+ row.putLong(5, snapshot.getSecond().generation());
+ row.putBool(6, snapshot.getSecond().inService());
+ row.putBool(7, snapshot.getSecond().stable());
+ row.append();
+ }
+ writer.commit();
+ }
+
@Override
public List<NodeTimeseries> getNodeTimeseries(Instant startTime, Set<String> hostnames) {
try (SqlCompiler compiler = new SqlCompiler(engine)) {
@@ -116,7 +136,7 @@ public class QuestMetricsDb implements MetricsDb {
SqlExecutionContext context = newContext();
int partitions = 0;
try (SqlCompiler compiler = new SqlCompiler(engine)) {
- File tableRoot = new File(dataDir, tableName);
+ File tableRoot = new File(dataDir, table);
List<String> removeList = new ArrayList<>();
for (String dirEntry : tableRoot.list()) {
File partitionDir = new File(tableRoot, dirEntry);
@@ -131,7 +151,7 @@ public class QuestMetricsDb implements MetricsDb {
}
// Remove unless all partitions are old: Removing all partitions "will be supported in the future"
if ( removeList.size() < partitions && ! removeList.isEmpty())
- compiler.compile("alter table " + tableName + " drop partition " +
+ compiler.compile("alter table " + table + " drop partition " +
removeList.stream().map(dir -> "'" + dir + "'").collect(Collectors.joining(",")),
context);
}
@@ -141,27 +161,78 @@ public class QuestMetricsDb implements MetricsDb {
}
@Override
+ public void deconstruct() { close(); }
+
+ @Override
public void close() {
if (engine != null)
engine.close();
}
- private void ensureExists(String tableName) {
+ /**
+ * Repairs this db on corruption.
+ *
+ * @param e the exception indicating corruption
+ */
+ private void repair(Exception e) {
+ log.log(Level.WARNING, "QuestDb seems corrupted, wiping data and starting over", e);
+ IOUtils.recursiveDeleteDir(new File(dataDir));
+ initializeDb();
+ }
+
+ private void ensureExists(String table) {
SqlExecutionContext context = newContext();
- if (0 == engine.getStatus(context.getCairoSecurityContext(), new Path(), tableName)) return;
+ if (0 == engine.getStatus(context.getCairoSecurityContext(), new Path(), table)) { // table exists
+ ensureUpdated(table, context);
+ } else {
+ create(table, context);
+ }
+ }
+ private void ensureUpdated(String table, SqlExecutionContext context) {
try (SqlCompiler compiler = new SqlCompiler(engine)) {
- compiler.compile("create table " + tableName +
- " (hostname string, at timestamp, cpu_util float, mem_total_util float, disk_util float, application_generation long)" +
+ if (0 == engine.getStatus(context.getCairoSecurityContext(), new Path(), table)) {
+ ensureColumnExists("inService", "boolean", table, compiler, context); // TODO: Remove after December 2020
+ ensureColumnExists("stable", "boolean", table, compiler, context); // TODO: Remove after December 2020
+ }
+ } catch (SqlException e) {
+ repair(e);
+ }
+ }
+
+ private void create(String table, SqlExecutionContext context) {
+ try (SqlCompiler compiler = new SqlCompiler(engine)) {
+ compiler.compile("create table " + table +
+ " (hostname string, at timestamp, cpu_util float, mem_total_util float, disk_util float," +
+ " application_generation long, inService boolean, stable boolean)" +
" timestamp(at)" +
"PARTITION BY DAY;",
context);
- // We should do this if we get a version where selecting on stringhs work embedded, see below
+ // We should do this if we get a version where selecting on strings work embedded, see below
// compiler.compile("alter table " + tableName + " alter column hostname add index", context);
}
catch (SqlException e) {
- throw new IllegalStateException("Could not create Quest db table '" + tableName + "'", e);
+ throw new IllegalStateException("Could not create Quest db table '" + table + "'", e);
+ }
+ }
+
+ private void ensureColumnExists(String column, String columnType,
+ String table, SqlCompiler compiler, SqlExecutionContext context) throws SqlException {
+ if (columnNamesOf(table, compiler, context).contains(column)) return;
+ compiler.compile("alter table " + table + " add column " + column + " " + columnType, context);
+ }
+
+ private List<String> columnNamesOf(String tableName, SqlCompiler compiler, SqlExecutionContext context) throws SqlException {
+ List<String> columns = new ArrayList<>();
+ try (RecordCursorFactory factory = compiler.compile("show columns from " + tableName, context).getRecordCursorFactory()) {
+ try (RecordCursor cursor = factory.getCursor(context)) {
+ Record record = cursor.getRecord();
+ while (cursor.hasNext()) {
+ columns.add(record.getStr(0).toString());
+ }
+ }
}
+ return columns;
}
private long adjustIfRecent(long timestamp, long highestTimestampAdded) {
@@ -182,7 +253,7 @@ public class QuestMetricsDb implements MetricsDb {
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of("UTC"));
String from = formatter.format(startTime).substring(0, 19) + ".000000Z";
String to = formatter.format(clock.instant()).substring(0, 19) + ".000000Z";
- String sql = "select * from " + tableName + " where at in('" + from + "', '" + to + "');";
+ String sql = "select * from " + table + " where at in('" + from + "', '" + to + "');";
// WHERE clauses does not work:
// String sql = "select * from " + tableName + " where hostname in('host1', 'host2', 'host3');";
@@ -200,7 +271,8 @@ public class QuestMetricsDb implements MetricsDb {
record.getFloat(3),
record.getFloat(4),
record.getLong(5),
- true));
+ record.getBool(6),
+ record.getBool(7)));
}
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
index 5df45bbc1b1..9ac1ca2b4c1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
@@ -95,9 +95,14 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer {
}
@Override
- public void close() {
- super.close();
+ public void shutdown() {
+ super.shutdown();
this.deploymentExecutor.shutdownNow();
+ }
+
+ @Override
+ public void awaitShutdown() {
+ super.awaitShutdown();
try {
// Give deployments in progress some time to complete
this.deploymentExecutor.awaitTermination(1, TimeUnit.MINUTES);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
index 809c54146d0..c4744f6cb6a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
@@ -7,15 +7,21 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Deployer;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.Applications;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
import com.yahoo.vespa.hosted.provision.autoscale.AllocatableClusterResources;
import com.yahoo.vespa.hosted.provision.autoscale.Autoscaler;
+import com.yahoo.vespa.hosted.provision.autoscale.MetricSnapshot;
import com.yahoo.vespa.hosted.provision.autoscale.MetricsDb;
+import com.yahoo.vespa.hosted.provision.autoscale.NodeTimeseries;
+import com.yahoo.vespa.hosted.provision.node.History;
+import com.yahoo.vespa.orchestrator.status.ApplicationLock;
import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -29,6 +35,7 @@ import java.util.stream.Collectors;
public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
private final Autoscaler autoscaler;
+ private final MetricsDb metricsDb;
private final Deployer deployer;
private final Metric metric;
@@ -39,8 +46,9 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
Duration interval) {
super(nodeRepository, interval, metric);
this.autoscaler = new Autoscaler(metricsDb, nodeRepository);
- this.metric = metric;
+ this.metricsDb = metricsDb;
this.deployer = deployer;
+ this.metric = metric;
}
@Override
@@ -57,44 +65,69 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
private void autoscale(ApplicationId application, List<Node> applicationNodes) {
try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) {
if ( ! deployment.isValid()) return;
- nodesByCluster(applicationNodes).forEach((clusterId, clusterNodes) -> autoscale(application, clusterId, clusterNodes, deployment));
+ nodesByCluster(applicationNodes).forEach((clusterId, clusterNodes) -> autoscale(application, clusterId, NodeList.copyOf(clusterNodes), deployment));
}
}
private void autoscale(ApplicationId applicationId,
ClusterSpec.Id clusterId,
- List<Node> clusterNodes,
+ NodeList clusterNodes,
MaintenanceDeployment deployment) {
Application application = nodeRepository().applications().get(applicationId).orElse(new Application(applicationId));
- Optional<Cluster> cluster = application.cluster(clusterId);
- if (cluster.isEmpty()) return;
-
- var advice = autoscaler.autoscale(cluster.get(), clusterNodes);
-
- application = application.with(cluster.get().withAutoscalingStatus(advice.reason()));
- if (advice.isEmpty()) {
- applications().put(application, deployment.applicationLock().get());
- }
- else if ( ! cluster.get().targetResources().equals(advice.target())) {
- applications().put(application.with(cluster.get().withTarget(advice.target())), deployment.applicationLock().get());
+ if (application.cluster(clusterId).isEmpty()) return;
+ Cluster cluster = application.cluster(clusterId).get();
+ cluster = updateCompletion(cluster, clusterNodes);
+ var advice = autoscaler.autoscale(cluster, clusterNodes);
+ cluster = cluster.withAutoscalingStatus(advice.reason());
+
+ if (advice.isPresent() && !cluster.targetResources().equals(advice.target())) { // autoscale
+ cluster = cluster.withTarget(advice.target());
+ applications().put(application.with(cluster), deployment.applicationLock().get());
if (advice.target().isPresent()) {
- logAutoscaling(advice.target().get(), applicationId, cluster.get(), clusterNodes);
+ logAutoscaling(advice.target().get(), applicationId, cluster, clusterNodes);
deployment.activate();
}
}
+ else { // store cluster update
+ applications().put(application.with(cluster), deployment.applicationLock().get());
+ }
}
private Applications applications() {
return nodeRepository().applications();
}
+ /** Check if the last scaling event for this cluster has completed and if so record it in the returned instance */
+ private Cluster updateCompletion(Cluster cluster, NodeList clusterNodes) {
+ if (cluster.lastScalingEvent().isEmpty()) return cluster;
+ var event = cluster.lastScalingEvent().get();
+ if (event.completion().isPresent()) return cluster;
+
+ // Scaling event is complete if:
+ // - 1. no nodes which was retired by this are still present (which also implies data distribution is complete)
+ if (clusterNodes.retired().stream()
+ .anyMatch(node -> node.history().hasEventAt(History.Event.Type.retired, event.at())))
+ return cluster;
+ // - 2. all nodes have switched to the right config generation
+ for (NodeTimeseries nodeTimeseries : metricsDb.getNodeTimeseries(event.at(), clusterNodes)) {
+ Optional<MetricSnapshot> firstOnNewGeneration =
+ nodeTimeseries.asList().stream()
+ .filter(snapshot -> snapshot.generation() >= event.generation()).findFirst();
+ if (firstOnNewGeneration.isEmpty()) return cluster; // Not completed
+ }
+
+
+ // Set the completion time to the instant we notice completion.
+ Instant completionTime = nodeRepository().clock().instant();
+ return cluster.with(event.withCompletion(completionTime));
+ }
+
private void logAutoscaling(ClusterResources target,
ApplicationId application,
Cluster cluster,
- List<Node> clusterNodes) {
- ClusterResources current = new AllocatableClusterResources(clusterNodes, nodeRepository(), cluster.exclusive()).toAdvertisedClusterResources();
- ClusterSpec.Type clusterType = clusterNodes.get(0).allocation().get().membership().cluster().type();
- log.info("Autoscaling " + application + " " + clusterType + " " + cluster.id() + ":" +
+ NodeList clusterNodes) {
+ ClusterResources current = new AllocatableClusterResources(clusterNodes.asList(), nodeRepository(), cluster.exclusive()).toAdvertisedClusterResources();
+ log.info("Autoscaling " + application + " " + clusterNodes.clusterSpec() + ":" +
"\nfrom " + toString(current) + "\nto " + toString(target));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
index 0195466b689..e271d5dcd11 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
@@ -2,36 +2,48 @@
package com.yahoo.vespa.hosted.provision.maintenance;
import com.yahoo.component.Version;
+import com.yahoo.component.Vtag;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.OutOfCapacityException;
import com.yahoo.jdisc.Metric;
+import com.yahoo.lang.MutableInteger;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.JacksonFlag;
import com.yahoo.vespa.flags.ListFlag;
-import com.yahoo.vespa.flags.custom.HostCapacity;
+import com.yahoo.vespa.flags.PermanentFlags;
+import com.yahoo.vespa.flags.custom.ClusterCapacity;
+import com.yahoo.vespa.flags.custom.SharedHost;
+import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
+import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.provisioning.FatalProvisioningException;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing;
+import com.yahoo.vespa.hosted.provision.provisioning.NodeCandidate;
+import com.yahoo.vespa.hosted.provision.provisioning.NodePrioritizer;
import com.yahoo.vespa.hosted.provision.provisioning.NodeResourceComparator;
+import com.yahoo.vespa.hosted.provision.provisioning.NodeSpec;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost;
import com.yahoo.yolean.Exceptions;
import javax.naming.NameNotFoundException;
import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;
@@ -48,7 +60,8 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
private static final Logger log = Logger.getLogger(DynamicProvisioningMaintainer.class.getName());
private final HostProvisioner hostProvisioner;
- private final ListFlag<HostCapacity> targetCapacityFlag;
+ private final ListFlag<ClusterCapacity> preprovisionCapacityFlag;
+ private final JacksonFlag<SharedHost> sharedHostFlag;
DynamicProvisioningMaintainer(NodeRepository nodeRepository,
Duration interval,
@@ -57,7 +70,8 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
Metric metric) {
super(nodeRepository, interval, metric);
this.hostProvisioner = hostProvisioner;
- this.targetCapacityFlag = Flags.TARGET_CAPACITY.bindTo(flagSource);
+ this.preprovisionCapacityFlag = PermanentFlags.PREPROVISION_CAPACITY.bindTo(flagSource);
+ this.sharedHostFlag = PermanentFlags.SHARED_HOST.bindTo(flagSource);
}
@Override
@@ -104,8 +118,17 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
/** Converge zone to wanted capacity */
private void convergeToCapacity(NodeList nodes) {
- List<NodeResources> capacity = targetCapacity();
- List<Node> excessHosts = provision(capacity, nodes);
+ List<Node> excessHosts;
+ try {
+ excessHosts = provision(nodes);
+ } catch (OutOfCapacityException | IllegalStateException e) {
+ log.log(Level.WARNING, "Failed to provision preprovision capacity and/or find excess hosts: " + e.getMessage());
+ return; // avoid removing excess hosts
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Failed to provision preprovision capacity and/or find excess hosts", e);
+ return; // avoid removing excess hosts
+ }
+
excessHosts.forEach(host -> {
try {
hostProvisioner.deprovision(host);
@@ -119,72 +142,182 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
/**
* Provision hosts to ensure there is room to allocate spare nodes.
*
- * @param advertisedSpareCapacity the advertised resources of the spare nodes
- * @param nodes list of all nodes
+ * @param nodeList list of all nodes
* @return excess hosts that can safely be deprovisioned: An excess host 1. contains no nodes allocated
* to an application, and assuming the spare nodes have been allocated, and 2. is not parked
* without wantToDeprovision (which means an operator is looking at the node).
*/
- private List<Node> provision(List<NodeResources> advertisedSpareCapacity, NodeList nodes) {
- Map<String, Node> hostsByHostname = new HashMap<>(nodes.hosts().asList().stream()
+ private List<Node> provision(NodeList nodeList) {
+ final List<Node> nodes = new ArrayList<>(provisionUntilNoDeficit(nodeList));
+
+
+ Map<String, Node> sharedHosts = new HashMap<>(findSharedHosts(nodeList));
+
+ int minCount = sharedHostFlag.value().getMinCount();
+ int deficit = minCount - sharedHosts.size();
+ if (deficit > 0) {
+ provisionHosts(deficit, NodeResources.unspecified())
+ .forEach(host -> {
+ sharedHosts.put(host.hostname(), host);
+ nodes.add(host);
+ });
+ }
+
+ return candidatesForRemoval(nodes).stream()
+ .sorted(Comparator.comparing(node -> node.history().events().stream()
+ .map(History.Event::at).min(Comparator.naturalOrder()).orElseGet(() -> Instant.MIN)))
+ .filter(node -> {
+ if (!sharedHosts.containsKey(node.hostname()) || sharedHosts.size() > minCount) {
+ sharedHosts.remove(node.hostname());
+ return true;
+ } else {
+ return false;
+ }
+ })
+ .collect(Collectors.toList());
+ }
+
+ private List<Node> candidatesForRemoval(List<Node> nodes) {
+ Map<String, Node> hostsByHostname = new HashMap<>(nodes.stream()
+ .filter(node -> node.type() == NodeType.host)
.filter(host -> host.state() != Node.State.parked || host.status().wantToDeprovision())
.collect(Collectors.toMap(Node::hostname, Function.identity())));
- nodes.asList().stream()
+ nodes.stream()
.filter(node -> node.allocation().isPresent())
.flatMap(node -> node.parentHostname().stream())
.distinct()
.forEach(hostsByHostname::remove);
- List<Node> excessHosts = new ArrayList<>(hostsByHostname.values());
-
- var capacity = new ArrayList<>(advertisedSpareCapacity);
- for (Iterator<NodeResources> it = capacity.iterator(); it.hasNext() && !excessHosts.isEmpty(); ) {
- NodeResources resources = it.next();
- excessHosts.stream()
- .filter(nodeRepository()::canAllocateTenantNodeTo)
- .filter(host -> nodeRepository().resourcesCalculator()
- .advertisedResourcesOf(host.flavor())
- .satisfies(resources))
- .min(Comparator.comparingInt(n -> n.flavor().cost()))
- .ifPresent(host -> {
- excessHosts.remove(host);
- it.remove();
- });
+ return List.copyOf(hostsByHostname.values());
+ }
+
+ private Map<String, Node> findSharedHosts(NodeList nodeList) {
+ return nodeList.stream()
+ .filter(node -> NodeRepository.canAllocateTenantNodeTo(node, true))
+ .filter(node -> node.reservedTo().isEmpty())
+ .filter(node -> node.exclusiveTo().isEmpty())
+ .collect(Collectors.toMap(Node::hostname, Function.identity()));
+ }
+
+ /**
+ * @return the nodes in {@code nodeList} plus all hosts provisioned, plus all preprovision capacity
+ * nodes that were allocated.
+ * @throws OutOfCapacityException if there were problems provisioning hosts, and in case message
+ * should be sufficient (avoid no stack trace)
+ * @throws IllegalStateException if there was an algorithmic problem, and in case message
+ * should be sufficient (avoid no stack trace).
+ */
+ private List<Node> provisionUntilNoDeficit(NodeList nodeList) {
+ List<ClusterCapacity> preprovisionCapacity = preprovisionCapacityFlag.value();
+
+ // Worst-case each ClusterCapacity in preprovisionCapacity will require an allocation.
+ int maxProvisions = preprovisionCapacity.size();
+
+ var nodesPlusProvisioned = new ArrayList<>(nodeList.asList());
+ for (int numProvisions = 0;; ++numProvisions) {
+ var nodesPlusProvisionedPlusAllocated = new ArrayList<>(nodesPlusProvisioned);
+ Optional<ClusterCapacity> deficit = allocatePreprovisionCapacity(preprovisionCapacity, nodesPlusProvisionedPlusAllocated);
+ if (deficit.isEmpty()) {
+ return nodesPlusProvisionedPlusAllocated;
+ }
+
+ if (numProvisions >= maxProvisions) {
+ throw new IllegalStateException("Have provisioned " + numProvisions + " times but there's still deficit: aborting");
+ }
+
+ nodesPlusProvisioned.addAll(provisionHosts(deficit.get().count(), toNodeResources(deficit.get())));
}
+ }
- // Pre-provisioning is best effort, do one host at a time
- capacity.forEach(resources -> {
- try {
- Version osVersion = nodeRepository().osVersions().targetFor(NodeType.host).orElse(Version.emptyVersion);
- List<Node> hosts = hostProvisioner.provisionHosts(nodeRepository().database().getProvisionIndexes(1),
- resources, ApplicationId.defaultId(), osVersion,
- HostSharing.shared)
- .stream()
- .map(ProvisionedHost::generateHost)
- .collect(Collectors.toList());
- nodeRepository().addNodes(hosts, Agent.DynamicProvisioningMaintainer);
- } catch (OutOfCapacityException | IllegalArgumentException | IllegalStateException e) {
- log.log(Level.WARNING, "Failed to pre-provision " + resources + ": " + e.getMessage());
- } catch (RuntimeException e) {
- log.log(Level.WARNING, "Failed to pre-provision " + resources + ", will retry in " + interval(), e);
+ private List<Node> provisionHosts(int count, NodeResources nodeResources) {
+ try {
+ Version osVersion = nodeRepository().osVersions().targetFor(NodeType.host).orElse(Version.emptyVersion);
+ List<Integer> provisionIndexes = nodeRepository().database().getProvisionIndexes(count);
+ List<Node> hosts = hostProvisioner.provisionHosts(provisionIndexes, nodeResources,
+ ApplicationId.defaultId(), osVersion, HostSharing.shared)
+ .stream()
+ .map(ProvisionedHost::generateHost)
+ .collect(Collectors.toList());
+ nodeRepository().addNodes(hosts, Agent.DynamicProvisioningMaintainer);
+ return hosts;
+ } catch (OutOfCapacityException | IllegalArgumentException | IllegalStateException e) {
+ throw new OutOfCapacityException("Failed to provision " + count + " " + nodeResources + ": " + e.getMessage());
+ } catch (RuntimeException e) {
+ throw new RuntimeException("Failed to provision " + count + " " + nodeResources + ", will retry in " + interval(), e);
+ }
+ }
+
+ /**
+ * Try to allocate the preprovision cluster capacity.
+ *
+ * @param mutableNodes represents all nodes in the node repo. As preprovision capacity is virtually allocated
+ * they are added to {@code mutableNodes}
+ * @return the part of a cluster capacity it was unable to allocate, if any
+ */
+ private Optional<ClusterCapacity> allocatePreprovisionCapacity(List<ClusterCapacity> preprovisionCapacity,
+ ArrayList<Node> mutableNodes) {
+ for (int clusterIndex = 0; clusterIndex < preprovisionCapacity.size(); ++clusterIndex) {
+ ClusterCapacity clusterCapacity = preprovisionCapacity.get(clusterIndex);
+ LockedNodeList nodeList = new LockedNodeList(mutableNodes, () -> {});
+ List<Node> candidates = findCandidates(clusterCapacity, clusterIndex, nodeList);
+ int deficit = Math.max(0, clusterCapacity.count() - candidates.size());
+ if (deficit > 0) {
+ return Optional.of(clusterCapacity.withCount(deficit));
}
- });
- return excessHosts;
+ // Simulate allocating the cluster
+ mutableNodes.addAll(candidates);
+ }
+
+ return Optional.empty();
}
+ private List<Node> findCandidates(ClusterCapacity clusterCapacity, int clusterIndex, LockedNodeList nodeList) {
+ NodeResources nodeResources = toNodeResources(clusterCapacity);
+
+ // We'll allocate each ClusterCapacity as a unique cluster in a dummy application
+ ApplicationId applicationId = ApplicationId.defaultId();
+ ClusterSpec.Id clusterId = ClusterSpec.Id.from(String.valueOf(clusterIndex));
+ ClusterSpec clusterSpec = ClusterSpec.request(ClusterSpec.Type.content, clusterId)
+ // build() requires a version, even though it is not (should not be) used
+ .vespaVersion(Vtag.currentVersion)
+ .build();
+ NodeSpec nodeSpec = NodeSpec.from(clusterCapacity.count(), nodeResources, false, true);
+ int wantedGroups = 1;
+
+ NodePrioritizer prioritizer = new NodePrioritizer(nodeList, applicationId, clusterSpec, nodeSpec, wantedGroups,
+ true, nodeRepository().nameResolver(), nodeRepository().resourcesCalculator(),
+ nodeRepository().spareCount());
+ List<NodeCandidate> nodeCandidates = prioritizer.collect(List.of());
+ MutableInteger index = new MutableInteger(0);
+ return nodeCandidates
+ .stream()
+ .limit(clusterCapacity.count())
+ .map(candidate -> candidate.toNode()
+ .allocate(applicationId,
+ ClusterMembership.from(clusterSpec, index.next()),
+ nodeResources,
+ nodeRepository().clock().instant()))
+ .collect(Collectors.toList());
+
+ }
+
+ private static NodeResources toNodeResources(ClusterCapacity clusterCapacity) {
+ return new NodeResources(clusterCapacity.vcpu(), clusterCapacity.memoryGb(), clusterCapacity.diskGb(),
+ clusterCapacity.bandwidthGbps());
+ }
/** Reads node resources declared by target capacity flag */
private List<NodeResources> targetCapacity() {
- return targetCapacityFlag.value().stream()
- .flatMap(cap -> {
- NodeResources resources = new NodeResources(cap.getVcpu(), cap.getMemoryGb(),
- cap.getDiskGb(), 1);
- return IntStream.range(0, cap.getCount()).mapToObj(i -> resources);
- })
- .sorted(NodeResourceComparator.memoryDiskCpuOrder().reversed())
- .collect(Collectors.toList());
+ return preprovisionCapacityFlag.value().stream()
+ .flatMap(cap -> {
+ NodeResources resources = new NodeResources(cap.vcpu(), cap.memoryGb(),
+ cap.diskGb(), cap.bandwidthGbps());
+ return IntStream.range(0, cap.count()).mapToObj(i -> resources);
+ })
+ .sorted(NodeResourceComparator.memoryDiskCpuOrder().reversed())
+ .collect(Collectors.toList());
}
/** Verify DNS configuration of given nodes */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
index ee55e22e89c..62d042d5e8b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
@@ -177,7 +177,7 @@ class MaintenanceDeployment implements Closeable {
if ( deployment.activate().isEmpty()) return false;
log.info(agent + " redeployed " + application + " to " +
- ( verifyTarget ? this : "move " + (node.hostname() + " from " + fromHost)));
+ ( verifyTarget ? this : "move " + (node + " from " + fromHost.hostname())));
return true;
}
finally {
@@ -225,7 +225,7 @@ class MaintenanceDeployment implements Closeable {
@Override
public String toString() {
return "move " +
- ( isEmpty() ? "none" : (node.hostname() + " from " + fromHost + " to " + toHost));
+ ( isEmpty() ? "none" : (node + " from " + fromHost.hostname() + " to " + toHost.hostname()));
}
public static Move empty() { return new Move(null, null, null); }
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java
index d2dcaaeae5b..4a5c28fe0c8 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.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.hosted.provision.maintenance;
+import com.yahoo.collections.Pair;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
@@ -26,10 +27,12 @@ import com.yahoo.vespa.service.monitor.ServiceMonitor;
import java.time.Duration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -41,6 +44,7 @@ import static com.yahoo.config.provision.NodeResources.DiskSpeed.any;
*/
public class MetricsReporter extends NodeRepositoryMaintainer {
+ private final Set<Pair<Metric.Context, String>> nonZeroMetrics = new HashSet<>();
private final Metric metric;
private final Orchestrator orchestrator;
private final ServiceMonitor serviceMonitor;
@@ -261,28 +265,39 @@ public class MetricsReporter extends NodeRepositoryMaintainer {
.forEach((lockPath, lockMetrics) -> {
Metric.Context context = getContext(Map.of("lockPath", lockPath));
- metric.set("lockAttempt.acquire", lockMetrics.getAndResetAcquireCount(), context);
- metric.set("lockAttempt.acquireFailed", lockMetrics.getAndResetAcquireFailedCount(), context);
- metric.set("lockAttempt.acquireTimedOut", lockMetrics.getAndResetAcquireTimedOutCount(), context);
- metric.set("lockAttempt.locked", lockMetrics.getAndResetAcquireSucceededCount(), context);
- metric.set("lockAttempt.release", lockMetrics.getAndResetReleaseCount(), context);
- metric.set("lockAttempt.releaseFailed", lockMetrics.getAndResetReleaseFailedCount(), context);
- metric.set("lockAttempt.reentry", lockMetrics.getAndResetReentryCount(), context);
- metric.set("lockAttempt.deadlock", lockMetrics.getAndResetDeadlockCount(), context);
- metric.set("lockAttempt.nakedRelease", lockMetrics.getAndResetNakedReleaseCount(), context);
- metric.set("lockAttempt.acquireWithoutRelease", lockMetrics.getAndResetAcquireWithoutReleaseCount(), context);
- metric.set("lockAttempt.foreignRelease", lockMetrics.getAndResetForeignReleaseCount(), context);
-
- setLockLatencyMetrics("acquire", lockMetrics.getAndResetAcquireLatencyMetrics(), context);
- setLockLatencyMetrics("locked", lockMetrics.getAndResetLockedLatencyMetrics(), context);
+ LatencyMetrics acquireLatencyMetrics = lockMetrics.getAndResetAcquireLatencyMetrics();
+ setNonZero("lockAttempt.acquireMaxActiveLatency", acquireLatencyMetrics.maxActiveLatencySeconds(), context);
+ setNonZero("lockAttempt.acquireHz", acquireLatencyMetrics.startHz(), context);
+ setNonZero("lockAttempt.acquireLoad", acquireLatencyMetrics.load(), context);
+
+ LatencyMetrics lockedLatencyMetrics = lockMetrics.getAndResetLockedLatencyMetrics();
+ setNonZero("lockAttempt.lockedLatency", lockedLatencyMetrics.maxLatencySeconds(), context);
+ setNonZero("lockAttempt.lockedLoad", lockedLatencyMetrics.load(), context);
+
+ setNonZero("lockAttempt.acquireTimedOut", lockMetrics.getAndResetAcquireTimedOutCount(), context);
+ setNonZero("lockAttempt.deadlock", lockMetrics.getAndResetDeadlockCount(), context);
+
+ // bucket for various rare errors - to reduce #metrics
+ setNonZero("lockAttempt.errors",
+ lockMetrics.getAndResetAcquireFailedCount() +
+ lockMetrics.getAndResetReleaseFailedCount() +
+ lockMetrics.getAndResetNakedReleaseCount() +
+ lockMetrics.getAndResetAcquireWithoutReleaseCount() +
+ lockMetrics.getAndResetForeignReleaseCount(),
+ context);
});
}
- private void setLockLatencyMetrics(String name, LatencyMetrics latencyMetrics, Metric.Context context) {
- metric.set("lockAttempt." + name + "Latency", latencyMetrics.latencySeconds(), context);
- metric.set("lockAttempt." + name + "MaxActiveLatency", latencyMetrics.maxActiveLatencySeconds(), context);
- metric.set("lockAttempt." + name + "Hz", latencyMetrics.startHz(), context);
- metric.set("lockAttempt." + name + "Load", latencyMetrics.load(), context);
+ private void setNonZero(String key, Number value, Metric.Context context) {
+ var metricKey = new Pair<>(context, key);
+ if (Double.compare(value.doubleValue(), 0.0) != 0) {
+ metric.set(key, value, context);
+ nonZeroMetrics.add(metricKey);
+ } else if (nonZeroMetrics.remove(metricKey)) {
+ // Need to set the metric to 0 after it has been set to non-zero, to avoid carrying
+ // a non-zero 'last' from earlier periods.
+ metric.set(key, value, context);
+ }
}
private void updateDockerMetrics(NodeList nodes) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
index 6d571fada9e..2999655e5fa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
@@ -153,7 +153,9 @@ public class NodeFailer extends NodeRepositoryMaintainer {
Map<Node, String> nodesByFailureReason = new HashMap<>();
for (Node node : activeNodes) {
if (node.history().hasEventBefore(History.Event.Type.down, graceTimeEnd) && ! applicationSuspended(node)) {
- nodesByFailureReason.put(node, "Node has been down longer than " + downTimeLimit);
+ // Allow a grace period after node re-activation
+ if ( ! node.history().hasEventAfter(History.Event.Type.activated, graceTimeEnd))
+ nodesByFailureReason.put(node, "Node has been down longer than " + downTimeLimit);
}
else if (hostSuspended(node, activeNodes)) {
Node hostNode = node.parentHostname().flatMap(parent -> nodeRepository().getNode(parent)).orElse(node);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainer.java
index ff7bc9393bd..017e1264f1c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainer.java
@@ -1,23 +1,18 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.maintenance;
-import com.yahoo.collections.Pair;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.autoscale.MetricSnapshot;
import com.yahoo.vespa.hosted.provision.autoscale.MetricsFetcher;
import com.yahoo.vespa.hosted.provision.autoscale.MetricsDb;
import com.yahoo.yolean.Exceptions;
import java.time.Duration;
-import java.util.Collection;
import java.util.logging.Level;
-import java.util.stream.Collectors;
/**
- * Maintainer which keeps the node metric db up to date by periodically fetching metrics from all
- * active nodes.
+ * Maintainer which keeps the node metric db up to date by periodically fetching metrics from all active nodes.
*
* @author bratseth
*/
@@ -43,12 +38,12 @@ public class NodeMetricsDbMaintainer extends NodeRepositoryMaintainer {
int warnings = 0;
for (ApplicationId application : activeNodesByApplication().keySet()) {
try {
- metricsDb.add(filter(metricsFetcher.fetchMetrics(application)));
+ metricsDb.add(metricsFetcher.fetchMetrics(application));
}
catch (Exception e) {
// TODO: Don't warn if this only happens occasionally
if (warnings++ < maxWarningsPerInvocation)
- log.log(Level.WARNING, "Could not update metrics for " + application + ": " + Exceptions.toMessageString(e));
+ log.log(Level.WARNING, "Could not update metrics for " + application + ": " + Exceptions.toMessageString(e), e);
}
}
metricsDb.gc();
@@ -59,11 +54,4 @@ public class NodeMetricsDbMaintainer extends NodeRepositoryMaintainer {
return warnings == 0;
}
- /** Filter out uninformative snapshots before storing */
- private Collection<Pair<String, MetricSnapshot>> filter(Collection<Pair<String, MetricSnapshot>> snapshots) {
- return snapshots.stream()
- .filter(snapshot -> snapshot.getSecond().inService())
- .collect(Collectors.toList());
- }
-
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
index 214872348a3..96d10415e63 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooter.java
@@ -3,8 +3,8 @@ package com.yahoo.vespa.hosted.provision.maintenance;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.IntFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.History;
@@ -32,7 +32,7 @@ public class NodeRebooter extends NodeRepositoryMaintainer {
NodeRebooter(NodeRepository nodeRepository, FlagSource flagSource, Metric metric) {
super(nodeRepository, Duration.ofMinutes(25), metric);
- this.rebootIntervalInDays = Flags.REBOOT_INTERVAL_IN_DAYS.bindTo(flagSource);
+ this.rebootIntervalInDays = PermanentFlags.REBOOT_INTERVAL_IN_DAYS.bindTo(flagSource);
this.random = new Random(nodeRepository.clock().millis()); // seed with clock for test determinism
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
index 9f2c6f05b00..ac33cc2441c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.provision.maintenance;
import com.google.inject.Inject;
import com.yahoo.component.AbstractComponent;
+import com.yahoo.concurrent.maintenance.Maintainer;
import com.yahoo.config.provision.Deployer;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostLivenessTracker;
@@ -18,7 +19,8 @@ import com.yahoo.vespa.orchestrator.Orchestrator;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
import java.time.Duration;
-import java.util.Optional;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* A component which sets up all the node repo maintenance jobs.
@@ -27,28 +29,7 @@ import java.util.Optional;
*/
public class NodeRepositoryMaintenance extends AbstractComponent {
- private final NodeFailer nodeFailer;
- private final NodeHealthTracker nodeHealthTracker;
- private final PeriodicApplicationMaintainer periodicApplicationMaintainer;
- private final OperatorChangeApplicationMaintainer operatorChangeApplicationMaintainer;
- private final ReservationExpirer reservationExpirer;
- private final InactiveExpirer inactiveExpirer;
- private final RetiredExpirer retiredExpirer;
- private final FailedExpirer failedExpirer;
- private final DirtyExpirer dirtyExpirer;
- private final ProvisionedExpirer provisionedExpirer;
- private final NodeRebooter nodeRebooter;
- private final MetricsReporter metricsReporter;
- private final InfrastructureProvisioner infrastructureProvisioner;
- private final Optional<LoadBalancerExpirer> loadBalancerExpirer;
- private final Optional<DynamicProvisioningMaintainer> dynamicProvisioningMaintainer;
- private final SpareCapacityMaintainer spareCapacityMaintainer;
- private final OsUpgradeActivator osUpgradeActivator;
- private final Rebalancer rebalancer;
- private final NodeMetricsDbMaintainer nodeMetricsDbMaintainer;
- private final AutoscalingMaintainer autoscalingMaintainer;
- private final ScalingSuggestionsMaintainer scalingSuggestionsMaintainer;
- private final SwitchRebalancer switchRebalancer;
+ private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>();
@SuppressWarnings("unused")
@Inject
@@ -59,60 +40,45 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
MetricsFetcher metricsFetcher, MetricsDb metricsDb) {
DefaultTimes defaults = new DefaultTimes(zone, deployer);
- nodeFailer = new NodeFailer(deployer, nodeRepository, defaults.failGrace, defaults.nodeFailerInterval, orchestrator, defaults.throttlePolicy, metric);
- nodeHealthTracker = new NodeHealthTracker(hostLivenessTracker, serviceMonitor, nodeRepository, defaults.nodeFailureStatusUpdateInterval, metric);
- periodicApplicationMaintainer = new PeriodicApplicationMaintainer(deployer, metric, nodeRepository,
- defaults.redeployMaintainerInterval, defaults.periodicRedeployInterval, flagSource);
- operatorChangeApplicationMaintainer = new OperatorChangeApplicationMaintainer(deployer, metric, nodeRepository, defaults.operatorChangeRedeployInterval);
- reservationExpirer = new ReservationExpirer(nodeRepository, defaults.reservationExpiry, metric);
- retiredExpirer = new RetiredExpirer(nodeRepository, orchestrator, deployer, metric, defaults.retiredInterval, defaults.retiredExpiry);
- inactiveExpirer = new InactiveExpirer(nodeRepository, defaults.inactiveExpiry, metric);
- failedExpirer = new FailedExpirer(nodeRepository, zone, defaults.failedExpirerInterval, metric);
- dirtyExpirer = new DirtyExpirer(nodeRepository, defaults.dirtyExpiry, metric);
- provisionedExpirer = new ProvisionedExpirer(nodeRepository, defaults.provisionedExpiry, metric);
- nodeRebooter = new NodeRebooter(nodeRepository, flagSource, metric);
- metricsReporter = new MetricsReporter(nodeRepository, metric, orchestrator, serviceMonitor, periodicApplicationMaintainer::pendingDeployments, defaults.metricsInterval);
- infrastructureProvisioner = new InfrastructureProvisioner(nodeRepository, infraDeployer, defaults.infrastructureProvisionInterval, metric);
- loadBalancerExpirer = provisionServiceProvider.getLoadBalancerService(nodeRepository).map(lbService ->
- new LoadBalancerExpirer(nodeRepository, defaults.loadBalancerExpirerInterval, lbService, metric));
- dynamicProvisioningMaintainer = provisionServiceProvider.getHostProvisioner().map(hostProvisioner ->
- new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, flagSource, metric));
- spareCapacityMaintainer = new SpareCapacityMaintainer(deployer, nodeRepository, metric, defaults.spareCapacityMaintenanceInterval);
- osUpgradeActivator = new OsUpgradeActivator(nodeRepository, defaults.osUpgradeActivatorInterval, metric);
- rebalancer = new Rebalancer(deployer, nodeRepository, metric, defaults.rebalancerInterval);
- nodeMetricsDbMaintainer = new NodeMetricsDbMaintainer(nodeRepository, metricsFetcher, metricsDb, defaults.nodeMetricsCollectionInterval, metric);
- autoscalingMaintainer = new AutoscalingMaintainer(nodeRepository, metricsDb, deployer, metric, defaults.autoscalingInterval);
- scalingSuggestionsMaintainer = new ScalingSuggestionsMaintainer(nodeRepository, metricsDb, defaults.scalingSuggestionsInterval, metric);
- switchRebalancer = new SwitchRebalancer(nodeRepository, defaults.switchRebalancerInterval, metric, deployer);
-
+ PeriodicApplicationMaintainer periodicApplicationMaintainer = new PeriodicApplicationMaintainer(deployer, metric, nodeRepository, defaults.redeployMaintainerInterval,
+ defaults.periodicRedeployInterval, flagSource);
+ InfrastructureProvisioner infrastructureProvisioner = new InfrastructureProvisioner(nodeRepository, infraDeployer, defaults.infrastructureProvisionInterval, metric);
+ maintainers.add(periodicApplicationMaintainer);
+ maintainers.add(infrastructureProvisioner);
+
+ maintainers.add(new NodeFailer(deployer, nodeRepository, defaults.failGrace, defaults.nodeFailerInterval, orchestrator, defaults.throttlePolicy, metric));
+ maintainers.add(new NodeHealthTracker(hostLivenessTracker, serviceMonitor, nodeRepository, defaults.nodeFailureStatusUpdateInterval, metric));
+ maintainers.add(new OperatorChangeApplicationMaintainer(deployer, metric, nodeRepository, defaults.operatorChangeRedeployInterval));
+ maintainers.add(new ReservationExpirer(nodeRepository, defaults.reservationExpiry, metric));
+ maintainers.add(new RetiredExpirer(nodeRepository, orchestrator, deployer, metric, defaults.retiredInterval, defaults.retiredExpiry));
+ maintainers.add(new InactiveExpirer(nodeRepository, defaults.inactiveExpiry, metric));
+ maintainers.add(new FailedExpirer(nodeRepository, zone, defaults.failedExpirerInterval, metric));
+ maintainers.add(new DirtyExpirer(nodeRepository, defaults.dirtyExpiry, metric));
+ maintainers.add(new ProvisionedExpirer(nodeRepository, defaults.provisionedExpiry, metric));
+ maintainers.add(new NodeRebooter(nodeRepository, flagSource, metric));
+ maintainers.add(new MetricsReporter(nodeRepository, metric, orchestrator, serviceMonitor, periodicApplicationMaintainer::pendingDeployments, defaults.metricsInterval));
+ maintainers.add(new SpareCapacityMaintainer(deployer, nodeRepository, metric, defaults.spareCapacityMaintenanceInterval));
+ maintainers.add(new OsUpgradeActivator(nodeRepository, defaults.osUpgradeActivatorInterval, metric));
+ maintainers.add(new Rebalancer(deployer, nodeRepository, metric, defaults.rebalancerInterval));
+ maintainers.add(new NodeMetricsDbMaintainer(nodeRepository, metricsFetcher, metricsDb, defaults.nodeMetricsCollectionInterval, metric));
+ maintainers.add(new AutoscalingMaintainer(nodeRepository, metricsDb, deployer, metric, defaults.autoscalingInterval));
+ maintainers.add(new ScalingSuggestionsMaintainer(nodeRepository, metricsDb, defaults.scalingSuggestionsInterval, metric));
+ maintainers.add(new SwitchRebalancer(nodeRepository, defaults.switchRebalancerInterval, metric, deployer));
+
+ provisionServiceProvider.getLoadBalancerService(nodeRepository)
+ .map(lbService -> new LoadBalancerExpirer(nodeRepository, defaults.loadBalancerExpirerInterval, lbService, metric))
+ .ifPresent(maintainers::add);
+ provisionServiceProvider.getHostProvisioner()
+ .map(hostProvisioner -> new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, flagSource, metric))
+ .ifPresent(maintainers::add);
// The DuperModel is filled with infrastructure applications by the infrastructure provisioner, so explicitly run that now
infrastructureProvisioner.maintainButThrowOnException();
}
@Override
public void deconstruct() {
- nodeFailer.close();
- nodeHealthTracker.close();
- periodicApplicationMaintainer.close();
- operatorChangeApplicationMaintainer.close();
- reservationExpirer.close();
- inactiveExpirer.close();
- retiredExpirer.close();
- failedExpirer.close();
- dirtyExpirer.close();
- nodeRebooter.close();
- spareCapacityMaintainer.close();
- provisionedExpirer.close();
- metricsReporter.close();
- infrastructureProvisioner.close();
- loadBalancerExpirer.ifPresent(NodeRepositoryMaintainer::close);
- dynamicProvisioningMaintainer.ifPresent(NodeRepositoryMaintainer::close);
- osUpgradeActivator.close();
- rebalancer.close();
- nodeMetricsDbMaintainer.close();
- autoscalingMaintainer.close();
- scalingSuggestionsMaintainer.close();
- switchRebalancer.close();
+ maintainers.forEach(Maintainer::shutdown);
+ maintainers.forEach(Maintainer::awaitShutdown);
}
private static class DefaultTimes {
@@ -164,7 +130,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
operatorChangeRedeployInterval = Duration.ofMinutes(3);
// Vespa upgrade frequency is higher in CD so (de)activate OS upgrades more frequently as well
osUpgradeActivatorInterval = zone.system().isCd() ? Duration.ofSeconds(30) : Duration.ofMinutes(5);
- periodicRedeployInterval = Duration.ofMinutes(30);
+ periodicRedeployInterval = Duration.ofMinutes(60);
provisionedExpiry = Duration.ofHours(4);
rebalancerInterval = Duration.ofMinutes(120);
redeployMaintainerInterval = Duration.ofMinutes(1);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
index 289d5a6742a..d20b06becaf 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
@@ -7,7 +7,7 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.flags.BooleanFlag;
import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
@@ -70,7 +70,7 @@ public class PeriodicApplicationMaintainer extends ApplicationMaintainer {
}
private boolean shouldMaintain(ApplicationId id) {
- BooleanFlag skipMaintenanceDeployment = Flags.SKIP_MAINTENANCE_DEPLOYMENT.bindTo(flagSource)
+ BooleanFlag skipMaintenanceDeployment = PermanentFlags.SKIP_MAINTENANCE_DEPLOYMENT.bindTo(flagSource)
.with(FetchVector.Dimension.APPLICATION_ID, id.serializedForm());
return ! skipMaintenanceDeployment.value();
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java
index 3546c8d8afb..7cb0270636f 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainer.java
@@ -8,6 +8,7 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.jdisc.Metric;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.Node;
+import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.Applications;
@@ -51,7 +52,7 @@ public class ScalingSuggestionsMaintainer extends NodeRepositoryMaintainer {
private int suggest(ApplicationId application, List<Node> applicationNodes) {
int successes = 0;
for (var cluster : nodesByCluster(applicationNodes).entrySet())
- successes += suggest(application, cluster.getKey(), cluster.getValue()) ? 1 : 0;
+ successes += suggest(application, cluster.getKey(), NodeList.copyOf(cluster.getValue())) ? 1 : 0;
return successes;
}
@@ -61,7 +62,7 @@ public class ScalingSuggestionsMaintainer extends NodeRepositoryMaintainer {
private boolean suggest(ApplicationId applicationId,
ClusterSpec.Id clusterId,
- List<Node> clusterNodes) {
+ NodeList clusterNodes) {
Application application = applications().get(applicationId).orElse(new Application(applicationId));
Optional<Cluster> cluster = application.cluster(clusterId);
if (cluster.isEmpty()) return true;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
index b490cdf4c24..8c9e54a2ae4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
@@ -33,14 +33,13 @@ public class SwitchRebalancer extends NodeMover<Move> {
@Override
protected boolean maintain() {
- if ( ! nodeRepository().isWorking()) return false;
+ if (!nodeRepository().isWorking()) return false;
+ if (!nodeRepository().zone().environment().isProduction()) return true;
+ NodeList allNodes = nodeRepository().list(); // Lockless as strong consistency is not needed
+ if (!zoneIsStable(allNodes)) return true;
- boolean success = true;
- // Using node list without holding lock as strong consistency is not needed here
- NodeList allNodes = nodeRepository().list();
- if (!zoneIsStable(allNodes)) return success;
findBestMove(allNodes).execute(false, Agent.SwitchRebalancer, deployer, metric, nodeRepository());
- return success;
+ return true;
}
@Override
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/History.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/History.java
index e92415d6538..3c2541bac27 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/History.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/History.java
@@ -39,6 +39,13 @@ public class History {
/** Returns this event if it is present in this history */
public Optional<Event> event(Event.Type type) { return Optional.ofNullable(events.get(type)); }
+ /** Returns true if a given event is registered in this history at the given time */
+ public boolean hasEventAt(Event.Type type, Instant time) {
+ return event(type)
+ .map(event -> event.at().equals(time))
+ .orElse(false);
+ }
+
/** Returns true if a given event is registered in this history after the given time */
public boolean hasEventAfter(Event.Type type, Instant time) {
return event(type)
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
index 3979b898145..4b9b14656ca 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
@@ -52,6 +52,7 @@ public class ApplicationSerializer {
private static final String toKey = "to";
private static final String generationKey = "generation";
private static final String atKey = "at";
+ private static final String completionKey = "completion";
public static byte[] toJson(Application application) {
Slime slime = new Slime();
@@ -140,13 +141,19 @@ public class ApplicationSerializer {
toSlime(event.to(), object.setObject(toKey));
object.setLong(generationKey, event.generation());
object.setLong(atKey, event.at().toEpochMilli());
+ event.completion().ifPresent(completion -> object.setLong(completionKey, completion.toEpochMilli()));
}
private static ScalingEvent scalingEventFromSlime(Inspector inspector) {
return new ScalingEvent(clusterResourcesFromSlime(inspector.field(fromKey)),
clusterResourcesFromSlime(inspector.field(toKey)),
inspector.field(generationKey).asLong(),
- Instant.ofEpochMilli(inspector.field(atKey).asLong()));
+ Instant.ofEpochMilli(inspector.field(atKey).asLong()),
+ optionalInstant(inspector.field(completionKey)));
+ }
+
+ private static Optional<Instant> optionalInstant(Inspector inspector) {
+ return inspector.valid() ? Optional.of(Instant.ofEpochMilli(inspector.asLong())) : Optional.empty();
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
index 42e26814d41..696853b2992 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java
@@ -70,7 +70,7 @@ public class CuratorDatabaseClient {
private static final Path containerImagesPath = root.append("dockerImages");
private static final Path firmwareCheckPath = root.append("firmwareCheck");
- private static final Duration defaultLockTimeout = Duration.ofMinutes(2);
+ private static final Duration defaultLockTimeout = Duration.ofMinutes(6);
private final NodeSerializer nodeSerializer;
private final CuratorDatabase db;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/JobControlFlags.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/JobControlFlags.java
index 2a2a45186f9..79f4403e534 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/JobControlFlags.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/JobControlFlags.java
@@ -3,8 +3,8 @@ package com.yahoo.vespa.hosted.provision.persistence;
import com.yahoo.concurrent.maintenance.JobControlState;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.ListFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
import java.util.Set;
@@ -20,7 +20,7 @@ public class JobControlFlags implements JobControlState {
public JobControlFlags(CuratorDatabaseClient curator, FlagSource flagSource) {
this.curator = curator;
- this.inactiveJobsFlag = Flags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
+ this.inactiveJobsFlag = PermanentFlags.INACTIVE_MAINTENANCE_JOBS.bindTo(flagSource);
}
@Override
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java
index 3cae4a5a5ea..2b03a5cae8c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Activator.java
@@ -16,6 +16,7 @@ import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.ScalingEvent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -60,6 +61,7 @@ class Activator {
* while holding the node repository lock on this application
*/
private void activateNodes(Collection<HostSpec> hosts, long generation, ApplicationTransaction transaction) {
+ Instant activationTime = nodeRepository.clock().instant(); // Use one timestamp for all activation changes
ApplicationId application = transaction.application();
Set<String> hostnames = hosts.stream().map(HostSpec::hostname).collect(Collectors.toSet());
NodeList allNodes = nodeRepository.list();
@@ -69,7 +71,7 @@ class Activator {
List<Node> reservedToActivate = updatePortsFrom(hosts, retainHostsInList(hostnames, reserved));
List<Node> oldActive = applicationNodes.state(Node.State.active).asList(); // All nodes active now
List<Node> continuedActive = retainHostsInList(hostnames, oldActive);
- List<Node> newActive = updateFrom(hosts, continuedActive); // All nodes that will be active when this is committed
+ List<Node> newActive = updateFrom(hosts, continuedActive, activationTime); // All nodes that will be active when this is committed
newActive.addAll(reservedToActivate);
if ( ! containsAll(hostnames, newActive))
throw new IllegalArgumentException("Activation of " + application + " failed. " +
@@ -84,16 +86,16 @@ class Activator {
List<Node> activeToRemove = removeHostsFromList(hostnames, oldActive);
activeToRemove = activeToRemove.stream().map(Node::unretire).collect(Collectors.toList()); // only active nodes can be retired. TODO: Move this line to deactivate
- nodeRepository.deactivate(activeToRemove, transaction);
+ nodeRepository.deactivate(activeToRemove, transaction); // TODO: Pass activation time in this call and next line
nodeRepository.activate(newActive, transaction.nested()); // activate also continued active to update node state
- rememberResourceChange(transaction, generation,
+ rememberResourceChange(transaction, generation, activationTime,
NodeList.copyOf(oldActive).not().retired(),
NodeList.copyOf(newActive).not().retired());
unreserveParentsOf(reservedToActivate);
}
- private void rememberResourceChange(ApplicationTransaction transaction, long generation,
+ private void rememberResourceChange(ApplicationTransaction transaction, long generation, Instant at,
NodeList oldNodes, NodeList newNodes) {
Optional<Application> application = nodeRepository.applications().get(transaction.application());
if (application.isEmpty()) return; // infrastructure app, hopefully :-|
@@ -102,15 +104,18 @@ class Activator {
.collect(Collectors.groupingBy(node -> node.allocation().get().membership().cluster().id()));
Application modified = application.get();
for (var clusterEntry : currentNodesByCluster.entrySet()) {
+ var cluster = modified.cluster(clusterEntry.getKey()).get();
var previousResources = oldNodes.cluster(clusterEntry.getKey()).toResources();
var currentResources = NodeList.copyOf(clusterEntry.getValue()).toResources();
- if ( ! previousResources.equals(currentResources)) {
- modified = modified.with(application.get().cluster(clusterEntry.getKey()).get()
- .with(new ScalingEvent(previousResources,
- currentResources,
- generation,
- nodeRepository.clock().instant())));
+ if ( ! previousResources.justNumbers().equals(currentResources.justNumbers())) {
+ cluster = cluster.with(ScalingEvent.create(previousResources, currentResources, generation, at));
}
+ if (cluster.targetResources().isPresent()
+ && cluster.targetResources().get().justNumbers().equals(currentResources.justNumbers())) {
+ cluster = cluster.withAutoscalingStatus("Cluster is ideally scaled within configured limits");
+ }
+ if (cluster != modified.cluster(clusterEntry.getKey()).get())
+ modified = modified.with(cluster);
}
if (modified != application.get())
@@ -202,11 +207,11 @@ class Activator {
}
/** Returns the input nodes with the changes resulting from applying the settings in hosts to the given list of nodes. */
- private List<Node> updateFrom(Collection<HostSpec> hosts, List<Node> nodes) {
+ private List<Node> updateFrom(Collection<HostSpec> hosts, List<Node> nodes, Instant at) {
List<Node> updated = new ArrayList<>();
for (Node node : nodes) {
HostSpec hostSpec = getHost(node.hostname(), hosts);
- node = hostSpec.membership().get().retired() ? node.retire(nodeRepository.clock().instant()) : node.unretire();
+ node = hostSpec.membership().get().retired() ? node.retire(at) : node.unretire();
if (! hostSpec.advertisedResources().equals(node.resources())) // A resized node
node = node.with(new Flavor(hostSpec.advertisedResources()));
Allocation allocation = node.allocation().get()
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FlavorConfigBuilder.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FlavorConfigBuilder.java
index e04c1aa208d..54530297baa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FlavorConfigBuilder.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FlavorConfigBuilder.java
@@ -55,9 +55,9 @@ public class FlavorConfigBuilder {
else if (flavorName.equals("host2"))
flavorConfigBuilder.addFlavor(flavorName, 16, 24, 100, 1, Flavor.Type.BARE_METAL);
else if (flavorName.equals("host3"))
- flavorConfigBuilder.addFlavor(flavorName, 24, 64, 100, 1, Flavor.Type.BARE_METAL);
+ flavorConfigBuilder.addFlavor(flavorName, 24, 64, 100, 10, Flavor.Type.BARE_METAL);
else if (flavorName.equals("host4"))
- flavorConfigBuilder.addFlavor(flavorName, 48, 128, 1000, 1, Flavor.Type.BARE_METAL);
+ flavorConfigBuilder.addFlavor(flavorName, 48, 128, 1000, 10, Flavor.Type.BARE_METAL);
else if (flavorName.equals("devhost"))
flavorConfigBuilder.addFlavor(flavorName, 4., 80., 100, 10, Flavor.Type.BARE_METAL);
else
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
index 6462fb6f19d..f02659aab5f 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
@@ -122,7 +122,9 @@ public class GroupPreparer {
NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requestedNodes,
highestIndex, nodeRepository);
NodePrioritizer prioritizer = new NodePrioritizer(
- allNodes, application, cluster, requestedNodes, wantedGroups, nodeRepository);
+ allNodes, application, cluster, requestedNodes, wantedGroups,
+ nodeRepository.zone().getCloud().dynamicProvisioning(), nodeRepository.nameResolver(),
+ nodeRepository.resourcesCalculator(), nodeRepository.spareCount());
allocation.offer(prioritizer.collect(surplusActiveNodes));
return allocation;
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
index 206aa077027..0b5a04ca42c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisioner.java
@@ -2,10 +2,12 @@
package com.yahoo.vespa.hosted.provision.provisioning;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.ApplicationTransaction;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.exception.LoadBalancerServiceException;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.flags.BooleanFlag;
@@ -82,7 +84,8 @@ public class LoadBalancerProvisioner {
try (var lock = db.lock(application)) {
ClusterSpec.Id clusterId = effectiveId(cluster);
List<Node> nodes = nodesOf(clusterId, application);
- provision(application, clusterId, nodes, false);
+ LoadBalancerId loadBalancerId = requireNonClashing(new LoadBalancerId(application, clusterId));
+ provision(loadBalancerId, nodes, false);
}
}
@@ -149,9 +152,30 @@ public class LoadBalancerProvisioner {
return canForwardTo;
}
+ /** Find all load balancer IDs owned by given tenant and application */
+ private List<LoadBalancerId> findLoadBalancers(TenantName tenant, ApplicationName application) {
+ return db.readLoadBalancerIds().stream()
+ .filter(id -> id.application().tenant().equals(tenant) &&
+ id.application().application().equals(application))
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ /** Require that load balancer IDs do not clash. This prevents name clashing when compacting endpoint DNS names */
+ private LoadBalancerId requireNonClashing(LoadBalancerId loadBalancerId) {
+ List<LoadBalancerId> loadBalancerIds = findLoadBalancers(loadBalancerId.application().tenant(),
+ loadBalancerId.application().application());
+ List<String> nonCompactableIds = withoutCompactableIds(loadBalancerId);
+ for (var id : loadBalancerIds) {
+ if (id.equals(loadBalancerId)) continue;
+ if (nonCompactableIds.equals(withoutCompactableIds(id))) {
+ throw new IllegalArgumentException(loadBalancerId + " clashes with " + id);
+ }
+ }
+ return loadBalancerId;
+ }
+
/** Idempotently provision a load balancer for given application and cluster */
- private void provision(ApplicationId application, ClusterSpec.Id clusterId, List<Node> nodes, boolean activate) {
- var id = new LoadBalancerId(application, clusterId);
+ private void provision(LoadBalancerId id, List<Node> nodes, boolean activate) {
var now = nodeRepository.clock().instant();
var loadBalancer = db.readLoadBalancer(id);
if (loadBalancer.isEmpty() && activate) return; // Nothing to activate as this load balancer was never prepared
@@ -171,6 +195,10 @@ public class LoadBalancerProvisioner {
db.writeLoadBalancer(newLoadBalancer);
}
+ private void provision(ApplicationId application, ClusterSpec.Id clusterId, List<Node> nodes, boolean activate) {
+ provision(new LoadBalancerId(application, clusterId), nodes, activate);
+ }
+
private LoadBalancerInstance provisionInstance(LoadBalancerId id, List<Node> nodes, boolean force) {
var reals = new LinkedHashSet<Real>();
for (var node : nodes) {
@@ -206,6 +234,18 @@ public class LoadBalancerProvisioner {
return nodes.stream().collect(Collectors.groupingBy(node -> effectiveId(node.allocation().get().membership().cluster())));
}
+ /** Returns a list of the non-compactable IDs of given load balancer */
+ private static List<String> withoutCompactableIds(LoadBalancerId id) {
+ List<String> ids = new ArrayList<>(2);
+ if (!"default".equals(id.cluster().value())) {
+ ids.add(id.cluster().value());
+ }
+ if (!id.application().instance().isDefault()) {
+ ids.add(id.application().instance().value());
+ }
+ return ids;
+ }
+
/** Find IP addresses reachable by the load balancer service */
private Set<String> reachableIpAddresses(Node node) {
Set<String> reachable = new LinkedHashSet<>(node.ipConfig().primary());
@@ -225,4 +265,5 @@ public class LoadBalancerProvisioner {
return cluster.combinedId().orElse(cluster.id());
}
+
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index 68e11c4c995..bc164dc37e0 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -203,7 +203,7 @@ class NodeAllocation {
* Such nodes will be marked retired during finalization of the list of accepted nodes.
* The conditions for this are:
*
- * This is a content or combined node. These must always be retired before being removed to allow the cluster to
+ * This is a stateful node. These must always be retired before being removed to allow the cluster to
* migrate away data.
*
* This is a container node and it is not desired due to having the wrong flavor. In this case this
@@ -218,7 +218,7 @@ class NodeAllocation {
if (candidate.allocation().get().membership().retired()) return true; // don't second-guess if already retired
if (! requestedNodes.considerRetiring()) return false;
- return cluster.type().isContent() ||
+ return cluster.isStateful() ||
(cluster.type() == ClusterSpec.Type.container && !hasCompatibleFlavor(candidate));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
index 14937e6afeb..460b7a821e6 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java
@@ -8,10 +8,10 @@ import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
-import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.Nodelike;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.IP;
+import com.yahoo.vespa.hosted.provision.persistence.NameResolver;
import com.yahoo.yolean.Exceptions;
import java.time.Instant;
@@ -25,7 +25,7 @@ import java.util.logging.Logger;
*
* @author smorgrav
*/
-abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
+public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
private static final Logger log = Logger.getLogger(NodeCandidate.class.getName());
@@ -224,8 +224,8 @@ abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
Node parent,
boolean violatesSpares,
LockedNodeList allNodes,
- NodeRepository nodeRepository) {
- return new VirtualNodeCandidate(resources, freeParentCapacity, parent, violatesSpares, true, allNodes, nodeRepository);
+ NameResolver nameResolver) {
+ return new VirtualNodeCandidate(resources, freeParentCapacity, parent, violatesSpares, true, allNodes, nameResolver);
}
public static NodeCandidate createNewExclusiveChild(Node node, Node parent) {
@@ -316,7 +316,7 @@ abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
/** Needed to construct the node */
private final LockedNodeList allNodes;
- private final NodeRepository nodeRepository;
+ private final NameResolver nameResolver;
private VirtualNodeCandidate(NodeResources resources,
NodeResources freeParentCapacity,
@@ -324,11 +324,11 @@ abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
boolean violatesSpares,
boolean exclusiveSwitch,
LockedNodeList allNodes,
- NodeRepository nodeRepository) {
+ NameResolver nameResolver) {
super(freeParentCapacity, Optional.of(parent), violatesSpares, exclusiveSwitch, false, true, false);
this.resources = resources;
this.allNodes = allNodes;
- this.nodeRepository = nodeRepository;
+ this.nameResolver = nameResolver;
}
@Override
@@ -361,7 +361,7 @@ abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
public NodeCandidate withNode() {
Optional<IP.Allocation> allocation;
try {
- allocation = parent.get().ipConfig().pool().findAllocation(allNodes, nodeRepository.nameResolver());
+ allocation = parent.get().ipConfig().pool().findAllocation(allNodes, nameResolver);
if (allocation.isEmpty()) return new InvalidNodeCandidate(resources, freeParentCapacity, parent.get(),
"No addresses available on parent host");
} catch (Exception e) {
@@ -382,7 +382,7 @@ abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidate> {
@Override
public NodeCandidate withExclusiveSwitch(boolean exclusiveSwitch) {
- return new VirtualNodeCandidate(resources, freeParentCapacity, parent.get(), violatesSpares, exclusiveSwitch, allNodes, nodeRepository);
+ return new VirtualNodeCandidate(resources, freeParentCapacity, parent.get(), violatesSpares, exclusiveSwitch, allNodes, nameResolver);
}
@Override
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
index abfd5e021c4..b88556fbfec 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
@@ -8,6 +8,7 @@ import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.persistence.NameResolver;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,7 +35,8 @@ public class NodePrioritizer {
private final NodeSpec requestedNodes;
private final ApplicationId application;
private final ClusterSpec clusterSpec;
- private final NodeRepository nodeRepository;
+ private final NameResolver nameResolver;
+ private final boolean dynamicProvisioning;
/** Whether node specification allows new nodes to be allocated. */
private final boolean canAllocateNew;
private final boolean canAllocateToSpareHosts;
@@ -42,19 +44,19 @@ public class NodePrioritizer {
private final int currentClusterSize;
private final Set<Node> spareHosts;
- NodePrioritizer(LockedNodeList allNodes, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
- int wantedGroups, NodeRepository nodeRepository) {
- boolean dynamicProvisioning = nodeRepository.zone().getCloud().dynamicProvisioning();
-
+ public NodePrioritizer(LockedNodeList allNodes, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
+ int wantedGroups, boolean dynamicProvisioning, NameResolver nameResolver,
+ HostResourcesCalculator hostResourcesCalculator, int spareCount) {
this.allNodes = allNodes;
- this.capacity = new HostCapacity(allNodes, nodeRepository.resourcesCalculator());
+ this.capacity = new HostCapacity(allNodes, hostResourcesCalculator);
this.requestedNodes = nodeSpec;
this.clusterSpec = clusterSpec;
this.application = application;
+ this.dynamicProvisioning = dynamicProvisioning;
this.spareHosts = dynamicProvisioning ?
capacity.findSpareHostsInDynamicallyProvisionedZones(allNodes.asList()) :
- capacity.findSpareHosts(allNodes.asList(), nodeRepository.spareCount());
- this.nodeRepository = nodeRepository;
+ capacity.findSpareHosts(allNodes.asList(), spareCount);
+ this.nameResolver = nameResolver;
NodeList nodesInCluster = allNodes.owner(application).type(clusterSpec.type()).cluster(clusterSpec.id());
NodeList nonRetiredNodesInCluster = nodesInCluster.not().retired();
@@ -81,7 +83,7 @@ public class NodePrioritizer {
}
/** Collects all node candidates for this application and returns them in the most-to-least preferred order */
- List<NodeCandidate> collect(List<Node> surplusActiveNodes) {
+ public List<NodeCandidate> collect(List<Node> surplusActiveNodes) {
addApplicationNodes();
addSurplusNodes(surplusActiveNodes);
addReadyNodes();
@@ -131,7 +133,7 @@ public class NodePrioritizer {
if ( !canAllocateNew) return;
for (Node host : allNodes) {
- if ( ! nodeRepository.canAllocateTenantNodeTo(host)) continue;
+ if ( ! NodeRepository.canAllocateTenantNodeTo(host, dynamicProvisioning)) continue;
if (host.reservedTo().isPresent() && !host.reservedTo().get().equals(application.tenant())) continue;
if (host.reservedTo().isPresent() && application.instance().isTester()) continue;
if (host.exclusiveTo().isPresent()) continue; // Never allocate new nodes to exclusive hosts
@@ -143,7 +145,7 @@ public class NodePrioritizer {
host,
spareHosts.contains(host),
allNodes,
- nodeRepository));
+ nameResolver));
}
}
@@ -209,7 +211,7 @@ public class NodePrioritizer {
if (node.type() != NodeType.tenant || node.parentHostname().isEmpty()) return true;
Optional<Node> parent = allNodes.parentOf(node);
if (parent.isEmpty()) return false;
- return nodeRepository.canAllocateTenantNodeTo(parent.get());
+ return NodeRepository.canAllocateTenantNodeTo(parent.get(), dynamicProvisioning);
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index ede6f4ef250..a6d68243160 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -29,7 +29,6 @@ import com.yahoo.vespa.hosted.provision.autoscale.AllocatableClusterResources;
import com.yahoo.vespa.hosted.provision.autoscale.AllocationOptimizer;
import com.yahoo.vespa.hosted.provision.autoscale.Limits;
import com.yahoo.vespa.hosted.provision.autoscale.ResourceTarget;
-import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeHostFilter;
@@ -168,7 +167,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
boolean firstDeployment = nodes.isEmpty();
AllocatableClusterResources currentResources =
firstDeployment // start at min, preserve current resources otherwise
- ? new AllocatableClusterResources(requested.minResources(), clusterSpec.type(), clusterSpec.isExclusive(), nodeRepository)
+ ? new AllocatableClusterResources(requested.minResources(), clusterSpec, nodeRepository)
: new AllocatableClusterResources(nodes, nodeRepository, clusterSpec.isExclusive());
return within(Limits.of(requested), clusterSpec.isExclusive(), currentResources, firstDeployment);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LocksResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LocksResponse.java
index 6f1334421ef..0f9babb53aa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LocksResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/LocksResponse.java
@@ -51,26 +51,6 @@ public class LocksResponse extends HttpResponse {
root.setString("hostname", hostname);
root.setString("time", Instant.now().toString());
- Cursor lockPathsCursor = root.setArray("lock-paths");
- lockMetricsByPath.forEach((lockPath, lockMetrics) -> {
- Cursor lockPathCursor = lockPathsCursor.addObject();
- lockPathCursor.setString("path", lockPath);
- lockPathCursor.setLong("acquireCount", lockMetrics.getCumulativeAcquireCount());
- lockPathCursor.setLong("acquireFailedCount", lockMetrics.getCumulativeAcquireFailedCount());
- lockPathCursor.setLong("acquireTimedOutCount", lockMetrics.getCumulativeAcquireTimedOutCount());
- lockPathCursor.setLong("lockedCount", lockMetrics.getCumulativeAcquireSucceededCount());
- lockPathCursor.setLong("releaseCount", lockMetrics.getCumulativeReleaseCount());
- lockPathCursor.setLong("releaseFailedCount", lockMetrics.getCumulativeReleaseFailedCount());
- lockPathCursor.setLong("reentryCount", lockMetrics.getCumulativeReentryCount());
- lockPathCursor.setLong("deadlock", lockMetrics.getCumulativeDeadlockCount());
- lockPathCursor.setLong("nakedRelease", lockMetrics.getCumulativeNakedReleaseCount());
- lockPathCursor.setLong("acquireWithoutRelease", lockMetrics.getCumulativeAcquireWithoutReleaseCount());
- lockPathCursor.setLong("foreignRelease", lockMetrics.getCumulativeForeignReleaseCount());
-
- setLatency(lockPathCursor, "acquire", lockMetrics.getAcquireLatencyMetrics());
- setLatency(lockPathCursor, "locked", lockMetrics.getLockedLatencyMetrics());
- });
-
Cursor threadsCursor = root.setArray("threads");
for (var threadLockStats : threadLockStatsList) {
Optional<LockAttempt> ongoingLockAttempt = threadLockStats.getTopMostOngoingLockAttempt();
@@ -102,18 +82,45 @@ public class LocksResponse extends HttpResponse {
Cursor recordingsCursor = root.setArray("recordings");
historicRecordings.forEach(recording -> setRecording(recordingsCursor.addObject(), recording));
}
+
+ Cursor lockPathsCursor = root.setArray("lock-paths");
+ lockMetricsByPath.forEach((lockPath, lockMetrics) -> {
+ Cursor lockPathCursor = lockPathsCursor.addObject();
+ lockPathCursor.setString("path", lockPath);
+ setNonZeroLong(lockPathCursor, "acquireCount", lockMetrics.getCumulativeAcquireCount());
+ setNonZeroLong(lockPathCursor, "acquireFailedCount", lockMetrics.getCumulativeAcquireFailedCount());
+ setNonZeroLong(lockPathCursor, "acquireTimedOutCount", lockMetrics.getCumulativeAcquireTimedOutCount());
+ setNonZeroLong(lockPathCursor, "lockedCount", lockMetrics.getCumulativeAcquireSucceededCount());
+ setNonZeroLong(lockPathCursor, "releaseCount", lockMetrics.getCumulativeReleaseCount());
+ setNonZeroLong(lockPathCursor, "releaseFailedCount", lockMetrics.getCumulativeReleaseFailedCount());
+ setNonZeroLong(lockPathCursor, "reentryCount", lockMetrics.getCumulativeReentryCount());
+ setNonZeroLong(lockPathCursor, "deadlock", lockMetrics.getCumulativeDeadlockCount());
+ setNonZeroLong(lockPathCursor, "nakedRelease", lockMetrics.getCumulativeNakedReleaseCount());
+ setNonZeroLong(lockPathCursor, "acquireWithoutRelease", lockMetrics.getCumulativeAcquireWithoutReleaseCount());
+ setNonZeroLong(lockPathCursor, "foreignRelease", lockMetrics.getCumulativeForeignReleaseCount());
+
+ setLatency(lockPathCursor, "acquire", lockMetrics.getAcquireLatencyMetrics());
+ setLatency(lockPathCursor, "locked", lockMetrics.getLockedLatencyMetrics());
+ });
+ }
+
+ private static void setNonZeroLong(Cursor cursor, String fieldName, long value) {
+ if (value != 0) {
+ cursor.setLong(fieldName, value);
+ }
}
private static void setLatency(Cursor cursor, String name, LatencyMetrics latencyMetrics) {
- cursor.setDouble(name + "Latency", latencyMetrics.latencySeconds());
- cursor.setDouble(name + "MaxActiveLatency", latencyMetrics.maxActiveLatencySeconds());
- cursor.setDouble(name + "Hz", latencyMetrics.endHz());
- cursor.setDouble(name + "Load", latencyMetrics.load());
+ setNonZeroDouble(cursor, name + "Latency", latencyMetrics.latencySeconds());
+ setNonZeroDouble(cursor, name + "MaxActiveLatency", latencyMetrics.maxActiveLatencySeconds());
+ setNonZeroDouble(cursor, name + "Hz", latencyMetrics.endHz());
+ setNonZeroDouble(cursor, name + "Load", latencyMetrics.load());
}
- private static double roundDouble(double value, int decimalPlaces) {
- double factor = Math.pow(10, decimalPlaces);
- return Math.round(value * factor) / factor;
+ private static void setNonZeroDouble(Cursor cursor, String fieldName, double value) {
+ if (Double.compare(value, 0.0) != 0) {
+ cursor.setDouble(fieldName, value);
+ }
}
@Override
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java
index 9332eb79f20..0d423333ce1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingIntegrationTest.java
@@ -59,7 +59,7 @@ public class AutoscalingIntegrationTest {
tester.nodeRepository().applications().put(application, lock);
}
var scaledResources = autoscaler.suggest(application.clusters().get(cluster1.id()),
- tester.nodeRepository().getNodes(application1));
+ tester.nodeRepository().list(application1));
assertTrue(scaledResources.isPresent());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
index 5393aa7cfb8..a217d97ac27 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
@@ -52,7 +52,7 @@ public class AutoscalingTest {
assertTrue("Too few measurements -> No change", tester.autoscale(application1, cluster1.id(), min, max).isEmpty());
tester.clock().advance(Duration.ofDays(1));
- tester.addCpuMeasurements(0.25f, 1f, 60, application1);
+ tester.addCpuMeasurements(0.25f, 1f, 120, application1);
ClusterResources scaledResources = tester.assertResources("Scaling up since resource usage is too high",
15, 1, 1.3, 28.6, 28.6,
tester.autoscale(application1, cluster1.id(), min, max).target());
@@ -62,7 +62,7 @@ public class AutoscalingTest {
tester.deactivateRetired(application1, cluster1, scaledResources);
- tester.clock().advance(Duration.ofDays(1));
+ tester.clock().advance(Duration.ofDays(2));
tester.addCpuMeasurements(0.8f, 1f, 3, application1);
assertTrue("Load change is large, but insufficient measurements for new config -> No change",
tester.autoscale(application1, cluster1.id(), min, max).isEmpty());
@@ -74,6 +74,8 @@ public class AutoscalingTest {
tester.assertResources("Scaling down to minimum since usage has gone down significantly",
14, 1, 1.0, 30.8, 30.8,
tester.autoscale(application1, cluster1.id(), min, max).target());
+
+ var events = tester.nodeRepository().applications().get(application1).get().cluster(cluster1.id()).get().scalingEvents();
}
/** We prefer fewer nodes for container clusters as (we assume) they all use the same disk and memory */
@@ -117,7 +119,7 @@ public class AutoscalingTest {
tester.nodeRepository().getNodes(application1).stream()
.allMatch(n -> n.allocation().get().requestedResources().diskSpeed() == NodeResources.DiskSpeed.slow);
- tester.clock().advance(Duration.ofDays(1));
+ tester.clock().advance(Duration.ofDays(2));
tester.addCpuMeasurements(0.25f, 1f, 120, application1);
// Changing min and max from slow to any
ClusterResources min = new ClusterResources( 2, 1,
@@ -225,6 +227,40 @@ public class AutoscalingTest {
}
@Test
+ public void not_using_out_of_service_measurements() {
+ NodeResources resources = new NodeResources(3, 100, 100, 1);
+ ClusterResources min = new ClusterResources(2, 1, new NodeResources(1, 1, 1, 1));
+ ClusterResources max = new ClusterResources(5, 1, new NodeResources(100, 1000, 1000, 1));
+ AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2));
+
+ ApplicationId application1 = tester.applicationId("application1");
+ ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1");
+
+ // deploy
+ tester.deploy(application1, cluster1, 2, 1, resources);
+ tester.addMeasurements(0.5f, 0.6f, 0.7f, 1, false, true, 120, application1);
+ assertTrue("Not scaling up since nodes were measured while cluster was unstable",
+ tester.autoscale(application1, cluster1.id(), min, max).isEmpty());
+ }
+
+ @Test
+ public void not_using_unstable_measurements() {
+ NodeResources resources = new NodeResources(3, 100, 100, 1);
+ ClusterResources min = new ClusterResources(2, 1, new NodeResources(1, 1, 1, 1));
+ ClusterResources max = new ClusterResources(5, 1, new NodeResources(100, 1000, 1000, 1));
+ AutoscalingTester tester = new AutoscalingTester(resources.withVcpu(resources.vcpu() * 2));
+
+ ApplicationId application1 = tester.applicationId("application1");
+ ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.container, "cluster1");
+
+ // deploy
+ tester.deploy(application1, cluster1, 2, 1, resources);
+ tester.addMeasurements(0.5f, 0.6f, 0.7f, 1, true, false, 120, application1);
+ assertTrue("Not scaling up since nodes were measured while cluster was unstable",
+ tester.autoscale(application1, cluster1.id(), min, max).isEmpty());
+ }
+
+ @Test
public void test_autoscaling_group_size_1() {
NodeResources resources = new NodeResources(3, 100, 100, 1);
ClusterResources min = new ClusterResources( 2, 2, new NodeResources(1, 1, 1, 1));
@@ -272,6 +308,7 @@ public class AutoscalingTest {
// deploy
tester.deploy(application1, cluster1, 6, 2, new NodeResources(10, 100, 100, 1));
+ tester.clock().advance(Duration.ofDays(1));
tester.addMemMeasurements(1.0f, 1f, 1000, application1);
tester.assertResources("Increase group size to reduce memory load",
8, 2, 12.9, 89.3, 62.5,
@@ -290,7 +327,7 @@ public class AutoscalingTest {
// deploy
tester.deploy(application1, cluster1, 6, 1, hostResources.withVcpu(hostResources.vcpu() / 2));
- tester.clock().advance(Duration.ofDays(1));
+ tester.clock().advance(Duration.ofDays(2));
tester.addMemMeasurements(0.02f, 0.95f, 120, application1);
tester.assertResources("Scaling down",
6, 1, 2.8, 4.0, 95.0,
@@ -313,8 +350,8 @@ public class AutoscalingTest {
tester.addMemMeasurements(0.02f, 0.95f, 120, application1);
assertTrue(tester.autoscale(application1, cluster1.id(), min, max).target().isEmpty());
- // Trying the same a day later causes autoscaling
- tester.clock().advance(Duration.ofDays(1));
+ // Trying the same later causes autoscaling
+ tester.clock().advance(Duration.ofDays(2));
tester.addMemMeasurements(0.02f, 0.95f, 120, application1);
tester.assertResources("Scaling down",
6, 1, 2.8, 4.0, 95.0,
@@ -376,7 +413,7 @@ public class AutoscalingTest {
// deploy (Why 103 Gb memory? See AutoscalingTester.MockHostResourcesCalculator
tester.deploy(application1, cluster1, 5, 1, new NodeResources(3, 103, 100, 1));
- tester.clock().advance(Duration.ofDays(1));
+ tester.clock().advance(Duration.ofDays(2));
tester.addMemMeasurements(0.9f, 0.6f, 120, application1);
ClusterResources scaledResources = tester.assertResources("Scaling up since resource usage is too high.",
8, 1, 3, 83, 34.3,
@@ -385,6 +422,7 @@ public class AutoscalingTest {
tester.deploy(application1, cluster1, scaledResources);
tester.deactivateRetired(application1, cluster1, scaledResources);
+ tester.clock().advance(Duration.ofDays(2));
tester.addMemMeasurements(0.3f, 0.6f, 1000, application1);
tester.assertResources("Scaling down since resource usage has gone down",
5, 1, 3, 83, 36,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
index 3faa4c244ee..43302c4fe23 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
@@ -138,6 +138,7 @@ class AutoscalingTester {
memory,
disk,
0,
+ true,
true))));
}
}
@@ -168,12 +169,18 @@ class AutoscalingTester {
memory,
disk,
0,
+ true,
true))));
}
}
}
- public void addMeasurements(float cpu, float memory, float disk, int generation, int count, ApplicationId applicationId) {
+ public void addMeasurements(float cpu, float memory, float disk, int generation, int count, ApplicationId applicationId) {
+ addMeasurements(cpu, memory, disk, generation, true, true, count, applicationId);
+ }
+
+ public void addMeasurements(float cpu, float memory, float disk, int generation, boolean inService, boolean stable,
+ int count, ApplicationId applicationId) {
List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active);
for (int i = 0; i < count; i++) {
clock().advance(Duration.ofMinutes(1));
@@ -183,7 +190,8 @@ class AutoscalingTester {
memory,
disk,
generation,
- true))));
+ inService,
+ stable))));
}
}
}
@@ -196,7 +204,7 @@ class AutoscalingTester {
nodeRepository().applications().put(application, lock);
}
return autoscaler.autoscale(application.clusters().get(clusterId),
- nodeRepository().getNodes(applicationId, Node.State.active));
+ nodeRepository().list(applicationId, Node.State.active));
}
public Autoscaler.Advice suggest(ApplicationId applicationId, ClusterSpec.Id clusterId,
@@ -207,7 +215,7 @@ class AutoscalingTester {
nodeRepository().applications().put(application, lock);
}
return autoscaler.suggest(application.clusters().get(clusterId),
- nodeRepository().getNodes(applicationId, Node.State.active));
+ nodeRepository().list(applicationId, Node.State.active));
}
public ClusterResources assertResources(String message,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java
index dd991f15087..0a62e5b6a68 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java
@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class MetricsV2MetricsFetcherTest {
@@ -70,14 +71,17 @@ public class MetricsV2MetricsFetcherTest {
assertEquals(0.15, values.get(0).getSecond().memory(), delta);
assertEquals(0.20, values.get(0).getSecond().disk(), delta);
assertEquals(3, values.get(0).getSecond().generation(), delta);
+ assertTrue(values.get(0).getSecond().stable());
}
{
+ httpClient.cannedResponse = cannedResponseForApplication2;
try (Mutex lock = tester.nodeRepository().lock(application1)) {
- tester.nodeRepository().write(tester.nodeRepository().getNodes(application1, Node.State.active)
+ tester.nodeRepository().write(tester.nodeRepository().getNodes(application2, Node.State.active)
.get(0).retire(tester.clock().instant()), lock);
}
- assertTrue("No metrics fetching while unstable", fetcher.fetchMetrics(application1).isEmpty());
+ List<Pair<String, MetricSnapshot>> values = new ArrayList<>(fetcher.fetchMetrics(application2));
+ assertFalse(values.get(0).getSecond().stable());
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java
index dba19d675dd..48c90125ac8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java
@@ -40,7 +40,7 @@ public class NodeMetricsDbTest {
MetricsDb db = MetricsDb.createTestInstance(tester.nodeRepository());
Collection<Pair<String, MetricSnapshot>> values = new ArrayList<>();
for (int i = 0; i < 40; i++) {
- values.add(new Pair<>(node0, new MetricSnapshot(clock.instant(), 0.9f, 0.6f, 0.6f, 0, true)));
+ values.add(new Pair<>(node0, new MetricSnapshot(clock.instant(), 0.9f, 0.6f, 0.6f, 0, true, false)));
clock.advance(Duration.ofMinutes(120));
}
db.add(values);
@@ -50,7 +50,7 @@ public class NodeMetricsDbTest {
assertEquals(35, measurementCount(db.getNodeTimeseries(clock.instant().minus(Duration.ofHours(72)), Set.of(node0))));
db.gc();
- assertEquals( 5, measurementCount(db.getNodeTimeseries(clock.instant().minus(Duration.ofHours(72)), Set.of(node0))));
+ assertEquals(23, measurementCount(db.getNodeTimeseries(clock.instant().minus(Duration.ofHours(72)), Set.of(node0))));
}
private int measurementCount(List<NodeTimeseries> measurements) {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java
index b97d5136485..1f61faed735 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.autoscale;
import com.yahoo.collections.Pair;
import com.yahoo.io.IOUtils;
import com.yahoo.test.ManualClock;
+import org.junit.Ignore;
import org.junit.Test;
import java.io.File;
@@ -16,6 +17,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
/**
* Tests the Quest metrics db.
@@ -34,6 +36,7 @@ public class QuestMetricsDbTest {
ManualClock clock = new ManualClock("2020-10-01T00:00:00");
QuestMetricsDb db = new QuestMetricsDb(dataDir, clock);
Instant startTime = clock.instant();
+
clock.advance(Duration.ofSeconds(1));
db.add(timeseries(1000, Duration.ofSeconds(1), clock, "host1", "host2", "host3"));
@@ -106,9 +109,56 @@ public class QuestMetricsDbTest {
assertEquals(24 * 10, db.getNodeTimeseries(startTime, Set.of("host1")).get(0).size());
db.gc();
- assertEquals(24 * 1 + dayOffset, db.getNodeTimeseries(startTime, Set.of("host1")).get(0).size());
+ assertEquals(48 * 1 + dayOffset, db.getNodeTimeseries(startTime, Set.of("host1")).get(0).size());
db.gc(); // no-op
- assertEquals(24 * 1 + dayOffset, db.getNodeTimeseries(startTime, Set.of("host1")).get(0).size());
+ assertEquals(48 * 1 + dayOffset, db.getNodeTimeseries(startTime, Set.of("host1")).get(0).size());
+ }
+
+ /** To manually test that we can read existing data */
+ @Ignore
+ @Test
+ public void testReadingAndAppendingToExistingData() {
+ String dataDir = "data/QuestMetricsDbExistingData";
+ if ( ! new File(dataDir).exists()) {
+ System.out.println("No existing data to check");
+ return;
+ }
+ IOUtils.createDirectory(dataDir + "/metrics");
+ ManualClock clock = new ManualClock("2020-10-01T00:00:00");
+ clock.advance(Duration.ofSeconds(9)); // Adjust to last data written
+ QuestMetricsDb db = new QuestMetricsDb(dataDir, clock);
+
+ List<NodeTimeseries> timeseries = db.getNodeTimeseries(clock.instant().minus(Duration.ofSeconds(9)), Set.of("host1"));
+ assertFalse("Could read existing data", timeseries.isEmpty());
+ assertEquals(10, timeseries.get(0).size());
+
+ System.out.println("Existing data read:");
+ for (var snapshot : timeseries.get(0).asList())
+ System.out.println(" " + snapshot);
+
+ clock.advance(Duration.ofSeconds(1));
+ db.add(timeseries(2, Duration.ofSeconds(1), clock, "host1"));
+ System.out.println("New data written and read:");
+ timeseries = db.getNodeTimeseries(clock.instant().minus(Duration.ofSeconds(2)), Set.of("host1"));
+ for (var snapshot : timeseries.get(0).asList())
+ System.out.println(" " + snapshot);
+ }
+
+ /** To update data for the manual test above */
+ @Ignore
+ @Test
+ public void updateExistingData() {
+ String dataDir = "data/QuestMetricsDbExistingData";
+ IOUtils.recursiveDeleteDir(new File(dataDir));
+ IOUtils.createDirectory(dataDir + "/metrics");
+ ManualClock clock = new ManualClock("2020-10-01T00:00:00");
+ QuestMetricsDb db = new QuestMetricsDb(dataDir, clock);
+ Instant startTime = clock.instant();
+ db.add(timeseries(10, Duration.ofSeconds(1), clock, "host1"));
+
+ int added = db.getNodeTimeseries(startTime, Set.of("host1")).get(0).asList().size();
+ System.out.println("Added " + added + " rows of data");
+ db.close();
}
private Collection<Pair<String, MetricSnapshot>> timeseries(int countPerHost, Duration sampleRate, ManualClock clock,
@@ -121,6 +171,7 @@ public class QuestMetricsDbTest {
i * 0.2,
i * 0.4,
i % 100,
+ true,
true)));
clock.advance(sampleRate);
}
@@ -136,8 +187,10 @@ public class QuestMetricsDbTest {
i * 0.2,
i * 0.4,
i % 100,
- true)));
+ true,
+ false)));
}
return timeseries;
}
+
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java
index 4b14174488e..0c1a59c883d 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTest.java
@@ -6,6 +6,8 @@ import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
+import com.yahoo.test.ManualClock;
+import com.yahoo.vespa.hosted.provision.applications.Cluster;
import com.yahoo.vespa.hosted.provision.applications.ScalingEvent;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;
import org.junit.Test;
@@ -13,9 +15,10 @@ import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
-
+import java.util.Optional;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
@@ -27,7 +30,7 @@ import static org.junit.Assert.assertTrue;
public class AutoscalingMaintainerTest {
@Test
- public void testAutoscalingMaintainer() {
+ public void test_autoscaling_maintainer() {
ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1");
ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec();
@@ -53,6 +56,7 @@ public class AutoscalingMaintainerTest {
new ClusterResources(10, 1, new NodeResources(6.5, 9, 20, 0.1)),
false, true));
+ tester.clock().advance(Duration.ofMinutes(10));
tester.maintainer().maintain(); // noop
assertTrue(tester.deployer().lastDeployTime(app1).isEmpty());
assertTrue(tester.deployer().lastDeployTime(app2).isEmpty());
@@ -60,6 +64,7 @@ public class AutoscalingMaintainerTest {
tester.addMeasurements(0.9f, 0.9f, 0.9f, 0, 500, app1);
tester.addMeasurements(0.9f, 0.9f, 0.9f, 0, 500, app2);
+ tester.clock().advance(Duration.ofMinutes(10));
tester.maintainer().maintain();
assertTrue(tester.deployer().lastDeployTime(app1).isEmpty()); // since autoscaling is off
assertTrue(tester.deployer().lastDeployTime(app2).isPresent());
@@ -84,16 +89,18 @@ public class AutoscalingMaintainerTest {
// Causes autoscaling
tester.clock().advance(Duration.ofSeconds(1));
+ tester.clock().advance(Duration.ofMinutes(10));
Instant firstMaintenanceTime = tester.clock().instant();
tester.maintainer().maintain();
assertTrue(tester.deployer().lastDeployTime(app1).isPresent());
assertEquals(firstMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli());
List<ScalingEvent> events = tester.nodeRepository().applications().get(app1).get().cluster(cluster1.id()).get().scalingEvents();
- assertEquals(1, events.size());
- assertEquals(2, events.get(0).from().nodes());
- assertEquals(4, events.get(0).to().nodes());
- assertEquals(1, events.get(0).generation());
- assertEquals(firstMaintenanceTime.toEpochMilli(), events.get(0).at().toEpochMilli());
+ assertEquals(2, events.size());
+ assertEquals(Optional.of(firstMaintenanceTime), events.get(0).completion());
+ assertEquals(2, events.get(1).from().nodes());
+ assertEquals(4, events.get(1).to().nodes());
+ assertEquals(1, events.get(1).generation());
+ assertEquals(firstMaintenanceTime.toEpochMilli(), events.get(1).at().toEpochMilli());
// Measure overload still, since change is not applied, but metrics are discarded
tester.clock().advance(Duration.ofSeconds(1));
@@ -110,13 +117,18 @@ public class AutoscalingMaintainerTest {
assertEquals(firstMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli());
// Add measurement of the expected generation, leading to rescaling
- tester.clock().advance(Duration.ofHours(2));
+ // - record scaling completion
+ tester.clock().advance(Duration.ofMinutes(5));
+ tester.addMeasurements(0.1f, 0.1f, 0.1f, 1, 1, app1);
+ tester.maintainer().maintain();
+ // - measure underload
+ tester.clock().advance(Duration.ofHours(1));
tester.addMeasurements(0.1f, 0.1f, 0.1f, 1, 500, app1);
Instant lastMaintenanceTime = tester.clock().instant();
tester.maintainer().maintain();
assertEquals(lastMaintenanceTime.toEpochMilli(), tester.deployer().lastDeployTime(app1).get().toEpochMilli());
events = tester.nodeRepository().applications().get(app1).get().cluster(cluster1.id()).get().scalingEvents();
- assertEquals(2, events.get(0).generation());
+ assertEquals(2, events.get(2).generation());
}
@Test
@@ -128,4 +140,90 @@ public class AutoscalingMaintainerTest {
AutoscalingMaintainer.toString(new ClusterResources(4, 2, new NodeResources(1, 2, 4, 1))));
}
+ @Test
+ public void test_scaling_event_recording() {
+ ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1");
+ ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec();
+ NodeResources lowResources = new NodeResources(4, 4, 10, 0.1);
+ NodeResources highResources = new NodeResources(8, 8, 20, 0.1);
+ Capacity app1Capacity = Capacity.from(new ClusterResources(2, 1, lowResources),
+ new ClusterResources(4, 2, highResources));
+ var tester = new AutoscalingMaintainerTester(new MockDeployer.ApplicationContext(app1, cluster1, app1Capacity));
+
+ // deploy
+ tester.deploy(app1, cluster1, app1Capacity);
+
+ for (int i = 0; i < 20; i++) {
+ // Record completion to keep scaling window at minimum
+ tester.addMeasurements(0.1f, 0.1f, 0.1f, i, 1, app1);
+ tester.maintainer().maintain();
+
+ tester.clock().advance(Duration.ofDays(1));
+
+ if (i % 2 == 0) // high load
+ tester.addMeasurements(0.9f, 0.9f, 0.9f, i, 200, app1);
+ else // low load
+ tester.addMeasurements(0.1f, 0.1f, 0.1f, i, 200, app1);
+ tester.maintainer().maintain();
+ }
+
+ assertEquals(Cluster.maxScalingEvents, tester.cluster(app1, cluster1).scalingEvents().size());
+ }
+
+ @Test
+ public void test_autoscaling_window() {
+ ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1");
+ ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec();
+ NodeResources lowResources = new NodeResources(4, 4, 10, 0.1);
+ NodeResources highResources = new NodeResources(8, 8, 20, 0.1);
+ Capacity app1Capacity = Capacity.from(new ClusterResources(2, 1, lowResources),
+ new ClusterResources(4, 2, highResources));
+ var tester = new AutoscalingMaintainerTester(new MockDeployer.ApplicationContext(app1, cluster1, app1Capacity));
+ ManualClock clock = tester.clock();
+
+ // deploy
+ tester.deploy(app1, cluster1, app1Capacity);
+
+ autoscale(false, Duration.ofMinutes( 1), Duration.ofMinutes( 5), clock, app1, cluster1, tester);
+ autoscale( true, Duration.ofMinutes(19), Duration.ofMinutes(10), clock, app1, cluster1, tester);
+ autoscale( true, Duration.ofMinutes(40), Duration.ofMinutes(20), clock, app1, cluster1, tester);
+ }
+
+ private void autoscale(boolean down, Duration completionTime, Duration expectedWindow,
+ ManualClock clock, ApplicationId application, ClusterSpec cluster,
+ AutoscalingMaintainerTester tester) {
+ long generation = tester.cluster(application, cluster).lastScalingEvent().get().generation();
+ tester.maintainer().maintain();
+ assertFalse("Not measured to be on the last generation yet",
+ tester.cluster(application, cluster).lastScalingEvent().get().completion().isPresent());
+
+ clock.advance(completionTime);
+ float load = down ? 0.1f : 1.0f;
+ tester.addMeasurements(load, load, load, generation, 200, application);
+ tester.maintainer().maintain();
+ assertEvent("Measured completion of the last scaling event, but no new autoscaling yet",
+ generation, Optional.of(clock.instant()),
+ tester.cluster(application, cluster).lastScalingEvent().get());
+ if (down)
+ clock.advance(expectedWindow.minus(completionTime).plus(expectedWindow.multipliedBy(2)));
+ else
+ clock.advance(expectedWindow.minus(completionTime));
+
+ tester.addMeasurements(load, load, load, generation, 200, application);
+ tester.maintainer().maintain();
+ assertEquals("We passed window duration so a new autoscaling is started: " +
+ tester.cluster(application, cluster).autoscalingStatus(),
+ generation + 1,
+ tester.cluster(application, cluster).lastScalingEvent().get().generation());
+ }
+
+ private void assertEvent(String explanation,
+ long expectedGeneration, Optional<Instant> expectedCompletion, ScalingEvent event) {
+ assertEquals(explanation + ". Generation", expectedGeneration, event.generation());
+ assertEquals(explanation + ". Generation " + expectedGeneration + ". Completion",
+ expectedCompletion, event.completion());
+ }
+
+
+
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java
index fadcd40ad0a..f53ae1baad2 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java
@@ -14,6 +14,8 @@ import com.yahoo.config.provisioning.FlavorsConfig;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.applications.Cluster;
+import com.yahoo.vespa.hosted.provision.applications.ScalingEvent;
import com.yahoo.vespa.hosted.provision.autoscale.MetricSnapshot;
import com.yahoo.vespa.hosted.provision.autoscale.MetricsDb;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
@@ -68,7 +70,7 @@ public class AutoscalingMaintainerTester {
return provisioningTester.deploy(application, cluster, capacity);
}
- public void addMeasurements(float cpu, float mem, float disk, int generation, int count, ApplicationId applicationId) {
+ public void addMeasurements(float cpu, float mem, float disk, long generation, int count, ApplicationId applicationId) {
List<Node> nodes = nodeRepository().getNodes(applicationId, Node.State.active);
for (int i = 0; i < count; i++) {
for (Node node : nodes)
@@ -77,10 +79,15 @@ public class AutoscalingMaintainerTester {
mem,
disk,
generation,
+ true,
true))));
}
}
+ public Cluster cluster(ApplicationId application, ClusterSpec cluster) {
+ return nodeRepository().applications().get(application).get().cluster(cluster.id()).get();
+ }
+
private FlavorsConfig flavorsConfig() {
FlavorConfigBuilder b = new FlavorConfigBuilder();
b.addFlavor("flt", 30, 30, 40, 3, Flavor.Type.BARE_METAL);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
index 86507508e68..5dfd1193581 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/CapacityCheckerTester.java
@@ -226,7 +226,7 @@ public class CapacityCheckerTester {
return m;
}
public String toString() {
- return String.format("%s/%s/%s/%d%s", clustertype, clusterid, group, index, retired ? "/retired" : "");
+ return String.format("%s/%s/%s/%d%s%s", clustertype, clusterid, group, index, retired ? "/retired" : "", clustertype.isContent() ? "/stateful" : "");
}
}
static class OwnerModel {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
index 2833c4e11ba..c67f6657c7f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainerTest.java
@@ -15,9 +15,10 @@ import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.Zone;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
-import com.yahoo.vespa.flags.custom.HostCapacity;
+import com.yahoo.vespa.flags.PermanentFlags;
+import com.yahoo.vespa.flags.custom.ClusterCapacity;
+import com.yahoo.vespa.flags.custom.SharedHost;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Address;
@@ -31,7 +32,6 @@ import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
-import org.junit.Ignore;
import org.junit.Test;
import java.time.Duration;
@@ -43,6 +43,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import java.util.stream.Stream;
import static com.yahoo.vespa.hosted.provision.maintenance.DynamicProvisioningMaintainerTest.MockHostProvisioner.Behaviour;
@@ -104,7 +105,7 @@ public class DynamicProvisioningMaintainerTest {
@Test
public void does_not_deprovision_when_preprovisioning_enabled() {
var tester = new DynamicProvisioningTester().addInitialNodes();
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(new HostCapacity(1, 3, 2, 1)), HostCapacity.class);
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(), List.of(new ClusterCapacity(1, 1, 3, 2, 1.0)), ClusterCapacity.class);
Optional<Node> failedHost = tester.nodeRepository.getNode("host2");
assertTrue(failedHost.isPresent());
@@ -116,23 +117,162 @@ public class DynamicProvisioningMaintainerTest {
@Test
public void provision_deficit_and_deprovision_excess() {
var tester = new DynamicProvisioningTester().addInitialNodes();
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(),
- List.of(new HostCapacity(24, 64, 100, 2),
- new HostCapacity(16, 24, 100, 1)),
- HostCapacity.class);
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, 48, 128, 1000, 10.0),
+ new ClusterCapacity(1, 16, 24, 100, 1.0)),
+ ClusterCapacity.class);
+
+ assertEquals(0, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(11, tester.nodeRepository.getNodes().size());
assertTrue(tester.nodeRepository.getNode("host2").isPresent());
- assertEquals(0 ,tester.hostProvisioner.provisionedHosts.size());
+ assertTrue(tester.nodeRepository.getNode("host2-1").isPresent());
+ assertTrue(tester.nodeRepository.getNode("host3").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname100").isEmpty());
+ assertTrue(tester.nodeRepository.getNode("hostname101").isEmpty());
- // failed host2 is removed
- Optional<Node> failedHost = tester.nodeRepository.getNode("host2");
- assertTrue(failedHost.isPresent());
tester.maintainer.maintain();
- assertTrue("Failed host is deprovisioned", tester.nodeRepository.getNode(failedHost.get().hostname()).isEmpty());
- assertTrue("Host with matching resources is kept", tester.nodeRepository.getNode("host3").isPresent());
- // Two more hosts are provisioned with expected resources
- NodeResources resources = new NodeResources(24, 64, 100, 1);
- assertEquals(2, tester.provisionedHostsMatching(resources));
+ assertEquals(2, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(2, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10)));
+ List<Node> nodesAfter = tester.nodeRepository.getNodes();
+ assertEquals(11, nodesAfter.size()); // 2 removed, 2 added
+ assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.getNode("host2").isEmpty());
+ assertTrue("Node on deprovisioned host removed", tester.nodeRepository.getNode("host2-1").isEmpty());
+ assertTrue("Host satisfying 16-24-100-1 is kept", tester.nodeRepository.getNode("host3").isPresent());
+ assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname100").isPresent());
+ assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname101").isPresent());
+ }
+
+ @Test
+ public void preprovision_with_shared_host() {
+ var tester = new DynamicProvisioningTester().addInitialNodes();
+ // Makes provisioned hosts 48-128-1000-10
+ tester.hostProvisioner.provisionSharedHost("host4");
+
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, 1, 30, 20, 3.0)),
+ ClusterCapacity.class);
+
+ assertEquals(0, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(11, tester.nodeRepository.getNodes().size());
+ assertTrue(tester.nodeRepository.getNode("host2").isPresent());
+ assertTrue(tester.nodeRepository.getNode("host2-1").isPresent());
+ assertTrue(tester.nodeRepository.getNode("host3").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname100").isEmpty());
+
+ // The first cluster will be allocated to host3 and a new host hostname100.
+ // hostname100 will be a large shared host specified above.
+ tester.maintainer.maintain();
+ verifyFirstMaintain(tester);
+
+ // Second maintain should be a no-op, otherwise we did wrong in the first maintain.
+ tester.maintainer.maintain();
+ verifyFirstMaintain(tester);
+
+ // Add a second cluster equal to the first. It should fit on existing host3 and hostname100.
+
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, 1, 30, 20, 3.0),
+ new ClusterCapacity(2, 1, 30, 20, 3.0)),
+ ClusterCapacity.class);
+
+ tester.maintainer.maintain();
+ verifyFirstMaintain(tester);
+
+ // Change second cluster such that it doesn't fit on host3, but does on hostname100,
+ // and with a size of 2 it should allocate a new shared host.
+ // The node allocation code prefers to allocate to the shared hosts instead of host3 (at least
+ // in this test, due to skew), so host3 will be deprovisioned when hostname101 is provisioned.
+ // host3 is a 24-64-100-10 while hostname100 is 48-128-1000-10.
+
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, 1, 30, 20, 3.0),
+ new ClusterCapacity(2, 24, 64, 100, 1.0)),
+ ClusterCapacity.class);
+
+ tester.maintainer.maintain();
+
+ assertEquals(2, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(2, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10)));
+ assertEquals(10, tester.nodeRepository.getNodes().size()); // 3 removed, 2 added
+ assertTrue("preprovision capacity is prefered on shared hosts", tester.nodeRepository.getNode("host3").isEmpty());
+ assertTrue(tester.nodeRepository.getNode("hostname100").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname101").isPresent());
+
+ // If the preprovision capacity is reduced, we should see shared hosts deprovisioned.
+
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(1, 1, 30, 20, 3.0)),
+ ClusterCapacity.class);
+
+ tester.maintainer.maintain();
+
+ assertEquals("one provisioned host has been deprovisioned, so there are 2 -> 1 provisioned hosts",
+ 1, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(1, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10)));
+ assertEquals(9, tester.nodeRepository.getNodes().size()); // 4 removed, 2 added
+ if (tester.nodeRepository.getNode("hostname100").isPresent()) {
+ assertTrue("hostname101 is superfluous and should have been deprovisioned",
+ tester.nodeRepository.getNode("hostname101").isEmpty());
+ } else {
+ assertTrue("hostname101 is required for preprovision capacity",
+ tester.nodeRepository.getNode("hostname101").isPresent());
+ }
+
+ }
+
+ private void verifyFirstMaintain(DynamicProvisioningTester tester) {
+ assertEquals(1, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(1, tester.provisionedHostsMatching(new NodeResources(48, 128, 1000, 10)));
+ assertEquals(10, tester.nodeRepository.getNodes().size()); // 2 removed, 1 added
+ assertTrue("Failed host 'host2' is deprovisioned", tester.nodeRepository.getNode("host2").isEmpty());
+ assertTrue("Node on deprovisioned host removed", tester.nodeRepository.getNode("host2-1").isEmpty());
+ assertTrue("One 1-30-20-3 node fits on host3", tester.nodeRepository.getNode("host3").isPresent());
+ assertTrue("New 48-128-1000-10 host added", tester.nodeRepository.getNode("hostname100").isPresent());
+ }
+
+ @Test
+ public void verify_min_count_of_shared_hosts() {
+ // What's going on here? We are trying to verify the impact of varying the minimum number of
+ // shared hosts (SharedHost.minCount()).
+ //
+ // addInitialNodes() adds 4 tenant hosts:
+ // host1 shared !removable # not removable because it got child nodes w/allocation
+ // host2 !shared removable # not counted as a shared host because it is failed
+ // host3 shared removable
+ // host4 shared !removable # not removable because it got child nodes w/allocation
+ //
+ // Hosts 1, 3, and 4 count as "shared hosts" with respect to the minCount lower boundary.
+ // Hosts 3 and 4 are removable, that is they will be deprovisioned as excess hosts unless
+ // prevented by minCount.
+
+ // minCount=0: All (2) removable hosts are deprovisioned
+ assertWithMinCount(0, 0, 2);
+ // minCount=1: The same thing happens, because there are 2 shared hosts left
+ assertWithMinCount(1, 0, 2);
+ assertWithMinCount(2, 0, 2);
+ // minCount=3: since we require 3 shared hosts, host3 is not deprovisioned.
+ assertWithMinCount(3, 0, 1);
+ // 4 shared hosts require we provision 1 shared host
+ assertWithMinCount(4, 1, 1);
+ // 5 shared hosts require we provision 2 shared hosts
+ assertWithMinCount(5, 2, 1);
+ assertWithMinCount(6, 3, 1);
+ }
+
+ private void assertWithMinCount(int minCount, int provisionCount, int deprovisionCount) {
+ var tester = new DynamicProvisioningTester().addInitialNodes();
+ tester.hostProvisioner.provisionSharedHost("host4");
+
+ tester.flagSource.withJacksonFlag(PermanentFlags.SHARED_HOST.id(), new SharedHost(null, minCount), SharedHost.class);
+ tester.maintainer.maintain();
+ assertEquals(provisionCount, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(deprovisionCount, tester.hostProvisioner.deprovisionedHosts);
+
+ // Verify next maintain is a no-op
+ tester.maintainer.maintain();
+ assertEquals(provisionCount, tester.hostProvisioner.provisionedHosts.size());
+ assertEquals(deprovisionCount, tester.hostProvisioner.deprovisionedHosts);
}
@Test
@@ -145,58 +285,95 @@ public class DynamicProvisioningMaintainerTest {
assertTrue(tester.nodeRepository.getNode(host2.hostname()).isPresent());
}
- @Ignore // TODO (hakon): Enable as test of min-capacity specified in flag
@Test
- public void provision_exact_capacity() {
- var tester = new DynamicProvisioningTester(Cloud.builder().dynamicProvisioning(true).build());
- NodeResources resources1 = new NodeResources(24, 64, 100, 1);
- NodeResources resources2 = new NodeResources(16, 24, 100, 1);
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(new HostCapacity(resources1.vcpu(), resources1.memoryGb(), resources1.diskGb(), 1),
- new HostCapacity(resources2.vcpu(), resources2.memoryGb(), resources2.diskGb(), 2)),
- HostCapacity.class);
+ public void test_minimum_capacity() {
+ var tester = new DynamicProvisioningTester();
+ NodeResources resources1 = new NodeResources(24, 64, 100, 10);
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, resources1.vcpu(), resources1.memoryGb(), resources1.diskGb(), resources1.bandwidthGbps())),
+ ClusterCapacity.class);
tester.maintainer.maintain();
// Hosts are provisioned
- assertEquals(1, tester.provisionedHostsMatching(resources1));
- assertEquals(2, tester.provisionedHostsMatching(resources2));
+ assertEquals(2, tester.provisionedHostsMatching(resources1));
+ assertEquals(0, tester.hostProvisioner.deprovisionedHosts);
// Next maintenance run does nothing
tester.assertNodesUnchanged();
- // Target capacity is changed
- NodeResources resources3 = new NodeResources(48, 128, 1000, 1);
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(new HostCapacity(resources1.vcpu(), resources1.memoryGb(), resources1.diskGb(), 1),
- new HostCapacity(resources3.vcpu(), resources3.memoryGb(), resources3.diskGb(), 1)),
- HostCapacity.class);
+ // Pretend shared-host flag has been set to host4's flavor
+ var sharedHostNodeResources = new NodeResources(48, 128, 1000, 10, NodeResources.DiskSpeed.fast, NodeResources.StorageType.remote);
+ tester.hostProvisioner.provisionSharedHost("host4");
- // Excess hosts are deprovisioned
- tester.maintainer.maintain();
- assertEquals(1, tester.provisionedHostsMatching(resources1));
- assertEquals(0, tester.provisionedHostsMatching(resources2));
- assertEquals(1, tester.provisionedHostsMatching(resources3));
- assertEquals(2, tester.nodeRepository.getNodes(Node.State.deprovisioned).size());
+ // Next maintenance run does nothing
+ tester.assertNodesUnchanged();
+
+ // Must be able to allocate 2 nodes with "no resource requirement"
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(2, 0, 0, 0, 0.0)),
+ ClusterCapacity.class);
+
+ // Next maintenance run does nothing
+ tester.assertNodesUnchanged();
// Activate hosts
- tester.maintainer.maintain(); // Resume provisioning of new hosts
List<Node> provisioned = tester.nodeRepository.list().state(Node.State.provisioned).asList();
tester.nodeRepository.setReady(provisioned, Agent.system, this.getClass().getSimpleName());
tester.provisioningTester.activateTenantHosts();
// Allocating nodes to a host does not result in provisioning of additional capacity
ApplicationId application = ProvisioningTester.applicationId();
+ NodeResources applicationNodeResources = new NodeResources(4, 8, 50, 0.1);
tester.provisioningTester.deploy(application,
- Capacity.from(new ClusterResources(2, 1, new NodeResources(4, 8, 50, 0.1))));
+ Capacity.from(new ClusterResources(2, 1, applicationNodeResources)));
assertEquals(2, tester.nodeRepository.list().owner(application).size());
tester.assertNodesUnchanged();
// Clearing flag does nothing
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(), HostCapacity.class);
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(), List.of(), ClusterCapacity.class);
+ tester.assertNodesUnchanged();
+
+ // Increasing the capacity provisions additional hosts
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(3, 0, 0, 0, 0.0)),
+ ClusterCapacity.class);
+ assertEquals(0, tester.provisionedHostsMatching(sharedHostNodeResources));
+ assertTrue(tester.nodeRepository.getNode("hostname102").isEmpty());
+ tester.maintainer.maintain();
+ assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources));
+ assertTrue(tester.nodeRepository.getNode("hostname102").isPresent());
+
+ // Next maintenance run does nothing
tester.assertNodesUnchanged();
- // Capacity reduction does not remove host with children
- tester.flagSource.withListFlag(Flags.TARGET_CAPACITY.id(), List.of(new HostCapacity(resources1.vcpu(), resources1.memoryGb(), resources1.diskGb(), 1)),
- HostCapacity.class);
+ // Requiring >0 capacity does nothing as long as it fits on the 3 hosts
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(3,
+ resources1.vcpu() - applicationNodeResources.vcpu(),
+ resources1.memoryGb() - applicationNodeResources.memoryGb(),
+ resources1.diskGb() - applicationNodeResources.diskGb(),
+ resources1.bandwidthGbps() - applicationNodeResources.bandwidthGbps())),
+ ClusterCapacity.class);
tester.assertNodesUnchanged();
+
+ // But requiring a bit more in the cluster => provisioning of 2 shared hosts.
+ tester.flagSource.withListFlag(PermanentFlags.PREPROVISION_CAPACITY.id(),
+ List.of(new ClusterCapacity(3,
+ resources1.vcpu() - applicationNodeResources.vcpu() + 1,
+ resources1.memoryGb() - applicationNodeResources.memoryGb() + 1,
+ resources1.diskGb() - applicationNodeResources.diskGb() + 1,
+ resources1.bandwidthGbps())),
+ ClusterCapacity.class);
+
+ assertEquals(1, tester.provisionedHostsMatching(sharedHostNodeResources));
+ assertTrue(tester.nodeRepository.getNode("hostname102").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname103").isEmpty());
+ assertTrue(tester.nodeRepository.getNode("hostname104").isEmpty());
+ tester.maintainer.maintain();
+ assertEquals(3, tester.provisionedHostsMatching(sharedHostNodeResources));
+ assertTrue(tester.nodeRepository.getNode("hostname102").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname103").isPresent());
+ assertTrue(tester.nodeRepository.getNode("hostname104").isPresent());
}
@Test
@@ -225,9 +402,7 @@ public class DynamicProvisioningMaintainerTest {
private static final ApplicationId proxyApp = ApplicationId.from("vespa", "proxy", "default");
private static final NodeFlavors flavors = FlavorConfigBuilder.createDummies("default", "docker", "host2", "host3", "host4");
- private final InMemoryFlagSource flagSource = new InMemoryFlagSource().withListFlag(Flags.TARGET_CAPACITY.id(),
- List.of(),
- HostCapacity.class);
+ private final InMemoryFlagSource flagSource = new InMemoryFlagSource();
private final NodeRepository nodeRepository;
private final MockHostProvisioner hostProvisioner;
@@ -260,9 +435,10 @@ public class DynamicProvisioningMaintainerTest {
List.of(createNode("host1", Optional.empty(), NodeType.host, Node.State.active, Optional.of(tenantHostApp)),
createNode("host1-1", Optional.of("host1"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
createNode("host1-2", Optional.of("host1"), NodeType.tenant, Node.State.failed, Optional.empty()),
- createNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantApp)),
+ createNode("host2", Optional.empty(), NodeType.host, Node.State.failed, Optional.of(tenantHostApp)),
createNode("host2-1", Optional.of("host2"), NodeType.tenant, Node.State.failed, Optional.empty()),
- createNode("host3", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
+ createNode("host3", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty(),
+ "host3-1", "host3-2", "host3-3", "host3-4", "host3-5"),
createNode("host4", Optional.empty(), NodeType.host, Node.State.provisioned, Optional.empty()),
createNode("host4-1", Optional.of("host4"), NodeType.tenant, Node.State.reserved, Optional.of(tenantApp)),
createNode("proxyhost1", Optional.empty(), NodeType.proxyhost, Node.State.provisioned, Optional.empty()),
@@ -281,8 +457,9 @@ public class DynamicProvisioningMaintainerTest {
return nodeRepository.database().addNodesInState(List.of(node), node.state(), Agent.system).get(0);
}
- private Node createNode(String hostname, Optional<String> parentHostname, NodeType nodeType, Node.State state, Optional<ApplicationId> application) {
- Flavor flavor = nodeRepository.flavors().getFlavor(parentHostname.isPresent() ? "docker" : "host2").orElseThrow();
+ private Node createNode(String hostname, Optional<String> parentHostname, NodeType nodeType,
+ Node.State state, Optional<ApplicationId> application, String... additionalHostnames) {
+ Flavor flavor = nodeRepository.flavors().getFlavor(parentHostname.isPresent() ? "docker" : "host3").orElseThrow();
Optional<Allocation> allocation = application
.map(app -> new Allocation(
app,
@@ -290,8 +467,9 @@ public class DynamicProvisioningMaintainerTest {
flavor.resources(),
Generation.initial(),
false));
+ List<Address> addresses = Stream.of(additionalHostnames).map(Address::new).collect(Collectors.toList());
Node.Builder builder = Node.create("fake-id-" + hostname, hostname, flavor, state, nodeType)
- .ipConfigWithEmptyPool(state == Node.State.active ? Set.of("::1") : Set.of());
+ .ipConfig(new IP.Config(state == Node.State.active ? Set.of("::1") : Set.of(), Set.of(), addresses));
parentHostname.ifPresent(builder::parentHostname);
allocation.ifPresent(builder::allocation);
return builder.build();
@@ -299,7 +477,7 @@ public class DynamicProvisioningMaintainerTest {
private long provisionedHostsMatching(NodeResources resources) {
return hostProvisioner.provisionedHosts.stream()
- .filter(host -> host.nodeResources().equals(resources))
+ .filter(host -> host.generateHost().resources().compatibleWith(resources))
.count();
}
@@ -319,27 +497,35 @@ public class DynamicProvisioningMaintainerTest {
private int deprovisionedHosts = 0;
private EnumSet<Behaviour> behaviours = EnumSet.noneOf(Behaviour.class);
+ private Optional<Flavor> provisionHostFlavor = Optional.empty();
public MockHostProvisioner(NodeFlavors flavors, MockNameResolver nameResolver) {
this.flavors = flavors;
this.nameResolver = nameResolver;
}
+ public MockHostProvisioner provisionSharedHost(String flavorName) {
+ provisionHostFlavor = Optional.of(flavors.getFlavorOrThrow(flavorName));
+ return this;
+ }
+
@Override
public List<ProvisionedHost> provisionHosts(List<Integer> provisionIndexes, NodeResources resources,
ApplicationId applicationId, Version osVersion, HostSharing sharing) {
- Flavor hostFlavor = flavors.getFlavors().stream()
- .filter(f -> !f.isDocker())
- .filter(f -> f.resources().compatibleWith(resources))
- .findFirst()
- .orElseThrow(() -> new IllegalArgumentException("No host flavor found satisfying " + resources));
+ Flavor hostFlavor = provisionHostFlavor
+ .orElseGet(() -> flavors.getFlavors().stream()
+ .filter(f -> !f.isDocker())
+ .filter(f -> f.resources().compatibleWith(resources))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("No host flavor found satisfying " + resources)));
+
List<ProvisionedHost> hosts = new ArrayList<>();
for (int index : provisionIndexes) {
hosts.add(new ProvisionedHost("host" + index,
"hostname" + index,
hostFlavor,
Optional.empty(),
- List.of(new Address("nodename" + index)),
+ createAddressesForHost(hostFlavor, index),
resources,
osVersion));
}
@@ -347,6 +533,13 @@ public class DynamicProvisioningMaintainerTest {
return hosts;
}
+ private List<Address> createAddressesForHost(Flavor flavor, int hostIndex) {
+ long numAddresses = Math.max(1, Math.round(flavor.resources().bandwidthGbps()));
+ return IntStream.range(0, (int) numAddresses)
+ .mapToObj(i -> new Address("nodename" + hostIndex + "_" + i))
+ .collect(Collectors.toList());
+ }
+
@Override
public List<Node> provision(Node host, Set<Node> children) throws FatalProvisioningException {
if (behaviours.contains(Behaviour.failProvisioning)) throw new FatalProvisioningException("Failed to provision node(s)");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
index a25858c034f..3e4887b6998 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
@@ -147,25 +147,14 @@ public class MetricsReporterTest {
// Verify sum of values across dimensions, and remove these metrics to avoid checking against
// metric.values below, which is not sensitive to dimensions.
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.acquire", 3);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.acquireFailed", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.acquireTimedOut", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.locked", 3);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.release", 3);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.releaseFailed", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.reentry", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.deadlock", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.nakedRelease", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.acquireWithoutRelease", 0);
- verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.foreignRelease", 0);
- metric.remove("lockAttempt.acquireLatency");
metric.remove("lockAttempt.acquireMaxActiveLatency");
metric.remove("lockAttempt.acquireHz");
metric.remove("lockAttempt.acquireLoad");
metric.remove("lockAttempt.lockedLatency");
- metric.remove("lockAttempt.lockedMaxActiveLatency");
- metric.remove("lockAttempt.lockedHz");
metric.remove("lockAttempt.lockedLoad");
+ verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.acquireTimedOut", 0);
+ verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.deadlock", 0);
+ verifyAndRemoveIntegerMetricSum(metric, "lockAttempt.errors", 0);
assertEquals(expectedMetrics, new TreeMap<>(metric.values));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java
index d403affc292..d4dbc6f55a5 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java
@@ -10,6 +10,7 @@ import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Report;
import com.yahoo.vespa.hosted.provision.node.Reports;
import org.junit.Test;
@@ -233,7 +234,7 @@ public class NodeFailerTest {
assertEquals(2, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.ready).size());
assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyFail1.hostname()).get().state());
assertEquals(Node.State.failed, tester.nodeRepository.getNode(readyFail2.hostname()).get().state());
-
+
String downHost1 = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname();
String downHost2 = tester.nodeRepository.getNodes(NodeFailTester.app2, Node.State.active).get(3).hostname();
tester.serviceMonitor.setHostDown(downHost1);
@@ -309,6 +310,36 @@ public class NodeFailerTest {
}
@Test
+ public void re_activate_grace_period_test() {
+ NodeFailTester tester = NodeFailTester.withTwoApplications();
+ String downNode = tester.nodeRepository.getNodes(NodeFailTester.app1, Node.State.active).get(1).hostname();
+
+ tester.serviceMonitor.setHostDown(downNode);
+ tester.allNodesMakeAConfigRequestExcept();
+ tester.runMaintainers();
+ assertEquals(0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size());
+
+ tester.clock.advance(Duration.ofMinutes(75));
+ tester.allNodesMakeAConfigRequestExcept();
+ tester.runMaintainers();
+ assertEquals(1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size());
+ assertEquals(Node.State.failed, tester.nodeRepository.getNode(downNode).get().state());
+
+ // Re-activate the node. It is still down, but should not be failed out until the grace period has passed again
+ tester.nodeRepository.reactivate(downNode, Agent.system, getClass().getSimpleName());
+ tester.clock.advance(Duration.ofMinutes(30));
+ tester.allNodesMakeAConfigRequestExcept();
+ tester.runMaintainers();
+ assertEquals(0, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size());
+
+ tester.clock.advance(Duration.ofMinutes(45));
+ tester.allNodesMakeAConfigRequestExcept();
+ tester.runMaintainers();
+ assertEquals(1, tester.nodeRepository.getNodes(NodeType.tenant, Node.State.failed).size());
+ assertEquals(Node.State.failed, tester.nodeRepository.getNode(downNode).get().state());
+ }
+
+ @Test
public void node_failing_can_allocate_spare() {
var resources = new NodeResources(1, 20, 15, 1);
Capacity capacity = Capacity.from(new ClusterResources(3, 1, resources), false, true);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainerTest.java
index 722911569de..4f0b0d55742 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMetricsDbMaintainerTest.java
@@ -19,6 +19,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
@@ -51,9 +52,8 @@ public class NodeMetricsDbMaintainerTest {
List<MetricSnapshot> allSnapshots = timeseriesList.stream()
.flatMap(timeseries -> timeseries.asList().stream())
.collect(Collectors.toList());
- assertEquals("Snapshot from the node not in service is filtered out",
- 1, allSnapshots.size());
- assertEquals(0.14, allSnapshots.get(0).cpu(), 0.000001);
+ assertTrue(allSnapshots.stream().anyMatch(snapshot -> snapshot.inService()));
+ assertTrue(allSnapshots.stream().anyMatch(snapshot -> ! snapshot.inService()));
}
private static class MockHttpClient implements MetricsV2MetricsFetcher.HttpClient {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
index 36d088a59df..2abe5ed7ebf 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRebooterTest.java
@@ -5,8 +5,8 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.curator.mock.MockCurator;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
@@ -142,7 +142,7 @@ public class NodeRebooterTest {
}
private static ProvisioningTester createTester(Duration rebootInterval, InMemoryFlagSource flagSource) {
- flagSource = flagSource.withIntFlag(Flags.REBOOT_INTERVAL_IN_DAYS.id(), (int) rebootInterval.toDays());
+ flagSource = flagSource.withIntFlag(PermanentFlags.REBOOT_INTERVAL_IN_DAYS.id(), (int) rebootInterval.toDays());
ProvisioningTester tester = new ProvisioningTester.Builder().flagSource(flagSource).build();
tester.clock().setInstant(Instant.ofEpochMilli(1605522619000L)); // Use a fixed random seed
((MockCurator) tester.getCurator()).setZooKeeperEnsembleConnectionSpec("zk1.host:1,zk2.host:2,zk3.host:3");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
index 55a183c8ec1..cd188bc017f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java
@@ -51,7 +51,7 @@ public class PeriodicApplicationMaintainerTest {
@After
public void after() {
- this.fixture.maintainer.close();
+ this.fixture.maintainer.awaitShutdown();
}
@Test(timeout = 60_000)
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java
index 15966a4c44b..d1fc13c9796 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java
@@ -56,6 +56,7 @@ public class ScalingSuggestionsMaintainerTest {
new ClusterResources(10, 1, new NodeResources(6.5, 5, 15, 0.1)),
false, true));
+ tester.clock().advance(Duration.ofHours(13));
addMeasurements(0.90f, 0.90f, 0.90f, 0, 500, app1, tester.nodeRepository(), metricsDb);
addMeasurements(0.99f, 0.99f, 0.99f, 0, 500, app2, tester.nodeRepository(), metricsDb);
@@ -81,6 +82,7 @@ public class ScalingSuggestionsMaintainerTest {
memory,
disk,
generation,
+ true,
true))));
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
index e63f31cf304..06473e60712 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
@@ -45,7 +45,8 @@ public class ApplicationSerializerTest {
List.of(new ScalingEvent(new ClusterResources(10, 5, minResources),
new ClusterResources(12, 6, minResources),
7L,
- Instant.ofEpochMilli(12345L))),
+ Instant.ofEpochMilli(12345L),
+ Optional.of(Instant.ofEpochMilli(67890L)))),
"Autoscaling status"));
Application original = new Application(ApplicationId.from("myTenant", "myApplication", "myInstance"),
clusters);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
index 8b9d60aeaf4..e5333ea4186 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializerTest.java
@@ -79,7 +79,7 @@ public class NodeSerializerTest {
node = node.allocate(ApplicationId.from(TenantName.from("myTenant"),
ApplicationName.from("myApplication"),
InstanceName.from("myInstance")),
- ClusterMembership.from("content/myId/0/0", Vtag.currentVersion, Optional.empty()),
+ ClusterMembership.from("content/myId/0/0/stateful", Vtag.currentVersion, Optional.empty()),
requestedResources,
clock.instant());
assertEquals(1, node.history().events().size());
@@ -134,7 +134,7 @@ public class NodeSerializerTest {
" \"applicationId\" : \"myApplication\",\n" +
" \"tenantId\" : \"myTenant\",\n" +
" \"instanceId\" : \"myInstance\",\n" +
- " \"serviceId\" : \"content/myId/0/0\",\n" +
+ " \"serviceId\" : \"content/myId/0/0/stateful\",\n" +
" \"restartGeneration\" : 3,\n" +
" \"currentRestartGeneration\" : 4,\n" +
" \"removable\" : true,\n" +
@@ -167,7 +167,7 @@ public class NodeSerializerTest {
node = node.allocate(ApplicationId.from(TenantName.from("myTenant"),
ApplicationName.from("myApplication"),
InstanceName.from("myInstance")),
- ClusterMembership.from("content/myId/0/0", Vtag.currentVersion, Optional.empty()),
+ ClusterMembership.from("content/myId/0/0/stateful", Vtag.currentVersion, Optional.empty()),
node.flavor().resources(),
clock.instant());
assertEquals(1, node.history().events().size());
@@ -217,7 +217,7 @@ public class NodeSerializerTest {
node = node.allocate(ApplicationId.from(TenantName.from("myTenant"),
ApplicationName.from("myApplication"),
InstanceName.from("myInstance")),
- ClusterMembership.from("content/myId/0/0", Vtag.currentVersion, Optional.empty()),
+ ClusterMembership.from("content/myId/0/0/stateful", Vtag.currentVersion, Optional.empty()),
node.flavor().resources(),
clock.instant());
@@ -315,7 +315,7 @@ public class NodeSerializerTest {
" \"hostname\" : \"myHostname\",\n" +
" \"ipAddresses\" : [\"127.0.0.1\"],\n" +
" \"instance\": {\n" +
- " \"serviceId\": \"content/myId/0/0\",\n" +
+ " \"serviceId\": \"content/myId/0/0/stateful\",\n" +
" \"wantedVespaVersion\": \"6.42.2\"\n" +
" }\n" +
"}";
@@ -408,7 +408,7 @@ public class NodeSerializerTest {
node = node.allocate(ApplicationId.from(TenantName.from("myTenant"),
ApplicationName.from("myApplication"),
InstanceName.from("myInstance")),
- ClusterMembership.from("content/myId/0/0", Vtag.currentVersion, Optional.empty()),
+ ClusterMembership.from("content/myId/0/0/stateful", Vtag.currentVersion, Optional.empty()),
node.flavor().resources(),
clock.instant());
assertTrue(node.allocation().isPresent());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
index e046bc0a512..f368f4d139c 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java
@@ -75,7 +75,6 @@ public class DockerProvisioningTest {
public void refuses_to_activate_on_non_active_host() {
ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build();
- ApplicationId zoneApplication = ProvisioningTester.applicationId();
List<Node> parents = tester.makeReadyNodes(10, new NodeResources(2, 4, 20, 2), NodeType.host, 1);
for (Node parent : parents)
tester.makeReadyVirtualDockerNodes(1, dockerResources, parent.hostname());
@@ -90,11 +89,8 @@ public class DockerProvisioningTest {
fail("Expected the allocation to fail due to parent hosts not being active yet");
} catch (OutOfCapacityException expected) { }
- // Activate the zone-app, thereby allocating the parents
- List<HostSpec> hosts = tester.prepare(zoneApplication,
- ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("zone-app")).vespaVersion(wantedVespaVersion).build(),
- Capacity.fromRequiredNodeType(NodeType.host));
- tester.activate(zoneApplication, hosts);
+ // Activate the hosts, thereby allocating the parents
+ tester.activateTenantHosts();
// Try allocating tenants again
List<HostSpec> nodes = tester.prepare(application1,
@@ -412,10 +408,6 @@ public class DockerProvisioningTest {
return nodes.asList().stream().map(Node::parentHostname).map(Optional::get).collect(Collectors.toSet());
}
- private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, ProvisioningTester tester) {
- prepareAndActivate(application, nodeCount, exclusive, dockerResources, tester);
- }
-
private void prepareAndActivate(ApplicationId application, int nodeCount, boolean exclusive, NodeResources resources, ProvisioningTester tester) {
Set<HostSpec> hosts = new HashSet<>(tester.prepare(application,
ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("myContainer")).vespaVersion("6.39").exclusive(exclusive).build(),
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
index c51ef7250e2..7a636a030ec 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/LoadBalancerProvisionerTest.java
@@ -33,6 +33,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author mpolden
@@ -236,6 +237,31 @@ public class LoadBalancerProvisionerTest {
assertEquals(cluster, lbs.get().get(0).id().cluster());
}
+ @Test
+ public void reject_load_balancers_with_clashing_names() {
+ ApplicationId instance1 = ApplicationId.from("t1", "a1", "default");
+ ApplicationId instance2 = ApplicationId.from("t1", "a1", "dev");
+ ApplicationId instance3 = ApplicationId.from("t1", "a1", "qrs");
+ ClusterSpec.Id devCluster = ClusterSpec.Id.from("dev");
+ ClusterSpec.Id defaultCluster = ClusterSpec.Id.from("default");
+
+ // instance1 is deployed
+ tester.activate(instance1, prepare(instance1, clusterRequest(ClusterSpec.Type.container, devCluster)));
+
+ // instance2 clashes because cluster name matches instance1
+ try {
+ prepare(instance2, clusterRequest(ClusterSpec.Type.container, defaultCluster));
+ fail("Expected exception");
+ } catch (IllegalArgumentException ignored) {
+ }
+
+ // instance2 changes cluster name and does not clash
+ tester.activate(instance2, prepare(instance2, clusterRequest(ClusterSpec.Type.container, ClusterSpec.Id.from("qrs"))));
+
+ // instance3 clashes because instance name matches instance2 cluster
+ tester.activate(instance3, prepare(instance3, clusterRequest(ClusterSpec.Type.container, defaultCluster)));
+ }
+
private void dirtyNodesOf(ApplicationId application) {
tester.nodeRepository().setDirty(tester.nodeRepository().getNodes(application), Agent.system, this.getClass().getSimpleName());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java
index 86427fe30ae..3945c518a77 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiTest.java
@@ -485,7 +485,7 @@ public class NodesV2ApiTest {
"{\"message\":\"Moved host2.yahoo.com to parked\"}");
tester.assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host2.yahoo.com",
new byte[0], Request.Method.PUT),
- 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Cannot make parked host host2.yahoo.com allocated to tenant2.application2.instance2 as 'content/id2/0/0' available for new allocation as it is not in state [dirty]\"}");
+ 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Cannot make parked host host2.yahoo.com allocated to tenant2.application2.instance2 as 'content/id2/0/0/stateful' available for new allocation as it is not in state [dirty]\"}");
// (... while dirty then ready works (the ready move will be initiated by node maintenance))
assertResponse(new Request("http://localhost:8080/nodes/v2/state/dirty/host2.yahoo.com",
new byte[0], Request.Method.PUT),
@@ -502,7 +502,7 @@ public class NodesV2ApiTest {
// Attempt to DELETE allocated node
tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node/host4.yahoo.com",
new byte[0], Request.Method.DELETE),
- 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"active child node host4.yahoo.com allocated to tenant3.application3.instance3 as 'content/id3/0/0' is currently allocated and cannot be removed\"}");
+ 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"active child node host4.yahoo.com allocated to tenant3.application3.instance3 as 'content/id3/0/0/stateful' is currently allocated and cannot be removed\"}");
// PUT current restart generation with string instead of long
tester.assertResponse(new Request("http://localhost:8080/nodes/v2/node/host4.yahoo.com",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/capacity-zone.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/capacity-zone.json
index f6b2f96023a..c3857e9c8ee 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/capacity-zone.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/capacity-zone.json
@@ -4,7 +4,7 @@
"failedTenantParent": "dockerhost1.yahoo.com",
"failedTenant": "host4.yahoo.com",
"failedTenantResources": "[vcpu: 1.0, memory: 4.0 Gb, disk 100.0 Gb, bandwidth: 1.0 Gbps, storage type: local]",
- "failedTenantAllocation": "allocated to tenant3.application3.instance3 as 'content/id3/0/0'",
+ "failedTenantAllocation": "allocated to tenant3.application3.instance3 as 'content/id3/0/0/stateful'",
"hostCandidateRejectionReasons": {
"singularReasonFailures": {
"insufficientVcpu": 0,
@@ -43,4 +43,4 @@
}
]
}
-} \ No newline at end of file
+}
diff --git a/parent/pom.xml b/parent/pom.xml
index 486f659e529..114968c02ef 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -570,6 +570,11 @@
<version>${apache.httpclient.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-csv</artifactId>
+ <version>1.8</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>${apache.httpcore.version}</version>
@@ -696,6 +701,11 @@
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <version>${junit.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
</dependency>
@@ -789,7 +799,6 @@
<surefire.version>2.22.0</surefire.version>
<tensorflow.version>1.12.0</tensorflow.version>
<zookeeper.client.version>3.5.8</zookeeper.client.version>
- <zookeeper.server.version>3.5.6</zookeeper.server.version>
<doclint>all</doclint>
<test.hide>true</test.hide>
diff --git a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
index 96c55d0d9f2..7da88e34ee9 100644
--- a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
+++ b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
@@ -9,7 +9,6 @@
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/test/make_bucket_space.h>
#include <vespa/document/util/bytebuffer.h>
-#include <vespa/metrics/loadmetric.h>
#include <vespa/vdslib/state/state.h>
#include <vespa/vdslib/state/node.h>
#include <vespa/vdslib/state/nodestate.h>
diff --git a/pom.xml b/pom.xml
index 930ee2ef7eb..762e1829d97 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,6 @@
<module>cloud-tenant-base-dependencies-enforcer</module>
<module>cloud-tenant-cd</module>
<module>clustercontroller-apps</module>
- <module>clustercontroller-apputil</module>
<module>clustercontroller-core</module>
<module>clustercontroller-reindexer</module>
<module>clustercontroller-utils</module>
diff --git a/python/vespa/.gitignore b/python/vespa/.gitignore
deleted file mode 100644
index 9ca09886342..00000000000
--- a/python/vespa/.gitignore
+++ /dev/null
@@ -1,141 +0,0 @@
-*.bak
-.gitattributes
-.last_checked
-.gitconfig
-*.bak
-*.log
-*~
-~*
-_tmp*
-tmp*
-tags
-
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# celery beat schedule file
-celerybeat-schedule
-
-# SageMath parsed files
-*.sage.py
-
-# dotenv
-.env
-
-# virtualenv
-.venv
-venv/
-ENV/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-
-.vscode
-*.swp
-
-# osx generated files
-.DS_Store
-.DS_Store?
-.Trashes
-ehthumbs.db
-Thumbs.db
-.idea
-
-# pytest
-.pytest_cache
-
-# tools/trust-doc-nbs
-docs_src/.last_checked
-
-# symlinks to fastai
-docs_src/fastai
-tools/fastai
-
-# link checker
-checklink/cookies.txt
-
-# .gitconfig is now autogenerated
-.gitconfig
-
diff --git a/python/vespa/MANIFEST.in b/python/vespa/MANIFEST.in
deleted file mode 100644
index 8f9127e0494..00000000000
--- a/python/vespa/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-include README.md
-recursive-exclude * __pycache__
diff --git a/python/vespa/Pipfile b/python/vespa/Pipfile
deleted file mode 100644
index b723d0199f8..00000000000
--- a/python/vespa/Pipfile
+++ /dev/null
@@ -1,11 +0,0 @@
-[[source]]
-name = "pypi"
-url = "https://pypi.org/simple"
-verify_ssl = true
-
-[dev-packages]
-
-[packages]
-
-[requires]
-python_version = "3.7"
diff --git a/python/vespa/README.md b/python/vespa/README.md
deleted file mode 100644
index 00d8cc2e769..00000000000
--- a/python/vespa/README.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# Vespa library for data analysis
-> Provide data analysis support for Vespa applications
-
-
-## Install
-
-`pip install pyvespa`
-
-## Connect to a Vespa app
-
-> Connect to a running Vespa application
-
-```
-from vespa.application import Vespa
-
-app = Vespa(url = "https://api.cord19.vespa.ai")
-```
-
-## Define a Query model
-
-> Easily define matching and ranking criteria
-
-```
-from vespa.query import Query, Union, WeakAnd, ANN, RankProfile
-from random import random
-
-match_phase = Union(
- WeakAnd(hits = 10),
- ANN(
- doc_vector="title_embedding",
- query_vector="title_vector",
- embedding_model=lambda x: [random() for x in range(768)],
- hits = 10,
- label="title"
- )
-)
-
-rank_profile = RankProfile(name="bm25", list_features=True)
-
-query_model = Query(match_phase=match_phase, rank_profile=rank_profile)
-```
-
-## Query the vespa app
-
-> Send queries via the query API. See the [query page](/vespa/query) for more examples.
-
-```
-query_result = app.query(
- query="Is remdesivir an effective treatment for COVID-19?",
- query_model=query_model
-)
-```
-
-```
-query_result.number_documents_retrieved
-```
-
-## Labelled data
-
-> How to structure labelled data
-
-```
-labelled_data = [
- {
- "query_id": 0,
- "query": "Intrauterine virus infections and congenital heart disease",
- "relevant_docs": [{"id": 0, "score": 1}, {"id": 3, "score": 1}]
- },
- {
- "query_id": 1,
- "query": "Clinical and immunologic studies in identical twins discordant for systemic lupus erythematosus",
- "relevant_docs": [{"id": 1, "score": 1}, {"id": 5, "score": 1}]
- }
-]
-```
-
-Non-relevant documents are assigned `"score": 0` by default. Relevant documents will be assigned `"score": 1` by default if the field is missing from the labelled data. The defaults for both relevant and non-relevant documents can be modified on the appropriate methods.
-
-## Collect training data
-
-> Collect training data to analyse and/or improve ranking functions. See the [collect training data page](/vespa/collect_training_data) for more examples.
-
-```
-training_data_batch = app.collect_training_data(
- labelled_data = labelled_data,
- id_field = "id",
- query_model = query_model,
- number_additional_docs = 2
-)
-training_data_batch
-```
-
-## Evaluating a query model
-
-> Define metrics and evaluate query models. See the [evaluation page](/vespa/evaluation) for more examples.
-
-We will define the following evaluation metrics:
-* % of documents retrieved per query
-* recall @ 10 per query
-* MRR @ 10 per query
-
-```
-from vespa.evaluation import MatchRatio, Recall, ReciprocalRank
-
-eval_metrics = [MatchRatio(), Recall(at=10), ReciprocalRank(at=10)]
-```
-
-Evaluate:
-
-```
-evaluation = app.evaluate(
- labelled_data = labelled_data,
- eval_metrics = eval_metrics,
- query_model = query_model,
- id_field = "id",
-)
-evaluation
-```
diff --git a/python/vespa/docs/sphinx/Makefile b/python/vespa/docs/sphinx/Makefile
deleted file mode 100644
index d0c3cbf1020..00000000000
--- a/python/vespa/docs/sphinx/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line, and also
-# from the environment for the first two.
-SPHINXOPTS ?=
-SPHINXBUILD ?= sphinx-build
-SOURCEDIR = source
-BUILDDIR = build
-
-# Put it first so that "make" without argument is like "make help".
-help:
- @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-.PHONY: help Makefile
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/python/vespa/docs/sphinx/source/application-package.ipynb b/python/vespa/docs/sphinx/source/application-package.ipynb
deleted file mode 100644
index 5042148b040..00000000000
--- a/python/vespa/docs/sphinx/source/application-package.ipynb
+++ /dev/null
@@ -1,139 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Create Vespa application packages\n",
- "\n",
- "> Python API to create application packages"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Our goal is to create the following `msmarco` schema using our python API, based on our [text search tutorial](https://docs.vespa.ai/documentation/tutorials/text-search.html)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "```\n",
- "schema msmarco {\n",
- " document msmarco {\n",
- " field id type string {\n",
- " indexing: attribute | summary\n",
- " }\n",
- " field title type string {\n",
- " indexing: index | summary\n",
- " index: enable-bm25\n",
- " }\n",
- " field body type string {\n",
- " indexing: index | summary\n",
- " index: enable-bm25\n",
- " }\n",
- " }\n",
- "\n",
- " fieldset default {\n",
- " fields: title, body\n",
- " }\n",
- "\n",
- " rank-profile default {\n",
- " first-phase {\n",
- " expression: nativeRank(title, body)\n",
- " }\n",
- " }\n",
- "\n",
- " rank-profile bm25 inherits default {\n",
- " first-phase {\n",
- " expression: bm25(title) + bm25(body)\n",
- " }\n",
- " }\n",
- "\n",
- "}\n",
- "```"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Schema API"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import Document, Field, Schema, FieldSet, RankProfile, ApplicationPackage\n",
- "\n",
- "document = Document(\n",
- " fields=[\n",
- " Field(name = \"id\", type = \"string\", indexing = [\"attribute\", \"summary\"]),\n",
- " Field(name = \"title\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\"),\n",
- " Field(name = \"body\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\") \n",
- " ]\n",
- ")\n",
- "\n",
- "msmarco_schema = Schema(\n",
- " name = \"msmarco\", \n",
- " document = document, \n",
- " fieldsets = [FieldSet(name = \"default\", fields = [\"title\", \"body\"])],\n",
- " rank_profiles = [RankProfile(name = \"default\", first_phase = \"nativeRank(title, body)\")]\n",
- ")\n",
- "\n",
- "app_package = ApplicationPackage(name = \"msmarco\", schema=msmarco_schema)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Modify the application package"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can add a new rank profile:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "app_package.schema.add_rank_profile(\n",
- " RankProfile(name = \"bm25\", inherits = \"default\", first_phase = \"bm25(title) + bm25(body)\")\n",
- ")"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/collect-training-data.ipynb b/python/vespa/docs/sphinx/source/collect-training-data.ipynb
deleted file mode 100644
index 1584b58e6b1..00000000000
--- a/python/vespa/docs/sphinx/source/collect-training-data.ipynb
+++ /dev/null
@@ -1,1232 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Collect training data from Vespa applications\n",
- "\n",
- "> Collect training data to analyse and/or improve ranking functions"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Example setup"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Connect to the application and define a query model."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.application import Vespa\n",
- "from vespa.query import Query, RankProfile, OR\n",
- "\n",
- "app = Vespa(url = \"https://api.cord19.vespa.ai\")\n",
- "query_model = Query(\n",
- " match_phase = OR(),\n",
- " rank_profile = RankProfile(name=\"bm25\", list_features=True))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Define some labelled data."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "labelled_data = [\n",
- " {\n",
- " \"query_id\": 0, \n",
- " \"query\": \"Intrauterine virus infections and congenital heart disease\",\n",
- " \"relevant_docs\": [{\"id\": 0, \"score\": 1}, {\"id\": 3, \"score\": 1}]\n",
- " },\n",
- " {\n",
- " \"query_id\": 1, \n",
- " \"query\": \"Clinical and immunologic studies in identical twins discordant for systemic lupus erythematosus\",\n",
- " \"relevant_docs\": [{\"id\": 1, \"score\": 1}, {\"id\": 5, \"score\": 1}]\n",
- " }\n",
- "]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Collect training data in batch"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>attributeMatch(authors.first)</th>\n",
- " <th>attributeMatch(authors.first).averageWeight</th>\n",
- " <th>attributeMatch(authors.first).completeness</th>\n",
- " <th>attributeMatch(authors.first).fieldCompleteness</th>\n",
- " <th>attributeMatch(authors.first).importance</th>\n",
- " <th>attributeMatch(authors.first).matches</th>\n",
- " <th>attributeMatch(authors.first).maxWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeightedWeight</th>\n",
- " <th>attributeMatch(authors.first).queryCompleteness</th>\n",
- " <th>...</th>\n",
- " <th>textSimilarity(results).queryCoverage</th>\n",
- " <th>textSimilarity(results).score</th>\n",
- " <th>textSimilarity(title).fieldCoverage</th>\n",
- " <th>textSimilarity(title).order</th>\n",
- " <th>textSimilarity(title).proximity</th>\n",
- " <th>textSimilarity(title).queryCoverage</th>\n",
- " <th>textSimilarity(title).score</th>\n",
- " <th>document_id</th>\n",
- " <th>query_id</th>\n",
- " <th>relevant</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.062500</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.055357</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>2</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>3</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.437500</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.224554</td>\n",
- " <td>3</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>4</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>5</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>6</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.111111</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.047222</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>7</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>8</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>9</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.041667</td>\n",
- " <td>5</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>10</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>11</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "<p>12 rows × 984 columns</p>\n",
- "</div>"
- ],
- "text/plain": [
- " attributeMatch(authors.first) \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).averageWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).completeness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).fieldCompleteness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).importance \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).matches \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).maxWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeightedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).queryCompleteness ... \\\n",
- "0 0.0 ... \n",
- "1 0.0 ... \n",
- "2 0.0 ... \n",
- "3 0.0 ... \n",
- "4 0.0 ... \n",
- "5 0.0 ... \n",
- "6 0.0 ... \n",
- "7 0.0 ... \n",
- "8 0.0 ... \n",
- "9 0.0 ... \n",
- "10 0.0 ... \n",
- "11 0.0 ... \n",
- "\n",
- " textSimilarity(results).queryCoverage textSimilarity(results).score \\\n",
- "0 0.0 0.0 \n",
- "1 0.0 0.0 \n",
- "2 0.0 0.0 \n",
- "3 0.0 0.0 \n",
- "4 0.0 0.0 \n",
- "5 0.0 0.0 \n",
- "6 0.0 0.0 \n",
- "7 0.0 0.0 \n",
- "8 0.0 0.0 \n",
- "9 0.0 0.0 \n",
- "10 0.0 0.0 \n",
- "11 0.0 0.0 \n",
- "\n",
- " textSimilarity(title).fieldCoverage textSimilarity(title).order \\\n",
- "0 0.062500 0.000000 \n",
- "1 1.000000 1.000000 \n",
- "2 0.285714 0.666667 \n",
- "3 0.142857 0.000000 \n",
- "4 1.000000 1.000000 \n",
- "5 0.285714 0.666667 \n",
- "6 0.111111 0.000000 \n",
- "7 1.000000 1.000000 \n",
- "8 0.187500 1.000000 \n",
- "9 0.083333 0.000000 \n",
- "10 1.000000 1.000000 \n",
- "11 0.187500 1.000000 \n",
- "\n",
- " textSimilarity(title).proximity textSimilarity(title).queryCoverage \\\n",
- "0 0.000000 0.142857 \n",
- "1 1.000000 1.000000 \n",
- "2 0.739583 0.571429 \n",
- "3 0.437500 0.142857 \n",
- "4 1.000000 1.000000 \n",
- "5 0.739583 0.571429 \n",
- "6 0.000000 0.083333 \n",
- "7 1.000000 1.000000 \n",
- "8 1.000000 0.250000 \n",
- "9 0.000000 0.083333 \n",
- "10 1.000000 1.000000 \n",
- "11 1.000000 0.250000 \n",
- "\n",
- " textSimilarity(title).score document_id query_id relevant \n",
- "0 0.055357 0 0 1 \n",
- "1 1.000000 213690 0 0 \n",
- "2 0.587426 225739 0 0 \n",
- "3 0.224554 3 0 1 \n",
- "4 1.000000 213690 0 0 \n",
- "5 0.587426 225739 0 0 \n",
- "6 0.047222 1 1 1 \n",
- "7 1.000000 176163 1 0 \n",
- "8 0.612500 13597 1 0 \n",
- "9 0.041667 5 1 1 \n",
- "10 1.000000 176163 1 0 \n",
- "11 0.612500 13597 1 0 \n",
- "\n",
- "[12 rows x 984 columns]"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "training_data_batch = app.collect_training_data(\n",
- " labelled_data = labelled_data,\n",
- " id_field = \"id\",\n",
- " query_model = query_model,\n",
- " number_additional_docs = 2\n",
- ")\n",
- "training_data_batch"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Collect training data point\n",
- "\n",
- "> You can have finer control with the `collect_training_data_point` method."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>attributeMatch(authors.first)</th>\n",
- " <th>attributeMatch(authors.first).averageWeight</th>\n",
- " <th>attributeMatch(authors.first).completeness</th>\n",
- " <th>attributeMatch(authors.first).fieldCompleteness</th>\n",
- " <th>attributeMatch(authors.first).importance</th>\n",
- " <th>attributeMatch(authors.first).matches</th>\n",
- " <th>attributeMatch(authors.first).maxWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeightedWeight</th>\n",
- " <th>attributeMatch(authors.first).queryCompleteness</th>\n",
- " <th>...</th>\n",
- " <th>textSimilarity(results).queryCoverage</th>\n",
- " <th>textSimilarity(results).score</th>\n",
- " <th>textSimilarity(title).fieldCoverage</th>\n",
- " <th>textSimilarity(title).order</th>\n",
- " <th>textSimilarity(title).proximity</th>\n",
- " <th>textSimilarity(title).queryCoverage</th>\n",
- " <th>textSimilarity(title).score</th>\n",
- " <th>document_id</th>\n",
- " <th>query_id</th>\n",
- " <th>relevant</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.062500</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.055357</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>2</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>3</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.437500</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.224554</td>\n",
- " <td>3</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>4</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>5</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>6</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.111111</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.047222</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>7</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>8</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>9</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.041667</td>\n",
- " <td>5</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>10</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>11</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "<p>12 rows × 984 columns</p>\n",
- "</div>"
- ],
- "text/plain": [
- " attributeMatch(authors.first) \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).averageWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).completeness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).fieldCompleteness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).importance \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).matches \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).maxWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeightedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).queryCompleteness ... \\\n",
- "0 0.0 ... \n",
- "1 0.0 ... \n",
- "2 0.0 ... \n",
- "3 0.0 ... \n",
- "4 0.0 ... \n",
- "5 0.0 ... \n",
- "6 0.0 ... \n",
- "7 0.0 ... \n",
- "8 0.0 ... \n",
- "9 0.0 ... \n",
- "10 0.0 ... \n",
- "11 0.0 ... \n",
- "\n",
- " textSimilarity(results).queryCoverage textSimilarity(results).score \\\n",
- "0 0.0 0.0 \n",
- "1 0.0 0.0 \n",
- "2 0.0 0.0 \n",
- "3 0.0 0.0 \n",
- "4 0.0 0.0 \n",
- "5 0.0 0.0 \n",
- "6 0.0 0.0 \n",
- "7 0.0 0.0 \n",
- "8 0.0 0.0 \n",
- "9 0.0 0.0 \n",
- "10 0.0 0.0 \n",
- "11 0.0 0.0 \n",
- "\n",
- " textSimilarity(title).fieldCoverage textSimilarity(title).order \\\n",
- "0 0.062500 0.000000 \n",
- "1 1.000000 1.000000 \n",
- "2 0.285714 0.666667 \n",
- "3 0.142857 0.000000 \n",
- "4 1.000000 1.000000 \n",
- "5 0.285714 0.666667 \n",
- "6 0.111111 0.000000 \n",
- "7 1.000000 1.000000 \n",
- "8 0.187500 1.000000 \n",
- "9 0.083333 0.000000 \n",
- "10 1.000000 1.000000 \n",
- "11 0.187500 1.000000 \n",
- "\n",
- " textSimilarity(title).proximity textSimilarity(title).queryCoverage \\\n",
- "0 0.000000 0.142857 \n",
- "1 1.000000 1.000000 \n",
- "2 0.739583 0.571429 \n",
- "3 0.437500 0.142857 \n",
- "4 1.000000 1.000000 \n",
- "5 0.739583 0.571429 \n",
- "6 0.000000 0.083333 \n",
- "7 1.000000 1.000000 \n",
- "8 1.000000 0.250000 \n",
- "9 0.000000 0.083333 \n",
- "10 1.000000 1.000000 \n",
- "11 1.000000 0.250000 \n",
- "\n",
- " textSimilarity(title).score document_id query_id relevant \n",
- "0 0.055357 0 0 1 \n",
- "1 1.000000 213690 0 0 \n",
- "2 0.587426 225739 0 0 \n",
- "3 0.224554 3 0 1 \n",
- "4 1.000000 213690 0 0 \n",
- "5 0.587426 225739 0 0 \n",
- "6 0.047222 1 1 1 \n",
- "7 1.000000 176163 1 0 \n",
- "8 0.612500 13597 1 0 \n",
- "9 0.041667 5 1 1 \n",
- "10 1.000000 176163 1 0 \n",
- "11 0.612500 13597 1 0 \n",
- "\n",
- "[12 rows x 984 columns]"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pandas import concat, DataFrame\n",
- "\n",
- "\n",
- "training_data = []\n",
- "for query_data in labelled_data:\n",
- " for doc_data in query_data[\"relevant_docs\"]:\n",
- " training_data_point = app.collect_training_data_point(\n",
- " query = query_data[\"query\"],\n",
- " query_id = query_data[\"query_id\"],\n",
- " relevant_id = doc_data[\"id\"],\n",
- " id_field = \"id\",\n",
- " query_model = query_model,\n",
- " number_additional_docs = 2\n",
- " )\n",
- " training_data.extend(training_data_point)\n",
- "training_data = DataFrame.from_records(training_data)\n",
- "training_data"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/conf.py b/python/vespa/docs/sphinx/source/conf.py
deleted file mode 100644
index a3784794c04..00000000000
--- a/python/vespa/docs/sphinx/source/conf.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
-import os
-import sys
-
-sys.path.insert(0, os.path.abspath("../../.."))
-
-
-# -- Project information -----------------------------------------------------
-
-project = "pyvespa"
-copyright = "Verizon Media 2020 Licensed under Apache License 2.0"
-author = "Vespa team"
-
-
-# -- General configuration ---------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = ["sphinx.ext.autodoc", "nbsphinx", "sphinx_rtd_theme"]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ["_templates"]
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = []
-
-master_doc = "index"
-
-# -- Options for HTML output -------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = "sphinx_rtd_theme"
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
-
-html_sidebars = {
- "**": [
- "about.html",
- "navigation.html",
- "relations.html", # needs 'show_related': True theme option to display
- "searchbox.html",
- "donate.html",
- ]
-}
diff --git a/python/vespa/docs/sphinx/source/connect-to-vespa-instance.ipynb b/python/vespa/docs/sphinx/source/connect-to-vespa-instance.ipynb
deleted file mode 100644
index 62c2eb8163b..00000000000
--- a/python/vespa/docs/sphinx/source/connect-to-vespa-instance.ipynb
+++ /dev/null
@@ -1,980 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# How to connect with running Vespa instances\n",
- "\n",
- "> Connect and interact with CORD-19 search app.\n",
- "\n",
- "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/vespa-engine/vespa/blob/master/python/vespa/docs/sphinx/source/connect-to-vespa-instance.ipynb)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This self-contained tutorial will show you how to connect to a pre-existing Vespa instance. We will use the https://cord19.vespa.ai/ app as an example. You can run this tutorial yourself in Google Colab by clicking on the badge located at the top of the tutorial."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Install"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The library is available at PyPI and therefore can be installed with `pip`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "!pip install pyvespa"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Connect to a running Vespa application"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can connect to a running Vespa application by creating an instance of [Vespa](reference-api.rst#vespa.application.Vespa) with the appropriate url. The resulting `app` will then be used to communicate with the application."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.application import Vespa\n",
- "\n",
- "app = Vespa(url = \"https://api.cord19.vespa.ai\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Define a Query model\n",
- "\n",
- "> Easily define matching and ranking criteria"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When building a search application, we usually want to expirement with different query models. A [Query](reference-api.rst#vespa.query.Query) model consists of a match phase and a ranking phase. The matching phase will define how to match documents based on the query sent and the ranking phase will define how to rank the matched documents. Both phases can get quite complex and being able to easily express and experiment with them is very valuable."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In the example below we define the match phase to be the [Union](reference-api.rst#vespa.query.Union) of the [WeakAnd](reference-api.rst#vespa.query.WeakAnd) and the [ANN](reference-api.rst#vespa.query.ANN) operators. The `WeakAnd` will match documents based on query terms while the Approximate Nearest Neighbor (`ANN`) operator will match documents based on the distance between the query and document embeddings. This is an illustration of how easy it is to combine term and semantic matching in Vespa. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.query import Union, WeakAnd, ANN\n",
- "from random import random\n",
- "\n",
- "match_phase = Union(\n",
- " WeakAnd(hits = 10), \n",
- " ANN(\n",
- " doc_vector=\"title_embedding\", \n",
- " query_vector=\"title_vector\", \n",
- " embedding_model=lambda x: [random() for x in range(768)],\n",
- " hits = 10,\n",
- " label=\"title\"\n",
- " )\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We then define the ranking to be done by the `bm25` rank-profile that is already defined in the application package. We set `list_features=True` to be able to collect ranking-features later in this tutorial. After defining the `match_phase` and the `rank_profile` we can instantiate the `Query` model."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.query import Query, RankProfile\n",
- "\n",
- "rank_profile = RankProfile(name=\"bm25\", list_features=True)\n",
- "\n",
- "query_model = Query(match_phase=match_phase, rank_profile=rank_profile)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Query the vespa app\n",
- "\n",
- "> Send queries via the query API. See the [query page](query.ipynb) for more examples."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can use the `query_model` that we just defined to issue queries to the application via the `query` method."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [],
- "source": [
- "query_result = app.query(\n",
- " query=\"Is remdesivir an effective treatment for COVID-19?\", \n",
- " query_model=query_model\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can see the number of documents that were retrieved by Vespa:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1046"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "query_result.number_documents_retrieved"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "And the number of documents that were returned to us:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "10"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "len(query_result.hits)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Labelled data\n",
- "\n",
- "> How to structure labelled data"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We often need to either evaluate query models or to collect data to improve query models through ML. In both cases we usually need labelled data. Lets create some labelled data to illustrate their expected format and their usage in the library."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Each data point contains a `query_id`, a `query` and `relevant_docs` associated with the query."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "labelled_data = [\n",
- " {\n",
- " \"query_id\": 0, \n",
- " \"query\": \"Intrauterine virus infections and congenital heart disease\",\n",
- " \"relevant_docs\": [{\"id\": 0, \"score\": 1}, {\"id\": 3, \"score\": 1}]\n",
- " },\n",
- " {\n",
- " \"query_id\": 1, \n",
- " \"query\": \"Clinical and immunologic studies in identical twins discordant for systemic lupus erythematosus\",\n",
- " \"relevant_docs\": [{\"id\": 1, \"score\": 1}, {\"id\": 5, \"score\": 1}]\n",
- " }\n",
- "]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Non-relevant documents are assigned `\"score\": 0` by default. Relevant documents will be assigned `\"score\": 1` by default if the field is missing from the labelled data. The defaults for both relevant and non-relevant documents can be modified on the appropriate methods."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Collect training data\n",
- "\n",
- "> Collect training data to analyse and/or improve ranking functions. See the [collect training data page](collect-training-data.ipynb) for more examples."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can colect training data with the [collect_training_data](reference-api.rst#vespa.application.Vespa.collect_training_data) method according to a specific [Query](reference-api.rst#vespa.query.Query) model. Below we will collect two documents for each query in addition to the relevant ones."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>attributeMatch(authors.first)</th>\n",
- " <th>attributeMatch(authors.first).averageWeight</th>\n",
- " <th>attributeMatch(authors.first).completeness</th>\n",
- " <th>attributeMatch(authors.first).fieldCompleteness</th>\n",
- " <th>attributeMatch(authors.first).importance</th>\n",
- " <th>attributeMatch(authors.first).matches</th>\n",
- " <th>attributeMatch(authors.first).maxWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeight</th>\n",
- " <th>attributeMatch(authors.first).normalizedWeightedWeight</th>\n",
- " <th>attributeMatch(authors.first).queryCompleteness</th>\n",
- " <th>...</th>\n",
- " <th>textSimilarity(results).queryCoverage</th>\n",
- " <th>textSimilarity(results).score</th>\n",
- " <th>textSimilarity(title).fieldCoverage</th>\n",
- " <th>textSimilarity(title).order</th>\n",
- " <th>textSimilarity(title).proximity</th>\n",
- " <th>textSimilarity(title).queryCoverage</th>\n",
- " <th>textSimilarity(title).score</th>\n",
- " <th>document_id</th>\n",
- " <th>query_id</th>\n",
- " <th>relevant</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.062500</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.055357</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>2</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>3</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.437500</td>\n",
- " <td>0.142857</td>\n",
- " <td>0.224554</td>\n",
- " <td>3</td>\n",
- " <td>0</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>4</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>213690</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>5</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.285714</td>\n",
- " <td>0.666667</td>\n",
- " <td>0.739583</td>\n",
- " <td>0.571429</td>\n",
- " <td>0.587426</td>\n",
- " <td>225739</td>\n",
- " <td>0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>6</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.111111</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.047222</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>7</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>8</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>9</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.000000</td>\n",
- " <td>0.083333</td>\n",
- " <td>0.041667</td>\n",
- " <td>5</td>\n",
- " <td>1</td>\n",
- " <td>1</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>10</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>176163</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>11</th>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>...</td>\n",
- " <td>0.0</td>\n",
- " <td>0.0</td>\n",
- " <td>0.187500</td>\n",
- " <td>1.000000</td>\n",
- " <td>1.000000</td>\n",
- " <td>0.250000</td>\n",
- " <td>0.612500</td>\n",
- " <td>13597</td>\n",
- " <td>1</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "<p>12 rows × 984 columns</p>\n",
- "</div>"
- ],
- "text/plain": [
- " attributeMatch(authors.first) \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).averageWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).completeness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).fieldCompleteness \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).importance \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).matches \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).maxWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).normalizedWeightedWeight \\\n",
- "0 0.0 \n",
- "1 0.0 \n",
- "2 0.0 \n",
- "3 0.0 \n",
- "4 0.0 \n",
- "5 0.0 \n",
- "6 0.0 \n",
- "7 0.0 \n",
- "8 0.0 \n",
- "9 0.0 \n",
- "10 0.0 \n",
- "11 0.0 \n",
- "\n",
- " attributeMatch(authors.first).queryCompleteness ... \\\n",
- "0 0.0 ... \n",
- "1 0.0 ... \n",
- "2 0.0 ... \n",
- "3 0.0 ... \n",
- "4 0.0 ... \n",
- "5 0.0 ... \n",
- "6 0.0 ... \n",
- "7 0.0 ... \n",
- "8 0.0 ... \n",
- "9 0.0 ... \n",
- "10 0.0 ... \n",
- "11 0.0 ... \n",
- "\n",
- " textSimilarity(results).queryCoverage textSimilarity(results).score \\\n",
- "0 0.0 0.0 \n",
- "1 0.0 0.0 \n",
- "2 0.0 0.0 \n",
- "3 0.0 0.0 \n",
- "4 0.0 0.0 \n",
- "5 0.0 0.0 \n",
- "6 0.0 0.0 \n",
- "7 0.0 0.0 \n",
- "8 0.0 0.0 \n",
- "9 0.0 0.0 \n",
- "10 0.0 0.0 \n",
- "11 0.0 0.0 \n",
- "\n",
- " textSimilarity(title).fieldCoverage textSimilarity(title).order \\\n",
- "0 0.062500 0.000000 \n",
- "1 1.000000 1.000000 \n",
- "2 0.285714 0.666667 \n",
- "3 0.142857 0.000000 \n",
- "4 1.000000 1.000000 \n",
- "5 0.285714 0.666667 \n",
- "6 0.111111 0.000000 \n",
- "7 1.000000 1.000000 \n",
- "8 0.187500 1.000000 \n",
- "9 0.083333 0.000000 \n",
- "10 1.000000 1.000000 \n",
- "11 0.187500 1.000000 \n",
- "\n",
- " textSimilarity(title).proximity textSimilarity(title).queryCoverage \\\n",
- "0 0.000000 0.142857 \n",
- "1 1.000000 1.000000 \n",
- "2 0.739583 0.571429 \n",
- "3 0.437500 0.142857 \n",
- "4 1.000000 1.000000 \n",
- "5 0.739583 0.571429 \n",
- "6 0.000000 0.083333 \n",
- "7 1.000000 1.000000 \n",
- "8 1.000000 0.250000 \n",
- "9 0.000000 0.083333 \n",
- "10 1.000000 1.000000 \n",
- "11 1.000000 0.250000 \n",
- "\n",
- " textSimilarity(title).score document_id query_id relevant \n",
- "0 0.055357 0 0 1 \n",
- "1 1.000000 213690 0 0 \n",
- "2 0.587426 225739 0 0 \n",
- "3 0.224554 3 0 1 \n",
- "4 1.000000 213690 0 0 \n",
- "5 0.587426 225739 0 0 \n",
- "6 0.047222 1 1 1 \n",
- "7 1.000000 176163 1 0 \n",
- "8 0.612500 13597 1 0 \n",
- "9 0.041667 5 1 1 \n",
- "10 1.000000 176163 1 0 \n",
- "11 0.612500 13597 1 0 \n",
- "\n",
- "[12 rows x 984 columns]"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "training_data_batch = app.collect_training_data(\n",
- " labelled_data = labelled_data,\n",
- " id_field = \"id\",\n",
- " query_model = query_model,\n",
- " number_additional_docs = 2\n",
- ")\n",
- "training_data_batch"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Evaluating a query model\n",
- "\n",
- "> Define metrics and evaluate query models. See the [evaluation page](evaluation.ipynb) for more examples."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We will define the following evaluation metrics:\n",
- "* % of documents retrieved per query\n",
- "* recall @ 10 per query\n",
- "* MRR @ 10 per query"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.evaluation import MatchRatio, Recall, ReciprocalRank\n",
- "\n",
- "eval_metrics = [MatchRatio(), Recall(at=10), ReciprocalRank(at=10)]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Evaluate:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>query_id</th>\n",
- " <th>match_ratio_retrieved_docs</th>\n",
- " <th>match_ratio_docs_available</th>\n",
- " <th>match_ratio_value</th>\n",
- " <th>recall_10_value</th>\n",
- " <th>reciprocal_rank_10_value</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0</td>\n",
- " <td>1254</td>\n",
- " <td>233281</td>\n",
- " <td>0.005375</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>1</td>\n",
- " <td>1003</td>\n",
- " <td>233281</td>\n",
- " <td>0.004300</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " query_id match_ratio_retrieved_docs match_ratio_docs_available \\\n",
- "0 0 1254 233281 \n",
- "1 1 1003 233281 \n",
- "\n",
- " match_ratio_value recall_10_value reciprocal_rank_10_value \n",
- "0 0.005375 0.0 0 \n",
- "1 0.004300 0.0 0 "
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "evaluation = app.evaluate(\n",
- " labelled_data = labelled_data,\n",
- " eval_metrics = eval_metrics, \n",
- " query_model = query_model, \n",
- " id_field = \"id\",\n",
- ")\n",
- "evaluation"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/create-and-deploy-vespa-cloud.ipynb b/python/vespa/docs/sphinx/source/create-and-deploy-vespa-cloud.ipynb
deleted file mode 100644
index 4f94ce2d7c4..00000000000
--- a/python/vespa/docs/sphinx/source/create-and-deploy-vespa-cloud.ipynb
+++ /dev/null
@@ -1,993 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Build end-to-end Vespa apps and deploy to Vespa Cloud\n",
- "\n",
- "> Python API to create, modify, deploy and interact with Vespa applications\n",
- "\n",
- "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/vespa-engine/vespa/blob/master/python/vespa/docs/sphinx/source/create-and-deploy-vespa-cloud.ipynb)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This self-contained tutorial will create a simplified text search application from scratch based on the MS MARCO dataset, similar to our [text search tutorials](https://docs.vespa.ai/documentation/tutorials/text-search.html). We will then deploy the app to [Vespa Cloud](https://cloud.vespa.ai/) and interact with it by feeding data, querying and evaluating different query models."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Application package API"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We first create a `Document` instance containing the `Field`s that we want to store in the app. In this case we will keep the application simple and only feed a unique `id`, `title` and `body` of the MS MARCO documents."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import Document, Field\n",
- "\n",
- "document = Document(\n",
- " fields=[\n",
- " Field(name = \"id\", type = \"string\", indexing = [\"attribute\", \"summary\"]),\n",
- " Field(name = \"title\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\"),\n",
- " Field(name = \"body\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\") \n",
- " ]\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The complete `Schema` of our application will be named `msmarco` and contains the `Document` instance that we defined above, the default `FieldSet` indicates that queries will look for matches by searching both in the titles and bodies of the documents. The default `RankProfile` indicates that all the matched documents will be ranked by the `nativeRank` expression involving the title and the body of the matched documents."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import Schema, FieldSet, RankProfile\n",
- "\n",
- "msmarco_schema = Schema(\n",
- " name = \"msmarco\", \n",
- " document = document, \n",
- " fieldsets = [FieldSet(name = \"default\", fields = [\"title\", \"body\"])],\n",
- " rank_profiles = [RankProfile(name = \"default\", first_phase = \"nativeRank(title, body)\")]\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Once the `Schema` is defined, all we have to do is to create our msmarco `ApplicationPackage`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import ApplicationPackage\n",
- "\n",
- "app_package = ApplicationPackage(name = \"msmarco\", schema=msmarco_schema)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "At this point, `app_package` contains all the relevant information required to create our MS MARCO text search app. We now need to deploy it."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Deploy to Vespa Cloud"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To be able to deploy to [Vespa Cloud](https://cloud.vespa.ai/), you need to sign-up, register an application name on the Vespa Cloud console and generate your user API key."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We first create a `VespaCloud` instance that will handle the secure communication with Vespa Cloud servers. In order to do that, all we need is your Vespa Cloud tenant name, the application name that you registered, the user key you generated on the Vespa Cloud console and the application package that we created above."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import VespaCloud\n",
- "\n",
- "vespa_cloud = VespaCloud(\n",
- " tenant=\"vespa-team\", \n",
- " application=\"ms-marco\", \n",
- " key_location=\"/Users/username/sample_application/username.vespa-team.pem\", \n",
- " application_package=app_package\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We then deploy the application to a particular instance (named `from-notebook` in this case) and specify a folder location necessary to store required files such as certificates to allow for secure data exchange between the client and the VespaCloud servers."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Note:** It takes around 15 min to call `cloud.deploy` for the first time, as Vespa Cloud will have the setup the environment. Subsequent calls will be much faster, usually taking less than 10 seconds."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "app = vespa_cloud.deploy(\n",
- " instance='from-notebook', \n",
- " disk_folder=\"/Users/username/sample_application\"\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `app` variable above will hold a `Vespa` instance that will be used to connect and interact with our text search application throughtout this tutorial."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Feed data to the app "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We now have our text search app up and running. We can start to feed data to it. We have pre-processed and sampled some MS MARCO data to use in this tutorial. We can load 996 documents that we want to feed and check the first two documents in this sample."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(996, 3)"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pandas import read_csv\n",
- "\n",
- "docs = read_csv(\"https://thigm85.github.io/data/msmarco/docs.tsv\", sep = \"\\t\")\n",
- "docs.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>id</th>\n",
- " <th>title</th>\n",
- " <th>body</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>D2185715</td>\n",
- " <td>What Is an Appropriate Gift for a Bris</td>\n",
- " <td>Hub Pages Religion and Philosophy Judaism...</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>D2819479</td>\n",
- " <td>lunge</td>\n",
- " <td>1lungenoun ˈlənj Popularity Bottom 40 of...</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " id title \\\n",
- "0 D2185715 What Is an Appropriate Gift for a Bris \n",
- "1 D2819479 lunge \n",
- "\n",
- " body \n",
- "0 Hub Pages Religion and Philosophy Judaism... \n",
- "1 1lungenoun ˈlənj Popularity Bottom 40 of... "
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "docs.head(2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To feed the data we need to specify the `schema` that we are sending data to. We named our schema `msmarco` in a previous section. Each data point needs to have a unique `data_id` associated with it, independent of having an id field or not. The `fields` should be a dict containing all the fields in the schema, which are `id`, `title` and `body` in our case. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "for idx, row in docs.iterrows():\n",
- " response = app.feed_data_point(\n",
- " schema = \"msmarco\", \n",
- " data_id = str(row[\"id\"]), \n",
- " fields = {\n",
- " \"id\": str(row[\"id\"]), \n",
- " \"title\": str(row[\"title\"]), \n",
- " \"body\": str(row[\"body\"])\n",
- " }\n",
- " )"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Make a simple query"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Once our application is fed we can start sending queries to it. The MS MARCO app expects to receive questions as queries and the goal of the application is to return documents that are relevant to the questions made."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In the example below, we will send a question via the `query` parameter. In addition, we need to specify how we want the documents to be matched and ranked. We do this by specifying a `Query` model. The query model below will have the `OR` operator in the match phase, indicating that the application will match all the documents which have at least one query term within the title or the body (due to the default `FieldSet` we defined earlier) of the document. And we will rank all the matched documents by the default `RankProfile` that we defined earlier."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.query import Query, OR, RankProfile as Ranking\n",
- "\n",
- "results = app.query(\n",
- " query=\"Where is my text?\", \n",
- " query_model = Query(\n",
- " match_phase=OR(), \n",
- " rank_profile=Ranking(name=\"default\")\n",
- " ),\n",
- " hits = 2\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In addition to the `query` and `query_model` parameters, we can specify a multitude of relevant Vespa parameters such as the number of `hits` that we want Vespa to return. We chose `hits=2` for simplicity in this tutorial."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "2"
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "len(results.hits)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Change the application package and redeploy"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can also make specific changes to our application by changing the application package and redeploying. Lets add a new rank profile based on BM25 to our `Schema`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "app_package.schema.add_rank_profile(\n",
- " RankProfile(name = \"bm25\", inherits = \"default\", first_phase = \"bm25(title) + bm25(body)\")\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "After that we can redeploy our application, similar to what we did earlier:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "app = vespa_cloud.deploy('from-notebook', \"/Users/username/sample_application\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can then use the newly created `bm25` rank profile to make queries:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "2"
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "results = app.query(\n",
- " query=\"Where is my text?\", \n",
- " query_model = Query(\n",
- " match_phase=OR(), \n",
- " rank_profile=Ranking(name=\"bm25\")\n",
- " ),\n",
- " hits = 2\n",
- ")\n",
- "len(results.hits)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Compare query models"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When we are building a search application, we often want to experiment and compare different query models. In this section we want to show how easy it is to compare different query models in Vespa."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Lets load some labelled data where each data point contains a `query_id`, a `query` and a list of `relevant_docs` associated with the query. In this case, we have only one relevant document for each query."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
- "outputs": [],
- "source": [
- "import requests, json\n",
- "\n",
- "labelled_data = json.loads(\n",
- " requests.get(\"https://thigm85.github.io/data/msmarco/query-labels.json\").text\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Following we can see two examples of the labelled data:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[{'query_id': '1',\n",
- " 'query': 'what county is aspen co',\n",
- " 'relevant_docs': [{'id': 'D1098819'}]},\n",
- " {'query_id': '2',\n",
- " 'query': 'where is aeropostale located',\n",
- " 'relevant_docs': [{'id': 'D2268823'}]}]"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "labelled_data[0:2]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Lets define two `Query` models to be compared. We are going to use the same `OR` operator in the match phase and compare the `default` and `bm25` rank profiles."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {},
- "outputs": [],
- "source": [
- "default_ranking = Query(\n",
- " match_phase=OR(), \n",
- " rank_profile=Ranking(name=\"default\")\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {},
- "outputs": [],
- "source": [
- "bm25_ranking = Query(\n",
- " match_phase=OR(), \n",
- " rank_profile=Ranking(name=\"bm25\")\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Now we will chose which evaluation metrics we want to look at. In this case we will chose the `MatchRatio` to check how many documents have been matched by the query, the `Recall` at 10 and the `ReciprocalRank` at 10."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.evaluation import MatchRatio, Recall, ReciprocalRank\n",
- "\n",
- "eval_metrics = [MatchRatio(), Recall(at = 10), ReciprocalRank(at = 10)]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We now can run the `evaluation` method for each `Query` model. This will make queries to the application and process the results to compute the pre-defined `eval_metrics` defined above."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [],
- "source": [
- "default_evaluation = app.evaluate(\n",
- " labelled_data=labelled_data, \n",
- " eval_metrics=eval_metrics, \n",
- " query_model=default_ranking, \n",
- " id_field=\"id\",\n",
- " timeout=5,\n",
- " hits=10\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {},
- "outputs": [],
- "source": [
- "bm25_evaluation = app.evaluate(\n",
- " labelled_data=labelled_data, \n",
- " eval_metrics=eval_metrics, \n",
- " query_model=bm25_ranking, \n",
- " id_field=\"id\",\n",
- " timeout=5,\n",
- " hits=10\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can then merge the DataFrames returned by the `evaluation` method and start to analyse the results."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>query_id</th>\n",
- " <th>match_ratio_retrieved_docs_default</th>\n",
- " <th>match_ratio_docs_available_default</th>\n",
- " <th>match_ratio_value_default</th>\n",
- " <th>recall_10_value_default</th>\n",
- " <th>reciprocal_rank_10_value_default</th>\n",
- " <th>match_ratio_retrieved_docs_bm25</th>\n",
- " <th>match_ratio_docs_available_bm25</th>\n",
- " <th>match_ratio_value_bm25</th>\n",
- " <th>recall_10_value_bm25</th>\n",
- " <th>reciprocal_rank_10_value_bm25</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>1</td>\n",
- " <td>914</td>\n",
- " <td>997</td>\n",
- " <td>0.916750</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000</td>\n",
- " <td>914</td>\n",
- " <td>997</td>\n",
- " <td>0.916750</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000000</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>2</td>\n",
- " <td>896</td>\n",
- " <td>997</td>\n",
- " <td>0.898696</td>\n",
- " <td>1.0</td>\n",
- " <td>0.125</td>\n",
- " <td>896</td>\n",
- " <td>997</td>\n",
- " <td>0.898696</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000000</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>2</th>\n",
- " <td>3</td>\n",
- " <td>970</td>\n",
- " <td>997</td>\n",
- " <td>0.972919</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000</td>\n",
- " <td>970</td>\n",
- " <td>997</td>\n",
- " <td>0.972919</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000000</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>3</th>\n",
- " <td>4</td>\n",
- " <td>981</td>\n",
- " <td>997</td>\n",
- " <td>0.983952</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000</td>\n",
- " <td>981</td>\n",
- " <td>997</td>\n",
- " <td>0.983952</td>\n",
- " <td>1.0</td>\n",
- " <td>1.000000</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>4</th>\n",
- " <td>5</td>\n",
- " <td>748</td>\n",
- " <td>997</td>\n",
- " <td>0.750251</td>\n",
- " <td>1.0</td>\n",
- " <td>0.500</td>\n",
- " <td>748</td>\n",
- " <td>997</td>\n",
- " <td>0.750251</td>\n",
- " <td>1.0</td>\n",
- " <td>0.333333</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " query_id match_ratio_retrieved_docs_default \\\n",
- "0 1 914 \n",
- "1 2 896 \n",
- "2 3 970 \n",
- "3 4 981 \n",
- "4 5 748 \n",
- "\n",
- " match_ratio_docs_available_default match_ratio_value_default \\\n",
- "0 997 0.916750 \n",
- "1 997 0.898696 \n",
- "2 997 0.972919 \n",
- "3 997 0.983952 \n",
- "4 997 0.750251 \n",
- "\n",
- " recall_10_value_default reciprocal_rank_10_value_default \\\n",
- "0 1.0 1.000 \n",
- "1 1.0 0.125 \n",
- "2 1.0 1.000 \n",
- "3 1.0 1.000 \n",
- "4 1.0 0.500 \n",
- "\n",
- " match_ratio_retrieved_docs_bm25 match_ratio_docs_available_bm25 \\\n",
- "0 914 997 \n",
- "1 896 997 \n",
- "2 970 997 \n",
- "3 981 997 \n",
- "4 748 997 \n",
- "\n",
- " match_ratio_value_bm25 recall_10_value_bm25 reciprocal_rank_10_value_bm25 \n",
- "0 0.916750 1.0 1.000000 \n",
- "1 0.898696 1.0 1.000000 \n",
- "2 0.972919 1.0 1.000000 \n",
- "3 0.983952 1.0 1.000000 \n",
- "4 0.750251 1.0 0.333333 "
- ]
- },
- "execution_count": 23,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pandas import merge\n",
- "\n",
- "eval_comparison = merge(\n",
- " left=default_evaluation, \n",
- " right=bm25_evaluation, \n",
- " on=\"query_id\", \n",
- " suffixes=('_default', '_bm25')\n",
- ")\n",
- "eval_comparison.head()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Notice that we expect to observe the same match ratio for both query models since they use the same `OR` operator."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>match_ratio_value_default</th>\n",
- " <th>match_ratio_value_bm25</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>mean</th>\n",
- " <td>0.866650</td>\n",
- " <td>0.866650</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>std</th>\n",
- " <td>0.181307</td>\n",
- " <td>0.181307</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " match_ratio_value_default match_ratio_value_bm25\n",
- "mean 0.866650 0.866650\n",
- "std 0.181307 0.181307"
- ]
- },
- "execution_count": 24,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "eval_comparison[[\"match_ratio_value_default\", \"match_ratio_value_bm25\"]].describe().loc[[\"mean\", \"std\"]]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `bm25` rank profile obtained a significantly higher recall than the `default`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>recall_10_value_default</th>\n",
- " <th>recall_10_value_bm25</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>mean</th>\n",
- " <td>0.840000</td>\n",
- " <td>0.960000</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>std</th>\n",
- " <td>0.368453</td>\n",
- " <td>0.196946</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " recall_10_value_default recall_10_value_bm25\n",
- "mean 0.840000 0.960000\n",
- "std 0.368453 0.196946"
- ]
- },
- "execution_count": 25,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "eval_comparison[[\"recall_10_value_default\", \"recall_10_value_bm25\"]].describe().loc[[\"mean\", \"std\"]]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Similarly, `bm25` also get a significantly higher reciprocal rank value when compared to the `default` rank profile."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>reciprocal_rank_10_value_default</th>\n",
- " <th>reciprocal_rank_10_value_bm25</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>mean</th>\n",
- " <td>0.724750</td>\n",
- " <td>0.943333</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>std</th>\n",
- " <td>0.399118</td>\n",
- " <td>0.216103</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " reciprocal_rank_10_value_default reciprocal_rank_10_value_bm25\n",
- "mean 0.724750 0.943333\n",
- "std 0.399118 0.216103"
- ]
- },
- "execution_count": 26,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "eval_comparison[[\"reciprocal_rank_10_value_default\", \"reciprocal_rank_10_value_bm25\"]].describe().loc[[\"mean\", \"std\"]]"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/create-and-deploy-vespa-docker.ipynb b/python/vespa/docs/sphinx/source/create-and-deploy-vespa-docker.ipynb
deleted file mode 100644
index 13e74aa173d..00000000000
--- a/python/vespa/docs/sphinx/source/create-and-deploy-vespa-docker.ipynb
+++ /dev/null
@@ -1,214 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Deploy Vespa apps to Docker\n",
- "\n",
- "> Python API to deploy Vespa applications to Docker containers."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This tutorial illustrate how to deploy a Vespa application to a Docker container in your local machine. It is required to have Docker installed in the machine you are running this tutorial from. For that reason we cannot run this tutorial in Google Colab as Docker is not available on their standard runtime machines."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Application package API"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We first create a `Document` instance containing the `Field`s that we want to store in the app. In this case we will keep the application simple and only feed a unique `id`, `title` and `body` of the MS MARCO documents."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import Document, Field\n",
- "\n",
- "document = Document(\n",
- " fields=[\n",
- " Field(name = \"id\", type = \"string\", indexing = [\"attribute\", \"summary\"]),\n",
- " Field(name = \"title\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\"),\n",
- " Field(name = \"body\", type = \"string\", indexing = [\"index\", \"summary\"], index = \"enable-bm25\") \n",
- " ]\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The complete `Schema` of our application will be named `msmarco` and contains the `Document` instance that we defined above, the default `FieldSet` indicates that queries will look for matches by searching both in the titles and bodies of the documents. The default `RankProfile` indicates that all the matched documents will be ranked by the `nativeRank` expression involving the title and the body of the matched documents."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import Schema, FieldSet, RankProfile\n",
- "\n",
- "msmarco_schema = Schema(\n",
- " name = \"msmarco\", \n",
- " document = document, \n",
- " fieldsets = [FieldSet(name = \"default\", fields = [\"title\", \"body\"])],\n",
- " rank_profiles = [RankProfile(name = \"default\", first_phase = \"nativeRank(title, body)\")]\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Once the `Schema` is defined, all we have to do is to create our msmarco `ApplicationPackage`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import ApplicationPackage\n",
- "\n",
- "app_package = ApplicationPackage(name = \"msmarco\", schema=msmarco_schema)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "At this point, `app_package` contains all the relevant information required to create our MS MARCO text search app. We now need to deploy it."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Deploy to a Docker container"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For the following to work you need to run this from a machine with Docker installed. We first create a `VespaDocker` instance based on the application package."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.package import VespaDocker\n",
- "\n",
- "vespa_docker = VespaDocker(application_package=app_package)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We then call the `deploy` method and specify a `disk_folder`. Behind the scenes, `pyvespa` will write the Vespa config files and store them in the `disk_folder`, it will then run a Vespa engine Docker container and deploy those config files in the container."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "app = vespa_docker.deploy(disk_folder=\"/Users/username/sample_application\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The app variable above will hold a `Vespa` instance that will be used to connect and interact with our text search application. We can see the deployment message returned by the Vespa engine:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[\"Uploading application '/app/application' using http://localhost:19071/application/v2/tenant/default/session\",\n",
- " \"Session 18 for tenant 'default' created.\",\n",
- " 'Preparing session 18 using http://localhost:19071/application/v2/tenant/default/session/18/prepared',\n",
- " \"WARNING: Host named 'msmarco' may not receive any config since it is not a canonical hostname. Disregard this warning when testing in a Docker container.\",\n",
- " \"Session 18 for tenant 'default' prepared.\",\n",
- " 'Activating session 18 using http://localhost:19071/application/v2/tenant/default/session/18/active',\n",
- " \"Session 18 for tenant 'default' activated.\",\n",
- " 'Checksum: 09203c16fa5f582b712711bb98932812',\n",
- " 'Timestamp: 1598011224920',\n",
- " 'Generation: 18',\n",
- " '']"
- ]
- },
- "execution_count": null,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "app.deployment_message"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Interact with the deployed application"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "From this point on you can interact with the deployed application the same way we did in the following tutorials:\n",
- "* [How to connect with running Vespa instances](connect-to-vespa-instance.ipynb)\n",
- "* [Build end-to-end Vespa apps and deploy to Vespa Cloud](create-and-deploy-vespa-cloud.ipynb)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "vespa",
- "language": "python",
- "name": "vespa"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.3"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/deploy-application.ipynb b/python/vespa/docs/sphinx/source/deploy-application.ipynb
deleted file mode 100644
index 9bef636f889..00000000000
--- a/python/vespa/docs/sphinx/source/deploy-application.ipynb
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Deploy Vespa applications\n",
- "\n",
- "> Python API to deploy application packages to Vespa Cloud or to Docker containers"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "TBD"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/python/vespa/docs/sphinx/source/evaluation.ipynb b/python/vespa/docs/sphinx/source/evaluation.ipynb
deleted file mode 100644
index 54026cd5544..00000000000
--- a/python/vespa/docs/sphinx/source/evaluation.ipynb
+++ /dev/null
@@ -1,297 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Evaluate query models\n",
- "\n",
- "> Define metrics and evaluate query models"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Example setup"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Connect to the application and define a query model."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.application import Vespa\n",
- "from vespa.query import Query, RankProfile, OR\n",
- "\n",
- "app = Vespa(url = \"https://api.cord19.vespa.ai\")\n",
- "query_model = Query(\n",
- " match_phase = OR(),\n",
- " rank_profile = RankProfile(name=\"bm25\", list_features=True))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Define some labelled data."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "labelled_data = [\n",
- " {\n",
- " \"query_id\": 0, \n",
- " \"query\": \"Intrauterine virus infections and congenital heart disease\",\n",
- " \"relevant_docs\": [{\"id\": 0, \"score\": 1}, {\"id\": 3, \"score\": 1}]\n",
- " },\n",
- " {\n",
- " \"query_id\": 1, \n",
- " \"query\": \"Clinical and immunologic studies in identical twins discordant for systemic lupus erythematosus\",\n",
- " \"relevant_docs\": [{\"id\": 1, \"score\": 1}, {\"id\": 5, \"score\": 1}]\n",
- " }\n",
- "]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Define metrics"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.evaluation import MatchRatio, Recall, ReciprocalRank\n",
- "\n",
- "eval_metrics = [MatchRatio(), Recall(at=10), ReciprocalRank(at=10)]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Evaluate in batch"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>query_id</th>\n",
- " <th>match_ratio_retrieved_docs</th>\n",
- " <th>match_ratio_docs_available</th>\n",
- " <th>match_ratio_value</th>\n",
- " <th>recall_10_value</th>\n",
- " <th>reciprocal_rank_10_value</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0</td>\n",
- " <td>189800</td>\n",
- " <td>233281</td>\n",
- " <td>0.813611</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>1</td>\n",
- " <td>207809</td>\n",
- " <td>233281</td>\n",
- " <td>0.890810</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " query_id match_ratio_retrieved_docs match_ratio_docs_available \\\n",
- "0 0 189800 233281 \n",
- "1 1 207809 233281 \n",
- "\n",
- " match_ratio_value recall_10_value reciprocal_rank_10_value \n",
- "0 0.813611 0.0 0 \n",
- "1 0.890810 0.0 0 "
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "evaluation = app.evaluate(\n",
- " labelled_data = labelled_data,\n",
- " eval_metrics = eval_metrics, \n",
- " query_model = query_model, \n",
- " id_field = \"id\",\n",
- ")\n",
- "evaluation"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Evaluate specific query\n",
- "\n",
- "> You can have finer control with the `evaluate_query` method."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "<div>\n",
- "<style scoped>\n",
- " .dataframe tbody tr th:only-of-type {\n",
- " vertical-align: middle;\n",
- " }\n",
- "\n",
- " .dataframe tbody tr th {\n",
- " vertical-align: top;\n",
- " }\n",
- "\n",
- " .dataframe thead th {\n",
- " text-align: right;\n",
- " }\n",
- "</style>\n",
- "<table border=\"1\" class=\"dataframe\">\n",
- " <thead>\n",
- " <tr style=\"text-align: right;\">\n",
- " <th></th>\n",
- " <th>query_id</th>\n",
- " <th>match_ratio_retrieved_docs</th>\n",
- " <th>match_ratio_docs_available</th>\n",
- " <th>match_ratio_value</th>\n",
- " <th>recall_10_value</th>\n",
- " <th>reciprocal_rank_10_value</th>\n",
- " </tr>\n",
- " </thead>\n",
- " <tbody>\n",
- " <tr>\n",
- " <th>0</th>\n",
- " <td>0</td>\n",
- " <td>189800</td>\n",
- " <td>233281</td>\n",
- " <td>0.813611</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " <tr>\n",
- " <th>1</th>\n",
- " <td>1</td>\n",
- " <td>207809</td>\n",
- " <td>233281</td>\n",
- " <td>0.890810</td>\n",
- " <td>0.0</td>\n",
- " <td>0</td>\n",
- " </tr>\n",
- " </tbody>\n",
- "</table>\n",
- "</div>"
- ],
- "text/plain": [
- " query_id match_ratio_retrieved_docs match_ratio_docs_available \\\n",
- "0 0 189800 233281 \n",
- "1 1 207809 233281 \n",
- "\n",
- " match_ratio_value recall_10_value reciprocal_rank_10_value \n",
- "0 0.813611 0.0 0 \n",
- "1 0.890810 0.0 0 "
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from pandas import concat, DataFrame\n",
- "\n",
- "evaluation = []\n",
- "for query_data in labelled_data:\n",
- " query_evaluation = app.evaluate_query(\n",
- " eval_metrics = eval_metrics, \n",
- " query_model = query_model, \n",
- " query_id = query_data[\"query_id\"], \n",
- " query = query_data[\"query\"], \n",
- " id_field = \"id\",\n",
- " relevant_docs = query_data[\"relevant_docs\"],\n",
- " default_score = 0\n",
- " )\n",
- " evaluation.append(query_evaluation)\n",
- "evaluation = DataFrame.from_records(evaluation)\n",
- "evaluation"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/howto.rst b/python/vespa/docs/sphinx/source/howto.rst
deleted file mode 100644
index 680e5f1575c..00000000000
--- a/python/vespa/docs/sphinx/source/howto.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-How-to guides
-=============
-
-.. toctree::
- :hidden:
-
- application-package
- deploy-application
- query-model
- query
- evaluation
- collect-training-data
diff --git a/python/vespa/docs/sphinx/source/index.rst b/python/vespa/docs/sphinx/source/index.rst
deleted file mode 100644
index 03ef20c133e..00000000000
--- a/python/vespa/docs/sphinx/source/index.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. pyvespa documentation master file, created by
- sphinx-quickstart on Wed Aug 26 11:11:55 2020.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Vespa python API
-================
-
-.. toctree::
- :hidden:
-
- install
- quickstart
- howto
- reference-api
-
-Vespa_ is the scalable open-sourced serving engine that enable us to store, compute and rank big data at user
-serving time. ``pyvespa`` provides a python API to Vespa. It allow us to create, modify, deploy and interact with
-running Vespa instances. The main goal of the library is to allow for faster prototyping and to facilitate
-Machine Learning experiments for Vespa applications.
-
-.. _Vespa: https://vespa.ai/
-
-
-Install
-+++++++
-
-You can install ``pyvespa`` via ``pip``:
-
-.. code:: bash
-
- pip install pyvespa
-
-Quick-start
-+++++++++++
-
-The best way to get started is by following the tutorials below. You can easily run them yourself on Google Colab
-by clicking on the badge at the top of the tutorial.
-
-
-- :doc:`connect-to-vespa-instance`
-- :doc:`create-and-deploy-vespa-cloud`
-- :doc:`create-and-deploy-vespa-docker`
-
-
-How-to guides
-+++++++++++++
-
-- :doc:`application-package`
-- :doc:`deploy-application`
-- :doc:`query-model`
-- :doc:`query`
-- :doc:`evaluation`
-- :doc:`collect-training-data`
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/python/vespa/docs/sphinx/source/install.rst b/python/vespa/docs/sphinx/source/install.rst
deleted file mode 100644
index 7cf6b16eaa5..00000000000
--- a/python/vespa/docs/sphinx/source/install.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Install pyvespa
-===============
-
-To install ``pyvespa`` type
-
-.. code:: bash
-
- pip install pyvespa
diff --git a/python/vespa/docs/sphinx/source/query-model.ipynb b/python/vespa/docs/sphinx/source/query-model.ipynb
deleted file mode 100644
index bd2e73601dc..00000000000
--- a/python/vespa/docs/sphinx/source/query-model.ipynb
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Query models\n",
- "\n",
- "> Python API define query models"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "TBD"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/python/vespa/docs/sphinx/source/query.ipynb b/python/vespa/docs/sphinx/source/query.ipynb
deleted file mode 100644
index ec1d5e3ec01..00000000000
--- a/python/vespa/docs/sphinx/source/query.ipynb
+++ /dev/null
@@ -1,297 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Query Vespa applications\n",
- "\n",
- "> Python API to query Vespa applications"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can connect to the CORD-19 Search app and use it to exemplify the query API"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.application import Vespa\n",
- "\n",
- "app = Vespa(url = \"https://api.cord19.vespa.ai\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Specify the request body\n",
- "\n",
- "> Full flexibility by specifying the entire request body"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "body = {\n",
- " 'yql': 'select title, abstract from sources * where userQuery();',\n",
- " 'hits': 5,\n",
- " 'query': 'Is remdesivir an effective treatment for COVID-19?',\n",
- " 'type': 'any',\n",
- " 'ranking': 'bm25'\n",
- "}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "results = app.query(body=body)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "202768"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "results.number_documents_retrieved"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Specify a query model"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Query + term-matching + rank profile"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.query import Query, OR, RankProfile\n",
- "\n",
- "results = app.query(\n",
- " query=\"Is remdesivir an effective treatment for COVID-19?\", \n",
- " query_model = Query(\n",
- " match_phase=OR(), \n",
- " rank_profile=RankProfile(name=\"bm25\")\n",
- " )\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "202768"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "results.number_documents_retrieved"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Query + term-matching + ann operator + rank_profile"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "from vespa.query import Query, ANN, WeakAnd, Union, RankProfile\n",
- "from random import random\n",
- "\n",
- "match_phase = Union(\n",
- " WeakAnd(hits = 10), \n",
- " ANN(\n",
- " doc_vector=\"title_embedding\", \n",
- " query_vector=\"title_vector\", \n",
- " embedding_model=lambda x: [random() for x in range(768)],\n",
- " hits = 10,\n",
- " label=\"title\"\n",
- " )\n",
- ")\n",
- "rank_profile = RankProfile(name=\"bm25\", list_features=True)\n",
- "query_model = Query(match_phase=match_phase, rank_profile=rank_profile)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "results = app.query(query=\"Is remdesivir an effective treatment for COVID-19?\", \n",
- " query_model=query_model)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1049"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "results.number_documents_retrieved"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Recall specific documents"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Let's take a look at the top 3 ids from the last query."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[198698, 120155, 120154]"
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "top_ids = [hit[\"fields\"][\"id\"] for hit in results.hits[0:3]]\n",
- "top_ids"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Assume that we now want to retrieve the second and third ids above. We can do so with the `recall` argument."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [],
- "source": [
- "results_with_recall = app.query(query=\"Is remdesivir an effective treatment for COVID-19?\", \n",
- " query_model=query_model,\n",
- " recall = (\"id\", top_ids[1:3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "It will only retrieve the documents with Vespa field `id` that is defined on the list that is inside the tuple."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[120155, 120154]"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "id_recalled = [hit[\"fields\"][\"id\"] for hit in results_with_recall.hits]\n",
- "id_recalled"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.5"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python/vespa/docs/sphinx/source/quickstart.rst b/python/vespa/docs/sphinx/source/quickstart.rst
deleted file mode 100644
index e740b89b7f9..00000000000
--- a/python/vespa/docs/sphinx/source/quickstart.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-Quick-start
-===========
-
-The best way to get started is by following the tutorials below. You can easily run them yourself on Google Colab
-by clicking on the badge at the top of the tutorial.
-
-.. toctree::
-
- connect-to-vespa-instance
- create-and-deploy-vespa-cloud
- create-and-deploy-vespa-docker
diff --git a/python/vespa/docs/sphinx/source/reference-api.rst b/python/vespa/docs/sphinx/source/reference-api.rst
deleted file mode 100644
index a8bd94b9e9f..00000000000
--- a/python/vespa/docs/sphinx/source/reference-api.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-Reference API
-=============
-
-vespa.application module
-------------------------
-
-.. automodule:: vespa.application
- :members:
- :undoc-members:
- :show-inheritance:
- :special-members: __init__
-
-vespa.evaluation module
------------------------
-
-.. automodule:: vespa.evaluation
- :members:
- :undoc-members:
- :show-inheritance:
-
-vespa.package module
---------------------
-
-.. automodule:: vespa.package
- :members:
- :undoc-members:
- :show-inheritance:
-
-vespa.query module
-------------------
-
-.. automodule:: vespa.query
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/python/vespa/docs/sphinx/source/requirements.txt b/python/vespa/docs/sphinx/source/requirements.txt
deleted file mode 100644
index 261dd62a660..00000000000
--- a/python/vespa/docs/sphinx/source/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-python/vespa
-sphinx>=1.4
-ipykernel
-nbsphinx
-sphinx-rtd-theme \ No newline at end of file
diff --git a/python/vespa/setup.py b/python/vespa/setup.py
deleted file mode 100644
index 8a1bcd0a6b6..00000000000
--- a/python/vespa/setup.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os
-import setuptools
-
-
-def get_target_version():
- build_nr = os.environ.get("GITHUB_RUN_NUMBER", "0+dev")
- version = "0.1"
- return "{}.{}".format(version, build_nr)
-
-
-min_python = "3.6"
-
-setuptools.setup(
- name="pyvespa",
- version=get_target_version(),
- description="Python API for vespa.ai",
- keywords="vespa, search engine, data science",
- author="Thiago G. Martins",
- author_email="tmartins@verizonmedia.com",
- license=(
- "Apache Software License 2.0",
- "OSI Approved :: Apache Software License",
- ),
- packages=setuptools.find_packages(),
- include_package_data=True,
- install_requires=["requests", "pandas", "docker", "jinja2", "cryptography"],
- python_requires=">=3.6",
- zip_safe=False,
- data_files=[
- (
- "templates",
- [
- "vespa/templates/hosts.xml",
- "vespa/templates/services.xml",
- "vespa/templates/schema.txt",
- ],
- )
- ],
-)
diff --git a/python/vespa/vespa/_nbdev.py b/python/vespa/vespa/_nbdev.py
deleted file mode 100644
index b68d7b2f4bc..00000000000
--- a/python/vespa/vespa/_nbdev.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# AUTOGENERATED BY NBDEV! DO NOT EDIT!
-
-__all__ = ["index", "modules", "custom_doc_links", "git_url"]
-
-index = {}
-
-modules = []
-
-doc_url = "https://vespa-engine.github.io/vespa/"
-
-git_url = "https://github.com/vespa-engine/vespa/tree/master/"
-
-def custom_doc_links(name): return None
diff --git a/python/vespa/vespa/application.py b/python/vespa/vespa/application.py
deleted file mode 100644
index c11e56d2125..00000000000
--- a/python/vespa/vespa/application.py
+++ /dev/null
@@ -1,301 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-from typing import Optional, Dict, Tuple, List
-from pandas import DataFrame
-from requests import post
-from requests.models import Response
-
-from vespa.query import Query, VespaResult
-from vespa.evaluation import EvalMetric
-
-
-class Vespa(object):
- def __init__(
- self,
- url: str,
- port: Optional[int] = None,
- deployment_message: Optional[List[str]] = None,
- cert: Optional[str] = None,
- ) -> None:
- """
- Establish a connection with a Vespa application.
-
- :param url: Vespa instance URL.
- :param port: Vespa instance port.
- :param deployment_message: Message returned by Vespa engine after deployment. Used internally by deploy methods.
- :param cert: Path to certificate and key file.
-
- >>> Vespa(url = "https://cord19.vespa.ai")
- >>> Vespa(url = "http://localhost", port = 8080)
- >>> Vespa(url = "https://api.vespa-external.aws.oath.cloud", port = 4443, cert = "/path/to/cert-and-key.pem")
-
- """
- self.url = url
- self.port = port
- self.deployment_message = deployment_message
- self.cert = cert
-
- if port is None:
- self.end_point = self.url
- else:
- self.end_point = str(url).rstrip("/") + ":" + str(port)
- self.search_end_point = self.end_point + "/search/"
-
- def __repr__(self):
- if self.port:
- return "Vespa({}, {})".format(self.url, self.port)
- else:
- return "Vespa({})".format(self.url)
-
- def query(
- self,
- body: Optional[Dict] = None,
- query: Optional[str] = None,
- query_model: Optional[Query] = None,
- debug_request: bool = False,
- recall: Optional[Tuple] = None,
- **kwargs
- ) -> VespaResult:
- """
- Send a query request to the Vespa application.
-
- Either send 'body' containing all the request parameters or specify 'query' and 'query_model'.
-
- :param body: Dict containing all the request parameters.
- :param query: Query string
- :param query_model: Query model
- :param debug_request: return request body for debugging instead of sending the request.
- :param recall: Tuple of size 2 where the first element is the name of the field to use to recall and the
- second element is a list of the values to be recalled.
- :param kwargs: Additional parameters to be sent along the request.
- :return: Either the request body if debug_request is True or the result from the Vespa application
- """
-
- if body is None:
- assert query is not None, "No 'query' specified."
- assert query_model is not None, "No 'query_model' specified."
- body = query_model.create_body(query=query)
- if recall is not None:
- body.update(
- {
- "recall": "+("
- + " ".join(
- ["{}:{}".format(recall[0], str(doc)) for doc in recall[1]]
- )
- + ")"
- }
- )
-
- body.update(kwargs)
-
- if debug_request:
- return VespaResult(vespa_result={}, request_body=body)
- else:
- r = post(self.search_end_point, json=body, cert=self.cert)
- return VespaResult(vespa_result=r.json())
-
- def feed_data_point(self, schema: str, data_id: str, fields: Dict) -> Response:
- """
- Feed a data point to a Vespa app.
-
- :param schema: The schema that we are sending data to.
- :param data_id: Unique id associated with this data point.
- :param fields: Dict containing all the fields required by the `schema`.
- :return: Response of the HTTP POST request.
- """
- end_point = "{}/document/v1/{}/{}/docid/{}".format(
- self.end_point, schema, schema, str(data_id)
- )
- vespa_format = {"fields": fields}
- response = post(end_point, json=vespa_format, cert=self.cert)
- return response
-
- def collect_training_data_point(
- self,
- query: str,
- query_id: str,
- relevant_id: str,
- id_field: str,
- query_model: Query,
- number_additional_docs: int,
- relevant_score: int = 1,
- default_score: int = 0,
- **kwargs
- ) -> List[Dict]:
- """
- Collect training data based on a single query
-
- :param query: Query string.
- :param query_id: Query id represented as str.
- :param relevant_id: Relevant id represented as a str.
- :param id_field: The Vespa field representing the document id.
- :param query_model: Query model.
- :param number_additional_docs: Number of additional documents to retrieve for each relevant document.
- :param relevant_score: Score to assign to relevant documents. Default to 1.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :param kwargs: Extra keyword arguments to be included in the Vespa Query.
- :return: List of dicts containing the document id (document_id), query id (query_id), scores (relevant)
- and vespa rank features returned by the Query model RankProfile used.
- """
-
- assert (
- query_model.rank_profile.list_features == "true"
- ), "Enable rank features via RankProfile is necessary."
-
- relevant_id_result = self.query(
- query=query,
- query_model=query_model,
- recall=(id_field, [relevant_id]),
- **kwargs
- )
- hits = relevant_id_result.hits
- features = []
- if len(hits) == 1 and hits[0]["fields"][id_field] == relevant_id:
- random_hits_result = self.query(
- query=query,
- query_model=query_model,
- hits=number_additional_docs,
- **kwargs
- )
- hits.extend(random_hits_result.hits)
-
- features = annotate_data(
- hits=hits,
- query_id=query_id,
- id_field=id_field,
- relevant_id=relevant_id,
- relevant_score=relevant_score,
- default_score=default_score,
- )
- return features
-
- def collect_training_data(
- self,
- labelled_data: List[Dict],
- id_field: str,
- query_model: Query,
- number_additional_docs: int,
- relevant_score: int = 1,
- default_score: int = 0,
- **kwargs
- ) -> DataFrame:
- """
- Collect training data based on a set of labelled data.
-
- :param labelled_data: Labelled data containing query, query_id and relevant ids.
- :param id_field: The Vespa field representing the document id.
- :param query_model: Query model.
- :param number_additional_docs: Number of additional documents to retrieve for each relevant document.
- :param relevant_score: Score to assign to relevant documents. Default to 1.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :param kwargs: Extra keyword arguments to be included in the Vespa Query.
- :return: DataFrame containing document id (document_id), query id (query_id), scores (relevant)
- and vespa rank features returned by the Query model RankProfile used.
- """
-
- training_data = []
- for query_data in labelled_data:
- for doc_data in query_data["relevant_docs"]:
- training_data_point = self.collect_training_data_point(
- query=query_data["query"],
- query_id=query_data["query_id"],
- relevant_id=doc_data["id"],
- id_field=id_field,
- query_model=query_model,
- number_additional_docs=number_additional_docs,
- relevant_score=doc_data.get("score", relevant_score),
- default_score=default_score,
- **kwargs
- )
- training_data.extend(training_data_point)
- training_data = DataFrame.from_records(training_data)
- return training_data
-
- def evaluate_query(
- self,
- eval_metrics: List[EvalMetric],
- query_model: Query,
- query_id: str,
- query: str,
- id_field: str,
- relevant_docs: List[Dict],
- default_score: int = 0,
- **kwargs
- ) -> Dict:
- """
- Evaluate a query according to evaluation metrics
-
- :param eval_metrics: A list of evaluation metrics.
- :param query_model: Query model.
- :param query_id: Query id represented as str.
- :param query: Query string.
- :param id_field: The Vespa field representing the document id.
- :param relevant_docs: A list with dicts where each dict contains a doc id a optionally a doc score.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :param kwargs: Extra keyword arguments to be included in the Vespa Query.
- :return: Dict containing query_id and metrics according to the selected evaluation metrics.
- """
-
- query_results = self.query(query=query, query_model=query_model, **kwargs)
- evaluation = {"query_id": query_id}
- for evaluator in eval_metrics:
- evaluation.update(
- evaluator.evaluate_query(
- query_results, relevant_docs, id_field, default_score
- )
- )
- return evaluation
-
- def evaluate(
- self,
- labelled_data: List[Dict],
- eval_metrics: List[EvalMetric],
- query_model: Query,
- id_field: str,
- default_score: int = 0,
- **kwargs
- ) -> DataFrame:
- """
-
- :param labelled_data: Labelled data containing query, query_id and relevant ids.
- :param eval_metrics: A list of evaluation metrics.
- :param query_model: Query model.
- :param id_field: The Vespa field representing the document id.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :param kwargs: Extra keyword arguments to be included in the Vespa Query.
- :return: DataFrame containing query_id and metrics according to the selected evaluation metrics.
- """
- evaluation = []
- for query_data in labelled_data:
- evaluation_query = self.evaluate_query(
- eval_metrics=eval_metrics,
- query_model=query_model,
- query_id=query_data["query_id"],
- query=query_data["query"],
- id_field=id_field,
- relevant_docs=query_data["relevant_docs"],
- default_score=default_score,
- **kwargs
- )
- evaluation.append(evaluation_query)
- evaluation = DataFrame.from_records(evaluation)
- return evaluation
-
-
-# todo: a better pattern for labelled data would be (query_id, query, doc_id, score) with the possibility od
-# assigning a specific default value for those docs not mentioned
-def annotate_data(hits, query_id, id_field, relevant_id, relevant_score, default_score):
- data = []
- for h in hits:
- rank_features = h["fields"]["rankfeatures"]
- rank_features.update({"document_id": h["fields"][id_field]})
- rank_features.update({"query_id": query_id})
- rank_features.update(
- {
- "relevant": relevant_score
- if h["fields"][id_field] == relevant_id
- else default_score
- }
- )
- data.append(rank_features)
- return data
diff --git a/python/vespa/vespa/evaluation.py b/python/vespa/vespa/evaluation.py
deleted file mode 100644
index 4ca7a1d136b..00000000000
--- a/python/vespa/vespa/evaluation.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-from typing import Dict, List
-from vespa.query import VespaResult
-
-
-class EvalMetric(object):
- def __init__(self) -> None:
- pass
-
- def evaluate_query(
- self, query_results, relevant_docs, id_field, default_score
- ) -> Dict:
- raise NotImplementedError
-
-
-class MatchRatio(EvalMetric):
- def __init__(self) -> None:
- """
- Computes the ratio of documents retrieved by the match phase.
- """
- super().__init__()
- self.name = "match_ratio"
-
- def evaluate_query(
- self,
- query_results: VespaResult,
- relevant_docs: List[Dict],
- id_field: str,
- default_score: int,
- ) -> Dict:
- """
- Evaluate query results.
-
- :param query_results: Raw query results returned by Vespa.
- :param relevant_docs: A list with dicts where each dict contains a doc id a optionally a doc score.
- :param id_field: The Vespa field representing the document id.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :return: Dict containing the number of retrieved docs (_retrieved_docs), the number of docs available in
- the corpus (_docs_available) and the match ratio (_value).
- """
- retrieved_docs = query_results.number_documents_retrieved
- docs_available = query_results.number_documents_indexed
- value = 0
- if docs_available > 0:
- value = retrieved_docs / docs_available
- return {
- str(self.name) + "_retrieved_docs": retrieved_docs,
- str(self.name) + "_docs_available": docs_available,
- str(self.name) + "_value": value,
- }
-
-
-class Recall(EvalMetric):
- def __init__(self, at: int) -> None:
- """
- Compute the recall at position `at`
-
- :param at: Maximum position on the resulting list to look for relevant docs.
- """
- super().__init__()
- self.name = "recall_" + str(at)
- self.at = at
-
- def evaluate_query(
- self,
- query_results: VespaResult,
- relevant_docs: List[Dict],
- id_field: str,
- default_score: int,
- ) -> Dict:
- """
- Evaluate query results.
-
- :param query_results: Raw query results returned by Vespa.
- :param relevant_docs: A list with dicts where each dict contains a doc id a optionally a doc score.
- :param id_field: The Vespa field representing the document id.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :return: Dict containing the recall value (_value).
- """
-
- relevant_ids = {str(doc["id"]) for doc in relevant_docs}
- try:
- retrieved_ids = {
- str(hit["fields"][id_field]) for hit in query_results.hits[: self.at]
- }
- except KeyError:
- retrieved_ids = set()
-
- return {
- str(self.name)
- + "_value": len(relevant_ids & retrieved_ids) / len(relevant_ids)
- }
-
-
-class ReciprocalRank(EvalMetric):
- def __init__(self, at: int):
- """
- Compute the reciprocal rank at position `at`
-
- :param at: Maximum position on the resulting list to look for relevant docs.
- """
- super().__init__()
- self.name = "reciprocal_rank_" + str(at)
- self.at = at
-
- def evaluate_query(
- self,
- query_results: VespaResult,
- relevant_docs: List[Dict],
- id_field: str,
- default_score: int,
- ) -> Dict:
- """
- Evaluate query results.
-
- :param query_results: Raw query results returned by Vespa.
- :param relevant_docs: A list with dicts where each dict contains a doc id a optionally a doc score.
- :param id_field: The Vespa field representing the document id.
- :param default_score: Score to assign to the additional documents that are not relevant. Default to 0.
- :return: Dict containing the reciprocal rank value (_value).
- """
-
- relevant_ids = {str(doc["id"]) for doc in relevant_docs}
- rr = 0
- hits = query_results.hits[: self.at]
- for index, hit in enumerate(hits):
- if hit["fields"][id_field] in relevant_ids:
- rr = 1 / (index + 1)
- break
-
- return {str(self.name) + "_value": rr}
diff --git a/python/vespa/vespa/json_serialization.py b/python/vespa/vespa/json_serialization.py
deleted file mode 100644
index d5f059326e7..00000000000
--- a/python/vespa/vespa/json_serialization.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import datetime
-import json
-import typing
-
-T = typing.TypeVar("T")
-
-
-class ToJson(object):
- """
- Utility mix-in class for serializing an object to JSON. It does not really
- do any conversion on its own, but forces serialization into a standardized
- API.
-
- The serialized class is put into an envelope with some data to make it easier
- to understand what has happened.
-
- {
- "version": 1,
- "class": "Field",
- "serialized_at": "2018-10-24T12:55:32+00:00",
- "data": { ... }
- }
-
- * version: This value is hard-coded to 1.
- * class: The name of the class we serialized. For debugging purposes.
- * serialized_at: The time we serialized the instance of the class. For debugging purposes.
- * data: The actual data of the serialized class.
-
- All serialization is based on converting objects to a `dict` which is then converted
- to JSON using the standard Python json library.
- """
-
- @property
- def to_dict(self) -> typing.Mapping:
- raise NotImplementedError
-
- @property
- def to_envelope(self) -> typing.Mapping:
- return {
- "version": 1,
- "class": self.__class__.__name__,
- "serialized_at": datetime.datetime.utcnow().isoformat(),
- "data": self.to_dict,
- }
-
- @property
- def to_json(self) -> str:
- mapping = self.to_envelope
- return json.dumps(mapping)
-
-
-class FromJson(typing.Generic[T]):
- """
- A mix-in class for deserializing from JSON to an object that implements this class.
- All JSON must have the same envelope as ToJson to be able to properly deserialize the
- contents of the mapping.
- """
-
- deserializers: typing.MutableMapping[str, "FromJson"] = {}
-
- def __init_subclass__(cls, **kwargs):
- super().__init_subclass__(**kwargs) # type: ignore
- FromJson.deserializers[cls.__name__] = cls
-
- @staticmethod
- def from_json(json_string: str) -> T:
- mapping = json.loads(json_string)
- return FromJson.map(mapping)
-
- @staticmethod
- def map(mapping: typing.Mapping) -> T:
- mapping_class = FromJson.deserializers[mapping["class"]]
- return mapping_class.from_dict(mapping["data"])
-
- @staticmethod
- def from_dict(mapping: typing.Mapping) -> T:
- raise NotImplementedError
diff --git a/python/vespa/vespa/package.py b/python/vespa/vespa/package.py
deleted file mode 100644
index 301a9df43bd..00000000000
--- a/python/vespa/vespa/package.py
+++ /dev/null
@@ -1,786 +0,0 @@
-import sys
-import http.client
-import json
-import os
-import re
-import zipfile
-from base64 import standard_b64encode
-from datetime import datetime, timedelta
-from io import BytesIO
-from pathlib import Path
-from time import sleep, strftime, gmtime
-from typing import List, Mapping, Optional, IO
-
-import docker
-from cryptography import x509
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives.asymmetric import ec
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives import serialization
-from jinja2 import Environment, PackageLoader, select_autoescape
-
-from vespa.json_serialization import ToJson, FromJson
-from vespa.application import Vespa
-
-
-class Field(ToJson, FromJson["Field"]):
- def __init__(
- self,
- name: str,
- type: str,
- indexing: Optional[List[str]] = None,
- index: Optional[str] = None,
- ) -> None:
- """
- Object representing a Vespa document field.
-
- :param name: Field name.
- :param type: Field data type.
- :param indexing: Configures how to process data of a field during indexing.
- :param index: Sets index parameters. Content in fields with index are normalized and tokenized by default.
- """
- self.name = name
- self.type = type
- self.indexing = indexing
- self.index = index
-
- @property
- def indexing_to_text(self) -> Optional[str]:
- if self.indexing is not None:
- return " | ".join(self.indexing)
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "Field":
- return Field(
- name=mapping["name"],
- type=mapping["type"],
- indexing=mapping.get("indexing", None),
- index=mapping.get("index", None),
- )
-
- @property
- def to_dict(self) -> Mapping:
- map = {"name": self.name, "type": self.type}
- if self.indexing is not None:
- map.update(indexing=self.indexing)
- if self.index is not None:
- map.update(index=self.index)
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return (
- self.name == other.name
- and self.type == other.type
- and self.indexing == other.indexing
- and self.index == other.index
- )
-
- def __repr__(self):
- return "{0}({1}, {2}, {3}, {4})".format(
- self.__class__.__name__,
- repr(self.name),
- repr(self.type),
- repr(self.indexing),
- repr(self.index),
- )
-
-
-class Document(ToJson, FromJson["Document"]):
- def __init__(self, fields: Optional[List[Field]] = None) -> None:
- """
- Object representing a Vespa document.
-
- """
- self.fields = [] if not fields else fields
-
- def add_fields(self, *fields: Field):
- """
- Add Fields to the document.
-
- :param fields: fields to be added
- :return:
- """
- self.fields.extend(fields)
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "Document":
- return Document(fields=[FromJson.map(field) for field in mapping.get("fields")])
-
- @property
- def to_dict(self) -> Mapping:
- map = {"fields": [field.to_envelope for field in self.fields]}
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return self.fields == other.fields
-
- def __repr__(self):
- return "{0}({1})".format(
- self.__class__.__name__, repr(self.fields) if self.fields else None
- )
-
-
-class FieldSet(ToJson, FromJson["FieldSet"]):
- def __init__(self, name: str, fields: List[str]) -> None:
- """
- A fieldset groups fields together for searching.
-
- :param name: Name of the fieldset
- :param fields: Field names to be included in the fieldset.
- """
- self.name = name
- self.fields = fields
-
- @property
- def fields_to_text(self):
- if self.fields is not None:
- return ", ".join(self.fields)
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "FieldSet":
- return FieldSet(name=mapping["name"], fields=mapping["fields"])
-
- @property
- def to_dict(self) -> Mapping:
- map = {"name": self.name, "fields": self.fields}
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return self.name == other.name and self.fields == other.fields
-
- def __repr__(self):
- return "{0}({1}, {2})".format(
- self.__class__.__name__, repr(self.name), repr(self.fields)
- )
-
-
-class RankProfile(ToJson, FromJson["RankProfile"]):
- def __init__(
- self, name: str, first_phase: str, inherits: Optional[str] = None
- ) -> None:
- """
- Define a Vespa rank profile
-
- :param name: Rank profile name.
- :param first_phase: First phase ranking expression.
- """
- self.name = name
- self.first_phase = first_phase
- self.inherits = inherits
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "RankProfile":
- return RankProfile(
- name=mapping["name"],
- first_phase=mapping["first_phase"],
- inherits=mapping.get("inherits", None),
- )
-
- @property
- def to_dict(self) -> Mapping:
- map = {"name": self.name, "first_phase": self.first_phase}
- if self.inherits is not None:
- map.update({"inherits": self.inherits})
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return (
- self.name == other.name
- and self.first_phase == other.first_phase
- and self.inherits == other.inherits
- )
-
- def __repr__(self):
- return "{0}({1}, {2}, {3})".format(
- self.__class__.__name__,
- repr(self.name),
- repr(self.first_phase),
- repr(self.inherits),
- )
-
-
-class Schema(ToJson, FromJson["Schema"]):
- def __init__(
- self,
- name: str,
- document: Document,
- fieldsets: Optional[List[FieldSet]] = None,
- rank_profiles: Optional[List[RankProfile]] = None,
- ) -> None:
- """
- Create a Vespa Schema.
-
- :param name: Schema name.
- :param document: Vespa document associated with the Schema.
- :param fieldsets: A list of `FieldSet` associated with the Schema.
- :param rank_profiles: A list of `RankProfile` associated with the Schema.
- """
- self.name = name
- self.document = document
-
- self.fieldsets = {}
- if fieldsets is not None:
- self.fieldsets = {fieldset.name: fieldset for fieldset in fieldsets}
-
- self.rank_profiles = {}
- if rank_profiles is not None:
- self.rank_profiles = {
- rank_profile.name: rank_profile for rank_profile in rank_profiles
- }
-
- def add_rank_profile(self, rank_profile: RankProfile) -> None:
- """
- Add a `RankProfile` to the `Schema`.
- :param rank_profile: `RankProfile` to be added.
- :return: None.
- """
- self.rank_profiles[rank_profile.name] = rank_profile
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "Schema":
- return Schema(
- name=mapping["name"],
- document=FromJson.map(mapping["document"]),
- fieldsets=[FromJson.map(fieldset) for fieldset in mapping["fieldsets"]],
- rank_profiles=[
- FromJson.map(rank_profile) for rank_profile in mapping["rank_profiles"]
- ],
- )
-
- @property
- def to_dict(self) -> Mapping:
- map = {
- "name": self.name,
- "document": self.document.to_envelope,
- "fieldsets": [
- self.fieldsets[name].to_envelope for name in self.fieldsets.keys()
- ],
- "rank_profiles": [
- self.rank_profiles[name].to_envelope
- for name in self.rank_profiles.keys()
- ],
- }
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return (
- self.name == other.name
- and self.document == other.document
- and self.fieldsets == other.fieldsets
- and self.rank_profiles == other.rank_profiles
- )
-
- def __repr__(self):
- return "{0}({1}, {2}, {3}, {4})".format(
- self.__class__.__name__,
- repr(self.name),
- repr(self.document),
- repr(
- [field for field in self.fieldsets.values()] if self.fieldsets else None
- ),
- repr(
- [rank_profile for rank_profile in self.rank_profiles.values()]
- if self.rank_profiles
- else None
- ),
- )
-
-
-class ApplicationPackage(ToJson, FromJson["ApplicationPackage"]):
- def __init__(self, name: str, schema: Schema) -> None:
- """
- Vespa Application Package.
-
- :param name: Application name.
- :param schema: Schema of the application.
- """
- self.name = name
- self.schema = schema
-
- @property
- def schema_to_text(self):
- env = Environment(
- loader=PackageLoader("vespa", "templates"),
- autoescape=select_autoescape(
- disabled_extensions=("txt",),
- default_for_string=True,
- default=True,
- ),
- )
- env.trim_blocks = True
- env.lstrip_blocks = True
- schema_template = env.get_template("schema.txt")
- return schema_template.render(
- schema_name=self.schema.name,
- document_name=self.schema.name,
- fields=self.schema.document.fields,
- fieldsets=self.schema.fieldsets,
- rank_profiles=self.schema.rank_profiles,
- )
-
- @property
- def hosts_to_text(self):
- env = Environment(
- loader=PackageLoader("vespa", "templates"),
- autoescape=select_autoescape(
- disabled_extensions=("txt",),
- default_for_string=True,
- default=True,
- ),
- )
- env.trim_blocks = True
- env.lstrip_blocks = True
- schema_template = env.get_template("hosts.xml")
- return schema_template.render()
-
- @property
- def services_to_text(self):
- env = Environment(
- loader=PackageLoader("vespa", "templates"),
- autoescape=select_autoescape(
- disabled_extensions=("txt",),
- default_for_string=True,
- default=True,
- ),
- )
- env.trim_blocks = True
- env.lstrip_blocks = True
- schema_template = env.get_template("services.xml")
- return schema_template.render(
- application_name=self.name,
- document_name=self.schema.name,
- )
-
- @staticmethod
- def from_dict(mapping: Mapping) -> "ApplicationPackage":
- schema = mapping.get("schema", None)
- if schema is not None:
- schema = FromJson.map(schema)
- return ApplicationPackage(name=mapping["name"], schema=schema)
-
- @property
- def to_dict(self) -> Mapping:
- map = {"name": self.name}
- if self.schema is not None:
- map.update({"schema": self.schema.to_envelope})
- return map
-
- def __eq__(self, other):
- if not isinstance(other, self.__class__):
- return False
- return self.name == other.name and self.schema == other.schema
-
- def __repr__(self):
- return "{0}({1}, {2})".format(
- self.__class__.__name__, repr(self.name), repr(self.schema)
- )
-
-
-class VespaDocker(object):
- def __init__(
- self,
- application_package: ApplicationPackage,
- output_file: IO = sys.stdout,
- ) -> None:
- """
- Deploy application to a Vespa container
-
- :param application_package: ApplicationPackage to be deployed.
- :param output_file: Output file to write output messages.
- """
- self.application_package = application_package
- self.container = None
- self.local_port = 8080
- self.output = output_file
-
- def _run_vespa_engine_container(self, disk_folder: str, container_memory: str):
- """
- Run a vespa container.
-
- :param disk_folder: Folder containing the application files.
- :param container_memory: Memory limit of the container
- :return:
- """
- client = docker.from_env()
- if self.container is None:
- try:
- self.container = client.containers.get(self.application_package.name)
- except docker.errors.NotFound:
- self.container = client.containers.run(
- "vespaengine/vespa",
- detach=True,
- mem_limit=container_memory,
- name=self.application_package.name,
- hostname=self.application_package.name,
- privileged=True,
- volumes={disk_folder: {"bind": "/app", "mode": "rw"}},
- ports={self.local_port: self.local_port, 19112: 19112},
- )
-
- def _check_configuration_server(self) -> bool:
- """
- Check if configuration server is running and ready for deployment
-
- :return: True if configuration server is running.
- """
- return (
- self.container is not None
- and self.container.exec_run(
- "bash -c 'curl -s --head http://localhost:19071/ApplicationStatus'"
- )
- .output.decode("utf-8")
- .split("\r\n")[0]
- == "HTTP/1.1 200 OK"
- )
-
- def _create_application_package_files(self, dir_path):
- Path(os.path.join(dir_path, "application/schemas")).mkdir(
- parents=True, exist_ok=True
- )
- with open(
- os.path.join(
- dir_path,
- "application/schemas/{}.sd".format(
- self.application_package.schema.name
- ),
- ),
- "w",
- ) as f:
- f.write(self.application_package.schema_to_text)
- with open(os.path.join(dir_path, "application/hosts.xml"), "w") as f:
- f.write(self.application_package.hosts_to_text)
- with open(os.path.join(dir_path, "application/services.xml"), "w") as f:
- f.write(self.application_package.services_to_text)
-
- def deploy(self, disk_folder: str, container_memory: str = "4G"):
- """
- Deploy the application into a Vespa container.
-
- :param disk_folder: Disk folder to save the required Vespa config files.
- :param container_memory: Docker container memory available to the application.
-
- :return: a Vespa connection instance.
- """
-
- self._create_application_package_files(dir_path=disk_folder)
-
- self._run_vespa_engine_container(
- disk_folder=disk_folder, container_memory=container_memory
- )
-
- while not self._check_configuration_server():
- print("Waiting for configuration server.", file=self.output)
- sleep(5)
-
- deployment = self.container.exec_run(
- "bash -c '/opt/vespa/bin/vespa-deploy prepare /app/application && /opt/vespa/bin/vespa-deploy activate'"
- )
-
- deployment_message = deployment.output.decode("utf-8").split("\n")
-
- if not any(re.match("Generation: [0-9]+", line) for line in deployment_message):
- raise RuntimeError(deployment_message)
-
- return Vespa(
- url="http://localhost",
- port=self.local_port,
- deployment_message=deployment_message,
- )
-
-
-class VespaCloud(object):
- def __init__(
- self,
- tenant: str,
- application: str,
- key_location: str,
- application_package: ApplicationPackage,
- output_file: IO = sys.stdout,
- ) -> None:
- """
- Deploy application to the Vespa Cloud (cloud.vespa.ai)
-
- :param tenant: Tenant name registered in the Vespa Cloud.
- :param application: Application name registered in the Vespa Cloud.
- :param key_location: Location of the private key used for signing HTTP requests to the Vespa Cloud.
- :param application_package: ApplicationPackage to be deployed.
- :param output_file: Output file to write output messages.
- """
- self.tenant = tenant
- self.application = application
- self.application_package = application_package
- self.api_key = self._read_private_key(key_location)
- self.api_public_key_bytes = standard_b64encode(
- self.api_key.public_key().public_bytes(
- serialization.Encoding.PEM,
- serialization.PublicFormat.SubjectPublicKeyInfo,
- )
- )
- self.data_key, self.data_certificate = self._create_certificate_pair()
- self.private_cert_file_name = "private_cert.txt"
- self.connection = http.client.HTTPSConnection(
- "api.vespa-external.aws.oath.cloud", 4443
- )
- self.output = output_file
-
- @staticmethod
- def _read_private_key(key_location: str) -> ec.EllipticCurvePrivateKey:
- with open(key_location, "rb") as key_data:
- key = serialization.load_pem_private_key(
- key_data.read(), None, default_backend()
- )
- if not isinstance(key, ec.EllipticCurvePrivateKey):
- raise TypeError(
- "Key at " + key_location + " must be an elliptic curve private key"
- )
- return key
-
- def _write_private_key_and_cert(
- self, key: ec.EllipticCurvePrivateKey, cert: x509.Certificate, disk_folder: str
- ) -> None:
- cert_file = os.path.join(disk_folder, self.private_cert_file_name)
- with open(cert_file, "w+") as file:
- file.write(
- key.private_bytes(
- serialization.Encoding.PEM,
- serialization.PrivateFormat.TraditionalOpenSSL,
- serialization.NoEncryption(),
- ).decode("UTF-8")
- )
- file.write(cert.public_bytes(serialization.Encoding.PEM).decode("UTF-8"))
-
- @staticmethod
- def _create_certificate_pair() -> (ec.EllipticCurvePrivateKey, x509.Certificate):
- key = ec.generate_private_key(ec.SECP384R1, default_backend())
- name = x509.Name([x509.NameAttribute(x509.NameOID.COMMON_NAME, u"localhost")])
- certificate = (
- x509.CertificateBuilder()
- .subject_name(name)
- .issuer_name(name)
- .serial_number(x509.random_serial_number())
- .not_valid_before(datetime.utcnow() - timedelta(minutes=1))
- .not_valid_after(datetime.utcnow() + timedelta(days=7))
- .public_key(key.public_key())
- .sign(key, hashes.SHA256(), default_backend())
- )
- return (key, certificate)
-
- def _request(
- self, method: str, path: str, body: BytesIO = BytesIO(), headers={}
- ) -> dict:
- digest = hashes.Hash(hashes.SHA256(), default_backend())
- body.seek(0)
- digest.update(body.read())
- content_hash = standard_b64encode(digest.finalize()).decode("UTF-8")
- timestamp = (
- datetime.utcnow().isoformat() + "Z"
- ) # Java's Instant.parse requires the neutral time zone appended
- url = "https://" + self.connection.host + ":" + str(self.connection.port) + path
-
- canonical_message = method + "\n" + url + "\n" + timestamp + "\n" + content_hash
- signature = self.api_key.sign(
- canonical_message.encode("UTF-8"), ec.ECDSA(hashes.SHA256())
- )
-
- headers = {
- "X-Timestamp": timestamp,
- "X-Content-Hash": content_hash,
- "X-Key-Id": self.tenant + ":" + self.application + ":" + "default",
- "X-Key": self.api_public_key_bytes,
- "X-Authorization": standard_b64encode(signature),
- **headers,
- }
-
- body.seek(0)
- self.connection.request(method, path, body, headers)
- with self.connection.getresponse() as response:
- parsed = json.load(response)
- if response.status != 200:
- raise RuntimeError(
- "Status code "
- + str(response.status)
- + " doing "
- + method
- + " at "
- + url
- + ":\n"
- + parsed["message"]
- )
- return parsed
-
- def _get_dev_region(self) -> str:
- return self._request("GET", "/zone/v1/environment/dev/default")["name"]
-
- def _get_endpoint(self, instance: str, region: str) -> str:
- endpoints = self._request(
- "GET",
- "/application/v4/tenant/{}/application/{}/instance/{}/environment/dev/region/{}".format(
- self.tenant, self.application, instance, region
- ),
- )["endpoints"]
- container_url = [
- endpoint["url"]
- for endpoint in endpoints
- if endpoint["cluster"]
- == "{}_container".format(self.application_package.name)
- ]
- if not container_url:
- raise RuntimeError("No endpoints found for container 'test_app_container'")
- return container_url[0]
-
- def _to_application_zip(self) -> BytesIO:
- buffer = BytesIO()
- with zipfile.ZipFile(buffer, "a") as zip_archive:
- zip_archive.writestr(
- "application/schemas/{}.sd".format(
- self.application_package.schema.name
- ),
- self.application_package.schema_to_text,
- )
- zip_archive.writestr(
- "application/services.xml", self.application_package.services_to_text
- )
- zip_archive.writestr(
- "application/security/clients.pem",
- self.data_certificate.public_bytes(serialization.Encoding.PEM),
- )
-
- return buffer
-
- def _start_deployment(self, instance: str, job: str, disk_folder: str) -> int:
- deploy_path = (
- "/application/v4/tenant/{}/application/{}/instance/{}/deploy/{}".format(
- self.tenant, self.application, instance, job
- )
- )
-
- application_zip_bytes = self._to_application_zip()
-
- self._write_private_key_and_cert(
- self.data_key, self.data_certificate, disk_folder
- )
-
- response = self._request(
- "POST",
- deploy_path,
- application_zip_bytes,
- {"Content-Type": "application/zip"},
- )
- print(response["message"], file=self.output)
- return response["run"]
-
- def _get_deployment_status(
- self, instance: str, job: str, run: int, last: int
- ) -> (str, int):
-
- update = self._request(
- "GET",
- "/application/v4/tenant/{}/application/{}/instance/{}/job/{}/run/{}?after={}".format(
- self.tenant, self.application, instance, job, run, last
- ),
- )
-
- for step, entries in update["log"].items():
- for entry in entries:
- self._print_log_entry(step, entry)
- last = update.get("lastId", last)
-
- fail_status_message = {
- "error": "Unexpected error during deployment; see log for details",
- "aborted": "Deployment was aborted, probably by a newer deployment",
- "outOfCapacity": "No capacity left in zone; please contact the Vespa team",
- "deploymentFailed": "Deployment failed; see log for details",
- "installationFailed": "Installation failed; see Vespa log for details",
- "running": "Deployment not completed",
- "endpointCertificateTimeout": "Endpoint certificate not ready in time; please contact Vespa team",
- "testFailure": "Unexpected status; tests are not run for manual deployments",
- }
-
- if update["active"]:
- return "active", last
- else:
- status = update["status"]
- if status == "success":
- return "success", last
- elif status in fail_status_message.keys():
- raise RuntimeError(fail_status_message[status])
- else:
- raise RuntimeError("Unexpected status: {}".format(status))
-
- def _follow_deployment(self, instance: str, job: str, run: int) -> None:
- last = -1
- while True:
- try:
- status, last = self._get_deployment_status(instance, job, run, last)
- except RuntimeError:
- raise
-
- if status == "active":
- sleep(1)
- elif status == "success":
- return
- else:
- raise RuntimeError("Unexpected status: {}".format(status))
-
- def _print_log_entry(self, step: str, entry: dict):
- timestamp = strftime("%H:%M:%S", gmtime(entry["at"] / 1e3))
- message = entry["message"].replace("\n", "\n" + " " * 23)
- if step != "copyVespaLogs" or entry["type"] == "error":
- print(
- "{:<7} [{}] {}".format(entry["type"].upper(), timestamp, message),
- file=self.output,
- )
-
- def deploy(self, instance: str, disk_folder: str) -> Vespa:
- """
- Deploy the given application package as the given instance in the Vespa Cloud dev environment.
-
- :param instance: Name of this instance of the application, in the Vespa Cloud.
- :param disk_folder: Disk folder to save the required Vespa config files.
-
- :return: a Vespa connection instance.
- """
- region = self._get_dev_region()
- job = "dev-" + region
- run = self._start_deployment(instance, job, disk_folder)
- self._follow_deployment(instance, job, run)
- endpoint_url = self._get_endpoint(instance=instance, region=region)
- return Vespa(
- url=endpoint_url,
- cert=os.path.join(disk_folder, self.private_cert_file_name),
- )
-
- def delete(self, instance: str):
- """
- Delete the specified instance from the dev environment in the Vespa Cloud.
- :param instance: Name of the instance to delete.
- :return:
- """
- print(
- self._request(
- "DELETE",
- "/application/v4/tenant/{}/application/{}/instance/{}/environment/dev/region/{}".format(
- self.tenant, self.application, instance, self._get_dev_region()
- ),
- )["message"],
- file=self.output,
- )
-
- def close(self):
- self.connection.close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.close()
diff --git a/python/vespa/vespa/query.py b/python/vespa/vespa/query.py
deleted file mode 100644
index ed67819b821..00000000000
--- a/python/vespa/vespa/query.py
+++ /dev/null
@@ -1,229 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-from typing import Callable, List, Optional, Dict
-
-
-#
-# Match phase
-#
-class MatchFilter(object):
- """
- Abstract class for match filters.
- """
-
- def create_match_filter(self, query: str) -> str:
- """
- Create part of the YQL expression related to the filter.
-
- :param query: Query input.
- :return: Part of the YQL expression related to the filter.
- """
- raise NotImplementedError
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict:
- """
- Relevant request properties associated with the filter.
-
- :param query: Query input.
- :return: dict containing the relevant request properties associated with the filter.
- """
- raise NotImplementedError
-
-
-class AND(MatchFilter):
- def __init__(self) -> None:
- """
- Filter that match document containing all the query terms.
- """
- super().__init__()
-
- def create_match_filter(self, query: str) -> str:
- return '(userInput("{}"))'.format(query)
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict:
- return {}
-
-
-class OR(MatchFilter):
- def __init__(self) -> None:
- """
- Filter that match any document containing at least one query term.
- """
- super().__init__()
-
- def create_match_filter(self, query: str) -> str:
- return '([{{"grammar": "any"}}]userInput("{}"))'.format(query)
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict:
- return {}
-
-
-class WeakAnd(MatchFilter):
- def __init__(self, hits: int, field: str = "default") -> None:
- """
- Match documents according to the weakAND algorithm.
-
- Reference: https://docs.vespa.ai/documentation/using-wand-with-vespa.html
-
- :param hits: Lower bound on the number of hits to be retrieved.
- :param field: Which Vespa field to search.
- """
- super().__init__()
- self.hits = hits
- self.field = field
-
- def create_match_filter(self, query: str) -> str:
- query_tokens = query.split(" ")
- terms = ", ".join(
- ['{} contains "{}"'.format(self.field, token) for token in query_tokens]
- )
- return '([{{"targetNumHits": {}}}]weakAnd({}))'.format(self.hits, terms)
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict:
- return {}
-
-
-class ANN(MatchFilter):
- def __init__(
- self,
- doc_vector: str,
- query_vector: str,
- embedding_model: Callable[[str], List[float]],
- hits: int,
- label: str,
- ) -> None:
- """
- Match documents according to the nearest neighbor operator.
-
- Reference: https://docs.vespa.ai/documentation/reference/query-language-reference.html#nearestneighbor
-
- :param doc_vector: Name of the document field to be used in the distance calculation.
- :param query_vector: Name of the query field to be used in the distance calculation.
- :param embedding_model: Model that takes query str as input and return list of floats as output.
- :param hits: Lower bound on the number of hits to return.
- :param label: A label to identify this specific operator instance.
- """
- super().__init__()
- self.doc_vector = doc_vector
- self.query_vector = query_vector
- self.embedding_model = embedding_model
- self.hits = hits
- self.label = label
-
- def create_match_filter(self, query: str) -> str:
- return '([{{"targetNumHits": {}, "label": "{}"}}]nearestNeighbor({}, {}))'.format(
- self.hits, self.label, self.doc_vector, self.query_vector
- )
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict[str, str]:
- embedding_vector = self.embedding_model(query)
- return {
- "ranking.features.query({})".format(self.query_vector): str(
- embedding_vector
- )
- }
-
-
-class Union(MatchFilter):
- def __init__(self, *args: MatchFilter) -> None:
- """
- Match documents that belongs to the union of many match filters.
-
- :param args: Match filters to be taken the union of.
- """
- super().__init__()
- self.operators = args
-
- def create_match_filter(self, query: str) -> str:
- match_filters = []
- for operator in self.operators:
- match_filter = operator.create_match_filter(query=query)
- if match_filter is not None:
- match_filters.append(match_filter)
- return " or ".join(match_filters)
-
- def get_query_properties(self, query: Optional[str] = None) -> Dict[str, str]:
- query_properties = {}
- for operator in self.operators:
- query_properties.update(operator.get_query_properties(query=query))
- return query_properties
-
-
-#
-# Ranking phase
-#
-class RankProfile(object):
- def __init__(self, name: str = "default", list_features: bool = False) -> None:
- """
- Define a rank profile.
-
- :param name: Name of the rank profile as defined in a Vespa search definition.
- :param list_features: Should the ranking features be returned. Either 'true' or 'false'.
- """
- self.name = name
- self.list_features = "false"
- if list_features:
- self.list_features = "true"
-
-
-class Query(object):
- def __init__(
- self,
- match_phase: MatchFilter = AND(),
- rank_profile: RankProfile = RankProfile(),
- ) -> None:
- """
- Define a query model.
-
- :param match_phase: Define the match criteria. One of the MatchFilter options available.
- :param rank_profile: Define the rank criteria.
- """
- self.match_phase = match_phase
- self.rank_profile = rank_profile
-
- def create_body(self, query: str) -> Dict[str, str]:
- """
- Create the appropriate request body to be sent to Vespa.
-
- :param query: Query input.
- :return: dict representing the request body.
- """
-
- match_filter = self.match_phase.create_match_filter(query=query)
- query_properties = self.match_phase.get_query_properties(query=query)
-
- body = {
- "yql": "select * from sources * where {};".format(match_filter),
- "ranking": {
- "profile": self.rank_profile.name,
- "listFeatures": self.rank_profile.list_features,
- },
- }
- body.update(query_properties)
- return body
-
-
-class VespaResult(object):
- def __init__(self, vespa_result, request_body=None):
- self._vespa_result = vespa_result
- self._request_body = request_body
-
- @property
- def request_body(self) -> Optional[Dict]:
- return self._request_body
-
- @property
- def json(self) -> Dict:
- return self._vespa_result
-
- @property
- def hits(self) -> List:
- return self._vespa_result.get("root", {}).get("children", [])
-
- @property
- def number_documents_retrieved(self) -> int:
- return self._vespa_result.get("root", {}).get("fields", {}).get("totalCount", 0)
-
- @property
- def number_documents_indexed(self) -> int:
- return self._vespa_result.get("root", {}).get("coverage", {}).get("documents", 0)
diff --git a/python/vespa/vespa/templates/hosts.xml b/python/vespa/vespa/templates/hosts.xml
deleted file mode 100644
index 5c88f4c1609..00000000000
--- a/python/vespa/vespa/templates/hosts.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!-- Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
-<hosts>
- <host name="localhost">
- <alias>node1</alias>
- </host>
-</hosts> \ No newline at end of file
diff --git a/python/vespa/vespa/templates/schema.txt b/python/vespa/vespa/templates/schema.txt
deleted file mode 100644
index 0849cbbad6f..00000000000
--- a/python/vespa/vespa/templates/schema.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-schema {{ schema_name }} {
- document {{ document_name }} {
- {% for field in fields %}
- field {{ field.name }} type {{ field.type }} {
- {% if field.indexing %}
- indexing: {{ field.indexing_to_text }}
- {% endif %}
- {% if field.index %}
- index: {{ field.index }}
- {% endif %}
- }
- {% endfor %}
- }
-{% for key, value in fieldsets.items() %}
- fieldset {{ key }} {
- fields: {{ value.fields_to_text }}
- }
-{% endfor %}
-{% for key, value in rank_profiles.items() %}
- rank-profile {{ key }}{% if value.inherits %} inherits {{ value.inherits }}{% endif %} {
- {% if value.first_phase %}
- first-phase {
- expression: {{ value.first_phase }}
- }
- {% endif %}
- }
-{% endfor %}
-} \ No newline at end of file
diff --git a/python/vespa/vespa/templates/services.xml b/python/vespa/vespa/templates/services.xml
deleted file mode 100644
index c6bda296be9..00000000000
--- a/python/vespa/vespa/templates/services.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<services version="1.0">
- <container id="{{ application_name }}_container" version="1.0">
- <search></search>
- <document-api></document-api>
- </container>
- <content id="{{ application_name }}_content" version="1.0">
- <redundancy reply-after="1">1</redundancy>
- <documents>
- <document type="{{ document_name }}" mode="index"></document>
- </documents>
- <nodes>
- <node distribution-key="0" hostalias="node1"></node>
- </nodes>
- </content>
-</services> \ No newline at end of file
diff --git a/python/vespa/vespa/test_application.py b/python/vespa/vespa/test_application.py
deleted file mode 100644
index 84bd1c0a6ad..00000000000
--- a/python/vespa/vespa/test_application.py
+++ /dev/null
@@ -1,375 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-import unittest
-from unittest.mock import Mock, call
-from pandas import DataFrame
-from pandas.testing import assert_frame_equal
-
-from vespa.application import Vespa
-from vespa.query import Query, OR, RankProfile, VespaResult
-
-
-class TestVespa(unittest.TestCase):
- def test_end_point(self):
- self.assertEqual(
- Vespa(url="https://cord19.vespa.ai").end_point, "https://cord19.vespa.ai"
- )
- self.assertEqual(
- Vespa(url="http://localhost", port=8080).end_point, "http://localhost:8080"
- )
- self.assertEqual(
- Vespa(url="http://localhost/", port=8080).end_point, "http://localhost:8080"
- )
-
-
-class TestVespaQuery(unittest.TestCase):
- def test_query(self):
- app = Vespa(url="http://localhost", port=8080)
-
- body = {"yql": "select * from sources * where test"}
- self.assertDictEqual(
- app.query(body=body, debug_request=True).request_body, body
- )
-
- self.assertDictEqual(
- app.query(
- query="this is a test",
- query_model=Query(match_phase=OR(), rank_profile=RankProfile()),
- debug_request=True,
- hits=10,
- ).request_body,
- {
- "yql": 'select * from sources * where ([{"grammar": "any"}]userInput("this is a test"));',
- "ranking": {"profile": "default", "listFeatures": "false"},
- "hits": 10,
- },
- )
-
- self.assertDictEqual(
- app.query(
- query="this is a test",
- query_model=Query(match_phase=OR(), rank_profile=RankProfile()),
- debug_request=True,
- hits=10,
- recall=("id", [1, 5]),
- ).request_body,
- {
- "yql": 'select * from sources * where ([{"grammar": "any"}]userInput("this is a test"));',
- "ranking": {"profile": "default", "listFeatures": "false"},
- "hits": 10,
- "recall": "+(id:1 id:5)",
- },
- )
-
-
-class TestVespaCollectData(unittest.TestCase):
- def setUp(self) -> None:
- self.app = Vespa(url="http://localhost", port=8080)
- self.raw_vespa_result_recall = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- "children": [
- {
- "id": "id:covid-19:doc::40215",
- "relevance": 30.368213170494712,
- "source": "content",
- "fields": {
- "vespa_id_field": "abc",
- "sddocname": "doc",
- "body_text": "this is a body",
- "title": "this is a title",
- "rankfeatures": {"a": 1, "b": 2},
- },
- }
- ],
- }
- }
-
- self.raw_vespa_result_additional = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- "children": [
- {
- "id": "id:covid-19:doc::40216",
- "relevance": 10,
- "source": "content",
- "fields": {
- "vespa_id_field": "def",
- "sddocname": "doc",
- "body_text": "this is a body 2",
- "title": "this is a title 2",
- "rankfeatures": {"a": 3, "b": 4},
- },
- },
- {
- "id": "id:covid-19:doc::40217",
- "relevance": 8,
- "source": "content",
- "fields": {
- "vespa_id_field": "ghi",
- "sddocname": "doc",
- "body_text": "this is a body 3",
- "title": "this is a title 3",
- "rankfeatures": {"a": 5, "b": 6},
- },
- },
- ],
- }
- }
-
- def test_disable_rank_features(self):
- with self.assertRaises(AssertionError):
- self.app.collect_training_data_point(
- query="this is a query",
- query_id="123",
- relevant_id="abc",
- id_field="vespa_id_field",
- query_model=Query(),
- number_additional_docs=2,
- )
-
- def test_collect_training_data_point(self):
-
- self.app.query = Mock(
- side_effect=[
- VespaResult(self.raw_vespa_result_recall),
- VespaResult(self.raw_vespa_result_additional),
- ]
- )
- query_model = Query(rank_profile=RankProfile(list_features=True))
- data = self.app.collect_training_data_point(
- query="this is a query",
- query_id="123",
- relevant_id="abc",
- id_field="vespa_id_field",
- query_model=query_model,
- number_additional_docs=2,
- timeout="15s",
- )
-
- self.assertEqual(self.app.query.call_count, 2)
- self.app.query.assert_has_calls(
- [
- call(
- query="this is a query",
- query_model=query_model,
- recall=("vespa_id_field", ["abc"]),
- timeout="15s",
- ),
- call(
- query="this is a query",
- query_model=query_model,
- hits=2,
- timeout="15s",
- ),
- ]
- )
- expected_data = [
- {"document_id": "abc", "query_id": "123", "relevant": 1, "a": 1, "b": 2},
- {"document_id": "def", "query_id": "123", "relevant": 0, "a": 3, "b": 4},
- {"document_id": "ghi", "query_id": "123", "relevant": 0, "a": 5, "b": 6},
- ]
- self.assertEqual(data, expected_data)
-
- def test_collect_training_data_point_0_recall_hits(self):
-
- self.raw_vespa_result_recall = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 0},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- }
- }
- self.app.query = Mock(
- side_effect=[
- VespaResult(self.raw_vespa_result_recall),
- VespaResult(self.raw_vespa_result_additional),
- ]
- )
- query_model = Query(rank_profile=RankProfile(list_features=True))
- data = self.app.collect_training_data_point(
- query="this is a query",
- query_id="123",
- relevant_id="abc",
- id_field="vespa_id_field",
- query_model=query_model,
- number_additional_docs=2,
- timeout="15s",
- )
-
- self.assertEqual(self.app.query.call_count, 1)
- self.app.query.assert_has_calls(
- [
- call(
- query="this is a query",
- query_model=query_model,
- recall=("vespa_id_field", ["abc"]),
- timeout="15s",
- ),
- ]
- )
- expected_data = []
- self.assertEqual(data, expected_data)
-
- def test_collect_training_data(self):
-
- mock_return_value = [
- {"document_id": "abc", "query_id": "123", "relevant": 1, "a": 1, "b": 2,},
- {"document_id": "def", "query_id": "123", "relevant": 0, "a": 3, "b": 4,},
- {"document_id": "ghi", "query_id": "123", "relevant": 0, "a": 5, "b": 6,},
- ]
- self.app.collect_training_data_point = Mock(return_value=mock_return_value)
- labelled_data = [
- {
- "query_id": 123,
- "query": "this is a query",
- "relevant_docs": [{"id": "abc", "score": 1}],
- }
- ]
- query_model = Query(rank_profile=RankProfile(list_features=True))
- data = self.app.collect_training_data(
- labelled_data=labelled_data,
- id_field="vespa_id_field",
- query_model=query_model,
- number_additional_docs=2,
- timeout="15s",
- )
- self.app.collect_training_data_point.assert_has_calls(
- [
- call(
- query="this is a query",
- query_id=123,
- relevant_id="abc",
- id_field="vespa_id_field",
- query_model=query_model,
- number_additional_docs=2,
- relevant_score=1,
- default_score=0,
- timeout="15s",
- )
- ]
- )
- assert_frame_equal(data, DataFrame.from_records(mock_return_value))
-
-
-class TestVespaEvaluate(unittest.TestCase):
- def setUp(self) -> None:
- self.app = Vespa(url="http://localhost", port=8080)
-
- self.labelled_data = [
- {
- "query_id": 0,
- "query": "Intrauterine virus infections and congenital heart disease",
- "relevant_docs": [{"id": "def", "score": 1}, {"id": "abc", "score": 1}],
- },
- ]
-
- self.query_results = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- "children": [
- {
- "id": "id:covid-19:doc::40216",
- "relevance": 10,
- "source": "content",
- "fields": {
- "vespa_id_field": "ghi",
- "sddocname": "doc",
- "body_text": "this is a body 2",
- "title": "this is a title 2",
- "rankfeatures": {"a": 3, "b": 4},
- },
- },
- {
- "id": "id:covid-19:doc::40217",
- "relevance": 8,
- "source": "content",
- "fields": {
- "vespa_id_field": "def",
- "sddocname": "doc",
- "body_text": "this is a body 3",
- "title": "this is a title 3",
- "rankfeatures": {"a": 5, "b": 6},
- },
- },
- ],
- }
- }
-
- def test_evaluate_query(self):
- self.app.query = Mock(return_value={})
- eval_metric = Mock()
- eval_metric.evaluate_query = Mock(return_value={"metric": 1})
- eval_metric2 = Mock()
- eval_metric2.evaluate_query = Mock(return_value={"metric_2": 2})
- query_model = Query()
- evaluation = self.app.evaluate_query(
- eval_metrics=[eval_metric, eval_metric2],
- query_model=query_model,
- query_id="0",
- query="this is a test",
- id_field="vespa_id_field",
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- default_score=0,
- hits=10,
- )
- self.assertEqual(self.app.query.call_count, 1)
- self.app.query.assert_has_calls(
- [call(query="this is a test", query_model=query_model, hits=10),]
- )
- self.assertEqual(eval_metric.evaluate_query.call_count, 1)
- eval_metric.evaluate_query.assert_has_calls(
- [call({}, self.labelled_data[0]["relevant_docs"], "vespa_id_field", 0),]
- )
- self.assertDictEqual(evaluation, {"query_id": "0", "metric": 1, "metric_2": 2})
-
- def test_evaluate(self):
- self.app.evaluate_query = Mock(side_effect=[{"query_id": "0", "metric": 1},])
- evaluation = self.app.evaluate(
- labelled_data=self.labelled_data,
- eval_metrics=[Mock()],
- query_model=Mock(),
- id_field="mock",
- default_score=0,
- )
- assert_frame_equal(
- evaluation, DataFrame.from_records([{"query_id": "0", "metric": 1}])
- )
diff --git a/python/vespa/vespa/test_evaluation.py b/python/vespa/vespa/test_evaluation.py
deleted file mode 100644
index b6941985d94..00000000000
--- a/python/vespa/vespa/test_evaluation.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-import unittest
-
-from vespa.query import VespaResult
-from vespa.evaluation import MatchRatio, Recall, ReciprocalRank
-
-
-class TestEvalMetric(unittest.TestCase):
- def setUp(self) -> None:
- self.labelled_data = [
- {
- "query_id": 0,
- "query": "Intrauterine virus infections and congenital heart disease",
- "relevant_docs": [{"id": "def", "score": 1}, {"id": "abc", "score": 1}],
- },
- ]
-
- self.query_results = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- "children": [
- {
- "id": "id:covid-19:doc::40216",
- "relevance": 10,
- "source": "content",
- "fields": {
- "vespa_id_field": "ghi",
- "sddocname": "doc",
- "body_text": "this is a body 2",
- "title": "this is a title 2",
- "rankfeatures": {"a": 3, "b": 4},
- },
- },
- {
- "id": "id:covid-19:doc::40217",
- "relevance": 8,
- "source": "content",
- "fields": {
- "vespa_id_field": "def",
- "sddocname": "doc",
- "body_text": "this is a body 3",
- "title": "this is a title 3",
- "rankfeatures": {"a": 5, "b": 6},
- },
- },
- ],
- }
- }
-
- def test_match_ratio(self):
- metric = MatchRatio()
-
- evaluation = metric.evaluate_query(
- query_results=VespaResult(self.query_results),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
-
- self.assertDictEqual(
- evaluation,
- {
- "match_ratio_retrieved_docs": 1083,
- "match_ratio_docs_available": 62529,
- "match_ratio_value": 1083 / 62529,
- },
- )
-
- evaluation = metric.evaluate_query(
- query_results=VespaResult(
- {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- }
- }
- ),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
-
- self.assertDictEqual(
- evaluation,
- {
- "match_ratio_retrieved_docs": 0,
- "match_ratio_docs_available": 62529,
- "match_ratio_value": 0 / 62529,
- },
- )
-
- evaluation = metric.evaluate_query(
- query_results=VespaResult(
- {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- }
- }
- ),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
-
- self.assertDictEqual(
- evaluation,
- {
- "match_ratio_retrieved_docs": 1083,
- "match_ratio_docs_available": 0,
- "match_ratio_value": 0,
- },
- )
-
- def test_recall(self):
- metric = Recall(at=2)
- evaluation = metric.evaluate_query(
- query_results=VespaResult(self.query_results),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
- self.assertDictEqual(
- evaluation, {"recall_2_value": 0.5,},
- )
-
- metric = Recall(at=1)
- evaluation = metric.evaluate_query(
- query_results=VespaResult(self.query_results),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
- self.assertDictEqual(
- evaluation, {"recall_1_value": 0.0,},
- )
-
- def test_reciprocal_rank(self):
- metric = ReciprocalRank(at=2)
- evaluation = metric.evaluate_query(
- query_results=VespaResult(self.query_results),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
- self.assertDictEqual(
- evaluation, {"reciprocal_rank_2_value": 0.5,},
- )
-
- metric = ReciprocalRank(at=1)
- evaluation = metric.evaluate_query(
- query_results=VespaResult(self.query_results),
- relevant_docs=self.labelled_data[0]["relevant_docs"],
- id_field="vespa_id_field",
- default_score=0,
- )
- self.assertDictEqual(
- evaluation, {"reciprocal_rank_1_value": 0.0,},
- )
diff --git a/python/vespa/vespa/test_package.py b/python/vespa/vespa/test_package.py
deleted file mode 100644
index 1dca8bbf014..00000000000
--- a/python/vespa/vespa/test_package.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import unittest
-
-from vespa.package import (
- Field,
- Document,
- FieldSet,
- RankProfile,
- Schema,
- ApplicationPackage,
-)
-
-
-class TestField(unittest.TestCase):
- def test_field_name_type(self):
- field = Field(name="test_name", type="string")
- self.assertEqual(field.name, "test_name")
- self.assertEqual(field.type, "string")
- self.assertEqual(field.to_dict, {"name": "test_name", "type": "string"})
- self.assertEqual(field, Field(name="test_name", type="string"))
- self.assertEqual(field, Field.from_dict(field.to_dict))
- self.assertIsNone(field.indexing_to_text)
-
- def test_field_name_type_indexing_index(self):
- field = Field(
- name="body",
- type="string",
- indexing=["index", "summary"],
- index="enable-bm25",
- )
- self.assertEqual(field.name, "body")
- self.assertEqual(field.type, "string")
- self.assertEqual(field.indexing, ["index", "summary"])
- self.assertEqual(field.index, "enable-bm25")
- self.assertEqual(
- field.to_dict,
- {
- "name": "body",
- "type": "string",
- "indexing": ["index", "summary"],
- "index": "enable-bm25",
- },
- )
- self.assertEqual(
- field,
- Field(
- name="body",
- type="string",
- indexing=["index", "summary"],
- index="enable-bm25",
- ),
- )
- self.assertEqual(field, Field.from_dict(field.to_dict))
- self.assertEqual(field.indexing_to_text, "index | summary")
-
-
-class TestDocument(unittest.TestCase):
- def test_empty_document(self):
- document = Document()
- self.assertEqual(document.fields, [])
- self.assertEqual(document.to_dict, {"fields": []})
- self.assertEqual(document, Document.from_dict(document.to_dict))
-
- def test_document_one_field(self):
- document = Document()
- field = Field(name="test_name", type="string")
- document.add_fields(field)
- self.assertEqual(document.fields, [field])
- self.assertEqual(document, Document.from_dict(document.to_dict))
- self.assertEqual(document, Document([field]))
-
- def test_document_two_fields(self):
- document = Document()
- field_1 = Field(name="test_name", type="string")
- field_2 = Field(
- name="body",
- type="string",
- indexing=["index", "summary"],
- index="enable-bm25",
- )
- document.add_fields(field_1, field_2)
- self.assertEqual(document.fields, [field_1, field_2])
- self.assertEqual(document, Document.from_dict(document.to_dict))
- self.assertEqual(document, Document([field_1, field_2]))
-
-
-class TestFieldSet(unittest.TestCase):
- def test_fieldset(self):
- field_set = FieldSet(name="default", fields=["title", "body"])
- self.assertEqual(field_set.name, "default")
- self.assertEqual(field_set.fields, ["title", "body"])
- self.assertEqual(field_set, FieldSet.from_dict(field_set.to_dict))
- self.assertEqual(field_set.fields_to_text, "title, body")
-
-
-class TestRankProfile(unittest.TestCase):
- def test_rank_profile(self):
- rank_profile = RankProfile(name="bm25", first_phase="bm25(title) + bm25(body)")
- self.assertEqual(rank_profile.name, "bm25")
- self.assertEqual(rank_profile.first_phase, "bm25(title) + bm25(body)")
- self.assertEqual(rank_profile, RankProfile.from_dict(rank_profile.to_dict))
-
- def test_rank_profile_inherits(self):
- rank_profile = RankProfile(
- name="bm25", first_phase="bm25(title) + bm25(body)", inherits="default"
- )
- self.assertEqual(rank_profile.name, "bm25")
- self.assertEqual(rank_profile.first_phase, "bm25(title) + bm25(body)")
- self.assertEqual(rank_profile, RankProfile.from_dict(rank_profile.to_dict))
-
-
-class TestSchema(unittest.TestCase):
- def test_schema(self):
- schema = Schema(
- name="test_schema",
- document=Document(fields=[Field(name="test_name", type="string")]),
- fieldsets=[FieldSet(name="default", fields=["title", "body"])],
- rank_profiles=[
- RankProfile(name="bm25", first_phase="bm25(title) + bm25(body)")
- ],
- )
- self.assertEqual(schema, Schema.from_dict(schema.to_dict))
- self.assertDictEqual(
- schema.rank_profiles,
- {"bm25": RankProfile(name="bm25", first_phase="bm25(title) + bm25(body)")},
- )
- schema.add_rank_profile(
- RankProfile(name="default", first_phase="NativeRank(title)")
- )
- self.assertDictEqual(
- schema.rank_profiles,
- {
- "bm25": RankProfile(
- name="bm25", first_phase="bm25(title) + bm25(body)"
- ),
- "default": RankProfile(name="default", first_phase="NativeRank(title)"),
- },
- )
-
-
-class TestApplicationPackage(unittest.TestCase):
- def setUp(self) -> None:
- test_schema = Schema(
- name="msmarco",
- document=Document(
- fields=[
- Field(name="id", type="string", indexing=["attribute", "summary"]),
- Field(
- name="title",
- type="string",
- indexing=["index", "summary"],
- index="enable-bm25",
- ),
- Field(
- name="body",
- type="string",
- indexing=["index", "summary"],
- index="enable-bm25",
- ),
- ]
- ),
- fieldsets=[FieldSet(name="default", fields=["title", "body"])],
- rank_profiles=[
- RankProfile(name="default", first_phase="nativeRank(title, body)"),
- RankProfile(
- name="bm25",
- first_phase="bm25(title) + bm25(body)",
- inherits="default",
- ),
- ],
- )
- self.app_package = ApplicationPackage(name="test_app", schema=test_schema)
-
- def test_application_package(self):
- self.assertEqual(
- self.app_package, ApplicationPackage.from_dict(self.app_package.to_dict)
- )
-
- def test_schema_to_text(self):
- expected_result = (
- "schema msmarco {\n"
- " document msmarco {\n"
- " field id type string {\n"
- " indexing: attribute | summary\n"
- " }\n"
- " field title type string {\n"
- " indexing: index | summary\n"
- " index: enable-bm25\n"
- " }\n"
- " field body type string {\n"
- " indexing: index | summary\n"
- " index: enable-bm25\n"
- " }\n"
- " }\n"
- " fieldset default {\n"
- " fields: title, body\n"
- " }\n"
- " rank-profile default {\n"
- " first-phase {\n"
- " expression: nativeRank(title, body)\n"
- " }\n"
- " }\n"
- " rank-profile bm25 inherits default {\n"
- " first-phase {\n"
- " expression: bm25(title) + bm25(body)\n"
- " }\n"
- " }\n"
- "}"
- )
- self.assertEqual(self.app_package.schema_to_text, expected_result)
-
- def test_hosts_to_text(self):
- expected_result = (
- '<?xml version="1.0" encoding="utf-8" ?>\n'
- "<!-- Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->\n"
- "<hosts>\n"
- ' <host name="localhost">\n'
- " <alias>node1</alias>\n"
- " </host>\n"
- "</hosts>"
- )
- self.assertEqual(self.app_package.hosts_to_text, expected_result)
-
- def test_services_to_text(self):
- expected_result = (
- '<?xml version="1.0" encoding="UTF-8"?>\n'
- '<services version="1.0">\n'
- ' <container id="test_app_container" version="1.0">\n'
- " <search></search>\n"
- " <document-api></document-api>\n"
- " </container>\n"
- ' <content id="test_app_content" version="1.0">\n'
- ' <redundancy reply-after="1">1</redundancy>\n'
- " <documents>\n"
- ' <document type="msmarco" mode="index"></document>\n'
- " </documents>\n"
- " <nodes>\n"
- ' <node distribution-key="0" hostalias="node1"></node>\n'
- " </nodes>\n"
- " </content>\n"
- "</services>"
- )
-
- self.assertEqual(self.app_package.services_to_text, expected_result)
diff --git a/python/vespa/vespa/test_query.py b/python/vespa/vespa/test_query.py
deleted file mode 100644
index 1e933f25c7d..00000000000
--- a/python/vespa/vespa/test_query.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-import unittest
-
-from vespa.query import Query, OR, AND, WeakAnd, ANN, Union, RankProfile, VespaResult
-
-
-class TestMatchFilter(unittest.TestCase):
- def setUp(self) -> None:
- self.query = "this is a test"
-
- def test_and(self):
- match_filter = AND()
- self.assertEqual(
- match_filter.create_match_filter(query=self.query),
- '(userInput("this is a test"))',
- )
- self.assertDictEqual(match_filter.get_query_properties(query=self.query), {})
-
- def test_or(self):
- match_filter = OR()
- self.assertEqual(
- match_filter.create_match_filter(query=self.query),
- '([{"grammar": "any"}]userInput("this is a test"))',
- )
- self.assertDictEqual(match_filter.get_query_properties(query=self.query), {})
-
- def test_weak_and(self):
- match_filter = WeakAnd(hits=10, field="field_name")
- self.assertEqual(
- match_filter.create_match_filter(query=self.query),
- '([{"targetNumHits": 10}]weakAnd(field_name contains "this", field_name contains "is", field_name contains "", '
- 'field_name contains "a", field_name contains "test"))',
- )
- self.assertDictEqual(match_filter.get_query_properties(query=self.query), {})
-
- def test_ann(self):
- match_filter = ANN(
- doc_vector="doc_vector",
- query_vector="query_vector",
- embedding_model=lambda x: [1, 2, 3],
- hits=10,
- label="label",
- )
- self.assertEqual(
- match_filter.create_match_filter(query=self.query),
- '([{"targetNumHits": 10, "label": "label"}]nearestNeighbor(doc_vector, query_vector))',
- )
- self.assertDictEqual(
- match_filter.get_query_properties(query=self.query),
- {"ranking.features.query(query_vector)": "[1, 2, 3]"},
- )
-
- def test_union(self):
- match_filter = Union(
- WeakAnd(hits=10, field="field_name"),
- ANN(
- doc_vector="doc_vector",
- query_vector="query_vector",
- embedding_model=lambda x: [1, 2, 3],
- hits=10,
- label="label",
- ),
- )
- self.assertEqual(
- match_filter.create_match_filter(query=self.query),
- '([{"targetNumHits": 10}]weakAnd(field_name contains "this", field_name contains "is", '
- 'field_name contains "", '
- 'field_name contains "a", field_name contains "test")) or '
- '([{"targetNumHits": 10, "label": "label"}]nearestNeighbor(doc_vector, query_vector))',
- )
- self.assertDictEqual(
- match_filter.get_query_properties(query=self.query),
- {"ranking.features.query(query_vector)": "[1, 2, 3]"},
- )
-
-
-class TestRankProfile(unittest.TestCase):
- def test_rank_profile(self):
- rank_profile = RankProfile(name="rank_profile", list_features=True)
- self.assertEqual(rank_profile.name, "rank_profile")
- self.assertEqual(rank_profile.list_features, "true")
-
-
-class TestQuery(unittest.TestCase):
- def setUp(self) -> None:
- self.query = "this is a test"
-
- def test_default(self):
- query = Query()
- self.assertDictEqual(
- query.create_body(query=self.query),
- {
- "yql": 'select * from sources * where (userInput("this is a test"));',
- "ranking": {"profile": "default", "listFeatures": "false"},
- },
- )
-
- def test_match_and_rank(self):
- query = Query(
- match_phase=ANN(
- doc_vector="doc_vector",
- query_vector="query_vector",
- embedding_model=lambda x: [1, 2, 3],
- hits=10,
- label="label",
- ),
- rank_profile=RankProfile(name="bm25", list_features=True),
- )
- self.assertDictEqual(
- query.create_body(query=self.query),
- {
- "yql": 'select * from sources * where ([{"targetNumHits": 10, "label": "label"}]nearestNeighbor(doc_vector, query_vector));',
- "ranking": {"profile": "bm25", "listFeatures": "true"},
- "ranking.features.query(query_vector)": "[1, 2, 3]",
- },
- )
-
-
-class TestVespaResult(unittest.TestCase):
- def setUp(self) -> None:
- self.raw_vespa_result_empty_hits = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 0},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- }
- }
-
- self.raw_vespa_result = {
- "root": {
- "id": "toplevel",
- "relevance": 1.0,
- "fields": {"totalCount": 1083},
- "coverage": {
- "coverage": 100,
- "documents": 62529,
- "full": True,
- "nodes": 2,
- "results": 1,
- "resultsFull": 1,
- },
- "children": [
- {
- "id": "id:covid-19:doc::40215",
- "relevance": 30.368213170494712,
- "source": "content",
- "fields": {
- "sddocname": "doc",
- "body_text": "this is a body",
- "title": "this is a title",
- },
- }
- ],
- }
- }
-
- def test_json(self):
- vespa_result = VespaResult(vespa_result=self.raw_vespa_result)
- self.assertDictEqual(vespa_result.json, self.raw_vespa_result)
-
- def test_hits(self):
- empty_hits_vespa_result = VespaResult(
- vespa_result=self.raw_vespa_result_empty_hits
- )
- self.assertEqual(empty_hits_vespa_result.hits, [])
- vespa_result = VespaResult(vespa_result=self.raw_vespa_result)
- self.assertEqual(
- vespa_result.hits,
- [
- {
- "id": "id:covid-19:doc::40215",
- "relevance": 30.368213170494712,
- "source": "content",
- "fields": {
- "sddocname": "doc",
- "body_text": "this is a body",
- "title": "this is a title",
- },
- }
- ],
- )
diff --git a/screwdriver.yaml b/screwdriver.yaml
new file mode 100644
index 00000000000..6b3795e6da6
--- /dev/null
+++ b/screwdriver.yaml
@@ -0,0 +1,77 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+---
+cache:
+ job:
+ main: [/main_job_cache]
+
+jobs:
+ main:
+ requires: [~pr, ~commit]
+ image: vespaengine/vespa-build-centos7
+ annotations:
+ screwdriver.cd/cpu: 8
+ screwdriver.cd/ram: 16
+ screwdriver.cd/disk: HIGH
+ screwdriver.cd/timeout: 600
+
+ environment:
+ LOCAL_MVN_REPO: "/tmp/vespa/mvnrepo"
+ VESPA_MAVEN_EXTRA_OPTS: "-Dmaven.repo.local=/tmp/vespa/mvnrepo -Dmaven.javadoc.skip=true -Dmaven.source.skip=true"
+ CCACHE_TMP_DIR: "/tmp/ccache_tmp"
+ CCACHE_DATA_DIR: "/tmp/vespa/ccache"
+ MAIN_CACHE_FILE: "/main_job_cache/vespa.tar"
+
+ steps:
+ - inspect: |
+ set -x
+ env | grep -v TOKEN
+ cat /proc/cpuinfo
+ cat /proc/meminfo
+ df -h
+ uname -a
+ - restore-cache: |
+ (cd /tmp && if [[ -f $MAIN_CACHE_FILE ]]; then tar xf $MAIN_CACHE_FILE; fi)
+
+ mkdir -p $CCACHE_DATA_DIR
+ mkdir -p $CCACHE_TMP_DIR
+
+ export CCACHE_DIR=$CCACHE_DATA_DIR
+
+ rm -f $CCACHE_DIR/ccache.conf
+ ccache -M 20G
+ ccache -o log_file=$SD_ARTIFACTS_DIR/ccache_log.txt
+ ccache -o temporary_dir=$CCACHE_TMP_DIR
+ ccache -p
+ ccache -z
+
+ - compile: |
+ export TRAVIS_REPO_SLUG="vespa-engine/vespa"
+ if [[ -z $SD_PULL_REQUEST ]]; then
+ export TRAVIS_PULL_REQUEST=false
+ else
+ export TRAVIS_PULL_REQUEST=$SD_PULL_REQUEST
+ fi
+
+ travis/travis-build.sh
+
+ - save-cache: |
+ if [[ -z "$SD_PULL_REQUEST" ]]; then
+ # Remove what we have produced
+ rm -rf $LOCAL_MVN_REPO/com/yahoo
+ rm -rf $LOCAL_MVN_REPO/ai/vespa
+
+ # Tar toghether the /tmp/vespa folder containing ccache and cleaned mvn repo
+ mkdir -p $(dirname $MAIN_CACHE_FILE)
+ (cd /tmp && tar cf $MAIN_CACHE_FILE vespa)
+
+ # Wipe the cache if we exceed 2GB to avoid pulling and pusing too large files
+ if (( $(stat --format='%s' $MAIN_CACHE_FILE) > $(( 2*1000*1000*1000 )) )); then
+ tar cf $MAIN_CACHE_FILE --files-from=/dev/null;
+ echo "Cleaning cache file. $MAIN_CACHE_FILE is now $(stat --format='%s' $MAIN_CACHE_FILE) bytes."
+ fi
+ fi
+
+ - inspect-after: |
+ du -sh /tmp/vespa/*
+ ls -la /main_job_cache || true
+ df -h
diff --git a/searchcommon/src/vespa/searchcommon/common/schema.cpp b/searchcommon/src/vespa/searchcommon/common/schema.cpp
index c59edbef22f..735365f6aaf 100644
--- a/searchcommon/src/vespa/searchcommon/common/schema.cpp
+++ b/searchcommon/src/vespa/searchcommon/common/schema.cpp
@@ -69,17 +69,17 @@ namespace index {
const uint32_t Schema::UNKNOWN_FIELD_ID(std::numeric_limits<uint32_t>::max());
-Schema::Field::Field(vespalib::stringref n, DataType dt)
+Schema::Field::Field(vespalib::stringref n, DataType dt) noexcept
: Field(n, dt, schema::CollectionType::SINGLE, "")
{
}
-Schema::Field::Field(vespalib::stringref n, DataType dt, CollectionType ct)
+Schema::Field::Field(vespalib::stringref n, DataType dt, CollectionType ct) noexcept
: Field(n, dt, ct, "")
{
}
-Schema::Field::Field(vespalib::stringref n, DataType dt, CollectionType ct, vespalib::stringref tensor_spec)
+Schema::Field::Field(vespalib::stringref n, DataType dt, CollectionType ct, vespalib::stringref tensor_spec) noexcept
: _name(n),
_dataType(dt),
_collectionType(ct),
@@ -95,8 +95,8 @@ Schema::Field::Field(const std::vector<vespalib::string> & lines)
{
}
-Schema::Field::Field(const Field &) = default;
-Schema::Field & Schema::Field::operator = (const Field &) = default;
+Schema::Field::Field(const Field &) noexcept = default;
+Schema::Field & Schema::Field::operator = (const Field &) noexcept = default;
Schema::Field::Field(Field &&) noexcept = default;
Schema::Field & Schema::Field::operator = (Field &&) noexcept = default;
@@ -125,7 +125,7 @@ Schema::Field::operator!=(const Field &rhs) const
return !((*this) == rhs);
}
-Schema::IndexField::IndexField(vespalib::stringref name, DataType dt)
+Schema::IndexField::IndexField(vespalib::stringref name, DataType dt) noexcept
: Field(name, dt),
_avgElemLen(512),
_interleaved_features(false)
@@ -133,7 +133,7 @@ Schema::IndexField::IndexField(vespalib::stringref name, DataType dt)
}
Schema::IndexField::IndexField(vespalib::stringref name, DataType dt,
- CollectionType ct)
+ CollectionType ct) noexcept
: Field(name, dt, ct),
_avgElemLen(512),
_interleaved_features(false)
@@ -147,8 +147,8 @@ Schema::IndexField::IndexField(const std::vector<vespalib::string> &lines)
{
}
-Schema::IndexField::IndexField(const IndexField &) = default;
-Schema::IndexField & Schema::IndexField::operator = (const IndexField &) = default;
+Schema::IndexField::IndexField(const IndexField &) noexcept = default;
+Schema::IndexField & Schema::IndexField::operator = (const IndexField &) noexcept = default;
Schema::IndexField::IndexField(IndexField &&) noexcept = default;
Schema::IndexField & Schema::IndexField::operator = (IndexField &&) noexcept = default;
diff --git a/searchcommon/src/vespa/searchcommon/common/schema.h b/searchcommon/src/vespa/searchcommon/common/schema.h
index 9003578adaf..740cf4ffad6 100644
--- a/searchcommon/src/vespa/searchcommon/common/schema.h
+++ b/searchcommon/src/vespa/searchcommon/common/schema.h
@@ -38,16 +38,16 @@ public:
vespalib::string _tensor_spec;
public:
- Field(vespalib::stringref n, DataType dt);
- Field(vespalib::stringref n, DataType dt, CollectionType ct);
- Field(vespalib::stringref n, DataType dt, CollectionType ct, vespalib::stringref tensor_spec);
+ Field(vespalib::stringref n, DataType dt) noexcept;
+ Field(vespalib::stringref n, DataType dt, CollectionType ct) noexcept;
+ Field(vespalib::stringref n, DataType dt, CollectionType ct, vespalib::stringref tensor_spec) noexcept;
/**
* Create this field based on the given config lines.
**/
Field(const std::vector<vespalib::string> & lines);
- Field(const Field &);
- Field & operator = (const Field &);
+ Field(const Field &) noexcept;
+ Field & operator = (const Field &) noexcept;
Field(Field &&) noexcept;
Field & operator = (Field &&) noexcept;
@@ -83,10 +83,10 @@ public:
bool _interleaved_features;
public:
- IndexField(vespalib::stringref name, DataType dt);
- IndexField(vespalib::stringref name, DataType dt, CollectionType ct);
- IndexField(const IndexField &);
- IndexField & operator = (const IndexField &);
+ IndexField(vespalib::stringref name, DataType dt) noexcept;
+ IndexField(vespalib::stringref name, DataType dt, CollectionType ct) noexcept;
+ IndexField(const IndexField &) noexcept;
+ IndexField & operator = (const IndexField &) noexcept;
IndexField(IndexField &&) noexcept;
IndexField & operator = (IndexField &&) noexcept;
/**
diff --git a/searchcore/src/apps/verify_ranksetup/verify_ranksetup.cpp b/searchcore/src/apps/verify_ranksetup/verify_ranksetup.cpp
index bea93f82c2d..559e8fd14cd 100644
--- a/searchcore/src/apps/verify_ranksetup/verify_ranksetup.cpp
+++ b/searchcore/src/apps/verify_ranksetup/verify_ranksetup.cpp
@@ -11,8 +11,8 @@
#include <vespa/config/common/exceptions.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value_cache/constant_value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/common/schemaconfigurer.h>
#include <vespa/searchcore/config/config-ranking-constants.h>
#include <vespa/searchcore/config/config-onnx-models.h>
@@ -42,7 +42,7 @@ using vespa::config::search::core::OnnxModelsConfig;
using vespa::config::search::core::VerifyRanksetupConfig;
using vespalib::eval::BadConstantValue;
using vespalib::eval::ConstantValue;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::SimpleConstantValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
@@ -97,7 +97,7 @@ struct DummyConstantValueRepo : IConstantValueRepo {
for (const auto &entry: cfg.constant) {
if (entry.name == name) {
try {
- auto tensor = EngineOrFactory::get().from_spec(TensorSpec(entry.type));
+ auto tensor = vespalib::eval::value_from_spec(TensorSpec(entry.type), FastValueBuilderFactory::get());
return std::make_unique<SimpleConstantValue>(std::move(tensor));
} catch (std::exception &) {
return std::make_unique<BadConstantValue>();
diff --git a/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp b/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
index f034ccdd6d1..a842caef379 100644
--- a/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
+++ b/searchcore/src/apps/vespa-dump-feed/vespa-dump-feed.cpp
@@ -6,7 +6,6 @@
#include <vespa/document/document.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/documentapi/documentapi.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/messagebus/destinationsession.h>
#include <vespa/messagebus/protocolset.h>
#include <vespa/messagebus/rpcmessagebus.h>
@@ -47,7 +46,6 @@ public:
class FeedHandler : public mbus::IMessageHandler
{
private:
- documentapi::LoadTypeSet _loadTypes;
mbus::RPCMessageBus _mbus;
mbus::DestinationSession::UP _session;
OutputFile &_idx;
@@ -95,8 +93,7 @@ FeedHandler::handleMessage(mbus::Message::UP message)
}
FeedHandler::FeedHandler(std::shared_ptr<const document::DocumentTypeRepo> repo, OutputFile &idx, OutputFile &dat)
- : _loadTypes(),
- _mbus(mbus::MessageBusParams().addProtocol(mbus::IProtocol::SP(new documentapi::DocumentProtocol(_loadTypes, repo))),
+ : _mbus(mbus::MessageBusParams().addProtocol(std::make_shared<documentapi::DocumentProtocol>(repo)),
mbus::RPCNetworkParams()),
_session(_mbus.getMessageBus()
.createDestinationSession(mbus::DestinationSessionParams()
diff --git a/searchcore/src/apps/vespa-feed-bm/bm_cluster_controller.cpp b/searchcore/src/apps/vespa-feed-bm/bm_cluster_controller.cpp
index 15fbb2e2344..a1b40c56e11 100644
--- a/searchcore/src/apps/vespa-feed-bm/bm_cluster_controller.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/bm_cluster_controller.cpp
@@ -42,7 +42,8 @@ BmClusterController::BmClusterController(SharedRpcResources& shared_rpc_resource
void
BmClusterController::set_cluster_up(bool distributor)
{
- StorageMessageAddress storage_address("storage", distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0);
+ static vespalib::string _storage("storage");
+ StorageMessageAddress storage_address(&_storage, distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0);
auto req = make_set_cluster_state_request();
auto target_resolver = std::make_unique<storage::rpc::CachingRpcTargetResolver>(_shared_rpc_resources.slobrok_mirror(),
_shared_rpc_resources.target_factory(), 1);
diff --git a/searchcore/src/apps/vespa-feed-bm/bm_message_bus.cpp b/searchcore/src/apps/vespa-feed-bm/bm_message_bus.cpp
index ec50a4c7c01..b608593dada 100644
--- a/searchcore/src/apps/vespa-feed-bm/bm_message_bus.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/bm_message_bus.cpp
@@ -129,16 +129,15 @@ BmMessageBus::ReplyHandler::message_aborted(uint64_t msg_id)
}
BmMessageBus::BmMessageBus(const config::ConfigUri& config_uri,
- std::shared_ptr<const document::DocumentTypeRepo> document_type_repo,
- const documentapi::LoadTypeSet& load_types)
+ std::shared_ptr<const document::DocumentTypeRepo> document_type_repo)
: _reply_handler(std::make_unique<ReplyHandler>()),
_message_bus(),
_session()
{
mbus::RPCNetworkParams params(config_uri);
mbus::ProtocolSet protocol_set;
- protocol_set.add(std::make_shared<DocumentProtocol>(load_types, document_type_repo));
- protocol_set.add(std::make_shared<StorageProtocol>(document_type_repo, load_types));
+ protocol_set.add(std::make_shared<DocumentProtocol>(document_type_repo));
+ protocol_set.add(std::make_shared<StorageProtocol>(document_type_repo));
params.setIdentity(mbus::Identity("vespa-bm-client"));
_message_bus = std::make_unique<mbus::RPCMessageBus>(
protocol_set,
diff --git a/searchcore/src/apps/vespa-feed-bm/bm_message_bus.h b/searchcore/src/apps/vespa-feed-bm/bm_message_bus.h
index 9ebe394e9e6..a9cff1fb826 100644
--- a/searchcore/src/apps/vespa-feed-bm/bm_message_bus.h
+++ b/searchcore/src/apps/vespa-feed-bm/bm_message_bus.h
@@ -6,7 +6,6 @@
namespace config { class ConfigUri; }
namespace document { class DocumentTypeRepo; }
-namespace documentapi { class LoadTypeSet; }
namespace mbus {
@@ -32,8 +31,7 @@ class BmMessageBus
std::unique_ptr<mbus::SourceSession> _session;
public:
BmMessageBus(const config::ConfigUri& config_uri,
- std::shared_ptr<const document::DocumentTypeRepo> document_type_repo,
- const documentapi::LoadTypeSet& load_types);
+ std::shared_ptr<const document::DocumentTypeRepo> document_type_repo);
~BmMessageBus();
uint32_t get_error_count() const;
void send_msg(std::unique_ptr<mbus::Message> msg, const mbus::Route &route, PendingTracker &tracker);
diff --git a/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.cpp b/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.cpp
index 714add169fd..38c8490de69 100644
--- a/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.cpp
@@ -19,10 +19,14 @@ using storage::lib::NodeType;
namespace feedbm {
+namespace {
+ vespalib::string _Storage("storage");
+}
+
DocumentApiMessageBusBmFeedHandler::DocumentApiMessageBusBmFeedHandler(BmMessageBus &message_bus)
: IBmFeedHandler(),
_name(vespalib::string("DocumentApiMessageBusBmFeedHandler(distributor)")),
- _storage_address(std::make_unique<StorageMessageAddress>("storage", NodeType::DISTRIBUTOR, 0)),
+ _storage_address(std::make_unique<StorageMessageAddress>(&_Storage, NodeType::DISTRIBUTOR, 0)),
_message_bus(message_bus),
_route(_storage_address->to_mbus_route())
{
@@ -82,12 +86,6 @@ DocumentApiMessageBusBmFeedHandler::get_name() const
}
bool
-DocumentApiMessageBusBmFeedHandler::manages_buckets() const
-{
- return true;
-}
-
-bool
DocumentApiMessageBusBmFeedHandler::manages_timestamp() const
{
return true;
diff --git a/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.h
index 52e0b89007f..c71bb113c5b 100644
--- a/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/document_api_message_bus_bm_feed_handler.h
@@ -34,7 +34,6 @@ public:
void attach_bucket_info_queue(PendingTracker &tracker) override;
uint32_t get_error_count() const override;
const vespalib::string &get_name() const override;
- bool manages_buckets() const override;
bool manages_timestamp() const override;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/i_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/i_bm_feed_handler.h
index f359e5a7fa2..26cbf27b455 100644
--- a/searchcore/src/apps/vespa-feed-bm/i_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/i_bm_feed_handler.h
@@ -31,7 +31,6 @@ public:
virtual void attach_bucket_info_queue(PendingTracker& tracker) = 0;
virtual uint32_t get_error_count() const = 0;
virtual const vespalib::string &get_name() const = 0;
- virtual bool manages_buckets() const = 0;
virtual bool manages_timestamp() const = 0;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/pending_tracker.cpp b/searchcore/src/apps/vespa-feed-bm/pending_tracker.cpp
index 25a14db9267..94bed4cb3bd 100644
--- a/searchcore/src/apps/vespa-feed-bm/pending_tracker.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/pending_tracker.cpp
@@ -2,14 +2,16 @@
#include "pending_tracker.h"
#include "bucket_info_queue.h"
+#include <thread>
+#include <chrono>
+
+using namespace std::chrono_literals;
namespace feedbm {
PendingTracker::PendingTracker(uint32_t limit)
: _pending(0u),
_limit(limit),
- _mutex(),
- _cond(),
_bucket_info_queue()
{
}
@@ -20,22 +22,26 @@ PendingTracker::~PendingTracker()
}
void
+PendingTracker::retain() {
+ while (_pending >= _limit) {
+ std::this_thread::sleep_for(1ms);
+ }
+ _pending++;
+}
+
+void
PendingTracker::drain()
{
if (_bucket_info_queue) {
_bucket_info_queue->get_bucket_info_loop();
}
- std::unique_lock<std::mutex> guard(_mutex);
while (_pending > 0) {
- _cond.wait(guard);
+ std::this_thread::sleep_for(1ms);
if (_bucket_info_queue) {
- guard.unlock();
_bucket_info_queue->get_bucket_info_loop();
- guard.lock();
}
}
if (_bucket_info_queue) {
- guard.unlock();
_bucket_info_queue->get_bucket_info_loop();
}
}
diff --git a/searchcore/src/apps/vespa-feed-bm/pending_tracker.h b/searchcore/src/apps/vespa-feed-bm/pending_tracker.h
index 96b1a50141b..4ca84ab7442 100644
--- a/searchcore/src/apps/vespa-feed-bm/pending_tracker.h
+++ b/searchcore/src/apps/vespa-feed-bm/pending_tracker.h
@@ -2,8 +2,6 @@
#pragma once
-#include <mutex>
-#include <condition_variable>
#include <atomic>
#include <memory>
@@ -18,10 +16,8 @@ class BucketInfoQueue;
* benchmark feeding.
*/
class PendingTracker {
- uint32_t _pending;
+ std::atomic<uint32_t> _pending;
uint32_t _limit;
- std::mutex _mutex;
- std::condition_variable _cond;
std::unique_ptr<BucketInfoQueue> _bucket_info_queue;
public:
@@ -29,20 +25,9 @@ public:
~PendingTracker();
void release() {
- std::unique_lock<std::mutex> guard(_mutex);
- --_pending;
- if (_pending < _limit) {
- _cond.notify_all();
- }
+ _pending--;
}
- void retain() {
- std::unique_lock<std::mutex> guard(_mutex);
- while (_pending >= _limit) {
- _cond.wait(guard);
- }
- ++_pending;
- }
-
+ void retain();
void drain();
void attach_bucket_info_queue(storage::spi::PersistenceProvider& provider, std::atomic<uint32_t>& errors);
diff --git a/searchcore/src/apps/vespa-feed-bm/runtest.sh b/searchcore/src/apps/vespa-feed-bm/runtest.sh
index fc67354f7f6..123cce6fdf0 100755
--- a/searchcore/src/apps/vespa-feed-bm/runtest.sh
+++ b/searchcore/src/apps/vespa-feed-bm/runtest.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-numdocs=2000000
+numdocs=500000
stripe_bits=8
base_cmd="numactl --cpunodebind=0 --localalloc perf stat -ddd env LD_PRELOAD=$HOME/vespa/lib64/vespa/malloc/libvespamalloc.so ./vespa-feed-bm --documents $numdocs --put-passes 1 --update-passes 10 --remove-passes 0 --indexing-sequencer throughput"
@@ -8,12 +8,13 @@ base_cmd="numactl --cpunodebind=0 --localalloc perf stat -ddd env LD_PRELOAD=$HO
spi_only="$base_cmd --max-pending 8000 --client-threads 1"
base_for_rest="$base_cmd --max-pending 2000 --client-threads 2 --response-threads 3"
-chain_base="$base_for_rest --use-storage-chain "
+chain_base="$base_for_rest --use-storage-chain"
chain_stripe="$chain_base --bucket-db-stripe-bits $stripe_bits"
chain_stripe_async="$chain_stripe --use-async-message-handling"
service_layer="$base_for_rest --enable-service-layer --bucket-db-stripe-bits $stripe_bits --use-async-message-handling"
service_layer_rpc="$service_layer --rpc-network-threads 3 --rpc-targets-per-node 14"
service_layer_mbus="$service_layer --use-message-bus"
+distributor_chain="$service_layer_rpc --enable-distributor --use-storage-chain"
distributor="$service_layer_rpc --enable-distributor"
echo "Running test: spi_only"
@@ -28,5 +29,7 @@ echo "Running test: service_layer_rpc"
$service_layer_rpc
echo "Running test: service_layer_mbus"
$service_layer_mbus
+echo "Running test: distributor_chain"
+$distributor_chain
echo "Running test: distributor"
$distributor
diff --git a/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.cpp b/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.cpp
index daebc8a7a47..11149eecb3f 100644
--- a/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.cpp
@@ -150,12 +150,6 @@ SpiBmFeedHandler::get_name() const
}
bool
-SpiBmFeedHandler::manages_buckets() const
-{
- return false;
-}
-
-bool
SpiBmFeedHandler::manages_timestamp() const
{
return false;
diff --git a/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.h
index f6cbcc3b954..a78aa06628b 100644
--- a/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/spi_bm_feed_handler.h
@@ -31,7 +31,6 @@ public:
void attach_bucket_info_queue(PendingTracker &tracker) override;
uint32_t get_error_count() const override;
const vespalib::string &get_name() const override;
- bool manages_buckets() const override;
bool manages_timestamp() const override;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.cpp b/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.cpp
index 8cde6a7a25d..82cf2df065f 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.cpp
@@ -100,12 +100,6 @@ StorageApiChainBmFeedHandler::get_name() const
}
bool
-StorageApiChainBmFeedHandler::manages_buckets() const
-{
- return _distributor;
-}
-
-bool
StorageApiChainBmFeedHandler::manages_timestamp() const
{
return _distributor;
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.h
index 689b4c20203..0c4b715122e 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_chain_bm_feed_handler.h
@@ -32,7 +32,6 @@ public:
void attach_bucket_info_queue(PendingTracker &tracker) override;
uint32_t get_error_count() const override;
const vespalib::string &get_name() const override;
- bool manages_buckets() const override;
bool manages_timestamp() const override;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.cpp b/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.cpp
index 18c1b979895..f63a8e33cc0 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.cpp
@@ -17,11 +17,14 @@ using storage::lib::NodeType;
namespace feedbm {
+namespace {
+ vespalib::string _Storage("storage");
+}
StorageApiMessageBusBmFeedHandler::StorageApiMessageBusBmFeedHandler(BmMessageBus &message_bus, bool distributor)
: IBmFeedHandler(),
_name(vespalib::string("StorageApiMessageBusBmFeedHandler(") + (distributor ? "distributor" : "service-layer") + ")"),
_distributor(distributor),
- _storage_address(std::make_unique<StorageMessageAddress>("storage", distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0)),
+ _storage_address(std::make_unique<StorageMessageAddress>(&_Storage, distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0)),
_message_bus(message_bus),
_route(_storage_address->to_mbus_route())
{
@@ -83,12 +86,6 @@ StorageApiMessageBusBmFeedHandler::get_name() const
}
bool
-StorageApiMessageBusBmFeedHandler::manages_buckets() const
-{
- return _distributor;
-}
-
-bool
StorageApiMessageBusBmFeedHandler::manages_timestamp() const
{
return _distributor;
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.h
index 6925053ad43..2aafd0c6830 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_message_bus_bm_feed_handler.h
@@ -38,7 +38,6 @@ public:
void attach_bucket_info_queue(PendingTracker &tracker) override;
uint32_t get_error_count() const override;
const vespalib::string &get_name() const override;
- bool manages_buckets() const override;
bool manages_timestamp() const override;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.cpp b/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.cpp
index 55de3e6048f..04d49bba0a3 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.cpp
@@ -6,14 +6,12 @@
#include "storage_reply_error_checker.h"
#include <vespa/document/fieldvalue/document.h>
#include <vespa/document/update/documentupdate.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/storageapi/messageapi/storagemessage.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storage/storageserver/message_dispatcher.h>
#include <vespa/storage/storageserver/rpc/message_codec_provider.h>
#include <vespa/storage/storageserver/rpc/shared_rpc_resources.h>
#include <vespa/storage/storageserver/rpc/storage_api_rpc_service.h>
-#include <cassert>
using document::Document;
using document::DocumentId;
@@ -26,6 +24,10 @@ using storage::lib::NodeType;
namespace feedbm {
+namespace {
+ vespalib::string _Storage("storage");
+}
+
class StorageApiRpcBmFeedHandler::MyMessageDispatcher : public storage::MessageDispatcher,
public StorageReplyErrorChecker
{
@@ -68,10 +70,10 @@ StorageApiRpcBmFeedHandler::StorageApiRpcBmFeedHandler(SharedRpcResources& share
: IBmFeedHandler(),
_name(vespalib::string("StorageApiRpcBmFeedHandler(") + (distributor ? "distributor" : "service-layer") + ")"),
_distributor(distributor),
- _storage_address(std::make_unique<StorageMessageAddress>("storage", distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0)),
+ _storage_address(std::make_unique<StorageMessageAddress>(&_Storage, distributor ? NodeType::DISTRIBUTOR : NodeType::STORAGE, 0)),
_shared_rpc_resources(shared_rpc_resources_in),
_message_dispatcher(std::make_unique<MyMessageDispatcher>()),
- _message_codec_provider(std::make_unique<storage::rpc::MessageCodecProvider>(repo, std::make_shared<documentapi::LoadTypeSet>())),
+ _message_codec_provider(std::make_unique<storage::rpc::MessageCodecProvider>(repo)),
_rpc_client(std::make_unique<storage::rpc::StorageApiRpcService>(*_message_dispatcher, _shared_rpc_resources, *_message_codec_provider, rpc_params))
{
}
@@ -133,12 +135,6 @@ StorageApiRpcBmFeedHandler::get_name() const
}
bool
-StorageApiRpcBmFeedHandler::manages_buckets() const
-{
- return _distributor;
-}
-
-bool
StorageApiRpcBmFeedHandler::manages_timestamp() const
{
return _distributor;
diff --git a/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.h b/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.h
index ff38c24e167..5057d8889a5 100644
--- a/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.h
+++ b/searchcore/src/apps/vespa-feed-bm/storage_api_rpc_bm_feed_handler.h
@@ -47,7 +47,6 @@ public:
void attach_bucket_info_queue(PendingTracker &tracker) override;
uint32_t get_error_count() const override;
const vespalib::string &get_name() const override;
- bool manages_buckets() const override;
bool manages_timestamp() const override;
};
diff --git a/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp b/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp
index a55638651d6..170885d1d99 100644
--- a/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp
+++ b/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp
@@ -15,7 +15,6 @@
#include <vespa/config-bucketspaces.h>
#include <vespa/config-imported-fields.h>
#include <vespa/config-indexschema.h>
-#include <vespa/config-load-type.h>
#include <vespa/config-persistence.h>
#include <vespa/config-rank-profiles.h>
#include <vespa/config-slobroks.h>
@@ -86,7 +85,6 @@ using namespace std::chrono_literals;
using namespace vespa::config::search::core;
using namespace vespa::config::search::summary;
using namespace vespa::config::search;
-using vespa::config::content::LoadTypeConfigBuilder;
using vespa::config::content::PersistenceConfigBuilder;
using vespa::config::content::StorDistributionConfigBuilder;
using vespa::config::content::StorFilestorConfigBuilder;
@@ -271,6 +269,7 @@ class BMParams {
uint32_t _update_passes;
uint32_t _remove_passes;
uint32_t _rpc_network_threads;
+ uint32_t _rpc_events_before_wakeup;
uint32_t _rpc_targets_per_node;
uint32_t _response_threads;
uint32_t _max_pending;
@@ -294,7 +293,8 @@ public:
_put_passes(2),
_update_passes(1),
_remove_passes(2),
- _rpc_network_threads(1), // Same default as in stor-communicationmanager.def
+ _rpc_network_threads(1), // Same default as previous in stor-communicationmanager.def
+ _rpc_events_before_wakeup(1), // Same default as in stor-communicationmanager.def
_rpc_targets_per_node(1), // Same default as in stor-communicationmanager.def
_response_threads(2), // Same default as in stor-filestor.def
_max_pending(1000),
@@ -320,6 +320,7 @@ public:
uint32_t get_update_passes() const { return _update_passes; }
uint32_t get_remove_passes() const { return _remove_passes; }
uint32_t get_rpc_network_threads() const { return _rpc_network_threads; }
+ uint32_t get_rpc_events_before_wakup() const { return _rpc_events_before_wakeup; }
uint32_t get_rpc_targets_per_node() const { return _rpc_targets_per_node; }
uint32_t get_response_threads() const { return _response_threads; }
bool get_enable_distributor() const { return _enable_distributor; }
@@ -338,6 +339,7 @@ public:
void set_update_passes(uint32_t update_passes_in) { _update_passes = update_passes_in; }
void set_remove_passes(uint32_t remove_passes_in) { _remove_passes = remove_passes_in; }
void set_rpc_network_threads(uint32_t threads_in) { _rpc_network_threads = threads_in; }
+ void set_rpc_events_before_wakeup(uint32_t value) { _rpc_events_before_wakeup = value; }
void set_rpc_targets_per_node(uint32_t targets_in) { _rpc_targets_per_node = targets_in; }
void set_response_threads(uint32_t threads_in) { _response_threads = threads_in; }
void set_enable_distributor(bool value) { _enable_distributor = value; }
@@ -444,7 +446,6 @@ struct MyStorageConfig
StorServerConfigBuilder stor_server;
StorStatusConfigBuilder stor_status;
BucketspacesConfigBuilder bucketspaces;
- LoadTypeConfigBuilder load_type;
MetricsmanagerConfigBuilder metricsmanager;
SlobroksConfigBuilder slobroks;
MessagebusConfigBuilder messagebus;
@@ -462,7 +463,6 @@ struct MyStorageConfig
stor_server(),
stor_status(),
bucketspaces(),
- load_type(),
metricsmanager(),
slobroks(),
messagebus()
@@ -495,6 +495,7 @@ struct MyStorageConfig
make_slobroks_config(slobroks, slobrok_port);
stor_communicationmanager.useDirectStorageapiRpc = true;
stor_communicationmanager.rpc.numNetworkThreads = params.get_rpc_network_threads();
+ stor_communicationmanager.rpc.eventsBeforeWakeup = params.get_rpc_events_before_wakup();
stor_communicationmanager.rpc.numTargetsPerNode = params.get_rpc_targets_per_node();
stor_communicationmanager.mbusport = mbus_port;
stor_communicationmanager.rpcport = rpc_port;
@@ -516,7 +517,6 @@ struct MyStorageConfig
set.addBuilder(config_id, &stor_server);
set.addBuilder(config_id, &stor_status);
set.addBuilder(config_id, &bucketspaces);
- set.addBuilder(config_id, &load_type);
set.addBuilder(config_id, &metricsmanager);
set.addBuilder(config_id, &slobroks);
set.addBuilder(config_id, &messagebus);
@@ -883,7 +883,8 @@ PersistenceProviderFixture::start_service_layer(const BMParams& params)
_service_layer->getNode().waitUntilInitialized();
LOG(info, "start rpc client shared resources");
config::ConfigUri client_config_uri("bm-rpc-client", _config_context);
- _rpc_client_shared_rpc_resources = std::make_unique<SharedRpcResources>(client_config_uri, _rpc_client_port, 100);
+ _rpc_client_shared_rpc_resources = std::make_unique<SharedRpcResources>
+ (client_config_uri, _rpc_client_port, 100, params.get_rpc_events_before_wakup());
_rpc_client_shared_rpc_resources->start_server_and_register_slobrok("bm-rpc-client");
wait_slobrok("storage/cluster.storage/storage/0/default");
wait_slobrok("storage/cluster.storage/storage/0");
@@ -919,9 +920,7 @@ PersistenceProviderFixture::start_message_bus()
{
config::ConfigUri config_uri("bm-message-bus", _config_context);
LOG(info, "Starting message bus");
- _message_bus = std::make_unique<BmMessageBus>(config_uri,
- _repo,
- documentapi::LoadTypeSet());
+ _message_bus = std::make_unique<BmMessageBus>(config_uri, _repo);
LOG(info, "Started message bus");
}
@@ -1309,7 +1308,7 @@ void benchmark_async_spi(const BMParams &bm_params)
LOG(info, "start initialize");
provider.initialize();
LOG(info, "create %u buckets", f.num_buckets());
- if (!f._feed_handler->manages_buckets()) {
+ if (!bm_params.needs_distributor()) {
f.create_buckets();
}
if (bm_params.needs_service_layer()) {
@@ -1376,6 +1375,7 @@ App::usage()
"[--put-passes put-passes]\n"
"[--update-passes update-passes]\n"
"[--remove-passes remove-passes]\n"
+ "[--rpc-events-before-wakeup events]\n"
"[--rpc-network-threads threads]\n"
"[--rpc-targets-per-node targets]\n"
"[--response-threads threads]\n"
@@ -1406,6 +1406,7 @@ App::get_options()
{ "put-passes", 1, nullptr, 0 },
{ "remove-passes", 1, nullptr, 0 },
{ "response-threads", 1, nullptr, 0 },
+ { "rpc-events-before-wakeup", 1, nullptr, 0 },
{ "rpc-network-threads", 1, nullptr, 0 },
{ "rpc-targets-per-node", 1, nullptr, 0 },
{ "skip-get-spi-bucket-info", 0, nullptr, 0 },
@@ -1427,6 +1428,7 @@ App::get_options()
LONGOPT_PUT_PASSES,
LONGOPT_REMOVE_PASSES,
LONGOPT_RESPONSE_THREADS,
+ LONGOPT_RPC_EVENTS_BEFORE_WAKEUP,
LONGOPT_RPC_NETWORK_THREADS,
LONGOPT_RPC_TARGETS_PER_NODE,
LONGOPT_SKIP_GET_SPI_BUCKET_INFO,
@@ -1478,6 +1480,9 @@ App::get_options()
case LONGOPT_RESPONSE_THREADS:
_bm_params.set_response_threads(atoi(opt_argument));
break;
+ case LONGOPT_RPC_EVENTS_BEFORE_WAKEUP:
+ _bm_params.set_rpc_events_before_wakeup(atoi(opt_argument));
+ break;
case LONGOPT_RPC_NETWORK_THREADS:
_bm_params.set_rpc_network_threads(atoi(opt_argument));
break;
diff --git a/searchcore/src/apps/vespa-gen-testdocs/vespa-gen-testdocs.cpp b/searchcore/src/apps/vespa-gen-testdocs/vespa-gen-testdocs.cpp
index 080d98734bd..c2b0735ff8f 100644
--- a/searchcore/src/apps/vespa-gen-testdocs/vespa-gen-testdocs.cpp
+++ b/searchcore/src/apps/vespa-gen-testdocs/vespa-gen-testdocs.cpp
@@ -219,12 +219,12 @@ class ConstTextFieldGenerator : public FieldGenerator
{
string _value;
public:
- ConstTextFieldGenerator(std::vector<string> argv);
+ ConstTextFieldGenerator(std::vector<string> argv) noexcept;
virtual ~ConstTextFieldGenerator() override;
virtual void generateValue(vespalib::asciistream &doc, uint32_t id) override;
};
-ConstTextFieldGenerator::ConstTextFieldGenerator(std::vector<string> argv)
+ConstTextFieldGenerator::ConstTextFieldGenerator(std::vector<string> argv) noexcept
: FieldGenerator(argv[0]),
_value()
{
diff --git a/searchcore/src/apps/vespa-proton-cmd/vespa-proton-cmd.cpp b/searchcore/src/apps/vespa-proton-cmd/vespa-proton-cmd.cpp
index 8c7e6f13c18..8b6203c78a2 100644
--- a/searchcore/src/apps/vespa-proton-cmd/vespa-proton-cmd.cpp
+++ b/searchcore/src/apps/vespa-proton-cmd/vespa-proton-cmd.cpp
@@ -3,7 +3,8 @@
#include <vespa/slobrok/sbmirror.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/time.h>
@@ -28,10 +29,12 @@ private:
FRT_RPCRequest *_req;
public:
- App() : _frt(),
- _target(nullptr),
- _req(nullptr) {}
- virtual ~App()
+ App()
+ : _frt(),
+ _target(nullptr),
+ _req(nullptr)
+ {}
+ ~App() override
{
assert(!_frt);
assert(_target == nullptr);
diff --git a/searchcore/src/tests/proton/attribute/attribute_test.cpp b/searchcore/src/tests/proton/attribute/attribute_test.cpp
index c98127f4daf..8076e3d05e9 100644
--- a/searchcore/src/tests/proton/attribute/attribute_test.cpp
+++ b/searchcore/src/tests/proton/attribute/attribute_test.cpp
@@ -7,8 +7,9 @@
#include <vespa/document/update/arithmeticvalueupdate.h>
#include <vespa/document/update/assignvalueupdate.h>
#include <vespa/document/update/documentupdate.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/searchcommon/attribute/attributecontent.h>
#include <vespa/searchcommon/attribute/iattributevector.h>
@@ -82,7 +83,7 @@ using std::string;
using vespalib::ForegroundTaskExecutor;
using vespalib::ForegroundThreadExecutor;
using vespalib::SequencedTaskExecutorObserver;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
@@ -644,7 +645,7 @@ TEST_F(FilterAttributeManagerTest, readable_attribute_vector_filters_attributes)
namespace {
Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
const vespalib::string sparse_tensor = "tensor(x{},y{})";
@@ -668,7 +669,7 @@ Document::UP
createTensorPutDoc(DocBuilder &builder, const Value &tensor) {
return builder.startDocument("id:ns:searchdocument::1").
startAttributeField("a1").
- addTensor(EngineOrFactory::get().copy(tensor)).endField().endDocument();
+ addTensor(SimpleValue::from_value(tensor)).endField().endDocument();
}
}
@@ -712,7 +713,7 @@ TEST_F(AttributeWriterTest, handles_tensor_assign_update)
.add({{"x", "8"}, {"y", "9"}}, 11));
TensorDataType xySparseTensorDataType(vespalib::eval::ValueType::from_spec(sparse_tensor));
TensorFieldValue new_value(xySparseTensorDataType);
- new_value = EngineOrFactory::get().copy(*new_tensor);
+ new_value = SimpleValue::from_value(*new_tensor);
upd.addUpdate(FieldUpdate(upd.getType().getField("a1"))
.addUpdate(AssignValueUpdate(new_value)));
DummyFieldUpdateCallback onUpdate;
diff --git a/searchcore/src/tests/proton/common/attribute_updater/attribute_updater_test.cpp b/searchcore/src/tests/proton/common/attribute_updater/attribute_updater_test.cpp
index 5e6d8cf1659..c74c93a376a 100644
--- a/searchcore/src/tests/proton/common/attribute_updater/attribute_updater_test.cpp
+++ b/searchcore/src/tests/proton/common/attribute_updater/attribute_updater_test.cpp
@@ -22,8 +22,10 @@
#include <vespa/document/update/tensor_add_update.h>
#include <vespa/document/update/tensor_modify_update.h>
#include <vespa/document/update/tensor_remove_update.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcore/proton/common/attribute_updater.h>
#include <vespa/searchlib/attribute/attributefactory.h>
#include <vespa/searchlib/attribute/reference_attribute.h>
@@ -50,10 +52,10 @@ using search::tensor::ITensorAttribute;
using search::tensor::DenseTensorAttribute;
using search::tensor::SerializedTensorAttribute;
using search::tensor::TensorAttribute;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
+using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::TensorSpec;
namespace search {
@@ -411,7 +413,7 @@ getTensorDataType(const vespalib::string &spec)
std::unique_ptr<Value>
makeTensor(const TensorSpec &spec)
{
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
std::unique_ptr<TensorFieldValue>
@@ -441,7 +443,7 @@ struct TensorFixture : public Fixture {
}
void assertTensor(const TensorSpec &expSpec) {
- auto actual = EngineOrFactory::get().to_spec(*attribute->getTensor(1));
+ auto actual = spec_from_value(*attribute->getTensor(1));
EXPECT_EQUAL(expSpec, actual);
}
};
diff --git a/searchcore/src/tests/proton/docsummary/docsummary.cpp b/searchcore/src/tests/proton/docsummary/docsummary.cpp
index 04258b3989f..5741a844ded 100644
--- a/searchcore/src/tests/proton/docsummary/docsummary.cpp
+++ b/searchcore/src/tests/proton/docsummary/docsummary.cpp
@@ -2,7 +2,8 @@
#include <tests/proton/common/dummydbowner.h>
#include <vespa/config/helper/configgetter.hpp>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/document/repo/documenttyperepo.h>
@@ -59,7 +60,7 @@ using storage::spi::Timestamp;
using vespa::config::search::core::ProtonConfig;
using vespa::config::content::core::BucketspacesConfig;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using namespace vespalib::slime;
typedef std::unique_ptr<GeneralResult> GeneralResultPtr;
@@ -139,7 +140,7 @@ getDocTypeName()
}
vespalib::eval::Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
vespalib::string asVstring(vespalib::Memory str) {
@@ -334,7 +335,7 @@ assertTensor(const vespalib::eval::Value::UP & exp, const std::string & fieldNam
EXPECT_EQUAL(exp.get() == nullptr, data.size == 0u);
if (exp) {
vespalib::nbostream x(data.data, data.size);
- auto tensor = EngineOrFactory::get().decode(x);
+ auto tensor = SimpleValue::from_stream(x);
EXPECT_TRUE(tensor.get() != nullptr);
EXPECT_EQUAL(*exp, *tensor);
}
diff --git a/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp b/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp
index 58b7838bf35..86f0e8fdcf8 100644
--- a/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp
+++ b/searchcore/src/tests/proton/docsummary/summaryfieldconverter_test.cpp
@@ -45,10 +45,10 @@
#include <vespa/vespalib/data/slime/json_format.h>
#include <vespa/vespalib/data/slime/binary_format.h>
#include <vespa/searchlib/util/slime_output_raw_buf_adapter.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
-#include <vespa/eval/tensor/types.h>
#include <vespa/vespalib/data/slime/slime.h>
using document::Annotation;
@@ -94,10 +94,10 @@ using search::linguistics::TERM;
using vespa::config::search::SummarymapConfig;
using vespa::config::search::SummarymapConfigBuilder;
using vespalib::Slime;
+using vespalib::eval::SimpleValue;
+using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
using vespalib::geo::ZCurve;
using vespalib::slime::Cursor;
using vespalib::string;
@@ -677,7 +677,7 @@ Test::requireThatPredicateIsPrinted()
}
Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
void
diff --git a/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp b/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp
index c28a099a990..d06da31b415 100644
--- a/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp
+++ b/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp
@@ -5,8 +5,9 @@
#include <vespa/document/update/assignvalueupdate.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/update/documentupdate.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/test/test_utils.h>
#include <vespa/searchcore/proton/bucketdb/bucketdbhandler.h>
#include <vespa/searchcore/proton/test/bucketfactory.h>
#include <vespa/searchcore/proton/common/feedtoken.h>
@@ -57,10 +58,10 @@ using storage::spi::UpdateResult;
using vespalib::ThreadStackExecutor;
using vespalib::ThreadStackExecutorBase;
using vespalib::makeClosure;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::tensor::test::makeTensor;
using namespace proton;
using namespace search::index;
@@ -329,13 +330,13 @@ struct UpdateContext {
auto fieldValue = field.createValue();
if (fieldName == "tensor") {
dynamic_cast<TensorFieldValue &>(*fieldValue) =
- makeTensor<Value>(TensorSpec("tensor(x{},y{})").
- add({{"x","8"},{"y","9"}}, 11));
+ SimpleValue::from_spec(TensorSpec("tensor(x{},y{})").
+ add({{"x","8"},{"y","9"}}, 11));
} else if (fieldName == "tensor2") {
auto tensorFieldValue = std::make_unique<TensorFieldValue>(tensor1DType);
*tensorFieldValue =
- makeTensor<Value>(TensorSpec("tensor(x{})").
- add({{"x","8"}}, 11));
+ SimpleValue::from_spec(TensorSpec("tensor(x{})").
+ add({{"x","8"}}, 11));
fieldValue = std::move(tensorFieldValue);
} else {
fieldValue->assign(document::StringFieldValue("new value"));
diff --git a/searchcore/src/tests/proton/documentmetastore/lidreusedelayer/lidreusedelayer_test.cpp b/searchcore/src/tests/proton/documentmetastore/lidreusedelayer/lidreusedelayer_test.cpp
index 6e4fe34a3c9..23267e0628b 100644
--- a/searchcore/src/tests/proton/documentmetastore/lidreusedelayer/lidreusedelayer_test.cpp
+++ b/searchcore/src/tests/proton/documentmetastore/lidreusedelayer/lidreusedelayer_test.cpp
@@ -166,7 +166,7 @@ public:
performCycleLids(const std::vector<uint32_t> &lids)
{
_writeService.master().execute(
- makeLambdaTask([=]() { cycledLids(lids);}));
+ makeLambdaTask([this, lids]() { cycledLids(lids);}));
}
void
@@ -175,7 +175,7 @@ public:
if (lids.empty())
return;
_writeService.index().execute(
- makeLambdaTask([=]() { performCycleLids(lids);}));
+ makeLambdaTask([this, lids]() { performCycleLids(lids);}));
}
bool
diff --git a/searchcore/src/tests/proton/matching/matching_test.cpp b/searchcore/src/tests/proton/matching/matching_test.cpp
index 11ea6e87233..0278aba41d9 100644
--- a/searchcore/src/tests/proton/matching/matching_test.cpp
+++ b/searchcore/src/tests/proton/matching/matching_test.cpp
@@ -32,9 +32,9 @@
#include <vespa/searchcore/proton/matching/match_params.h>
#include <vespa/searchcore/proton/matching/match_tools.h>
#include <vespa/searchcore/proton/matching/match_context.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/log/log.h>
@@ -59,8 +59,8 @@ using storage::spi::Timestamp;
using search::fef::indexproperties::hitcollector::HeapSize;
using vespalib::nbostream;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
void inject_match_phase_limiting(Properties &setup, const vespalib::string &attribute, size_t max_hits, bool descending)
{
@@ -667,9 +667,8 @@ TEST("require that summary features are filled") {
EXPECT_TRUE(!f[2].is_double());
EXPECT_TRUE(f[2].is_data());
{
- auto engine = EngineOrFactory::get();
nbostream buf(f[2].as_data().data, f[2].as_data().size);
- auto actual = engine.to_spec(*engine.decode(buf));
+ auto actual = spec_from_value(*SimpleValue::from_stream(buf));
auto expect = TensorSpec("tensor(x[3])").add({{"x", 0}}, 0).add({{"x", 1}}, 1).add({{"x", 2}}, 2);
EXPECT_EQUAL(actual, expect);
}
diff --git a/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp b/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp
index 90a6e173129..7b545344e9b 100644
--- a/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp
+++ b/searchcore/src/tests/proton/matching/request_context/request_context_test.cpp
@@ -1,8 +1,8 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/searchcore/proton/matching/requestcontext.h>
#include <vespa/searchlib/attribute/attribute_blueprint_params.h>
#include <vespa/searchlib/fef/properties.h>
@@ -14,7 +14,7 @@ using search::attribute::IAttributeContext;
using search::attribute::IAttributeFunctor;
using search::attribute::IAttributeVector;
using search::fef::Properties;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using namespace proton;
@@ -38,7 +38,7 @@ private:
void insert_tensor_in_properties(const vespalib::string& tensor_name, const Value& tensor_value) {
vespalib::nbostream stream;
- EngineOrFactory::get().encode(tensor_value, stream);
+ encode_value(tensor_value, stream);
_props.add(tensor_name, vespalib::stringref(stream.data(), stream.size()));
}
@@ -49,14 +49,14 @@ public:
_attr_ctx(),
_props(),
_request_ctx(_doom, _attr_ctx, _props, AttributeBlueprintParams()),
- _query_tensor(EngineOrFactory::get().from_spec(TensorSpec("tensor(x[2])")
- .add({{"x", 0}}, 3).add({{"x", 1}}, 5)))
+ _query_tensor(SimpleValue::from_spec(TensorSpec("tensor(x[2])")
+ .add({{"x", 0}}, 3).add({{"x", 1}}, 5)))
{
insert_tensor_in_properties("my_tensor", *_query_tensor);
_props.add("my_string", "foo bar");
}
TensorSpec expected_query_tensor() const {
- return EngineOrFactory::get().to_spec(*_query_tensor);
+ return spec_from_value(*_query_tensor);
}
Value::UP get_query_tensor(const vespalib::string& tensor_name) const {
return _request_ctx.get_query_tensor(tensor_name);
@@ -68,7 +68,7 @@ TEST_F(RequestContextTest, query_tensor_can_be_retrieved)
auto tensor = get_query_tensor("my_tensor");
ASSERT_TRUE(tensor);
EXPECT_TRUE(tensor->is_tensor());
- EXPECT_EQ(expected_query_tensor(), EngineOrFactory::get().to_spec(*tensor));
+ EXPECT_EQ(expected_query_tensor(), spec_from_value(*tensor));
}
TEST_F(RequestContextTest, non_existing_query_tensor_returns_nullptr)
diff --git a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
index 95a41a255ce..17859c74feb 100644
--- a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
+++ b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
@@ -14,7 +14,6 @@
#include <vespa/searchcore/proton/persistenceengine/persistenceengine.h>
#include <vespa/vdslib/distribution/distribution.h>
#include <vespa/vdslib/state/clusterstate.h>
-#include <vespa/metrics/loadmetric.h>
#include <vespa/vespalib/testkit/testapp.h>
#include <algorithm>
#include <set>
diff --git a/searchcore/src/tests/proton/server/documentretriever_test.cpp b/searchcore/src/tests/proton/server/documentretriever_test.cpp
index ee9388e2141..058374cfc59 100644
--- a/searchcore/src/tests/proton/server/documentretriever_test.cpp
+++ b/searchcore/src/tests/proton/server/documentretriever_test.cpp
@@ -20,10 +20,10 @@
#include <vespa/document/fieldset/fieldsets.h>
#include <vespa/document/repo/configbuilder.h>
#include <vespa/document/repo/documenttyperepo.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
-#include <vespa/eval/tensor/test/test_utils.h>
#include <vespa/persistence/spi/bucket.h>
#include <vespa/persistence/spi/test.h>
#include <vespa/searchcommon/common/schema.h>
@@ -89,11 +89,10 @@ using storage::spi::Timestamp;
using storage::spi::test::makeSpiBucket;
using vespalib::make_string;
using vespalib::string;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::ValueType;
using vespalib::eval::Value;
-using vespalib::tensor::test::makeTensor;
using namespace document::config_builder;
using namespace search::index;
@@ -112,8 +111,8 @@ const char dyn_field_nas[] = "dynamic null attr string field"; // in document, n
const char position_field[] = "position_field";
vespalib::string dyn_field_tensor("dynamic_tensor_field");
vespalib::string tensor_spec("tensor(x{})");
-std::unique_ptr<Value> static_tensor = makeTensor<Value>(TensorSpec(tensor_spec).add({{"x", "1"}}, 1.5));
-std::unique_ptr<Value> dynamic_tensor = makeTensor<Value>(TensorSpec(tensor_spec).add({{"x", "2"}}, 3.5));
+std::unique_ptr<Value> static_tensor = SimpleValue::from_spec(TensorSpec(tensor_spec).add({{"x", "1"}}, 1.5));
+std::unique_ptr<Value> dynamic_tensor = SimpleValue::from_spec(TensorSpec(tensor_spec).add({{"x", "2"}}, 3.5));
const char zcurve_field[] = "position_field_zcurve";
const char position_array_field[] = "position_array";
const char zcurve_array_field[] = "position_array_zcurve";
@@ -169,7 +168,7 @@ struct MyDocumentStore : proton::test::DummyDocumentStore {
doc->set(zcurve_field, static_zcurve_value);
doc->setValue(dyn_field_p, static_value_p);
TensorFieldValue tensorFieldValue(tensorDataType);
- tensorFieldValue = EngineOrFactory::get().copy(*static_tensor);
+ tensorFieldValue = SimpleValue::from_value(*static_tensor);
doc->setValue(dyn_field_tensor, tensorFieldValue);
if (_set_position_struct_field) {
FieldValue::UP fv = PositionDataType::getInstance().createFieldValue();
diff --git a/searchcore/src/tests/proton/summaryengine/summaryengine.cpp b/searchcore/src/tests/proton/summaryengine/summaryengine.cpp
index 7e5e3527b1d..f5f2cc7a2a5 100644
--- a/searchcore/src/tests/proton/summaryengine/summaryengine.cpp
+++ b/searchcore/src/tests/proton/summaryengine/summaryengine.cpp
@@ -13,7 +13,6 @@
#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/log/log.h>
-#include <vespa/metrics/metrics.h>
LOG_SETUP("summaryengine_test");
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.cpp
index 42971fe3d4c..a691c36097e 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.cpp
@@ -76,7 +76,7 @@ AttributeWriter::WriteField::buildFieldPath(const DocumentType &docType)
_fieldPath = std::move(fp);
}
-AttributeWriter::WriteContext::WriteContext(ExecutorId executorId)
+AttributeWriter::WriteContext::WriteContext(ExecutorId executorId) noexcept
: _executorId(executorId),
_fields(),
_hasStructFieldAttribute(false),
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.h
index f63a2c6efba..0ca03f07de3 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.h
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_writer.h
@@ -56,7 +56,7 @@ public:
// When this is true, the context only contains a single field.
bool _use_two_phase_put;
public:
- WriteContext(ExecutorId executorId);
+ WriteContext(ExecutorId executorId) noexcept;
WriteContext(WriteContext &&rhs) noexcept;
~WriteContext();
WriteContext &operator=(WriteContext &&rhs) noexcept;
diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp
index ecca993fa27..0d432c069c9 100644
--- a/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp
+++ b/searchcore/src/vespa/searchcore/proton/docsummary/documentstoreadapter.cpp
@@ -3,7 +3,7 @@
#include "documentstoreadapter.h"
#include <vespa/searchsummary/docsummary/summaryfieldconverter.h>
#include <vespa/document/fieldvalue/stringfieldvalue.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/document/fieldvalue/tensorfieldvalue.h>
@@ -86,7 +86,7 @@ DocumentStoreAdapter::writeField(const FieldValue &value, ResType type)
const auto &tvalue = static_cast<const TensorFieldValue &>(value);
auto tensor = tvalue.getAsTensorPtr();
if (tensor) {
- vespalib::eval::EngineOrFactory::get().encode(*tensor, serialized);
+ encode_value(*tensor, serialized);
}
}
return _resultPacker.AddSerializedTensor(serialized.peek(), serialized.size());
diff --git a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.cpp b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.cpp
index 7fab995dfb9..fa8097419a5 100644
--- a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.cpp
+++ b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.cpp
@@ -17,15 +17,6 @@ DocumentMetaStoreAttribute::getFixedName()
return _G_documentMetaStoreName;
}
-
-void
-DocumentMetaStoreAttribute::notImplemented() const
-{
- throw vespalib::IllegalStateException(
- "The function is not implemented for DocumentMetaStoreAttribute");
-}
-
-
DocumentMetaStoreAttribute::DocumentMetaStoreAttribute(const vespalib::string &name)
: NotImplementedAttribute(name, Config(BasicType::NONE))
{ }
diff --git a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.h b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.h
index 721aa8fe126..f4e936e663a 100644
--- a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.h
+++ b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastoreattribute.h
@@ -13,9 +13,6 @@ namespace proton {
**/
class DocumentMetaStoreAttribute : public search::NotImplementedAttribute
{
-protected:
- void notImplemented() const override __attribute__((noinline));
-
public:
DocumentMetaStoreAttribute(const vespalib::string &name=getFixedName());
~DocumentMetaStoreAttribute() override;
diff --git a/searchcore/src/vespa/searchcore/proton/flushengine/flushengine.h b/searchcore/src/vespa/searchcore/proton/flushengine/flushengine.h
index 2a7115f4d33..160423c7c68 100644
--- a/searchcore/src/vespa/searchcore/proton/flushengine/flushengine.h
+++ b/searchcore/src/vespa/searchcore/proton/flushengine/flushengine.h
@@ -112,6 +112,11 @@ public:
vespalib::ThreadStackExecutor::Stats getExecutorStats() { return _executor.getStats(); }
/**
+ * Returns the underlying executor. Only used for state explorers.
+ */
+ const vespalib::SyncableThreadExecutor& get_executor() const { return _executor; }
+
+ /**
* Starts the scheduling thread of this manager.
*
* @return This, to allow chaining.
diff --git a/searchcore/src/vespa/searchcore/proton/initializer/task_runner.cpp b/searchcore/src/vespa/searchcore/proton/initializer/task_runner.cpp
index 06d875151cc..089294967ee 100644
--- a/searchcore/src/vespa/searchcore/proton/initializer/task_runner.cpp
+++ b/searchcore/src/vespa/searchcore/proton/initializer/task_runner.cpp
@@ -75,8 +75,8 @@ TaskRunner::internalRunTask(InitializerTask::SP task, Context::SP context)
// run by context executor
assert(task->getState() == State::BLOCKED);
setTaskRunning(*task);
- auto done(makeLambdaTask([=]() { setTaskDone(*task, context); }));
- _executor.execute(makeLambdaTask([=, done(std::move(done))]() mutable
+ auto done(makeLambdaTask([this, task, context]() { setTaskDone(*task, context); }));
+ _executor.execute(makeLambdaTask([task, context, done(std::move(done))]() mutable
{ task->run();
context->execute(std::move(done)); }));
}
@@ -124,7 +124,7 @@ TaskRunner::runTask(InitializerTask::SP rootTask,
vespalib::Executor::Task::UP doneTask)
{
auto context(std::make_shared<Context>(rootTask, contextExecutor, std::move(doneTask)));
- context->execute(makeLambdaTask([=]() { pollTask(context); } ));
+ context->execute(makeLambdaTask([this, context=std::move(context)]() { pollTask(context); } ));
}
}
diff --git a/searchcore/src/vespa/searchcore/proton/matchengine/matchengine.h b/searchcore/src/vespa/searchcore/proton/matchengine/matchengine.h
index 34aacdafcad..8adc198bb40 100644
--- a/searchcore/src/vespa/searchcore/proton/matchengine/matchengine.h
+++ b/searchcore/src/vespa/searchcore/proton/matchengine/matchengine.h
@@ -60,6 +60,11 @@ public:
vespalib::ThreadStackExecutor::Stats getExecutorStats() { return _executor.getStats(); }
/**
+ * Returns the underlying executor. Only used for state explorers.
+ */
+ const vespalib::SyncableThreadExecutor& get_executor() const { return _executor; }
+
+ /**
* Closes the request handler interface. This will prevent any more data
* from entering this object, allowing you to flush all pending operations
* without having to safe-guard against input.
diff --git a/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.cpp b/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.cpp
index 88aea2bd86c..81557f28100 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.cpp
@@ -24,6 +24,8 @@ PartitionDocidRangeScheduler::PartitionDocidRangeScheduler(size_t num_threads, u
}
}
+PartitionDocidRangeScheduler::~PartitionDocidRangeScheduler() = default;
+
//-----------------------------------------------------------------------------
DocidRange
@@ -35,8 +37,8 @@ TaskDocidRangeScheduler::next_task(size_t thread_id)
++_next_task;
}
_assigned[thread_id] += work.size();
- size_t todo = _unassigned.load(std::memory_order::memory_order_relaxed);
- _unassigned.store(clamped_sub(todo, work.size()), std::memory_order::memory_order_relaxed);
+ size_t todo = _unassigned.load(std::memory_order_relaxed);
+ _unassigned.store(clamped_sub(todo, work.size()), std::memory_order_relaxed);
return work;
}
@@ -50,6 +52,8 @@ TaskDocidRangeScheduler::TaskDocidRangeScheduler(size_t num_threads, size_t num_
{
}
+TaskDocidRangeScheduler::~TaskDocidRangeScheduler() = default;
+
//-----------------------------------------------------------------------------
size_t
@@ -57,7 +61,7 @@ AdaptiveDocidRangeScheduler::take_idle(const Guard &)
{
size_t thread_id = _idle.back();
_idle.pop_back();
- _num_idle.store(_idle.size(), std::memory_order::memory_order_relaxed);
+ _num_idle.store(_idle.size(), std::memory_order_relaxed);
assert(_workers[thread_id].is_idle);
return thread_id;
}
@@ -68,7 +72,7 @@ AdaptiveDocidRangeScheduler::make_idle(const Guard &, size_t thread_id)
assert(!_workers[thread_id].is_idle);
_workers[thread_id].is_idle = true;
_idle.push_back(thread_id);
- _num_idle.store(_idle.size(), std::memory_order::memory_order_relaxed);
+ _num_idle.store(_idle.size(), std::memory_order_relaxed);
}
void
@@ -113,7 +117,7 @@ AdaptiveDocidRangeScheduler::AdaptiveDocidRangeScheduler(size_t num_threads, uin
}
}
-AdaptiveDocidRangeScheduler::~AdaptiveDocidRangeScheduler() {}
+AdaptiveDocidRangeScheduler::~AdaptiveDocidRangeScheduler() = default;
DocidRange
AdaptiveDocidRangeScheduler::first_range(size_t thread_id)
diff --git a/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.h b/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.h
index 19e5ec0343d..8cbcdd7ba6f 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.h
+++ b/searchcore/src/vespa/searchcore/proton/matching/docid_range_scheduler.h
@@ -60,7 +60,7 @@ public:
IdleObserver() : _num_idle(_always_zero) {}
IdleObserver(const std::atomic<size_t> &num_idle) : _num_idle(num_idle) {}
bool is_always_zero() const { return (&_num_idle == &_always_zero); }
- size_t get() const { return _num_idle.load(std::memory_order::memory_order_relaxed); }
+ size_t get() const { return _num_idle.load(std::memory_order_relaxed); }
};
/**
@@ -125,6 +125,7 @@ private:
std::vector<DocidRange> _ranges;
public:
PartitionDocidRangeScheduler(size_t num_threads, uint32_t docid_limit);
+ ~PartitionDocidRangeScheduler() override;
DocidRange first_range(size_t thread_id) override { return _ranges[thread_id]; }
DocidRange next_range(size_t) override { return DocidRange(); }
size_t total_size(size_t thread_id) const override { return _ranges[thread_id].size(); }
@@ -151,10 +152,11 @@ private:
DocidRange next_task(size_t thread_id);
public:
TaskDocidRangeScheduler(size_t num_threads, size_t num_tasks, uint32_t docid_limit);
+ ~TaskDocidRangeScheduler() override;
DocidRange first_range(size_t thread_id) override { return next_task(thread_id); }
DocidRange next_range(size_t thread_id) override { return next_task(thread_id); }
size_t total_size(size_t thread_id) const override { return _assigned[thread_id]; }
- size_t unassigned_size() const override { return _unassigned.load(std::memory_order::memory_order_relaxed); }
+ size_t unassigned_size() const override { return _unassigned.load(std::memory_order_relaxed); }
IdleObserver make_idle_observer() const override { return IdleObserver(); }
DocidRange share_range(size_t, DocidRange todo) override { return todo; }
};
diff --git a/searchcore/src/vespa/searchcore/proton/matching/docsum_matcher.cpp b/searchcore/src/vespa/searchcore/proton/matching/docsum_matcher.cpp
index a7a74de35d9..f3fc0cac326 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/docsum_matcher.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/docsum_matcher.cpp
@@ -3,9 +3,7 @@
#include "docsum_matcher.h"
#include "match_tools.h"
#include "search_session.h"
-#include <vespa/eval/eval/tensor.h>
-#include <vespa/eval/eval/tensor_engine.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/searchcommon/attribute/i_search_context.h>
#include <vespa/searchlib/queryeval/blueprint.h>
@@ -74,7 +72,7 @@ get_feature_set(const MatchToolsFactory &mtf,
auto obj = resolver.resolve(j).as_object(docId);
if (! obj.get().type().is_double()) {
vespalib::nbostream buf;
- vespalib::eval::EngineOrFactory::get().encode(obj.get(), buf);
+ encode_value(obj.get(), buf);
f[j].set_data(vespalib::Memory(buf.peek(), buf.size()));
} else {
f[j].set_double(obj.get().as_double());
diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_master.cpp b/searchcore/src/vespa/searchcore/proton/matching/match_master.cpp
index 6c86f6c2d1c..6e56d6365ec 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/match_master.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/match_master.cpp
@@ -10,7 +10,6 @@
#include <vespa/vespalib/data/slime/inserter.h>
#include <vespa/vespalib/data/slime/inject.h>
#include <vespa/vespalib/data/slime/cursor.h>
-#include <vespa/eval/eval/tensor_engine.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/log/log.h>
diff --git a/searchcore/src/vespa/searchcore/proton/matching/querylimiter.h b/searchcore/src/vespa/searchcore/proton/matching/querylimiter.h
index 45783959957..576c5921b61 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/querylimiter.h
+++ b/searchcore/src/vespa/searchcore/proton/matching/querylimiter.h
@@ -37,7 +37,7 @@ private:
void releaseToken();
std::mutex _lock;
std::condition_variable _cond;
- volatile int _activeThreads;
+ int _activeThreads;
// These are updated asynchronously at reconfig.
volatile int _maxThreads;
diff --git a/searchcore/src/vespa/searchcore/proton/matching/requestcontext.cpp b/searchcore/src/vespa/searchcore/proton/matching/requestcontext.cpp
index 008fd5f2013..6ad2f69ae7a 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/requestcontext.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/requestcontext.cpp
@@ -1,8 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "requestcontext.h"
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchlib/attribute/attributevector.h>
#include <vespa/searchlib/fef/properties.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -11,7 +11,7 @@
#include <vespa/log/log.h>
LOG_SETUP(".proton.matching.requestcontext");
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
namespace proton {
@@ -53,7 +53,7 @@ RequestContext::get_query_tensor(const vespalib::string& tensor_name) const
const vespalib::string& value = property.get();
vespalib::nbostream stream(value.data(), value.size());
try {
- return EngineOrFactory::get().decode(stream);
+ return decode_value(stream, FastValueBuilderFactory::get());
} catch (vespalib::Exception& ex) {
LOG(warning, "Query tensor '%s' could not be deserialized: %s",
tensor_name.c_str(), ex.getMessage().c_str());
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/attribute_metrics.h b/searchcore/src/vespa/searchcore/proton/metrics/attribute_metrics.h
index 3f09489f804..f60f676c31c 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/attribute_metrics.h
+++ b/searchcore/src/vespa/searchcore/proton/metrics/attribute_metrics.h
@@ -2,8 +2,8 @@
#pragma once
-#include <vespa/metrics/metrics.h>
#include "memory_usage_metrics.h"
+#include <map>
namespace proton {
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/content_proton_metrics.h b/searchcore/src/vespa/searchcore/proton/metrics/content_proton_metrics.h
index ef66314f658..f99523db534 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/content_proton_metrics.h
+++ b/searchcore/src/vespa/searchcore/proton/metrics/content_proton_metrics.h
@@ -5,7 +5,6 @@
#include "executor_metrics.h"
#include "resource_usage_metrics.h"
#include "trans_log_server_metrics.h"
-#include <vespa/metrics/metrics.h>
namespace proton {
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.cpp b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.cpp
index 05370920354..7b7fcc9e45d 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.cpp
+++ b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.cpp
@@ -4,6 +4,9 @@
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/log/log.h>
+LOG_SETUP(".proton.metrics.documentdb_tagged_metrics");
+
namespace proton {
using matching::MatchingStats;
@@ -167,13 +170,13 @@ DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::RankProfileMetrics
DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::~RankProfileMetrics() = default;
-DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::DocIdPartition::DocIdPartition(const vespalib::string &name, MetricSet *parent) :
- MetricSet("docid_partition", {{"docidPartition", name}}, "DocId Partition profile metrics", parent),
- docsMatched("docs_matched", {}, "Number of documents matched", this),
- docsRanked("docs_ranked", {}, "Number of documents ranked (first phase)", this),
- docsReRanked("docs_reranked", {}, "Number of documents re-ranked (second phase)", this),
- activeTime("active_time", {}, "Time (sec) spent doing actual work", this),
- waitTime("wait_time", {}, "Time (sec) spent waiting for other external threads and resources", this)
+DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::DocIdPartition::DocIdPartition(const vespalib::string &name, MetricSet *parent)
+ : MetricSet("docid_partition", {{"docidPartition", name}}, "DocId Partition profile metrics", parent),
+ docsMatched("docs_matched", {}, "Number of documents matched", this),
+ docsRanked("docs_ranked", {}, "Number of documents ranked (first phase)", this),
+ docsReRanked("docs_reranked", {}, "Number of documents re-ranked (second phase)", this),
+ activeTime("active_time", {}, "Time (sec) spent doing actual work", this),
+ waitTime("wait_time", {}, "Time (sec) spent waiting for other external threads and resources", this)
{ }
DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::DocIdPartition::~DocIdPartition() = default;
@@ -191,7 +194,8 @@ DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::DocIdPartition::up
}
void
-DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::update(const MatchingStats &stats)
+DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::update(const metrics::MetricLockGuard &,
+ const MatchingStats &stats)
{
docsMatched.inc(stats.docsMatched());
docsRanked.inc(stats.docsRanked());
@@ -213,14 +217,15 @@ DocumentDBTaggedMetrics::MatchingMetrics::RankProfileMetrics::update(const Match
queryLatency.addValueBatch(stats.queryLatencyAvg(), stats.queryLatencyCount(),
stats.queryLatencyMin(), stats.queryLatencyMax());
if (stats.getNumPartitions() > 0) {
- if (stats.getNumPartitions() <= partitions.size()) {
- for (size_t i = 0; i < stats.getNumPartitions(); ++i) {
- partitions[i]->update(stats.getPartition(i));
- }
- } else {
- vespalib::string msg(vespalib::make_string("Num partitions used '%ld' is larger than number of partitions '%ld' configured.",
- stats.getNumPartitions(), partitions.size()));
- throw vespalib::IllegalStateException(msg, VESPA_STRLOC);
+ for (size_t i = partitions.size(); i < stats.getNumPartitions(); ++i) {
+ // This loop is to handle live reconfigs that changes how many partitions(number of threads) might be used per query.
+ vespalib::string partition(vespalib::make_string("docid_part%02ld", i));
+ partitions.push_back(std::make_unique<DocIdPartition>(partition, this));
+ LOG(info, "Number of partitions has been increased to '%ld' from '%ld' previously configured. Adding part %ld",
+ stats.getNumPartitions(), partitions.size(), i);
+ }
+ for (size_t i = 0; i < stats.getNumPartitions(); ++i) {
+ partitions[i]->update(stats.getPartition(i));
}
}
}
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.h b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.h
index 26dd52a8577..133df81a9e6 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.h
+++ b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_tagged_metrics.h
@@ -9,6 +9,8 @@
#include <vespa/metrics/valuemetric.h>
#include <vespa/searchcore/proton/matching/matching_stats.h>
+namespace metrics { class MetricLockGuard; }
+
namespace proton {
/**
@@ -154,7 +156,7 @@ struct DocumentDBTaggedMetrics : metrics::MetricSet
size_t numDocIdPartitions,
metrics::MetricSet *parent);
~RankProfileMetrics() override;
- void update(const matching::MatchingStats &stats);
+ void update(const metrics::MetricLockGuard & guard, const matching::MatchingStats &stats);
};
using RankProfileMap = std::map<vespalib::string, RankProfileMetrics::UP>;
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/resource_usage_metrics.h b/searchcore/src/vespa/searchcore/proton/metrics/resource_usage_metrics.h
index 8f7036ee832..1878cd4b7c9 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/resource_usage_metrics.h
+++ b/searchcore/src/vespa/searchcore/proton/metrics/resource_usage_metrics.h
@@ -2,7 +2,8 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/valuemetric.h>
namespace proton {
diff --git a/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.h b/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.h
index 727b0c6304d..38b3abbbdcd 100644
--- a/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.h
+++ b/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.h
@@ -2,7 +2,8 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/valuemetric.h>
#include <vespa/searchlib/transactionlog/domainconfig.h>
namespace proton {
@@ -21,7 +22,7 @@ public:
typedef std::unique_ptr<DomainMetrics> UP;
DomainMetrics(metrics::MetricSet *parent, const vespalib::string &documentType);
- ~DomainMetrics();
+ ~DomainMetrics() override;
void update(const search::transactionlog::DomainInfo &stats);
};
diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
index 02efd1ef11f..114024f60ff 100644
--- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
+++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
@@ -3,7 +3,6 @@
#include "persistenceengine.h"
#include "ipersistenceengineowner.h"
#include "transport_latch.h"
-#include <vespa/metrics/loadmetric.h>
#include <vespa/vespalib/stllike/hash_set.h>
#include <vespa/document/fieldvalue/document.h>
#include <vespa/document/datatype/documenttype.h>
diff --git a/searchcore/src/vespa/searchcore/proton/server/CMakeLists.txt b/searchcore/src/vespa/searchcore/proton/server/CMakeLists.txt
index 57445775df3..73b7404ce31 100644
--- a/searchcore/src/vespa/searchcore/proton/server/CMakeLists.txt
+++ b/searchcore/src/vespa/searchcore/proton/server/CMakeLists.txt
@@ -35,7 +35,9 @@ vespa_add_library(searchcore_server STATIC
documentretrieverbase.cpp
documentsubdbcollection.cpp
emptysearchview.cpp
+ executor_explorer_utils.cpp
executor_thread_service.cpp
+ executor_threading_service_explorer.cpp
executorthreadingservice.cpp
fast_access_document_retriever.cpp
fast_access_doc_subdb.cpp
@@ -76,6 +78,7 @@ vespa_add_library(searchcore_server STATIC
proton_config_snapshot.cpp
proton_configurer.cpp
proton_disk_layout.cpp
+ proton_thread_pools_explorer.cpp
prune_session_cache_job.cpp
pruneremoveddocumentsjob.cpp
putdonecontext.cpp
diff --git a/searchcore/src/vespa/searchcore/proton/server/disk_mem_usage_forwarder.cpp b/searchcore/src/vespa/searchcore/proton/server/disk_mem_usage_forwarder.cpp
index 22af1dc1692..39716f93bc6 100644
--- a/searchcore/src/vespa/searchcore/proton/server/disk_mem_usage_forwarder.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/disk_mem_usage_forwarder.cpp
@@ -44,7 +44,7 @@ DiskMemUsageForwarder::removeDiskMemUsageListener(IDiskMemUsageListener *listene
void
DiskMemUsageForwarder::notifyDiskMemUsage(DiskMemUsageState state)
{
- _executor.execute(makeLambdaTask([=]() { forward(state); }));
+ _executor.execute(makeLambdaTask([this, state]() { forward(state); }));
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/document_db_explorer.cpp b/searchcore/src/vespa/searchcore/proton/server/document_db_explorer.cpp
index 0c3772cab5b..a5c3e8d6078 100644
--- a/searchcore/src/vespa/searchcore/proton/server/document_db_explorer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/document_db_explorer.cpp
@@ -1,12 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "document_db_explorer.h"
-
#include "document_meta_store_read_guards.h"
#include "document_subdb_collection_explorer.h"
+#include "executor_threading_service_explorer.h"
#include "maintenance_controller_explorer.h"
-#include <vespa/searchcore/proton/common/state_reporter_utils.h>
#include <vespa/searchcore/proton/bucketdb/bucket_db_explorer.h>
+#include <vespa/searchcore/proton/common/state_reporter_utils.h>
#include <vespa/searchcore/proton/matching/session_manager_explorer.h>
#include <vespa/vespalib/data/slime/slime.h>
@@ -42,6 +42,7 @@ DocumentDBExplorer::get_state(const Inserter &inserter, bool full) const
}
const vespalib::string SUB_DB = "subdb";
+const vespalib::string THREADING_SERVICE = "threadingservice";
const vespalib::string BUCKET_DB = "bucketdb";
const vespalib::string MAINTENANCE_CONTROLLER = "maintenancecontroller";
const vespalib::string SESSION = "session";
@@ -49,25 +50,24 @@ const vespalib::string SESSION = "session";
std::vector<vespalib::string>
DocumentDBExplorer::get_children_names() const
{
- return {SUB_DB, BUCKET_DB, MAINTENANCE_CONTROLLER, SESSION};
+ return {SUB_DB, THREADING_SERVICE, BUCKET_DB, MAINTENANCE_CONTROLLER, SESSION};
}
std::unique_ptr<StateExplorer>
DocumentDBExplorer::get_child(vespalib::stringref name) const
{
if (name == SUB_DB) {
- return std::unique_ptr<StateExplorer>
- (new DocumentSubDBCollectionExplorer(_docDb->getDocumentSubDBs()));
+ return std::make_unique<DocumentSubDBCollectionExplorer>(_docDb->getDocumentSubDBs());
+ } else if (name == THREADING_SERVICE) {
+ return std::make_unique<ExecutorThreadingServiceExplorer>(_docDb->getWriteService());
} else if (name == BUCKET_DB) {
// TODO(geirst): const_cast can be avoided if we add const guard to BucketDBOwner.
- return std::unique_ptr<StateExplorer>(new BucketDBExplorer(
- (const_cast<DocumentSubDBCollection &>(_docDb->getDocumentSubDBs())).getBucketDB().takeGuard()));
+ return std::make_unique<BucketDBExplorer>(
+ (const_cast<DocumentSubDBCollection &>(_docDb->getDocumentSubDBs())).getBucketDB().takeGuard());
} else if (name == MAINTENANCE_CONTROLLER) {
- return std::unique_ptr<StateExplorer>
- (new MaintenanceControllerExplorer(_docDb->getMaintenanceController().getJobList()));
+ return std::make_unique<MaintenanceControllerExplorer>(_docDb->getMaintenanceController().getJobList());
} else if (name == SESSION) {
- return std::unique_ptr<StateExplorer>
- (new matching::SessionManagerExplorer(_docDb->session_manager()));
+ return std::make_unique<matching::SessionManagerExplorer>(_docDb->session_manager());
}
return std::unique_ptr<StateExplorer>(nullptr);
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp b/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp
index c7b5aaafbfc..7323744c626 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdb.cpp
@@ -35,6 +35,7 @@
#include <vespa/searchlib/common/gatecallback.h>
#include <vespa/vespalib/util/closuretask.h>
#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/metrics/updatehook.h>
#include <vespa/log/log.h>
#include <vespa/searchcorespi/index/warmupconfig.h>
@@ -102,6 +103,18 @@ findDocumentDB(const ProtonConfig::DocumentdbVector & documentDBs, const vespali
return &_G_defaultProtonDocumentDBConfig;
}
+class MetricsUpdateHook : public metrics::UpdateHook {
+ DocumentDB &_db;
+public:
+ MetricsUpdateHook(DocumentDB &s)
+ : metrics::UpdateHook("documentdb-hook"),
+ _db(s)
+ {}
+ void updateMetrics(const MetricLockGuard & guard) override {
+ _db.updateMetrics(guard);
+ }
+};
+
}
template <typename FunctionType>
@@ -147,7 +160,6 @@ DocumentDB::DocumentDB(const vespalib::string &baseDir,
_configCV(),
_activeConfigSnapshot(),
_activeConfigSnapshotGeneration(0),
- _activeConfigSnapshotSerialNum(0u),
_validateAndSanitizeDocStore(protonCfg.validateAndSanitizeDocstore == vespa::config::search::core::ProtonConfig::ValidateAndSanitizeDocstore::YES),
_initGate(),
_clusterStateHandler(_writeService.master()),
@@ -156,7 +168,8 @@ DocumentDB::DocumentDB(const vespalib::string &baseDir,
_config_store(std::move(config_store)),
_sessionManager(std::make_shared<matching::SessionManager>(protonCfg.grouping.sessionmanager.maxentries)),
_metricsWireService(metricsWireService),
- _metricsHook(*this, _docTypeName.getName(), protonCfg.numthreadspersearch),
+ _metrics(_docTypeName.getName(), protonCfg.numthreadspersearch),
+ _metricsHook(std::make_unique<MetricsUpdateHook>(*this)),
_feedView(),
_refCount(),
_syncFeedViewEnabled(false),
@@ -176,7 +189,7 @@ DocumentDB::DocumentDB(const vespalib::string &baseDir,
_lidSpaceCompactionHandlers(),
_jobTrackers(),
_calc(),
- _metricsUpdater(_subDBs, _writeService, _jobTrackers, *_sessionManager, _writeFilter, _state)
+ _metricsUpdater(_subDBs, _writeService, _jobTrackers, *_sessionManager, _writeFilter)
{
assert(configSnapshot);
@@ -222,8 +235,7 @@ void DocumentDB::registerReference()
}
}
-void DocumentDB::setActiveConfig(const DocumentDBConfig::SP &config,
- SerialNum serialNum, int64_t generation) {
+void DocumentDB::setActiveConfig(const DocumentDBConfig::SP &config, int64_t generation) {
lock_guard guard(_configMutex);
registerReference();
_activeConfigSnapshot = config;
@@ -231,7 +243,6 @@ void DocumentDB::setActiveConfig(const DocumentDBConfig::SP &config,
if (_activeConfigSnapshotGeneration < generation) {
_activeConfigSnapshotGeneration = generation;
}
- _activeConfigSnapshotSerialNum = serialNum;
_configCV.notify_all();
}
@@ -297,7 +308,7 @@ DocumentDB::initFinish(DocumentDBConfig::SP configSnapshot)
syncFeedView();
// Check that feed view has been activated.
assert(_feedView.get());
- setActiveConfig(configSnapshot, _initConfigSerialNum, configSnapshot->getGeneration());
+ setActiveConfig(configSnapshot, configSnapshot->getGeneration());
startTransactionLogReplay();
}
@@ -469,7 +480,7 @@ DocumentDB::applyConfig(DocumentDBConfig::SP configSnapshot, SerialNum serialNum
}
_state.clearDelayedConfig();
}
- setActiveConfig(configSnapshot, serialNum, generation);
+ setActiveConfig(configSnapshot, generation);
if (params.shouldMaintenanceControllerChange()) {
forwardMaintenanceConfig();
}
@@ -1042,12 +1053,12 @@ DocumentDB::notifyAllBucketsChanged()
}
void
-DocumentDB::updateMetrics(DocumentDBTaggedMetrics &metrics)
+DocumentDB::updateMetrics(const metrics::MetricLockGuard & guard)
{
if (_state.getState() < DDBState::State::REPLAY_TRANSACTION_LOG) {
return;
}
- _metricsUpdater.updateMetrics(metrics);
+ _metricsUpdater.updateMetrics(guard, _metrics);
}
void
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb.h b/searchcore/src/vespa/searchcore/proton/server/documentdb.h
index a171861b590..9ea88360b07 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdb.h
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdb.h
@@ -18,7 +18,6 @@
#include "ireplayconfig.h"
#include "maintenancecontroller.h"
#include "threading_service_config.h"
-#include <vespa/metrics/updatehook.h>
#include <vespa/searchcore/proton/attribute/attribute_usage_filter.h>
#include <vespa/searchcore/proton/common/doctypename.h>
#include <vespa/searchcore/proton/common/monitored_refcount.h>
@@ -42,6 +41,10 @@ namespace search {
}
namespace vespa::config::search::core::internal { class InternalProtonType; }
+namespace metrics {
+ class UpdateHook;
+ class MetricLockGuard;
+}
namespace proton {
class AttributeConfigInspector;
@@ -68,26 +71,6 @@ class DocumentDB : public DocumentDBConfigOwner,
public search::transactionlog::SyncProxy
{
private:
- class MetricsUpdateHook : public metrics::UpdateHook {
- DocumentDBTaggedMetrics _metrics;
- DocumentDB &_db;
- public:
- MetricsUpdateHook(DocumentDB &s, const std::string &doc_type, size_t maxNumThreads)
- : metrics::UpdateHook("documentdb-hook"),
- _metrics(doc_type, maxNumThreads),
- _db(s) {}
- void updateMetrics(const MetricLockGuard & ) override { _db.updateMetrics(_metrics); }
- DocumentDBTaggedMetrics &getMetrics() { return _metrics; }
- };
-
- struct DocumentStoreCacheStats {
- search::CacheStats total;
- search::CacheStats readySubDb;
- search::CacheStats notReadySubDb;
- search::CacheStats removedSubDb;
- DocumentStoreCacheStats() : total(), readySubDb(), notReadySubDb(), removedSubDb() {}
- };
-
using InitializeThreads = std::shared_ptr<vespalib::SyncableThreadExecutor>;
using IFlushTargetList = std::vector<std::shared_ptr<searchcorespi::IFlushTarget>>;
using StatusReportUP = std::unique_ptr<StatusReport>;
@@ -114,7 +97,6 @@ private:
mutable std::condition_variable _configCV;
DocumentDBConfig::SP _activeConfigSnapshot;
int64_t _activeConfigSnapshotGeneration;
- SerialNum _activeConfigSnapshotSerialNum;
const bool _validateAndSanitizeDocStore;
vespalib::Gate _initGate;
@@ -126,9 +108,10 @@ private:
index::IndexConfig _indexCfg;
ConfigStore::UP _config_store;
std::shared_ptr<matching::SessionManager> _sessionManager; // TODO: This should not have to be a shared pointer.
- MetricsWireService &_metricsWireService;
- MetricsUpdateHook _metricsHook;
- vespalib::VarHolder<IFeedView::SP> _feedView;
+ MetricsWireService &_metricsWireService;
+ DocumentDBTaggedMetrics _metrics;
+ std::unique_ptr<metrics::UpdateHook> _metricsHook;
+ vespalib::VarHolder<IFeedView::SP> _feedView;
MonitoredRefCount _refCount;
bool _syncFeedViewEnabled;
IDocumentDBOwner &_owner;
@@ -145,7 +128,7 @@ private:
DocumentDBMetricsUpdater _metricsUpdater;
void registerReference();
- void setActiveConfig(const DocumentDBConfig::SP &config, SerialNum serialNum, int64_t generation);
+ void setActiveConfig(const DocumentDBConfig::SP &config, int64_t generation);
DocumentDBConfig::SP getActiveConfig() const;
void internalInit();
void initManagers();
@@ -294,7 +277,9 @@ public:
*
* @return document db metrics
**/
- DocumentDBTaggedMetrics &getMetrics() { return _metricsHook.getMetrics(); }
+ DocumentDBTaggedMetrics &getMetrics() {
+ return _metrics;
+ }
/**
* Obtain the metrics update hook for this document db.
@@ -302,7 +287,7 @@ public:
* @return metrics update hook
**/
metrics::UpdateHook & getMetricsUpdateHook() {
- return _metricsHook;
+ return *_metricsHook;
}
/**
@@ -414,7 +399,7 @@ public:
* the metric manager). Do not call this function in multiple
* threads at once.
**/
- void updateMetrics(DocumentDBTaggedMetrics &metrics);
+ void updateMetrics(const metrics::MetricLockGuard & guard);
/**
* Implement search::transactionlog::SyncProxy API.
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.cpp b/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.cpp
index 3a086046a27..8b923c7a372 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.cpp
@@ -34,8 +34,7 @@ DocumentDBMetricsUpdater::DocumentDBMetricsUpdater(const DocumentSubDBCollection
ExecutorThreadingService &writeService,
DocumentDBJobTrackers &jobTrackers,
matching::SessionManager &sessionManager,
- const AttributeUsageFilter &writeFilter,
- [[maybe_unused]] const DDBState &state)
+ const AttributeUsageFilter &writeFilter)
: _subDBs(subDBs),
_writeService(writeService),
_jobTrackers(jobTrackers),
@@ -170,12 +169,12 @@ updateAttributeMetrics(DocumentDBTaggedMetrics &metrics, const DocumentSubDBColl
}
void
-updateMatchingMetrics(DocumentDBTaggedMetrics &metrics, const IDocumentSubDB &ready)
+updateMatchingMetrics(const metrics::MetricLockGuard & guard, DocumentDBTaggedMetrics &metrics, const IDocumentSubDB &ready)
{
MatchingStats totalStats;
for (const auto &rankProfile : metrics.matching.rank_profiles) {
MatchingStats matchingStats = ready.getMatcherStats(rankProfile.first);
- rankProfile.second->update(matchingStats);
+ rankProfile.second->update(guard, matchingStats);
totalStats.add(matchingStats);
}
@@ -284,13 +283,13 @@ updateLidSpaceMetrics(MetricSetType &metrics, const search::IDocumentMetaStore &
}
void
-DocumentDBMetricsUpdater::updateMetrics(DocumentDBTaggedMetrics &metrics)
+DocumentDBMetricsUpdater::updateMetrics(const metrics::MetricLockGuard & guard, DocumentDBTaggedMetrics &metrics)
{
TotalStats totalStats;
ExecutorThreadingServiceStats threadingServiceStats = _writeService.getStats();
updateIndexMetrics(metrics, _subDBs.getReadySubDB()->getSearchableStats(), totalStats);
updateAttributeMetrics(metrics, _subDBs, totalStats);
- updateMatchingMetrics(metrics, *_subDBs.getReadySubDB());
+ updateMatchingMetrics(guard, metrics, *_subDBs.getReadySubDB());
updateSessionCacheMetrics(metrics, _sessionManager);
updateDocumentsMetrics(metrics, _subDBs);
updateDocumentStoreMetrics(metrics, _subDBs, _lastDocStoreCacheStats, totalStats);
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.h b/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.h
index dbf4c45007f..475da7f4e4c 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.h
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdb_metrics_updater.h
@@ -45,11 +45,10 @@ public:
ExecutorThreadingService &writeService,
DocumentDBJobTrackers &jobTrackers,
matching::SessionManager &sessionManager,
- const AttributeUsageFilter &writeFilter,
- const DDBState &state);
+ const AttributeUsageFilter &writeFilter);
~DocumentDBMetricsUpdater();
- void updateMetrics(DocumentDBTaggedMetrics &metrics);
+ void updateMetrics(const metrics::MetricLockGuard & guard, DocumentDBTaggedMetrics &metrics);
};
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.cpp b/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.cpp
index c254672bfd7..baa6c8eb450 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.cpp
@@ -71,7 +71,7 @@ DocumentDBConfig::DocumentDBConfig(
const search::LogDocumentStore::Config & storeConfig,
std::shared_ptr<const ThreadingServiceConfig> threading_service_config,
const vespalib::string &configId,
- const vespalib::string &docTypeName)
+ const vespalib::string &docTypeName) noexcept
: _configId(configId),
_docTypeName(docTypeName),
_generation(generation),
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.h b/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.h
index daca84d5fd1..dc163e91ade 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.h
+++ b/searchcore/src/vespa/searchcore/proton/server/documentdbconfig.h
@@ -170,7 +170,7 @@ public:
const search::LogDocumentStore::Config & storeConfig,
std::shared_ptr<const ThreadingServiceConfig> threading_service_config,
const vespalib::string &configId,
- const vespalib::string &docTypeName);
+ const vespalib::string &docTypeName) noexcept;
DocumentDBConfig(const DocumentDBConfig &cfg);
~DocumentDBConfig();
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp
new file mode 100644
index 00000000000..bbb87099988
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp
@@ -0,0 +1,57 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "executor_explorer_utils.h"
+#include <vespa/vespalib/data/slime/cursor.h>
+#include <vespa/vespalib/util/blockingthreadstackexecutor.h>
+#include <vespa/vespalib/util/singleexecutor.h>
+#include <vespa/vespalib/util/threadexecutor.h>
+#include <vespa/vespalib/util/threadstackexecutor.h>
+
+using vespalib::BlockingThreadStackExecutor;
+using vespalib::SingleExecutor;
+using vespalib::SyncableThreadExecutor;
+using vespalib::ThreadStackExecutor;
+using vespalib::slime::Cursor;
+
+
+namespace proton::explorer {
+
+namespace {
+
+void
+convert_syncable_executor_to_slime(const SyncableThreadExecutor& executor, const vespalib::string& type, Cursor& object)
+{
+ object.setString("type", type);
+ object.setLong("num_threads", executor.getNumThreads());
+ object.setLong("task_limit", executor.getTaskLimit());
+}
+
+void
+convert_single_executor_to_slime(const SingleExecutor& executor, Cursor& object)
+{
+ convert_syncable_executor_to_slime(executor, "SingleExecutor", object);
+ object.setLong("watermark", executor.get_watermark());
+ object.setDouble("reaction_time_sec", vespalib::to_s(executor.get_reaction_time()));
+}
+
+}
+
+void
+convert_executor_to_slime(const SyncableThreadExecutor* executor, Cursor& object)
+{
+ if (executor == nullptr) {
+ return;
+ }
+ if (const auto* single = dynamic_cast<const SingleExecutor*>(executor)) {
+ convert_single_executor_to_slime(*single, object);
+ } else if (const auto* blocking = dynamic_cast<const BlockingThreadStackExecutor*>(executor)) {
+ convert_syncable_executor_to_slime(*blocking, "BlockingThreadStackExecutor", object);
+ } else if (const auto* thread = dynamic_cast<const ThreadStackExecutor*>(executor)) {
+ convert_syncable_executor_to_slime(*thread, "ThreadStackExecutor", object);
+ } else {
+ convert_syncable_executor_to_slime(*executor, "SyncableThreadExecutor", object);
+ }
+}
+
+}
+
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.h b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.h
new file mode 100644
index 00000000000..0793fa6ac4a
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.h
@@ -0,0 +1,16 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+namespace vespalib { class SyncableThreadExecutor; }
+namespace vespalib::slime { struct Cursor; }
+
+namespace proton::explorer {
+
+/**
+ * Utility to convert an executor to slime for use with a state explorer.
+ */
+void convert_executor_to_slime(const vespalib::SyncableThreadExecutor* executor, vespalib::slime::Cursor& object);
+
+}
+
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.cpp b/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.cpp
index 24f5fa9a5e6..49dc038096c 100644
--- a/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.cpp
@@ -81,6 +81,10 @@ void ExecutorThreadService::setTaskLimit(uint32_t taskLimit) {
_executor.setTaskLimit(taskLimit);
}
+uint32_t ExecutorThreadService::getTaskLimit() const {
+ return _executor.getTaskLimit();
+}
+
void
ExecutorThreadService::wakeup() {
_executor.wakeup();
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.h b/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.h
index 4f27a8f86c2..325c36b7270 100644
--- a/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.h
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_thread_service.h
@@ -39,6 +39,7 @@ public:
size_t getNumThreads() const override { return _executor.getNumThreads(); }
void setTaskLimit(uint32_t taskLimit) override;
+ uint32_t getTaskLimit() const override;
void wakeup() override;
};
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.cpp b/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.cpp
new file mode 100644
index 00000000000..e3154ad6a47
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.cpp
@@ -0,0 +1,84 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "executor_explorer_utils.h"
+#include "executor_threading_service_explorer.h"
+#include "executorthreadingservice.h"
+#include <vespa/vespalib/data/slime/cursor.h>
+#include <vespa/vespalib/util/adaptive_sequenced_executor.h>
+#include <vespa/vespalib/util/sequencedtaskexecutor.h>
+
+using vespalib::AdaptiveSequencedExecutor;
+using vespalib::ISequencedTaskExecutor;
+using vespalib::SequencedTaskExecutor;
+using vespalib::slime::Cursor;
+
+namespace proton {
+
+using explorer::convert_executor_to_slime;
+
+namespace {
+
+void
+set_type(Cursor& object, const vespalib::string& type)
+{
+ object.setString("type", type);
+}
+
+void
+convert_sequenced_executor_to_slime(const SequencedTaskExecutor& executor, Cursor& object)
+{
+ set_type(object, "SequencedTaskExecutor");
+ object.setLong("num_executors", executor.getNumExecutors());
+ convert_executor_to_slime(executor.first_executor(), object.setObject("executor"));
+}
+
+void
+convert_adaptive_executor_to_slime(const AdaptiveSequencedExecutor& executor, Cursor& object)
+{
+ set_type(object, "AdaptiveSequencedExecutor");
+ object.setLong("num_strands", executor.getNumExecutors());
+ auto cfg = executor.get_config();
+ object.setLong("num_threads", cfg.num_threads);
+ object.setLong("max_waiting", cfg.max_waiting);
+ object.setLong("max_pending", cfg.max_pending);
+ object.setLong("wakeup_limit", cfg.wakeup_limit);
+}
+
+void
+convert_executor_to_slime(const ISequencedTaskExecutor* executor, Cursor& object)
+{
+ if (const auto* seq = dynamic_cast<const SequencedTaskExecutor*>(executor)) {
+ convert_sequenced_executor_to_slime(*seq, object);
+ } else if (const auto* ada = dynamic_cast<const AdaptiveSequencedExecutor*>(executor)) {
+ convert_adaptive_executor_to_slime(*ada, object);
+ } else {
+ set_type(object, "ISequencedTaskExecutor");
+ object.setLong("num_executors", executor->getNumExecutors());
+ }
+}
+
+}
+
+ExecutorThreadingServiceExplorer::ExecutorThreadingServiceExplorer(ExecutorThreadingService& service)
+ : _service(service)
+{
+}
+
+ExecutorThreadingServiceExplorer::~ExecutorThreadingServiceExplorer() = default;
+
+void
+ExecutorThreadingServiceExplorer::get_state(const vespalib::slime::Inserter& inserter, bool full) const
+{
+ auto& object = inserter.insertObject();
+ if (full) {
+ convert_executor_to_slime(&_service.getMasterExecutor(), object.setObject("master"));
+ convert_executor_to_slime(&_service.getIndexExecutor(), object.setObject("index"));
+ convert_executor_to_slime(&_service.getSummaryExecutor(), object.setObject("summary"));
+ convert_executor_to_slime(&_service.indexFieldInverter(), object.setObject("index_field_inverter"));
+ convert_executor_to_slime(&_service.indexFieldWriter(), object.setObject("index_field_writer"));
+ convert_executor_to_slime(&_service.attributeFieldWriter(), object.setObject("attribute_field_writer"));
+ }
+}
+
+}
+
diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.h b/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.h
new file mode 100644
index 00000000000..14d25add8d6
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/executor_threading_service_explorer.h
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/net/state_explorer.h>
+
+namespace proton {
+
+class ExecutorThreadingService;
+
+/**
+ * Class used to explore the state of the ExecutorThreadingService used in a document database.
+ */
+class ExecutorThreadingServiceExplorer : public vespalib::StateExplorer {
+private:
+ ExecutorThreadingService& _service;
+
+public:
+ ExecutorThreadingServiceExplorer(ExecutorThreadingService& service);
+ ~ExecutorThreadingServiceExplorer();
+
+ void get_state(const vespalib::slime::Inserter& inserter, bool full) const override;
+};
+
+}
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton.cpp b/searchcore/src/vespa/searchcore/proton/server/proton.cpp
index fa7ea039798..36d630bc519 100644
--- a/searchcore/src/vespa/searchcore/proton/server/proton.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/proton.cpp
@@ -10,6 +10,7 @@
#include "proton.h"
#include "proton_config_snapshot.h"
#include "proton_disk_layout.h"
+#include "proton_thread_pools_explorer.h"
#include "resource_usage_explorer.h"
#include "searchhandlerproxy.h"
#include "simpleflush.h"
@@ -17,9 +18,6 @@
#include <vespa/document/base/exceptions.h>
#include <vespa/document/datatype/documenttype.h>
#include <vespa/document/repo/documenttyperepo.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/eval/fast_value.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/searchcore/proton/flushengine/flush_engine_explorer.h>
#include <vespa/searchcore/proton/flushengine/flushengine.h>
#include <vespa/searchcore/proton/flushengine/tls_stats_factory.h>
@@ -37,6 +35,7 @@
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/lambdatask.h>
#include <vespa/vespalib/util/random.h>
+#include <vespa/metrics/updatehook.h>
#include <vespa/searchlib/aggregation/forcelink.hpp>
#include <vespa/searchlib/expression/forcelink.hpp>
@@ -57,7 +56,6 @@ using search::transactionlog::DomainStats;
using vespa::config::search::core::ProtonConfig;
using vespa::config::search::core::internal::InternalProtonType;
using vespalib::compression::CompressionConfig;
-using vespalib::eval::EngineOrFactory;
namespace proton {
@@ -75,17 +73,6 @@ convert(InternalProtonType::Packetcompresstype type)
}
void
-set_tensor_implementation(const ProtonConfig& cfg)
-{
- if (cfg.tensorImplementation == ProtonConfig::TensorImplementation::TENSOR_ENGINE) {
- EngineOrFactory::set(vespalib::tensor::DefaultTensorEngine::ref());
- } else if (cfg.tensorImplementation == ProtonConfig::TensorImplementation::FAST_VALUE) {
- EngineOrFactory::set(vespalib::eval::FastValueBuilderFactory::get());
- }
- LOG(info, "Tensor implementation used: %s", EngineOrFactory::get().to_string().c_str());
-}
-
-void
setBucketCheckSumType(const ProtonConfig & proton)
{
switch (proton.bucketdb.checksumtype) {
@@ -127,6 +114,18 @@ derive_shared_threads(const ProtonConfig &proton,
return std::max(scaledCores, proton.documentdb.size() + proton.flush.maxconcurrent + 1);
}
+struct MetricsUpdateHook : metrics::UpdateHook
+{
+ Proton &self;
+ MetricsUpdateHook(Proton &s)
+ : metrics::UpdateHook("proton-hook"),
+ self(s)
+ {}
+ void updateMetrics(const MetricLockGuard &guard) override {
+ self.updateMetrics(guard);
+ }
+};
+
const vespalib::string CUSTOM_COMPONENT_API_PATH = "/state/v1/custom/component";
VESPA_THREAD_STACK_TAG(proton_shared_executor)
@@ -136,7 +135,7 @@ VESPA_THREAD_STACK_TAG(close_executor)
}
-Proton::ProtonFileHeaderContext::ProtonFileHeaderContext([[maybe_unused]] const Proton &proton_, const vespalib::string &creator)
+Proton::ProtonFileHeaderContext::ProtonFileHeaderContext(const vespalib::string &creator)
: _hostName(),
_creator(creator),
_cluster(),
@@ -201,9 +200,9 @@ Proton::Proton(const config::ConfigUri & configUri,
ComponentConfigProducer(),
_configUri(configUri),
_mutex(),
- _metricsHook(*this),
+ _metricsHook(std::make_unique<MetricsUpdateHook>(*this)),
_metricsEngine(std::make_unique<MetricsEngine>()),
- _fileHeaderContext(*this, progName),
+ _fileHeaderContext(progName),
_tls(),
_diskMemUsageSampler(),
_persistenceEngine(),
@@ -234,7 +233,6 @@ Proton::Proton(const config::ConfigUri & configUri,
_threadPool(128 * 1024),
_distributionKey(-1),
_isInitializing(true),
- _isReplayDone(false),
_abortInit(false),
_initStarted(false),
_initComplete(false),
@@ -269,14 +267,13 @@ Proton::init(const BootstrapConfig::SP & configSnapshot)
const ProtonConfig &protonConfig = configSnapshot->getProtonConfig();
const HwInfo & hwInfo = configSnapshot->getHwInfo();
- set_tensor_implementation(protonConfig);
setBucketCheckSumType(protonConfig);
setFS4Compression(protonConfig);
_diskMemUsageSampler = std::make_unique<DiskMemUsageSampler>(protonConfig.basedir,
diskMemUsageSamplerConfig(protonConfig, hwInfo));
_tls = std::make_unique<TLS>(_configUri.createWithNewId(protonConfig.tlsconfigid), _fileHeaderContext);
- _metricsEngine->addMetricsHook(_metricsHook);
+ _metricsEngine->addMetricsHook(*_metricsHook);
_fileHeaderContext.setClusterName(protonConfig.clustername, protonConfig.basedir);
_matchEngine = std::make_unique<MatchEngine>(protonConfig.numsearcherthreads,
protonConfig.numthreadspersearch,
@@ -347,7 +344,6 @@ Proton::init(const BootstrapConfig::SP & configSnapshot)
_executor.sync();
waitForOnlineState();
- _isReplayDone = true;
_rpcHooks->set_online();
_flushEngine->start();
@@ -486,7 +482,7 @@ Proton::shutdown_config_fetching_and_state_exposing_components_once() noexcept
_customComponentBindToken.reset();
_stateServer.reset();
if (_metricsEngine) {
- _metricsEngine->removeMetricsHook(_metricsHook);
+ _metricsEngine->removeMetricsHook(*_metricsHook);
_metricsEngine->stop();
}
_has_shut_down_config_and_state_components = true;
@@ -730,7 +726,7 @@ updateExecutorMetrics(ExecutorMetrics &metrics,
}
void
-Proton::updateMetrics(const metrics::UpdateHook::MetricLockGuard &)
+Proton::updateMetrics(const metrics::MetricLockGuard &)
{
{
ContentProtonMetrics &metrics = _metricsEngine->root();
@@ -852,6 +848,7 @@ const vespalib::string DOCUMENT_DB = "documentdb";
const vespalib::string FLUSH_ENGINE = "flushengine";
const vespalib::string TLS_NAME = "tls";
const vespalib::string RESOURCE_USAGE = "resourceusage";
+const vespalib::string THREAD_POOLS = "threadpools";
struct StateExplorerProxy : vespalib::StateExplorer {
const StateExplorer &explorer;
@@ -897,8 +894,7 @@ Proton::get_state(const vespalib::slime::Inserter &, bool) const
std::vector<vespalib::string>
Proton::get_children_names() const
{
- std::vector<vespalib::string> names({DOCUMENT_DB, MATCH_ENGINE, FLUSH_ENGINE, TLS_NAME, RESOURCE_USAGE});
- return names;
+ return {DOCUMENT_DB, THREAD_POOLS, MATCH_ENGINE, FLUSH_ENGINE, TLS_NAME, RESOURCE_USAGE};
}
std::unique_ptr<vespalib::StateExplorer>
@@ -915,6 +911,13 @@ Proton::get_child(vespalib::stringref name) const
return std::make_unique<search::transactionlog::TransLogServerExplorer>(_tls->getTransLogServer());
} else if (name == RESOURCE_USAGE && _diskMemUsageSampler) {
return std::make_unique<ResourceUsageExplorer>(_diskMemUsageSampler->writeFilter());
+ } else if (name == THREAD_POOLS) {
+ return std::make_unique<ProtonThreadPoolsExplorer>(_sharedExecutor.get(),
+ (_matchEngine) ? &_matchEngine->get_executor() : nullptr,
+ (_summaryEngine) ? &_summaryEngine->get_executor() : nullptr,
+ (_flushEngine) ? &_flushEngine->get_executor() : nullptr,
+ &_executor,
+ _warmupExecutor.get());
}
return Explorer_UP(nullptr);
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton.h b/searchcore/src/vespa/searchcore/proton/server/proton.h
index f88cd7bf0cd..2241389a63c 100644
--- a/searchcore/src/vespa/searchcore/proton/server/proton.h
+++ b/searchcore/src/vespa/searchcore/proton/server/proton.h
@@ -31,6 +31,7 @@
namespace vespalib { class StateServer; }
namespace search::transactionlog { class TransLogServerApp; }
+namespace metrics { class MetricLockGuard; }
namespace proton {
class DiskMemUsageSampler;
@@ -60,16 +61,6 @@ private:
using InitializeThreads = std::shared_ptr<vespalib::SyncableThreadExecutor>;
using BucketSpace = document::BucketSpace;
- struct MetricsUpdateHook : metrics::UpdateHook
- {
- Proton &self;
- MetricsUpdateHook(Proton &s)
- : metrics::UpdateHook("proton-hook"),
- self(s) {}
- void updateMetrics(const MetricLockGuard &guard) override { self.updateMetrics(guard); }
- };
- friend struct MetricsUpdateHook;
-
class ProtonFileHeaderContext : public search::common::FileHeaderContext
{
vespalib::string _hostName;
@@ -78,23 +69,23 @@ private:
pid_t _pid;
public:
- ProtonFileHeaderContext(const Proton &proton_, const vespalib::string &creator);
+ ProtonFileHeaderContext(const vespalib::string &creator);
~ProtonFileHeaderContext() override;
void addTags(vespalib::GenericHeader &header, const vespalib::string &name) const override;
void setClusterName(const vespalib::string &clusterName, const vespalib::string &baseDir);
};
- const config::ConfigUri _configUri;
- mutable std::shared_mutex _mutex;
- MetricsUpdateHook _metricsHook;
- std::unique_ptr<MetricsEngine> _metricsEngine;
- ProtonFileHeaderContext _fileHeaderContext;
- std::unique_ptr<TLS> _tls;
+ const config::ConfigUri _configUri;
+ mutable std::shared_mutex _mutex;
+ std::unique_ptr<metrics::UpdateHook> _metricsHook;
+ std::unique_ptr<MetricsEngine> _metricsEngine;
+ ProtonFileHeaderContext _fileHeaderContext;
+ std::unique_ptr<TLS> _tls;
std::unique_ptr<DiskMemUsageSampler> _diskMemUsageSampler;
PersistenceEngine::UP _persistenceEngine;
DocumentDBMap _documentDBMap;
- std::unique_ptr<MatchEngine> _matchEngine;
+ std::unique_ptr<MatchEngine> _matchEngine;
std::unique_ptr<SummaryEngine> _summaryEngine;
std::unique_ptr<DocsumBySlime> _docsumBySlime;
MemoryFlushConfigUpdater::UP _memoryFlushConfigUpdater;
@@ -138,12 +129,6 @@ private:
void applyConfig(const BootstrapConfig::SP & configSnapshot) override;
MonitorReply::UP ping(MonitorRequest::UP request, MonitorClient &client) override;
- /**
- * Called by the metrics update hook (typically in the context of
- * the metric manager). Do not call this function in multiple
- * threads at once.
- **/
- void updateMetrics(const metrics::UpdateHook::MetricLockGuard &guard);
void waitForInitDone();
void waitForOnlineState();
uint32_t getDistributionKey() const override { return _distributionKey; }
@@ -161,6 +146,13 @@ public:
~Proton() override;
/**
+ * Called by the metrics update hook (typically in the context of
+ * the metric manager). Do not call this function in multiple
+ * threads at once.
+ **/
+ void updateMetrics(const metrics::MetricLockGuard &guard);
+
+ /**
* This method must be called after the constructor and before the destructor.
* If not I will force a 'core' upon you.
* All relevant initialization is conducted here.
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton_configurer.cpp b/searchcore/src/vespa/searchcore/proton/server/proton_configurer.cpp
index a7dada3047c..3d7e5e7af57 100644
--- a/searchcore/src/vespa/searchcore/proton/server/proton_configurer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/proton_configurer.cpp
@@ -72,7 +72,7 @@ ProtonConfigurer::setAllowReconfig(bool allowReconfig)
_allowReconfig = allowReconfig;
if (allowReconfig) {
// Ensure that pending config is applied
- _executor.execute(makeLambdaTask([=]() { performReconfigure(); }));
+ _executor.execute(makeLambdaTask([this]() { performReconfigure(); }));
}
}
if (!allowReconfig) {
@@ -102,7 +102,7 @@ ProtonConfigurer::reconfigure(std::shared_ptr<ProtonConfigSnapshot> configSnapsh
std::lock_guard<std::mutex> guard(_mutex);
_pendingConfigSnapshot = configSnapshot;
if (_allowReconfig) {
- _executor.execute(makeLambdaTask([=]() { performReconfigure(); }));
+ _executor.execute(makeLambdaTask([&]() { performReconfigure(); }));
}
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.cpp b/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.cpp
new file mode 100644
index 00000000000..e0db9e29c35
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.cpp
@@ -0,0 +1,43 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "executor_explorer_utils.h"
+#include "proton_thread_pools_explorer.h"
+#include <vespa/vespalib/data/slime/cursor.h>
+#include <vespa/vespalib/util/threadexecutor.h>
+
+using vespalib::SyncableThreadExecutor;
+
+namespace proton {
+
+using explorer::convert_executor_to_slime;
+
+ProtonThreadPoolsExplorer::ProtonThreadPoolsExplorer(const SyncableThreadExecutor* shared,
+ const SyncableThreadExecutor* match,
+ const SyncableThreadExecutor* docsum,
+ const SyncableThreadExecutor* flush,
+ const SyncableThreadExecutor* proton,
+ const SyncableThreadExecutor* warmup)
+ : _shared(shared),
+ _match(match),
+ _docsum(docsum),
+ _flush(flush),
+ _proton(proton),
+ _warmup(warmup)
+{
+}
+
+void
+ProtonThreadPoolsExplorer::get_state(const vespalib::slime::Inserter& inserter, bool full) const
+{
+ auto& object = inserter.insertObject();
+ if (full) {
+ convert_executor_to_slime(_shared, object.setObject("shared"));
+ convert_executor_to_slime(_match, object.setObject("match"));
+ convert_executor_to_slime(_docsum, object.setObject("docsum"));
+ convert_executor_to_slime(_flush, object.setObject("flush"));
+ convert_executor_to_slime(_proton, object.setObject("proton"));
+ convert_executor_to_slime(_warmup, object.setObject("warmup"));
+ }
+}
+
+}
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.h b/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.h
new file mode 100644
index 00000000000..8022a0483c4
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/server/proton_thread_pools_explorer.h
@@ -0,0 +1,35 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/net/state_explorer.h>
+
+namespace vespalib { class SyncableThreadExecutor; }
+
+namespace proton {
+
+/**
+ * Class used to explore the shared thread pools used by proton and it's document databases.
+ */
+class ProtonThreadPoolsExplorer : public vespalib::StateExplorer {
+private:
+ const vespalib::SyncableThreadExecutor* _shared;
+ const vespalib::SyncableThreadExecutor* _match;
+ const vespalib::SyncableThreadExecutor* _docsum;
+ const vespalib::SyncableThreadExecutor* _flush;
+ const vespalib::SyncableThreadExecutor* _proton;
+ const vespalib::SyncableThreadExecutor* _warmup;
+
+public:
+ ProtonThreadPoolsExplorer(const vespalib::SyncableThreadExecutor* shared,
+ const vespalib::SyncableThreadExecutor* match,
+ const vespalib::SyncableThreadExecutor* docsum,
+ const vespalib::SyncableThreadExecutor* flush,
+ const vespalib::SyncableThreadExecutor* proton,
+ const vespalib::SyncableThreadExecutor* warmup);
+
+ void get_state(const vespalib::slime::Inserter& inserter, bool full) const override;
+};
+
+}
+
diff --git a/searchcore/src/vespa/searchcore/proton/server/searchable_feed_view.cpp b/searchcore/src/vespa/searchcore/proton/server/searchable_feed_view.cpp
index 7cfad4f1ac1..b66822f39cc 100644
--- a/searchcore/src/vespa/searchcore/proton/server/searchable_feed_view.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/searchable_feed_view.cpp
@@ -65,7 +65,7 @@ SearchableFeedView::putIndexedFields(SerialNum serialNum, search::DocumentIdT li
return;
}
_writeService.index().execute(
- makeLambdaTask([=] {
+ makeLambdaTask([this, serialNum, lid, newDoc, onWriteDone] {
performIndexPut(serialNum, lid, newDoc, onWriteDone);
}));
}
@@ -100,7 +100,7 @@ SearchableFeedView::performIndexPut(SerialNum serialNum, search::DocumentIdT lid
void
SearchableFeedView::heartBeatIndexedFields(SerialNum serialNum)
{
- _writeService.index().execute(makeLambdaTask([=] { performIndexHeartBeat(serialNum); }));
+ _writeService.index().execute(makeLambdaTask([this, serialNum] { performIndexHeartBeat(serialNum); }));
}
void
@@ -126,7 +126,7 @@ SearchableFeedView::removeIndexedFields(SerialNum serialNum, search::DocumentIdT
return;
}
_writeService.index().execute(
- makeLambdaTask([=]() {
+ makeLambdaTask([this, serialNum, lid, onWriteDone]() {
performIndexRemove(serialNum, lid, onWriteDone);
}));
}
@@ -166,7 +166,7 @@ SearchableFeedView::removeIndexedFields(SerialNum serialNum, const LidVector &li
return;
_writeService.index().execute(
- makeLambdaTask([=]() {
+ makeLambdaTask([this, serialNum, lidsToRemove, onWriteDone]() {
performIndexRemove(serialNum, lidsToRemove, onWriteDone);
}));
}
@@ -200,7 +200,7 @@ void
SearchableFeedView::internalForceCommit(SerialNum serialNum, OnForceCommitDoneType onCommitDone)
{
Parent::internalForceCommit(serialNum, onCommitDone);
- _writeService.index().execute(makeLambdaTask([=]() { performIndexForceCommit(serialNum, onCommitDone); }));
+ _writeService.index().execute(makeLambdaTask([this, serialNum, onCommitDone]() { performIndexForceCommit(serialNum, onCommitDone); }));
_writeService.index().wakeup();
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
index 7f2b8fcaa63..814d68bdb8d 100644
--- a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
@@ -15,6 +15,7 @@
#include <vespa/searchcore/proton/reference/gid_to_lid_change_handler.h>
#include <vespa/searchlib/fef/indexproperties.h>
#include <vespa/searchlib/fef/properties.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/vespalib/util/closuretask.h>
using vespa::config::search::RankProfilesConfig;
@@ -27,7 +28,7 @@ using search::TuneFileDocumentDB;
using search::index::Schema;
using search::SerialNum;
using vespalib::ThreadStackExecutorBase;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using namespace searchcorespi;
namespace proton {
@@ -39,7 +40,7 @@ SearchableDocSubDB::SearchableDocSubDB(const Config &cfg, const Context &ctx)
_indexWriter(),
_rSearchView(),
_rFeedView(),
- _tensorLoader(EngineOrFactory::get()),
+ _tensorLoader(FastValueBuilderFactory::get()),
_constantValueCache(_tensorLoader),
_constantValueRepo(_constantValueCache),
_configurer(_iSummaryMgr, _rSearchView, _rFeedView, ctx._queryLimiter, _constantValueRepo, ctx._clock,
diff --git a/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.cpp b/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.cpp
index 7d5d49b19c7..0bd50fc0104 100644
--- a/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.cpp
@@ -120,7 +120,7 @@ StoreOnlyDocSubDB::StoreOnlyDocSubDB(const Config &cfg, const Context &ctx)
_pendingLidsForCommit(std::make_shared<PendingLidTracker>()),
_subDbId(cfg._subDbId),
_subDbType(cfg._subDbType),
- _fileHeaderContext(*this, ctx._fileHeaderContext, _docTypeName, _baseDir),
+ _fileHeaderContext(ctx._fileHeaderContext, _docTypeName, _baseDir),
_gidToLidChangeHandler(std::make_shared<DummyGidToLidChangeHandler>())
{
vespalib::mkdir(_baseDir, false); // Assume parent is created.
@@ -497,8 +497,7 @@ StoreOnlyDocSubDB::getDocumentDBReference()
}
StoreOnlySubDBFileHeaderContext::
-StoreOnlySubDBFileHeaderContext([[maybe_unused]] StoreOnlyDocSubDB &owner,
- const FileHeaderContext & parentFileHeaderContext,
+StoreOnlySubDBFileHeaderContext(const FileHeaderContext & parentFileHeaderContext,
const DocTypeName &docTypeName,
const vespalib::string &baseDir)
: FileHeaderContext(),
diff --git a/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.h b/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.h
index 1cdd22fcc41..7c3f7c82eb0 100644
--- a/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.h
+++ b/searchcore/src/vespa/searchcore/proton/server/storeonlydocsubdb.h
@@ -50,8 +50,6 @@ public:
void close() override { }
};
-class StoreOnlyDocSubDB;
-
/**
* File header context used by the store-only sub database.
*
@@ -65,8 +63,7 @@ class StoreOnlySubDBFileHeaderContext : public search::common::FileHeaderContext
vespalib::string _subDB;
public:
- StoreOnlySubDBFileHeaderContext(StoreOnlyDocSubDB &owner,
- const search::common::FileHeaderContext & parentFileHeaderContext,
+ StoreOnlySubDBFileHeaderContext(const search::common::FileHeaderContext & parentFileHeaderContext,
const DocTypeName &docTypeName,
const vespalib::string &baseDir);
~StoreOnlySubDBFileHeaderContext();
diff --git a/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp b/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp
index 7c3c796bda3..de5d9d4b644 100644
--- a/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp
@@ -687,7 +687,7 @@ StoreOnlyFeedView::removeDocuments(const RemoveDocumentsOperation &op, bool remo
std::shared_ptr<search::IDestructorCallback> onWriteDone;
vespalib::Executor::Task::UP removeBatchDoneTask;
if (explicitReuseLids) {
- removeBatchDoneTask = makeLambdaTask([=]() { _metaStore.removeBatchComplete(lidsToRemove); });
+ removeBatchDoneTask = makeLambdaTask([this, lidsToRemove]() { _metaStore.removeBatchComplete(lidsToRemove); });
} else {
removeBatchDoneTask = makeLambdaTask([]() {});
}
diff --git a/searchcore/src/vespa/searchcore/proton/summaryengine/summaryengine.h b/searchcore/src/vespa/searchcore/proton/summaryengine/summaryengine.h
index 029aefacfc8..c1cb1f91a2a 100644
--- a/searchcore/src/vespa/searchcore/proton/summaryengine/summaryengine.h
+++ b/searchcore/src/vespa/searchcore/proton/summaryengine/summaryengine.h
@@ -65,6 +65,11 @@ public:
vespalib::ThreadStackExecutor::Stats getExecutorStats() { return _executor.getStats(); }
/**
+ * Returns the underlying executor. Only used for state explorers.
+ */
+ const vespalib::SyncableThreadExecutor& get_executor() const { return _executor; }
+
+ /**
* Starts the underlying threads. This will throw a vespalib::Exception if
* it failed to start for any reason.
*/
diff --git a/searchcore/src/vespa/searchcore/proton/test/thread_service_observer.h b/searchcore/src/vespa/searchcore/proton/test/thread_service_observer.h
index 350673b9c90..0b1b9730363 100644
--- a/searchcore/src/vespa/searchcore/proton/test/thread_service_observer.h
+++ b/searchcore/src/vespa/searchcore/proton/test/thread_service_observer.h
@@ -48,6 +48,10 @@ public:
_service.setTaskLimit(taskLimit);
}
+ uint32_t getTaskLimit() const override {
+ return _service.getTaskLimit();
+ }
+
void wakeup() override {
_service.wakeup();
}
diff --git a/searchlib/src/apps/docstore/documentstoreinspect.cpp b/searchlib/src/apps/docstore/documentstoreinspect.cpp
index 2526ce456ae..8a3bb6b247b 100644
--- a/searchlib/src/apps/docstore/documentstoreinspect.cpp
+++ b/searchlib/src/apps/docstore/documentstoreinspect.cpp
@@ -71,7 +71,7 @@ DocumentStoreInspectApp::Main()
if (cmd == "dumpidxfile") {
vespalib::string idxfile;
if (_argc >= 4) {
- if (_argv[2] == vespalib::string("--idxfile")) {
+ if (vespalib::string(_argv[2]) == vespalib::string("--idxfile")) {
idxfile = _argv[3];
dumpIdxFile(idxfile);
} else {
diff --git a/searchlib/src/apps/tests/btreestress_test.cpp b/searchlib/src/apps/tests/btreestress_test.cpp
index 0fb356001f2..37fc6b26cc3 100644
--- a/searchlib/src/apps/tests/btreestress_test.cpp
+++ b/searchlib/src/apps/tests/btreestress_test.cpp
@@ -202,19 +202,19 @@ TEST_F("Test single threaded lower_bound reader during updates", Fixture)
{
uint32_t cnt = 1000000;
f._reportWork = true;
- f._writer.execute(makeLambdaTask([=]() { f.writeWork(cnt); }));
- f._readers.execute(makeLambdaTask([=]() { f.readWork(); }));
+ f._writer.execute(makeLambdaTask([this, cnt]() { f.writeWork(cnt); }));
+ f._readers.execute(makeLambdaTask([this]() { f.readWork(); }));
}
TEST_F("Test multithreaded lower_bound reader during updates", Fixture)
{
uint32_t cnt = 1000000;
f._reportWork = true;
- f._writer.execute(makeLambdaTask([=]() { f.writeWork(cnt); }));
- f._readers.execute(makeLambdaTask([=]() { f.readWork(); }));
- f._readers.execute(makeLambdaTask([=]() { f.readWork(); }));
- f._readers.execute(makeLambdaTask([=]() { f.readWork(); }));
- f._readers.execute(makeLambdaTask([=]() { f.readWork(); }));
+ f._writer.execute(makeLambdaTask([this, cnt]() { f.writeWork(cnt); }));
+ f._readers.execute(makeLambdaTask([this]() { f.readWork(); }));
+ f._readers.execute(makeLambdaTask([this]() { f.readWork(); }));
+ f._readers.execute(makeLambdaTask([this]() { f.readWork(); }));
+ f._readers.execute(makeLambdaTask([this]() { f.readWork(); }));
}
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/apps/tests/memoryindexstress_test.cpp b/searchlib/src/apps/tests/memoryindexstress_test.cpp
index 3f848b45cc3..e8590999bc1 100644
--- a/searchlib/src/apps/tests/memoryindexstress_test.cpp
+++ b/searchlib/src/apps/tests/memoryindexstress_test.cpp
@@ -371,9 +371,9 @@ Fixture::stressTest(uint32_t writeCnt)
LOG(info,
"starting stress test, 1 write thread, %u read threads, %u writes",
readThreads, writeCnt);
- _writer.execute(makeLambdaTask([=]() { writeWork(writeCnt); }));
+ _writer.execute(makeLambdaTask([this, writeCnt]() { writeWork(writeCnt); }));
for (uint32_t i = 0; i < readThreads; ++i) {
- _readers.execute(makeLambdaTask([=]() { readWork(); }));
+ _readers.execute(makeLambdaTask([this]() { readWork(); }));
}
}
diff --git a/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp b/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
index 51f243e1c37..f2a9ee2932f 100644
--- a/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
+++ b/searchlib/src/apps/vespa-ranking-expression-analyzer/vespa-ranking-expression-analyzer.cpp
@@ -4,13 +4,12 @@
#include <vespa/eval/eval/llvm/compiled_function.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/call_nodes.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/operator_nodes.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/eval/eval/vm_forest.h>
#include <vespa/eval/eval/fast_forest.h>
#include <vespa/eval/eval/llvm/deinline_forest.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/vespalib/io/mapped_file_input.h>
#include <vespa/eval/eval/param_usage.h>
#include <vespa/fastos/app.h>
@@ -154,7 +153,7 @@ struct FunctionInfo {
size_t get_path_len(const TreeList &trees) const {
size_t path = 0;
for (const Node *tree: trees) {
- InterpretedFunction ifun(EngineOrFactory::get(), *tree, NodeTypes());
+ InterpretedFunction ifun(FastValueBuilderFactory::get(), *tree, NodeTypes());
InterpretedFunction::Context ctx(ifun);
SimpleParams fun_params(params);
ifun.eval(ctx, fun_params);
diff --git a/searchlib/src/test/java/com/yahoo/searchlib/tensor/TensorConformanceTest.java b/searchlib/src/test/java/com/yahoo/searchlib/tensor/TensorConformanceTest.java
deleted file mode 100644
index 61aec069c72..00000000000
--- a/searchlib/src/test/java/com/yahoo/searchlib/tensor/TensorConformanceTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.searchlib.tensor;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.yahoo.io.GrowableByteBuffer;
-import com.yahoo.searchlib.rankingexpression.RankingExpression;
-import com.yahoo.searchlib.rankingexpression.evaluation.BooleanValue;
-import com.yahoo.searchlib.rankingexpression.evaluation.DoubleCompatibleValue;
-import com.yahoo.searchlib.rankingexpression.evaluation.MapContext;
-import com.yahoo.searchlib.rankingexpression.evaluation.StringValue;
-import com.yahoo.searchlib.rankingexpression.evaluation.TensorValue;
-import com.yahoo.searchlib.rankingexpression.evaluation.Value;
-import com.yahoo.searchlib.rankingexpression.parser.ParseException;
-import com.yahoo.tensor.Tensor;
-import com.yahoo.tensor.serialization.TypedBinaryFormat;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-
-import static org.junit.Assert.assertEquals;
-
-public class TensorConformanceTest {
-
- private static String testPath = "eval/src/apps/tensor_conformance/test_spec.json";
-
- @Test
- public void testConformance() throws IOException {
- File testSpec = new File(testPath);
- if (!testSpec.exists()) {
- testSpec = new File("../" + testPath);
- }
- int count = 0;
- List<Integer> failList = new ArrayList<>();
-
- try(BufferedReader br = new BufferedReader(new FileReader(testSpec))) {
- String test = br.readLine();
- while (test != null) {
- boolean success = testCase(test, count);
- if (!success) {
- failList.add(count);
- }
- test = br.readLine();
- count++;
- }
- }
- assertEquals(failList.size() + " conformance test fails: " + failList, 0, failList.size());
- }
-
- private boolean testCase(String test, int count) {
- try {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode node = mapper.readTree(test);
-
- if (node.has("num_tests")) {
- Assert.assertEquals(node.get("num_tests").asInt(), count);
- return true;
- }
- if (!node.has("expression")) {
- return true; // ignore
- }
-
- String expression = node.get("expression").asText();
- MapContext context = getInput(node.get("inputs"));
- Tensor expect = getTensor(node.get("result").get("expect").asText());
- Tensor result = evaluate(expression, context);
- boolean equals = Tensor.equals(result, expect);
- if (!equals) {
- System.out.println(count + " : Tensors not equal. Result: " + result.toString() + " Expected: " + expect.toString() + " -> expression \"" + expression + "\"");
- } else if (! result.type().valueType().equals(expect.type().valueType())) {
- System.out.println(count + " : Tensor cell value types not equal. Result: " + result.type() + " Expected: " + expect.type() + " -> expression \"" + expression + "\"");
- equals = false;
- }
- return equals;
-
- } catch (Exception e) {
- System.out.println(count + " : " + e.toString());
- }
- return false;
- }
-
- private Tensor evaluate(String expression, MapContext context) throws ParseException {
- Value value = new RankingExpression(expression).evaluate(context);
- if (!(value instanceof TensorValue)) {
- throw new IllegalArgumentException("Result is not a tensor");
- }
- return ((TensorValue)value).asTensor();
- }
-
- private MapContext getInput(JsonNode inputs) {
- MapContext context = new MapContext();
- for (Iterator<String> i = inputs.fieldNames(); i.hasNext(); ) {
- String name = i.next();
- String value = inputs.get(name).asText();
- Tensor tensor = getTensor(value);
- context.put(name, new TensorValue(tensor));
- }
- return context;
- }
-
- private Tensor getTensor(String binaryRepresentation) {
- byte[] bin = getBytes(binaryRepresentation);
- return TypedBinaryFormat.decode(Optional.empty(), GrowableByteBuffer.wrap(bin));
- }
-
- private byte[] getBytes(String binaryRepresentation) {
- return parseHexValue(binaryRepresentation.substring(2));
- }
-
- private byte[] parseHexValue(String s) {
- final int len = s.length();
- byte[] bytes = new byte[len/2];
- for (int i = 0; i < len; i += 2) {
- int c1 = hexValue(s.charAt(i)) << 4;
- int c2 = hexValue(s.charAt(i + 1));
- bytes[i/2] = (byte)(c1 + c2);
- }
- return bytes;
- }
-
- private int hexValue(Character c) {
- if (c >= 'a' && c <= 'f') {
- return c - 'a' + 10;
- } else if (c >= 'A' && c <= 'F') {
- return c - 'A' + 10;
- } else if (c >= '0' && c <= '9') {
- return c - '0';
- }
- throw new IllegalArgumentException("Hex contains illegal characters");
- }
-
-}
-
diff --git a/searchlib/src/tests/attribute/imported_attribute_vector/imported_attribute_vector_test.cpp b/searchlib/src/tests/attribute/imported_attribute_vector/imported_attribute_vector_test.cpp
index 1d6f68c5802..2d30f89015d 100644
--- a/searchlib/src/tests/attribute/imported_attribute_vector/imported_attribute_vector_test.cpp
+++ b/searchlib/src/tests/attribute/imported_attribute_vector/imported_attribute_vector_test.cpp
@@ -1,9 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/test/value_compare.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/searchcommon/attribute/search_context_params.h>
#include <vespa/searchlib/fef/termfieldmatchdata.h>
#include <vespa/searchlib/tensor/i_tensor_attribute.h>
@@ -16,10 +16,10 @@ using search::tensor::TensorAttribute;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
Value::UP createTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
namespace search::attribute {
diff --git a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
index 2bb55ac6977..c622ccae679 100644
--- a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
+++ b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
@@ -123,7 +123,7 @@ public:
_attr->shrinkLidSpace();
}
void clearDocs(uint32_t lidLow, uint32_t lidLimit) {
- _mvMapping->clearDocs(lidLow, lidLimit, [=](uint32_t docId) { _attr->clearDoc(docId); });
+ _mvMapping->clearDocs(lidLow, lidLimit, [this](uint32_t docId) { _attr->clearDoc(docId); });
}
size_t getTotalValueCnt() const { return _mvMapping->getTotalValueCnt(); }
diff --git a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp
index b23277bee21..51b4f1d760d 100644
--- a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp
+++ b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp
@@ -1,8 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/attribute/iattributecontext.h>
#include <vespa/searchlib/attribute/attribute_blueprint_factory.h>
#include <vespa/searchlib/attribute/attribute_read_guard.h>
@@ -51,7 +51,6 @@ using search::queryeval::SearchIterator;
using std::string;
using std::vector;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
using namespace search::attribute;
@@ -358,7 +357,7 @@ expect_nearest_neighbor_blueprint(const vespalib::string& attribute_tensor_type_
auto result = f.create_blueprint();
const auto& nearest = downcast<const NearestNeighborBlueprint>(*result);
EXPECT_EQ(attribute_tensor_type_spec, nearest.get_attribute_tensor().getTensorType().to_spec());
- EXPECT_EQ(converted_query_tensor, EngineOrFactory::get().to_spec(nearest.get_query_tensor()));
+ EXPECT_EQ(converted_query_tensor, spec_from_value(nearest.get_query_tensor()));
EXPECT_EQ(7u, nearest.get_target_num_hits());
}
diff --git a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp
index 98cb8c0485e..e3d84683d70 100644
--- a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp
+++ b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp
@@ -65,7 +65,7 @@ using queryeval::SimpleResult;
class DocSet : public std::set<uint32_t>
{
public:
- DocSet();
+ DocSet() noexcept;
~DocSet();
DocSet(const uint32_t *b, const uint32_t *e) : std::set<uint32_t>(b, e) {}
DocSet & put(const uint32_t &v) {
@@ -74,7 +74,7 @@ public:
}
};
-DocSet::DocSet() = default;
+DocSet::DocSet() noexcept = default;
DocSet::~DocSet() = default;
template <typename V, typename T>
diff --git a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
index daa85c91b2c..e1bd47af358 100644
--- a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
+++ b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
@@ -1,7 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/document/base/exceptions.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/fastos/file.h>
@@ -16,7 +17,7 @@
#include <vespa/searchlib/tensor/nearest_neighbor_index.h>
#include <vespa/searchlib/tensor/nearest_neighbor_index_factory.h>
#include <vespa/searchlib/tensor/nearest_neighbor_index_saver.h>
-#include <vespa/searchlib/tensor/serialized_tensor_attribute.h>
+#include <vespa/searchlib/tensor/serialized_fast_value_attribute.h>
#include <vespa/searchlib/tensor/tensor_attribute.h>
#include <vespa/searchlib/test/directory_handler.h>
#include <vespa/searchlib/util/fileutil.h>
@@ -40,7 +41,7 @@ using search::tensor::DefaultNearestNeighborIndexFactory;
using search::tensor::DenseTensorAttribute;
using search::tensor::DirectTensorAttribute;
using search::tensor::DocVectorAccess;
-using search::tensor::SerializedTensorAttribute;
+using search::tensor::SerializedFastValueAttribute;
using search::tensor::HnswIndex;
using search::tensor::HnswNode;
using search::tensor::NearestNeighborIndex;
@@ -52,7 +53,7 @@ using vespalib::eval::TensorSpec;
using vespalib::eval::CellType;
using vespalib::eval::ValueType;
using vespalib::eval::Value;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using DoubleVector = std::vector<double>;
using generation_t = vespalib::GenerationHandler::generation_t;
@@ -62,7 +63,7 @@ vespalib::string denseSpec("tensor(x[2],y[3])");
vespalib::string vec_2d_spec("tensor(x[2])");
Value::UP createTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
TensorSpec
@@ -344,7 +345,7 @@ struct Fixture {
} else if (_traits.use_direct_tensor_attribute) {
return std::make_shared<DirectTensorAttribute>(_name, _cfg);
} else {
- return std::make_shared<SerializedTensorAttribute>(_name, _cfg);
+ return std::make_shared<SerializedFastValueAttribute>(_name, _cfg);
}
}
@@ -904,7 +905,7 @@ public:
}
std::unique_ptr<Value> createDenseTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
std::unique_ptr<NearestNeighborBlueprint> make_blueprint(double brute_force_limit = 0.05) {
diff --git a/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp b/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp
index 3dbe0d00881..1cd91329912 100644
--- a/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp
+++ b/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp
@@ -6,7 +6,9 @@
#include <vespa/searchlib/engine/searchapi.h>
#include <vespa/searchlib/engine/docsumapi.h>
#include <vespa/searchlib/engine/monitorapi.h>
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/data/slime/binary_format.h>
#include <thread>
@@ -83,7 +85,7 @@ struct ProtoRpcAdapterTest : ::testing::Test {
FRT_Target *connect() {
return server.supervisor().GetTarget(server.supervisor().GetListenPort());
}
- ~ProtoRpcAdapterTest() = default;
+ ~ProtoRpcAdapterTest() override = default;
};
//-----------------------------------------------------------------------------
diff --git a/searchlib/src/tests/features/constant/constant_test.cpp b/searchlib/src/tests/features/constant/constant_test.cpp
index e513e20a35c..140c93125b0 100644
--- a/searchlib/src/tests/features/constant/constant_test.cpp
+++ b/searchlib/src/tests/features/constant/constant_test.cpp
@@ -6,8 +6,8 @@
#include <vespa/searchlib/fef/test/ftlib.h>
#include <vespa/searchlib/fef/test/indexenvironment.h>
#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
@@ -16,18 +16,18 @@ using namespace search::fef;
using namespace search::fef::indexproperties;
using namespace search::fef::test;
using namespace search::features;
-using vespalib::eval::Function;
-using vespalib::eval::Value;
using vespalib::eval::DoubleValue;
+using vespalib::eval::Function;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
+using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
namespace
{
Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
}
diff --git a/searchlib/src/tests/features/imported_dot_product/imported_dot_product_test.cpp b/searchlib/src/tests/features/imported_dot_product/imported_dot_product_test.cpp
index 3a755704c0d..3c9cf209484 100644
--- a/searchlib/src/tests/features/imported_dot_product/imported_dot_product_test.cpp
+++ b/searchlib/src/tests/features/imported_dot_product/imported_dot_product_test.cpp
@@ -6,9 +6,10 @@
#include <vespa/searchlib/fef/test/ftlib.h>
#include <vespa/searchlib/fef/test/rankresult.h>
#include <vespa/searchlib/fef/test/dummy_dependency_handler.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
using namespace search;
using namespace search::attribute;
@@ -17,6 +18,9 @@ using namespace search::fef;
using namespace search::fef::test;
using namespace search::index;
+using vespalib::eval::SimpleValue;
+using vespalib::eval::TensorSpec;
+
template <typename T>
std::unique_ptr<fef::Anything> create_param(const vespalib::string& param) {
Properties props;
@@ -109,12 +113,18 @@ struct ArrayFixture : FixtureBase {
template <typename ExpectedType>
void check_prepare_state_output(const vespalib::eval::Value & tensor, const ExpectedType & expected) {
vespalib::nbostream os;
- vespalib::eval::EngineOrFactory::get().encode(tensor, os);
+ encode_value(tensor, os);
vespalib::string input_vector(os.data(), os.size());
check_prepare_state_output(".tensor", input_vector, expected);
}
template <typename ExpectedType>
+ void check_prepare_state_output(const TensorSpec & spec, const ExpectedType & expected) {
+ auto value = SimpleValue::from_spec(spec);
+ check_prepare_state_output(*value, expected);
+ }
+
+ template <typename ExpectedType>
void check_prepare_state_output(const vespalib::string& input_vector, const ExpectedType & expected) {
check_prepare_state_output("", input_vector, expected);
}
@@ -196,25 +206,25 @@ TEST_F("prepareSharedState emits double vector for double imported attribute", A
TEST_F("prepareSharedState handles tensor as float from tensor for double imported attribute", ArrayFixture) {
f.setup_float_mappings(BasicType::DOUBLE);
- vespalib::tensor::DenseTensor<float> tensor(vespalib::eval::ValueType::from_spec("tensor<float>(x[3])"), {10.1, 20.2, 30.3});
+ auto tensor = TensorSpec::from_expr("tensor<float>(x[3]):[10.1,20.2,30.3]");
f.template check_prepare_state_output(tensor, dotproduct::ArrayParam<double>({10.1, 20.2, 30.3}));
}
TEST_F("prepareSharedState handles tensor as double from tensor for double imported attribute", ArrayFixture) {
f.setup_float_mappings(BasicType::DOUBLE);
- vespalib::tensor::DenseTensor<double> tensor(vespalib::eval::ValueType::from_spec("tensor(x[3])"), {10.1, 20.2, 30.3});
+ auto tensor = TensorSpec::from_expr("tensor(x[3]):[10.1,20.2,30.3]");
f.template check_prepare_state_output(tensor, dotproduct::ArrayParam<double>({10.1, 20.2, 30.3}));
}
TEST_F("prepareSharedState handles tensor as float from tensor for float imported attribute", ArrayFixture) {
f.setup_float_mappings(BasicType::FLOAT);
- vespalib::tensor::DenseTensor<float> tensor(vespalib::eval::ValueType::from_spec("tensor<float>(x[3])"), {10.1, 20.2, 30.3});
+ auto tensor = TensorSpec::from_expr("tensor<float>(x[3]):[10.1,20.2,30.3]");
f.template check_prepare_state_output(tensor, dotproduct::ArrayParam<float>({10.1, 20.2, 30.3}));
}
TEST_F("prepareSharedState handles tensor as double from tensor for float imported attribute", ArrayFixture) {
f.setup_float_mappings(BasicType::FLOAT);
- vespalib::tensor::DenseTensor<double> tensor(vespalib::eval::ValueType::from_spec("tensor(x[3])"), {10.1, 20.2, 30.3});
+ auto tensor = TensorSpec::from_expr("tensor(x[3]):[10.1,20.2,30.3]");
f.template check_prepare_state_output(tensor, dotproduct::ArrayParam<float>({10.1, 20.2, 30.3}));
}
diff --git a/searchlib/src/tests/features/tensor/tensor_test.cpp b/searchlib/src/tests/features/tensor/tensor_test.cpp
index 116b4ed2bb5..53049c4a385 100644
--- a/searchlib/src/tests/features/tensor/tensor_test.cpp
+++ b/searchlib/src/tests/features/tensor/tensor_test.cpp
@@ -11,12 +11,12 @@
#include <vespa/searchlib/fef/test/queryenvironment.h>
#include <vespa/searchlib/tensor/tensor_attribute.h>
#include <vespa/searchlib/tensor/direct_tensor_attribute.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/test/value_compare.h>
-#include <vespa/eval/tensor/test/test_utils.h>
#include <vespa/vespalib/objects/nbostream.h>
using search::feature_t;
@@ -28,12 +28,12 @@ using search::AttributeFactory;
using search::tensor::TensorAttribute;
using search::tensor::DirectTensorAttribute;
using search::AttributeVector;
-using vespalib::eval::EngineOrFactory;
using vespalib::eval::Function;
+using vespalib::eval::SimpleValue;
+using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::TensorSpec;
-using vespalib::tensor::test::makeTensor;
+using vespalib::eval::spec_from_value;
using AVC = search::attribute::Config;
using AVBT = search::attribute::BasicType;
@@ -46,7 +46,7 @@ namespace
{
Value::UP make_empty(const vespalib::string &type) {
- return EngineOrFactory::get().from_spec(TensorSpec(type));
+ return SimpleValue::from_spec(TensorSpec(type));
}
}
@@ -113,10 +113,10 @@ struct ExecFixture
DirectTensorAttribute *directAttr =
dynamic_cast<DirectTensorAttribute *>(attrs[1].get());
- auto doc_tensor = makeTensor<Value>(TensorSpec("tensor(x{})")
- .add({{"x", "a"}}, 3)
- .add({{"x", "b"}}, 5)
- .add({{"x", "c"}}, 7));
+ auto doc_tensor = SimpleValue::from_spec(TensorSpec("tensor(x{})")
+ .add({{"x", "a"}}, 3)
+ .add({{"x", "b"}}, 5)
+ .add({{"x", "c"}}, 7));
tensorAttr->setTensor(1, *doc_tensor);
directAttr->set_tensor(1, std::move(doc_tensor));
@@ -129,7 +129,7 @@ struct ExecFixture
std::unique_ptr<Value> tensor)
{
vespalib::nbostream stream;
- EngineOrFactory::get().encode(*tensor, stream);
+ encode_value(*tensor, stream);
test.getQueryEnv().getProperties().add(tensorName,
vespalib::stringref(stream.peek(), stream.size()));
setQueryTensorType(tensorName, tensorTypeSpec);
@@ -138,16 +138,16 @@ struct ExecFixture
void setupQueryEnvironment() {
setQueryTensor("tensorquery",
"tensor(q{})",
- makeTensor<Value>(TensorSpec("tensor(q{})")
- .add({{"q", "d"}}, 11 )
- .add({{"q", "e"}}, 13 )
- .add({{"q", "f"}}, 17 )));
+ SimpleValue::from_spec(TensorSpec("tensor(q{})")
+ .add({{"q", "d"}}, 11 )
+ .add({{"q", "e"}}, 13 )
+ .add({{"q", "f"}}, 17 )));
setQueryTensor("mappedtensorquery",
"tensor(x[2])",
- makeTensor<Value>(TensorSpec("tensor(x{},y{})")
- .add({{"x", "0"},{"y", "0"}}, 11 )
- .add({{"x", "0"},{"y", "1"}}, 13 )
- .add({{"x", "1"},{"y", "0"}}, 17 )));
+ SimpleValue::from_spec(TensorSpec("tensor(x{},y{})")
+ .add({{"x", "0"},{"y", "0"}}, 11 )
+ .add({{"x", "0"},{"y", "1"}}, 13 )
+ .add({{"x", "1"},{"y", "0"}}, 17 )));
setQueryTensorType("null", "tensor(q{})");
}
const Value &extractTensor(uint32_t docid) {
@@ -163,28 +163,28 @@ struct ExecFixture
TEST_F("require that tensor attribute can be extracted as tensor in attribute feature",
ExecFixture("attribute(tensorattr)"))
{
- EXPECT_EQUAL(*makeTensor<Value>(TensorSpec("tensor(x{})")
- .add({{"x", "b"}}, 5)
- .add({{"x", "c"}}, 7)
- .add({{"x", "a"}}, 3)), f.execute());
+ EXPECT_EQUAL(TensorSpec("tensor(x{})")
+ .add({{"x", "b"}}, 5)
+ .add({{"x", "c"}}, 7)
+ .add({{"x", "a"}}, 3), spec_from_value(f.execute()));
}
TEST_F("require that direct tensor attribute can be extracted in attribute feature",
ExecFixture("attribute(directattr)"))
{
- EXPECT_EQUAL(*makeTensor<Value>(TensorSpec("tensor(x{})")
- .add({{"x", "b"}}, 5)
- .add({{"x", "c"}}, 7)
- .add({{"x", "a"}}, 3)), f.execute());
+ EXPECT_EQUAL(TensorSpec("tensor(x{})")
+ .add({{"x", "b"}}, 5)
+ .add({{"x", "c"}}, 7)
+ .add({{"x", "a"}}, 3), spec_from_value(f.execute()));
}
TEST_F("require that tensor from query can be extracted as tensor in query feature",
ExecFixture("query(tensorquery)"))
{
- EXPECT_EQUAL(*makeTensor<Value>(TensorSpec("tensor(q{})")
- .add({{"q", "f"}}, 17)
- .add({{"q", "d"}}, 11)
- .add({{"q", "e"}}, 13)), f.execute());
+ EXPECT_EQUAL(TensorSpec("tensor(q{})")
+ .add({{"q", "f"}}, 17)
+ .add({{"q", "d"}}, 11)
+ .add({{"q", "e"}}, 13), spec_from_value(f.execute()));
}
TEST_F("require that empty tensor is created if attribute does not exists",
@@ -217,9 +217,9 @@ TEST_F("require that empty tensor with correct type is returned by direct tensor
TEST_F("require that wrong tensor type from query tensor gives empty tensor",
ExecFixture("query(mappedtensorquery)")) {
- EXPECT_EQUAL(*makeTensor<Value>(TensorSpec("tensor(x[2])")
- .add({{"x", 0}}, 0)
- .add({{"x", 1}}, 0)), f.execute());
+ EXPECT_EQUAL(TensorSpec("tensor(x[2])")
+ .add({{"x", 0}}, 0)
+ .add({{"x", 1}}, 0), spec_from_value(f.execute()));
}
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp b/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp
index 33fd7c856b3..2e83d2acbf2 100644
--- a/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp
+++ b/searchlib/src/tests/features/tensor_from_labels/tensor_from_labels_test.cpp
@@ -12,8 +12,9 @@
#include <vespa/searchlib/fef/test/indexenvironment.h>
#include <vespa/searchlib/fef/test/indexenvironmentbuilder.h>
#include <vespa/searchlib/fef/test/queryenvironment.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
@@ -27,7 +28,7 @@ using search::StringAttribute;
using vespalib::eval::Value;
using vespalib::eval::Function;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
typedef search::attribute::Config AVC;
typedef search::attribute::BasicType AVBT;
@@ -36,7 +37,7 @@ typedef search::AttributeVector::SP AttributePtr;
typedef FtTestApp FTA;
Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
Value::UP make_empty(const vespalib::string &type) {
diff --git a/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp b/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp
index 282c8134754..c339d8dae63 100644
--- a/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp
+++ b/searchlib/src/tests/features/tensor_from_weighted_set/tensor_from_weighted_set_test.cpp
@@ -12,8 +12,8 @@
#include <vespa/searchlib/fef/test/indexenvironment.h>
#include <vespa/searchlib/fef/test/indexenvironmentbuilder.h>
#include <vespa/searchlib/fef/test/queryenvironment.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/test/value_compare.h>
@@ -28,7 +28,7 @@ using search::StringAttribute;
using vespalib::eval::Value;
using vespalib::eval::Function;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
typedef search::attribute::Config AVC;
typedef search::attribute::BasicType AVBT;
@@ -37,7 +37,7 @@ typedef search::AttributeVector::SP AttributePtr;
typedef FtTestApp FTA;
Value::UP make_tensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
Value::UP make_empty(const vespalib::string &type) {
diff --git a/searchlib/src/tests/memoryindex/url_field_inverter/url_field_inverter_test.cpp b/searchlib/src/tests/memoryindex/url_field_inverter/url_field_inverter_test.cpp
index 86c58c11c09..cc28a8fd479 100644
--- a/searchlib/src/tests/memoryindex/url_field_inverter/url_field_inverter_test.cpp
+++ b/searchlib/src/tests/memoryindex/url_field_inverter/url_field_inverter_test.cpp
@@ -227,6 +227,8 @@ struct UrlFieldInverterTest : public ::testing::Test {
_inverters[urlField._hostname].get());
}
+ ~UrlFieldInverterTest() override;
+
void invertDocument(uint32_t docId, const Document &doc) {
_urlInverter->invertField(docId, doc.getValue(url));
}
@@ -245,6 +247,8 @@ struct UrlFieldInverterTest : public ::testing::Test {
}
};
+UrlFieldInverterTest::~UrlFieldInverterTest() = default;
+
struct SingleInverterTest : public UrlFieldInverterTest {
SingleInverterTest() : UrlFieldInverterTest(CollectionType::SINGLE) {}
};
diff --git a/searchlib/src/tests/query/stackdumpquerycreator_test.cpp b/searchlib/src/tests/query/stackdumpquerycreator_test.cpp
index 7f682b380bf..cb3989387b7 100644
--- a/searchlib/src/tests/query/stackdumpquerycreator_test.cpp
+++ b/searchlib/src/tests/query/stackdumpquerycreator_test.cpp
@@ -32,9 +32,9 @@ void appendString(RawBuf &buf, const string &s) {
}
void appendNumTerm(RawBuf &buf, const string &term_string) {
- uint8_t typefield = ParseItem::ITEM_NUMTERM |
- ParseItem::IF_WEIGHT |
- ParseItem::IF_UNIQUEID;
+ uint8_t typefield = static_cast<uint8_t>(ParseItem::ITEM_NUMTERM) |
+ static_cast<uint8_t>(ParseItem::IF_WEIGHT) |
+ static_cast<uint8_t>(ParseItem::IF_UNIQUEID);
buf.append(typefield);
buf.appendCompressedNumber(2); // weight
buf.appendCompressedPositiveNumber(42); // id
diff --git a/searchlib/src/tests/query/streaming_query_test.cpp b/searchlib/src/tests/query/streaming_query_test.cpp
index 94851c72886..dbd186fdcb5 100644
--- a/searchlib/src/tests/query/streaming_query_test.cpp
+++ b/searchlib/src/tests/query/streaming_query_test.cpp
@@ -226,7 +226,7 @@ public:
virtual bool getRewriteFloatTerms() const override { return true; }
};
-const char TERM_UNIQ = ParseItem::ITEM_TERM | ParseItem::IF_UNIQUEID;
+const char TERM_UNIQ = static_cast<char>(ParseItem::ITEM_TERM) | static_cast<char>(ParseItem::IF_UNIQUEID);
TEST("e is not rewritten even if allowed") {
const char term[6] = {TERM_UNIQ, 3, 1, 'c', 1, 'e'};
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp
index e1d0e034a89..10e03238e81 100644
--- a/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp
@@ -118,8 +118,8 @@ Test::Main()
return -1;
}
_type = _argv[1];
- _strict = _argv[2] == vespalib::string("strict");
- _optimize = _argv[3] == vespalib::string("optimize");
+ _strict = vespalib::string(_argv[2]) == vespalib::string("strict");
+ _optimize = vespalib::string(_argv[3]) == vespalib::string("optimize");
_numSearch = strtoul(_argv[4], NULL, 0);
_numDocs = strtoul(_argv[5], NULL, 0);
for (int i(6); i < _argc; i++) {
diff --git a/searchlib/src/tests/queryeval/nearest_neighbor/nearest_neighbor_test.cpp b/searchlib/src/tests/queryeval/nearest_neighbor/nearest_neighbor_test.cpp
index 23cb3831b6d..ad450a91f33 100644
--- a/searchlib/src/tests/queryeval/nearest_neighbor/nearest_neighbor_test.cpp
+++ b/searchlib/src/tests/queryeval/nearest_neighbor/nearest_neighbor_test.cpp
@@ -3,7 +3,8 @@
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/searchlib/common/bitvector.h>
#include <vespa/searchlib/common/feature.h>
#include <vespa/searchlib/fef/matchdata.h>
@@ -27,7 +28,7 @@ using vespalib::eval::Value;
using vespalib::eval::ValueType;
using vespalib::eval::CellType;
using vespalib::eval::TensorSpec;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using search::tensor::DistanceFunction;
using search::attribute::DistanceMetric;
@@ -41,7 +42,7 @@ DistanceFunction::UP euclid_d = search::tensor::make_distance_function(DistanceM
DistanceFunction::UP euclid_f = search::tensor::make_distance_function(DistanceMetric::Euclidean, CellType::FLOAT);
std::unique_ptr<Value> createTensor(const TensorSpec &spec) {
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
std::unique_ptr<Value> createTensor(const vespalib::string& type_spec, double v1, double v2) {
diff --git a/searchlib/src/tests/queryeval/predicate/predicate_search_test.cpp b/searchlib/src/tests/queryeval/predicate/predicate_search_test.cpp
index efa01b79580..382e2bdb8ff 100644
--- a/searchlib/src/tests/queryeval/predicate/predicate_search_test.cpp
+++ b/searchlib/src/tests/queryeval/predicate/predicate_search_test.cpp
@@ -41,6 +41,8 @@ public:
{
}
+ ~MyPostingList() override;
+
bool next(uint32_t doc_id) override {
if (_index < _entries.size()) {
while (_entries[_index].first <= doc_id) {
@@ -70,6 +72,8 @@ public:
uint32_t getInterval() const override { return _interval; }
};
+MyPostingList::~MyPostingList() = default;
+
template <int N>
vector<PredicatePostingList::UP>
make_posting_lists_vector(MyPostingList (&plists)[N]) {
diff --git a/searchlib/src/tests/tensor/dense_tensor_store/dense_tensor_store_test.cpp b/searchlib/src/tests/tensor/dense_tensor_store/dense_tensor_store_test.cpp
index 4ed366a6cc2..b5d4fb3130f 100644
--- a/searchlib/src/tests/tensor/dense_tensor_store/dense_tensor_store_test.cpp
+++ b/searchlib/src/tests/tensor/dense_tensor_store/dense_tensor_store_test.cpp
@@ -3,27 +3,24 @@
LOG_SETUP("dense_tensor_store_test");
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchlib/tensor/dense_tensor_store.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/test/value_compare.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include <vespa/eval/eval/test/value_compare.h>
using search::tensor::DenseTensorStore;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
-using vespalib::eval::EngineOrFactory;
-using vespalib::tensor::MutableDenseTensorView;
using EntryRef = DenseTensorStore::EntryRef;
Value::UP
makeTensor(const TensorSpec &spec)
{
- return EngineOrFactory::get().from_spec(spec);
+ return SimpleValue::from_spec(spec);
}
struct Fixture
@@ -47,8 +44,8 @@ struct Fixture
assertTensorView(ref, *expTensor);
}
void assertTensorView(EntryRef ref, const Value &expTensor) {
- MutableDenseTensorView actTensor(store.type());
- store.getTensor(ref, actTensor);
+ auto cells = store.get_typed_cells(ref);
+ vespalib::eval::DenseValueView actTensor(store.type(), cells);
EXPECT_EQUAL(expTensor, actTensor);
}
};
diff --git a/searchlib/src/tests/tensor/direct_tensor_store/direct_tensor_store_test.cpp b/searchlib/src/tests/tensor/direct_tensor_store/direct_tensor_store_test.cpp
index a6f4d56425b..f5160e4b879 100644
--- a/searchlib/src/tests/tensor/direct_tensor_store/direct_tensor_store_test.cpp
+++ b/searchlib/src/tests/tensor/direct_tensor_store/direct_tensor_store_test.cpp
@@ -2,14 +2,15 @@
#include <vespa/searchlib/tensor/direct_tensor_store.h>
#include <vespa/vespalib/gtest/gtest.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/datastore/datastore.hpp>
using namespace search::tensor;
using vespalib::datastore::EntryRef;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
@@ -40,7 +41,7 @@ public:
Value::UP
make_tensor(const TensorSpec& spec)
{
- auto value = EngineOrFactory::get().from_spec(spec);
+ auto value = SimpleValue::from_spec(spec);
return std::make_unique<MockBigTensor>(std::move(value));
}
diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
index 95fde42724b..dfcbfbbbe2b 100644
--- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
@@ -8,7 +8,6 @@
#include "attribute_blueprint_params.h"
#include "document_weight_or_filter_search.h"
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/searchlib/common/location.h>
#include <vespa/searchlib/common/locationiterators.h>
#include <vespa/searchlib/common/matching_elements_fields.h>
diff --git a/searchlib/src/vespa/searchlib/attribute/createsinglestd.cpp b/searchlib/src/vespa/searchlib/attribute/createsinglestd.cpp
index 148d18f79ff..ffaec9d0779 100644
--- a/searchlib/src/vespa/searchlib/attribute/createsinglestd.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/createsinglestd.cpp
@@ -7,8 +7,10 @@
#include "singlenumericattribute.hpp"
#include "singlestringattribute.h"
#include "singleboolattribute.h"
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/searchlib/tensor/dense_tensor_attribute.h>
#include <vespa/searchlib/tensor/serialized_tensor_attribute.h>
+#include <vespa/searchlib/tensor/serialized_fast_value_attribute.h>
namespace search {
@@ -46,7 +48,7 @@ AttributeFactory::createSingleStd(stringref name, const Config & info)
if (info.tensorType().is_dense()) {
return std::make_shared<tensor::DenseTensorAttribute>(name, info);
} else {
- return std::make_shared<tensor::SerializedTensorAttribute>(name, info);
+ return std::make_shared<tensor::SerializedFastValueAttribute>(name, info);
}
case BasicType::REFERENCE:
return std::make_shared<attribute::ReferenceAttribute>(name, info);
diff --git a/searchlib/src/vespa/searchlib/attribute/integerbase.cpp b/searchlib/src/vespa/searchlib/attribute/integerbase.cpp
index 084bb85c28c..c288d0507d7 100644
--- a/searchlib/src/vespa/searchlib/attribute/integerbase.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/integerbase.cpp
@@ -3,6 +3,7 @@
#include "integerbase.hpp"
#include "attributevector.hpp"
#include <vespa/document/fieldvalue/fieldvalue.h>
+#include <charconv>
namespace search {
@@ -14,7 +15,7 @@ IntegerAttribute::IntegerAttribute(const vespalib::string & name, const Config &
{
}
-IntegerAttribute::~IntegerAttribute() { }
+IntegerAttribute::~IntegerAttribute() = default;
uint32_t IntegerAttribute::clearDoc(DocId doc)
{
@@ -27,14 +28,23 @@ uint32_t IntegerAttribute::clearDoc(DocId doc)
return removed;
}
+namespace {
+
+// TODO Move to vespalib::to_string and template on value type
+vespalib::string
+to_string(int64_t v) {
+ char tmp[32];
+ auto res = std::to_chars(tmp, tmp + sizeof(tmp) - 1, v, 10);
+ return vespalib::string(tmp, res.ptr - tmp);
+}
+
+}
uint32_t IntegerAttribute::get(DocId doc, WeightedString * s, uint32_t sz) const
{
WeightedInt * v = new WeightedInt[sz];
unsigned num(static_cast<const AttributeVector *>(this)->get(doc, v, sz));
for(unsigned i(0); i < num; i++) {
- char tmp[32];
- snprintf(tmp, sizeof(tmp), "%" PRId64, v[i].getValue());
- s[i] = WeightedString(tmp, v[i].getWeight());
+ s[i] = WeightedString(to_string(v[i].getValue()), v[i].getWeight());
}
delete [] v;
return num;
@@ -49,8 +59,15 @@ uint32_t IntegerAttribute::get(DocId doc, WeightedConstChar * v, uint32_t sz) co
}
const char *
IntegerAttribute::getString(DocId doc, char * s, size_t sz) const {
- largeint_t v = getInt(doc);
- snprintf(s, sz, "%" PRId64, v);
+ if (sz > 1) {
+ largeint_t v = getInt(doc);
+ auto res = std::to_chars(s, s + sz - 1, v, 10);
+ if (res.ec == std::errc()) {
+ res.ptr[0] = 0;
+ } else {
+ s[0] = 0;
+ }
+ }
return s;
}
uint32_t IntegerAttribute::get(DocId doc, vespalib::string * s, uint32_t sz) const
@@ -58,9 +75,7 @@ uint32_t IntegerAttribute::get(DocId doc, vespalib::string * s, uint32_t sz) con
largeint_t * v = new largeint_t[sz];
unsigned num(static_cast<const AttributeVector *>(this)->get(doc, v, sz));
for(unsigned i(0); i < num; i++) {
- char tmp[32];
- snprintf(tmp, sizeof(tmp), "%" PRId64, v[i]);
- s[i] = tmp;
+ s[i] = to_string(v[i]);
}
delete [] v;
return num;
diff --git a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
index bafb859a246..1def5dab060 100644
--- a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
@@ -251,7 +251,7 @@ template <typename B, typename M>
void
MultiValueAttribute<B, M>::clearDocs(DocId lidLow, DocId lidLimit)
{
- _mvMapping.clearDocs(lidLow, lidLimit, [=](uint32_t docId) { this->clearDoc(docId); });
+ _mvMapping.clearDocs(lidLow, lidLimit, [this](uint32_t docId) { this->clearDoc(docId); });
}
diff --git a/searchlib/src/vespa/searchlib/attribute/not_implemented_attribute.h b/searchlib/src/vespa/searchlib/attribute/not_implemented_attribute.h
index a5b570a4864..f311907bd91 100644
--- a/searchlib/src/vespa/searchlib/attribute/not_implemented_attribute.h
+++ b/searchlib/src/vespa/searchlib/attribute/not_implemented_attribute.h
@@ -9,7 +9,7 @@ namespace search {
struct NotImplementedAttribute : AttributeVector {
using AttributeVector::AttributeVector;
- [[noreturn]] virtual void notImplemented() const ;
+ void notImplemented [[noreturn]] () const;
uint32_t getValueCount(DocId) const override;
largeint_t getInt(DocId) const override;
diff --git a/searchlib/src/vespa/searchlib/common/geo_location.h b/searchlib/src/vespa/searchlib/common/geo_location.h
index 261951caf3e..506434e75e0 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location.h
+++ b/searchlib/src/vespa/searchlib/common/geo_location.h
@@ -20,6 +20,7 @@ struct GeoLocation
static constexpr int32_t range_high = std::numeric_limits<int32_t>::max();
static constexpr uint32_t radius_inf = std::numeric_limits<uint32_t>::max();
struct Point {
+ Point(int32_t x_in, int32_t y_in) : x(x_in), y(y_in) {}
const int32_t x;
const int32_t y;
Point() = delete;
@@ -79,7 +80,7 @@ struct GeoLocation
int32_t x = 0;
int32_t y = 0;
vespalib::geo::ZCurve::decode(zcurve_encoded_xy, &x, &y);
- return inside_limit(Point{x, y});
+ return inside_limit(Point(x, y));
}
private:
diff --git a/searchlib/src/vespa/searchlib/engine/search_protocol_metrics.h b/searchlib/src/vespa/searchlib/engine/search_protocol_metrics.h
index 378a045e32b..9dc609091f0 100644
--- a/searchlib/src/vespa/searchlib/engine/search_protocol_metrics.h
+++ b/searchlib/src/vespa/searchlib/engine/search_protocol_metrics.h
@@ -2,7 +2,9 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/countmetric.h>
+#include <vespa/metrics/metricset.h>
#include <mutex>
namespace search::engine {
diff --git a/searchlib/src/vespa/searchlib/expression/resultvector.h b/searchlib/src/vespa/searchlib/expression/resultvector.h
index cf2f0730c37..2c10a26dd9a 100644
--- a/searchlib/src/vespa/searchlib/expression/resultvector.h
+++ b/searchlib/src/vespa/searchlib/expression/resultvector.h
@@ -82,6 +82,7 @@ public:
DECLARE_NBO_SERIALIZE;
using Vector = std::vector<B>;
using BaseType = B;
+ ~ResultNodeVectorT() override;
const Vector & getVector() const { return _result; }
Vector & getVector() { return _result; }
const ResultNode * find(const ResultNode & key) const override;
@@ -109,6 +110,9 @@ private:
};
template <typename B, typename C, typename G>
+ResultNodeVectorT<B, C, G>::~ResultNodeVectorT() = default;
+
+template <typename B, typename C, typename G>
ResultNodeVector & ResultNodeVectorT<B, C, G>::set(size_t index, const ResultNode & node)
{
_result[index].set(node);
diff --git a/searchlib/src/vespa/searchlib/features/CMakeLists.txt b/searchlib/src/vespa/searchlib/features/CMakeLists.txt
index 7bb4849bb87..271aa73ddcb 100644
--- a/searchlib/src/vespa/searchlib/features/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/features/CMakeLists.txt
@@ -35,6 +35,7 @@ vespa_add_library(searchlib_features OBJECT
matchesfeature.cpp
matchfeature.cpp
max_reduce_prod_join_replacer.cpp
+ mutable_dense_value_view.cpp
native_dot_product_feature.cpp
nativeattributematchfeature.cpp
nativefieldmatchfeature.cpp
diff --git a/searchlib/src/vespa/searchlib/features/attributefeature.cpp b/searchlib/src/vespa/searchlib/features/attributefeature.cpp
index eac69f87587..80d9a305ef4 100644
--- a/searchlib/src/vespa/searchlib/features/attributefeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/attributefeature.cpp
@@ -469,7 +469,7 @@ createTensorAttributeExecutor(const IAttributeVector *attribute, const vespalib:
tensorType.to_spec().c_str());
return ConstantTensorExecutor::createEmpty(tensorType, stash);
}
- if (tensorAttribute->supports_extract_dense_view()) {
+ if (tensorAttribute->supports_extract_cells_ref()) {
return stash.create<DenseTensorAttributeExecutor>(*tensorAttribute);
}
if (tensorAttribute->supports_get_tensor_ref()) {
diff --git a/searchlib/src/vespa/searchlib/features/constant_tensor_executor.h b/searchlib/src/vespa/searchlib/features/constant_tensor_executor.h
index 44e530821a2..f95cbfa4726 100644
--- a/searchlib/src/vespa/searchlib/features/constant_tensor_executor.h
+++ b/searchlib/src/vespa/searchlib/features/constant_tensor_executor.h
@@ -6,8 +6,8 @@
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/util/stash.h>
namespace search::features {
@@ -32,9 +32,9 @@ public:
return stash.create<ConstantTensorExecutor>(std::move(tensor));
}
static fef::FeatureExecutor &createEmpty(const vespalib::eval::ValueType &valueType, vespalib::Stash &stash) {
- const auto engine = vespalib::eval::EngineOrFactory::get();
+ const auto &factory = vespalib::eval::FastValueBuilderFactory::get();
auto spec = vespalib::eval::TensorSpec(valueType.to_spec());
- return stash.create<ConstantTensorExecutor>(engine.from_spec(spec));
+ return stash.create<ConstantTensorExecutor>(vespalib::eval::value_from_spec(spec, factory));
}
static fef::FeatureExecutor &createEmpty(vespalib::Stash &stash) {
return createEmpty(vespalib::eval::ValueType::double_type(), stash);
diff --git a/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.cpp b/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.cpp
index 8f7d82adadd..0de375b7acb 100644
--- a/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.cpp
+++ b/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.cpp
@@ -4,7 +4,6 @@
#include <vespa/searchlib/tensor/i_tensor_attribute.h>
using search::tensor::ITensorAttribute;
-using vespalib::tensor::MutableDenseTensorView;
namespace search::features {
@@ -18,7 +17,7 @@ DenseTensorAttributeExecutor(const ITensorAttribute& attribute)
void
DenseTensorAttributeExecutor::execute(uint32_t docId)
{
- _attribute.extract_dense_view(docId, _tensorView);
+ _tensorView.setCells(_attribute.extract_cells_ref(docId));
outputs().set_object(0, _tensorView);
}
diff --git a/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.h b/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.h
index a8a84447c88..fc09d37f35a 100644
--- a/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.h
+++ b/searchlib/src/vespa/searchlib/features/dense_tensor_attribute_executor.h
@@ -4,7 +4,7 @@
#include <vespa/searchlib/fef/featureexecutor.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include "mutable_dense_value_view.h"
namespace search::tensor { class ITensorAttribute; }
namespace search::features {
@@ -17,7 +17,7 @@ class DenseTensorAttributeExecutor : public fef::FeatureExecutor
{
private:
const search::tensor::ITensorAttribute& _attribute;
- vespalib::tensor::MutableDenseTensorView _tensorView;
+ mutable_value::MutableDenseValueView _tensorView;
public:
DenseTensorAttributeExecutor(const search::tensor::ITensorAttribute& attribute);
diff --git a/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp b/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp
index 83beee98634..06f0de631be 100644
--- a/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/dotproductfeature.cpp
@@ -10,7 +10,8 @@
#include <vespa/searchlib/attribute/floatbase.h>
#include <vespa/searchlib/attribute/multinumericattribute.h>
#include <vespa/searchlib/attribute/multienumattribute.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/stash.h>
@@ -19,7 +20,7 @@ LOG_SETUP(".features.dotproduct");
using namespace search::attribute;
using namespace search::fef;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::TypedCells;
using vespalib::hwaccelrated::IAccelrated;
@@ -500,7 +501,7 @@ template <typename T>
ArrayParam<T>::ArrayParam(vespalib::nbostream & stream) {
using vespalib::typify_invoke;
using vespalib::eval::TypifyCellType;
- auto tensor = EngineOrFactory::get().decode(stream);
+ auto tensor = vespalib::eval::decode_value(stream, FastValueBuilderFactory::get());
if (tensor->type().is_dense()) {
TypedCells cells = tensor->cells();
typify_invoke<1,TypifyCellType,CopyCellsToVector<T>>(cells.type, cells, values);
diff --git a/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.cpp b/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.cpp
new file mode 100644
index 00000000000..b0d669e8aaa
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.cpp
@@ -0,0 +1,14 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "mutable_dense_value_view.h"
+
+namespace search::features::mutable_value {
+
+MutableDenseValueView::MutableDenseValueView(const ValueType &type_in)
+ : _type(type_in),
+ _cells()
+{
+ assert(_type.is_dense());
+}
+
+}
diff --git a/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.h b/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.h
new file mode 100644
index 00000000000..d4e813ae927
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/features/mutable_dense_value_view.h
@@ -0,0 +1,33 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/value.h>
+#include <cassert>
+
+namespace search::features::mutable_value {
+
+using namespace vespalib::eval;
+
+/**
+ * A dense tensor with a cells reference that can be modified.
+ */
+class MutableDenseValueView : public Value {
+private:
+ const ValueType _type;
+ TypedCells _cells;
+public:
+ MutableDenseValueView(const ValueType &type_in);
+ void setCells(TypedCells cells_in) {
+ assert(cells_in.type == _type.cell_type());
+ _cells = cells_in;
+ }
+ const ValueType &type() const final override { return _type; }
+ TypedCells cells() const final override { return _cells; }
+ const Index &index() const final override { return TrivialIndex::get(); }
+ vespalib::MemoryUsage get_memory_usage() const final override {
+ return self_memory_usage<MutableDenseValueView>();
+ }
+};
+
+}
diff --git a/searchlib/src/vespa/searchlib/features/onnx_feature.cpp b/searchlib/src/vespa/searchlib/features/onnx_feature.cpp
index f05ee60076f..87e5ef2a5c2 100644
--- a/searchlib/src/vespa/searchlib/features/onnx_feature.cpp
+++ b/searchlib/src/vespa/searchlib/features/onnx_feature.cpp
@@ -4,8 +4,7 @@
#include <vespa/searchlib/fef/properties.h>
#include <vespa/searchlib/fef/onnx_model.h>
#include <vespa/searchlib/fef/featureexecutor.h>
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>
@@ -21,8 +20,7 @@ using search::fef::ParameterList;
using vespalib::Stash;
using vespalib::eval::ValueType;
using vespalib::make_string_short::fmt;
-using vespalib::tensor::MutableDenseTensorView;
-using vespalib::tensor::Onnx;
+using vespalib::eval::Onnx;
namespace search::features {
diff --git a/searchlib/src/vespa/searchlib/features/onnx_feature.h b/searchlib/src/vespa/searchlib/features/onnx_feature.h
index 19c6338d2ee..5a45b26f1f6 100644
--- a/searchlib/src/vespa/searchlib/features/onnx_feature.h
+++ b/searchlib/src/vespa/searchlib/features/onnx_feature.h
@@ -3,7 +3,7 @@
#pragma once
#include <vespa/searchlib/fef/blueprint.h>
-#include <vespa/eval/tensor/dense/onnx_wrapper.h>
+#include <vespa/eval/onnx/onnx_wrapper.h>
namespace search::features {
@@ -12,7 +12,7 @@ namespace search::features {
**/
class OnnxBlueprint : public fef::Blueprint {
private:
- using Onnx = vespalib::tensor::Onnx;
+ using Onnx = vespalib::eval::Onnx;
std::unique_ptr<Onnx> _model;
Onnx::WireInfo _wire_info;
public:
diff --git a/searchlib/src/vespa/searchlib/features/queryfeature.cpp b/searchlib/src/vespa/searchlib/features/queryfeature.cpp
index 9cded69d5de..c6196fcbc7f 100644
--- a/searchlib/src/vespa/searchlib/features/queryfeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/queryfeature.cpp
@@ -12,6 +12,8 @@
#include <vespa/searchlib/fef/feature_type.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/vespalib/locale/c.h>
#include <cerrno>
@@ -119,7 +121,7 @@ createTensorExecutor(const IQueryEnvironment &env,
if (prop.found() && !prop.get().empty()) {
const vespalib::string &value = prop.get();
vespalib::nbostream stream(value.data(), value.size());
- auto tensor = vespalib::eval::EngineOrFactory::get().decode(stream);
+ auto tensor = vespalib::eval::decode_value(stream, vespalib::eval::FastValueBuilderFactory::get());
if (!TensorDataType::isAssignableType(valueType, tensor->type())) {
LOG(warning, "Query feature type is '%s' but other tensor type is '%s'",
valueType.to_spec().c_str(), tensor->type().to_spec().c_str());
diff --git a/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp b/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
index c8cc573c0d2..8cba6013627 100644
--- a/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/rankingexpressionfeature.cpp
@@ -5,9 +5,8 @@
#include <vespa/searchlib/fef/properties.h>
#include <vespa/searchlib/fef/indexproperties.h>
#include <vespa/searchlib/features/rankingexpression/feature_name_extractor.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/eval/eval/param_usage.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/log/log.h>
LOG_SETUP(".features.rankingexpression");
@@ -18,7 +17,7 @@ using vespalib::ConstArrayRef;
using vespalib::eval::CompileCache;
using vespalib::eval::CompiledFunction;
using vespalib::eval::DoubleValue;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::Function;
using vespalib::eval::InterpretedFunction;
using vespalib::eval::LazyParams;
@@ -326,7 +325,7 @@ RankingExpressionBlueprint::setup(const fef::IIndexEnvironment &env,
}
}
} else {
- _interpreted_function.reset(new InterpretedFunction(EngineOrFactory::get(),
+ _interpreted_function.reset(new InterpretedFunction(FastValueBuilderFactory::get(),
*rank_function, node_types));
}
}
diff --git a/searchlib/src/vespa/searchlib/features/tensor_from_attribute_executor.h b/searchlib/src/vespa/searchlib/features/tensor_from_attribute_executor.h
index a6d3de54d00..f4a5b0b8d0a 100644
--- a/searchlib/src/vespa/searchlib/features/tensor_from_attribute_executor.h
+++ b/searchlib/src/vespa/searchlib/features/tensor_from_attribute_executor.h
@@ -3,9 +3,11 @@
#pragma once
#include <vespa/searchcommon/attribute/iattributevector.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/stllike/string.h>
-#include <vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h>
+
+using vespalib::eval::FastValueBuilderFactory;
namespace search::features {
@@ -20,6 +22,7 @@ private:
const search::attribute::IAttributeVector *_attribute;
vespalib::eval::ValueType _type;
WeightedBufferType _attrBuffer;
+ std::vector<vespalib::stringref> _addr_ref;
std::unique_ptr<vespalib::eval::Value> _tensor;
public:
@@ -28,9 +31,11 @@ public:
: _attribute(attribute),
_type(vespalib::eval::ValueType::tensor_type({{dimension}})),
_attrBuffer(),
+ _addr_ref(),
_tensor()
{
_attrBuffer.allocate(_attribute->getMaxValueCount());
+ _addr_ref.reserve(1);
}
void execute(uint32_t docId) override;
};
@@ -40,15 +45,16 @@ void
TensorFromAttributeExecutor<WeightedBufferType>::execute(uint32_t docId)
{
_attrBuffer.fill(*_attribute, docId);
- vespalib::tensor::DirectSparseTensorBuilder<double> builder(_type);
- builder.reserve(_attrBuffer.size());
- vespalib::tensor::SparseTensorAddressBuilder address;
+ auto factory = FastValueBuilderFactory::get();
+ auto builder = factory.create_value_builder<double>(_type, 1, 1, _attrBuffer.size());
for (size_t i = 0; i < _attrBuffer.size(); ++i) {
- address.clear();
- address.add(vespalib::string(_attrBuffer[i].value()));
- builder.insertCell(address, _attrBuffer[i].weight(), [](double, double v){ return v; });
+ vespalib::string label(_attrBuffer[i].value());
+ _addr_ref.clear();
+ _addr_ref.push_back(label);
+ auto cell_array = builder->add_subspace(_addr_ref);
+ cell_array[0] = _attrBuffer[i].weight();
}
- _tensor = builder.build();
+ _tensor = builder->build(std::move(builder));
outputs().set_object(0, *_tensor);
}
diff --git a/searchlib/src/vespa/searchlib/features/tensor_from_labels_feature.cpp b/searchlib/src/vespa/searchlib/features/tensor_from_labels_feature.cpp
index e6c5f22dd16..e4f0a010ae2 100644
--- a/searchlib/src/vespa/searchlib/features/tensor_from_labels_feature.cpp
+++ b/searchlib/src/vespa/searchlib/features/tensor_from_labels_feature.cpp
@@ -8,6 +8,7 @@
#include <vespa/searchlib/fef/feature_type.h>
#include <vespa/searchcommon/attribute/attributecontent.h>
#include <vespa/searchcommon/attribute/iattributevector.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value_type.h>
#include <vespa/log/log.h>
@@ -17,8 +18,7 @@ using namespace search::fef;
using search::attribute::IAttributeVector;
using search::attribute::WeightedConstCharContent;
using search::attribute::WeightedStringContent;
-using vespalib::tensor::DirectSparseTensorBuilder;
-using vespalib::tensor::SparseTensorAddressBuilder;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::ValueType;
using search::fef::FeatureType;
@@ -91,15 +91,16 @@ createQueryExecutor(const search::fef::IQueryEnvironment &env,
if (prop.found() && !prop.get().empty()) {
std::vector<vespalib::string> vector;
ArrayParser::parse(prop.get(), vector);
- DirectSparseTensorBuilder<double> tensorBuilder(type);
- tensorBuilder.reserve(vector.size());
- SparseTensorAddressBuilder address;
+ auto factory = FastValueBuilderFactory::get();
+ auto builder = factory.create_value_builder<double>(type, 1, 1, vector.size());
+ std::vector<vespalib::stringref> addr_ref;
for (const auto &elem : vector) {
- address.clear();
- address.add(elem);
- tensorBuilder.insertCell(address, 1.0, [](double, double v){ return v; });
+ addr_ref.clear();
+ addr_ref.push_back(elem);
+ auto cell_array = builder->add_subspace(addr_ref);
+ cell_array[0] = 1.0;
}
- return ConstantTensorExecutor::create(tensorBuilder.build(), stash);
+ return ConstantTensorExecutor::create(builder->build(std::move(builder)), stash);
}
return ConstantTensorExecutor::createEmpty(type, stash);
}
diff --git a/searchlib/src/vespa/searchlib/features/tensor_from_weighted_set_feature.cpp b/searchlib/src/vespa/searchlib/features/tensor_from_weighted_set_feature.cpp
index 8c290e1f2b0..88309120882 100644
--- a/searchlib/src/vespa/searchlib/features/tensor_from_weighted_set_feature.cpp
+++ b/searchlib/src/vespa/searchlib/features/tensor_from_weighted_set_feature.cpp
@@ -1,19 +1,16 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "tensor_from_weighted_set_feature.h"
-
#include "constant_tensor_executor.h"
#include "utils.h"
#include "tensor_from_attribute_executor.h"
#include "weighted_set_parser.hpp"
-
#include <vespa/searchlib/fef/properties.h>
#include <vespa/searchlib/fef/feature_type.h>
#include <vespa/searchcommon/attribute/attributecontent.h>
#include <vespa/searchcommon/attribute/iattributevector.h>
-#include <vespa/eval/eval/function.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value_type.h>
-#include <vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h>
#include <vespa/log/log.h>
LOG_SETUP(".features.tensor_from_weighted_set_feature");
@@ -22,8 +19,7 @@ using namespace search::fef;
using search::attribute::IAttributeVector;
using search::attribute::WeightedConstCharContent;
using search::attribute::WeightedStringContent;
-using vespalib::tensor::DirectSparseTensorBuilder;
-using vespalib::tensor::SparseTensorAddressBuilder;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::ValueType;
using search::fef::FeatureType;
@@ -106,15 +102,17 @@ createQueryExecutor(const search::fef::IQueryEnvironment &env,
if (prop.found() && !prop.get().empty()) {
WeightedStringVector vector;
WeightedSetParser::parse(prop.get(), vector);
- DirectSparseTensorBuilder<double> tensorBuilder(type);
- tensorBuilder.reserve(vector._data.size());
- SparseTensorAddressBuilder address;
+ auto factory = FastValueBuilderFactory::get();
+ size_t sz = vector._data.size();
+ auto builder = factory.create_value_builder<double>(type, 1, 1, sz);
+ std::vector<vespalib::stringref> addr_ref;
for (const auto &elem : vector._data) {
- address.clear();
- address.add(elem.value());
- tensorBuilder.insertCell(address, elem.weight(), [](double, double v){ return v; });
+ addr_ref.clear();
+ addr_ref.push_back(elem.value());
+ auto cell_array = builder->add_subspace(addr_ref);
+ cell_array[0] = elem.weight();
}
- return ConstantTensorExecutor::create(tensorBuilder.build(), stash);
+ return ConstantTensorExecutor::create(builder->build(std::move(builder)), stash);
}
return ConstantTensorExecutor::createEmpty(type, stash);
}
diff --git a/searchlib/src/vespa/searchlib/features/termdistancefeature.cpp b/searchlib/src/vespa/searchlib/features/termdistancefeature.cpp
index e9f48421fcf..5a60f2e617f 100644
--- a/searchlib/src/vespa/searchlib/features/termdistancefeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/termdistancefeature.cpp
@@ -13,7 +13,7 @@ namespace search::features {
TermDistanceExecutor::TermDistanceExecutor(const IQueryEnvironment & env,
- [[maybe_unused]] const TermDistanceParams & params) :
+ const TermDistanceParams & params) :
FeatureExecutor(),
_termA(env.getTerm(params.termX)),
_termB(env.getTerm(params.termY)),
diff --git a/searchlib/src/vespa/searchlib/grouping/sketch.h b/searchlib/src/vespa/searchlib/grouping/sketch.h
index c105b480a3d..a872e82bedb 100644
--- a/searchlib/src/vespa/searchlib/grouping/sketch.h
+++ b/searchlib/src/vespa/searchlib/grouping/sketch.h
@@ -100,6 +100,9 @@ struct SparseSketch : Sketch<BucketBits, HashT> {
}
return true;
}
+ bool operator==(const SparseSketch<BucketBits, HashT>& other) const {
+ return operator==(static_cast<const SketchType&>(other));
+ }
void print(std::ostream &out) const override {
out << " (" << hash_set.size() << " elements)";
@@ -161,6 +164,9 @@ struct NormalSketch : Sketch<BucketBits, HashT> {
}
return true;
}
+ bool operator==(const NormalSketch<BucketBits, HashT>& other) const {
+ return operator==(static_cast<const SketchType&>(other));
+ }
virtual void print(std::ostream &out) const override {
for (size_t i = 0; i < BUCKET_COUNT; ++i) {
diff --git a/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp b/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp
index 82302e4ab48..9af1ecee224 100644
--- a/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp
+++ b/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp
@@ -146,7 +146,7 @@ class QueryNodeConverter : public QueryVisitor {
}
void visit(Phrase &node) override {
- createComplexIntermediate(node, node.getChildren(), (ParseItem::ITEM_PHRASE | ParseItem::IF_WEIGHT));
+ createComplexIntermediate(node, node.getChildren(), (static_cast<uint8_t>(ParseItem::ITEM_PHRASE) | static_cast<uint8_t>(ParseItem::IF_WEIGHT)));
}
template <typename NODE>
@@ -173,17 +173,17 @@ class QueryNodeConverter : public QueryVisitor {
}
void visit(WeightedSetTerm &node) override {
- createWeightedSet(node, ParseItem::ITEM_WEIGHTED_SET | ParseItem::IF_WEIGHT);
+ createWeightedSet(node, static_cast<uint8_t>(ParseItem::ITEM_WEIGHTED_SET) | static_cast<uint8_t>(ParseItem::IF_WEIGHT));
visitNodes(node.getChildren());
}
void visit(DotProduct &node) override {
- createWeightedSet(node, ParseItem::ITEM_DOT_PRODUCT | ParseItem::IF_WEIGHT);
+ createWeightedSet(node, static_cast<uint8_t>(ParseItem::ITEM_DOT_PRODUCT) | static_cast<uint8_t>(ParseItem::IF_WEIGHT));
visitNodes(node.getChildren());
}
void visit(WandTerm &node) override {
- createWeightedSet(node, ParseItem::ITEM_WAND | ParseItem::IF_WEIGHT);
+ createWeightedSet(node, static_cast<uint8_t>(ParseItem::ITEM_WAND) | static_cast<uint8_t>(ParseItem::IF_WEIGHT));
appendCompressedPositiveNumber(node.getTargetNumHits());
appendDouble(node.getScoreThreshold());
appendDouble(node.getThresholdBoostFactor());
diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h
index c3f9685e47c..72520830d06 100644
--- a/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h
+++ b/searchlib/src/vespa/searchlib/queryeval/fake_requestcontext.h
@@ -4,8 +4,8 @@
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/attribute/iattributecontext.h>
#include <vespa/searchlib/attribute/attributevector.h>
#include <vespa/searchlib/attribute/attribute_blueprint_params.h>
@@ -35,7 +35,7 @@ public:
}
vespalib::eval::Value::UP get_query_tensor(const vespalib::string& tensor_name) const override {
if (_query_tensor && (tensor_name == _query_tensor_name)) {
- return vespalib::eval::EngineOrFactory::get().from_spec(*_query_tensor);
+ return vespalib::eval::value_from_spec(*_query_tensor, vespalib::eval::FastValueBuilderFactory::get());
}
return {};
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/iterators.cpp b/searchlib/src/vespa/searchlib/queryeval/iterators.cpp
index 32f6122558e..f9db8aea4f4 100644
--- a/searchlib/src/vespa/searchlib/queryeval/iterators.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/iterators.cpp
@@ -11,4 +11,6 @@ RankedSearchIteratorBase(const fef::TermFieldMatchDataArray &matchData)
_needUnpack(1)
{ }
+RankedSearchIteratorBase::~RankedSearchIteratorBase() = default;
+
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/iterators.h b/searchlib/src/vespa/searchlib/queryeval/iterators.h
index 0e44a6f6ff6..7adfe4aeba6 100644
--- a/searchlib/src/vespa/searchlib/queryeval/iterators.h
+++ b/searchlib/src/vespa/searchlib/queryeval/iterators.h
@@ -22,6 +22,7 @@ protected:
void incNeedUnpack() { ++_needUnpack; }
public:
RankedSearchIteratorBase(const fef::TermFieldMatchDataArray &matchData);
+ ~RankedSearchIteratorBase() override;
bool getUnpacked() const { return _needUnpack == 0; }
};
diff --git a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp
index d75cda2e513..d3ecffd1605 100644
--- a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp
@@ -4,16 +4,16 @@
#include "nearest_neighbor_blueprint.h"
#include "nearest_neighbor_iterator.h"
#include "nns_index_iterator.h"
+#include <vespa/eval/eval/dense_cells_value.h>
#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
#include <vespa/searchlib/tensor/dense_tensor_attribute.h>
#include <vespa/searchlib/tensor/distance_function_factory.h>
#include <vespa/log/log.h>
LOG_SETUP(".searchlib.queryeval.nearest_neighbor_blueprint");
+using vespalib::eval::DenseCellsValue;
using vespalib::eval::Value;
-using vespalib::tensor::DenseTensor;
namespace search::queryeval {
@@ -21,7 +21,7 @@ namespace {
template<typename LCT, typename RCT>
void
-convert_cells(std::unique_ptr<Value> &original, vespalib::eval::ValueType want_type)
+convert_cells(std::unique_ptr<Value> &original, const vespalib::eval::ValueType &want_type)
{
auto old_cells = original->cells().typify<LCT>();
std::vector<RCT> new_cells;
@@ -30,16 +30,16 @@ convert_cells(std::unique_ptr<Value> &original, vespalib::eval::ValueType want_t
RCT conv = value;
new_cells.push_back(conv);
}
- original = std::make_unique<DenseTensor<RCT>>(want_type, std::move(new_cells));
+ original = std::make_unique<DenseCellsValue<RCT>>(want_type, std::move(new_cells));
}
template<>
void
-convert_cells<float,float>(std::unique_ptr<Value> &, vespalib::eval::ValueType) {}
+convert_cells<float,float>(std::unique_ptr<Value> &, const vespalib::eval::ValueType &) {}
template<>
void
-convert_cells<double,double>(std::unique_ptr<Value> &, vespalib::eval::ValueType) {}
+convert_cells<double,double>(std::unique_ptr<Value> &, const vespalib::eval::ValueType &) {}
struct ConvertCellsSelector
{
diff --git a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.cpp b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.cpp
index 85b7e8f89e8..52814bb2631 100644
--- a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.cpp
@@ -5,7 +5,6 @@
using search::tensor::DenseTensorAttribute;
using vespalib::ConstArrayRef;
-using vespalib::tensor::MutableDenseTensorView;
using vespalib::eval::TypedCells;
using vespalib::eval::CellType;
@@ -36,10 +35,10 @@ public:
NearestNeighborImpl(Params params_in)
: NearestNeighborIterator(params_in),
_lhs(params().queryTensor.cells()),
- _fieldTensor(params().tensorAttribute.getTensorType()),
_lastScore(0.0)
{
- assert(is_compatible(_fieldTensor.fast_type(), params().queryTensor.type()));
+ assert(is_compatible(params().tensorAttribute.getTensorType(),
+ params().queryTensor.type()));
}
~NearestNeighborImpl();
@@ -74,13 +73,11 @@ public:
private:
double computeDistance(uint32_t docId, double limit) {
- params().tensorAttribute.extract_dense_view(docId, _fieldTensor);
- auto rhs = _fieldTensor.cells();
+ auto rhs = params().tensorAttribute.extract_cells_ref(docId);
return params().distanceFunction->calc_with_limit(_lhs, rhs, limit);
}
TypedCells _lhs;
- MutableDenseTensorView _fieldTensor;
double _lastScore;
};
diff --git a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.h b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.h
index 9b8ad6295b3..eec45ea1af0 100644
--- a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.h
+++ b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_iterator.h
@@ -5,7 +5,6 @@
#include "searchiterator.h"
#include "nearest_neighbor_distance_heap.h"
#include <vespa/eval/eval/value.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
#include <vespa/searchlib/fef/termfieldmatchdata.h>
#include <vespa/searchlib/tensor/dense_tensor_attribute.h>
#include <vespa/searchlib/tensor/distance_function.h>
diff --git a/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt b/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt
index fac6d015a5f..79b18a57a34 100644
--- a/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt
@@ -25,5 +25,8 @@ vespa_add_library(searchlib_tensor OBJECT
tensor_attribute.cpp
tensor_deserialize.cpp
tensor_store.cpp
+ serialized_fast_value_attribute.cpp
+ streamed_value_saver.cpp
+ streamed_value_store.cpp
DEPENDS
)
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
index 8b27dcc1cd4..be127a8be3e 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
@@ -5,8 +5,7 @@
#include "nearest_neighbor_index.h"
#include "nearest_neighbor_index_saver.h"
#include "tensor_attribute.hpp"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include <vespa/eval/eval/value.h>
#include <vespa/fastlib/io/bufferedfile.h>
#include <vespa/searchlib/attribute/load_utils.h>
#include <vespa/searchlib/attribute/readerbase.h>
@@ -19,7 +18,6 @@ using search::attribute::LoadUtils;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
using vespalib::slime::ObjectInserter;
-using vespalib::tensor::MutableDenseTensorView;
namespace search::tensor {
@@ -173,14 +171,14 @@ DenseTensorAttribute::getTensor(DocId docId) const
return _denseTensorStore.getTensor(ref);
}
-void
-DenseTensorAttribute::extract_dense_view(DocId docId, MutableDenseTensorView &tensor) const
+vespalib::eval::TypedCells
+DenseTensorAttribute::extract_cells_ref(DocId docId) const
{
EntryRef ref;
if (docId < getCommittedDocIdLimit()) {
ref = _refVector[docId];
}
- _denseTensorStore.getTensor(ref, tensor);
+ return _denseTensorStore.get_typed_cells(ref);
}
bool
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.h b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.h
index e06bbf331ac..55e7b8cb464 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.h
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.h
@@ -8,8 +8,6 @@
#include "tensor_attribute.h"
#include <memory>
-namespace vespalib::tensor { class MutableDenseTensorView; }
-
namespace search::tensor {
class NearestNeighborIndex;
@@ -37,8 +35,8 @@ public:
std::unique_ptr<PrepareResult> prepare_set_tensor(DocId docid, const vespalib::eval::Value& tensor) const override;
void complete_set_tensor(DocId docid, const vespalib::eval::Value& tensor, std::unique_ptr<PrepareResult> prepare_result) override;
std::unique_ptr<vespalib::eval::Value> getTensor(DocId docId) const override;
- void extract_dense_view(DocId docId, vespalib::tensor::MutableDenseTensorView &tensor) const override;
- bool supports_extract_dense_view() const override { return true; }
+ vespalib::eval::TypedCells extract_cells_ref(DocId docId) const override;
+ bool supports_extract_cells_ref() const override { return true; }
bool onLoad() override;
std::unique_ptr<AttributeSaver> onInitSave(vespalib::stringref fileName) override;
void compactWorst() override;
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
index ddbb956838b..bc8362c2643 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
@@ -1,12 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "dense_tensor_store.h"
-#include <vespa/eval/tensor/dense/dense_tensor_view.h>
-#include <vespa/eval/tensor/dense/mutable_dense_tensor_view.h>
+#include <vespa/eval/eval/value.h>
#include <vespa/vespalib/datastore/datastore.hpp>
using vespalib::datastore::Handle;
-using vespalib::tensor::MutableDenseTensorView;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
using CellType = vespalib::eval::CellType;
@@ -134,19 +132,7 @@ DenseTensorStore::getTensor(EntryRef ref) const
return {};
}
vespalib::eval::TypedCells cells_ref(getRawBuffer(ref), _type.cell_type(), getNumCells());
- return std::make_unique<vespalib::tensor::DenseTensorView>(_type, cells_ref);
-}
-
-void
-DenseTensorStore::getTensor(EntryRef ref, MutableDenseTensorView &tensor) const
-{
- if (!ref.valid()) {
- vespalib::eval::TypedCells cells_ref(&_emptySpace[0], _type.cell_type(), getNumCells());
- tensor.setCells(cells_ref);
- } else {
- vespalib::eval::TypedCells cells_ref(getRawBuffer(ref), _type.cell_type(), getNumCells());
- tensor.setCells(cells_ref);
- }
+ return std::make_unique<vespalib::eval::DenseValueView>(_type, cells_ref);
}
vespalib::eval::TypedCells
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
index 696a325f813..49e8a585fec 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
@@ -6,7 +6,6 @@
#include <vespa/eval/eval/value_type.h>
#include <vespa/eval/eval/typed_cells.h>
-namespace vespalib { namespace tensor { class MutableDenseTensorView; }}
namespace vespalib::eval { struct Value; }
namespace search::tensor {
@@ -66,7 +65,6 @@ public:
void holdTensor(EntryRef ref) override;
EntryRef move(EntryRef ref) override;
std::unique_ptr<vespalib::eval::Value> getTensor(EntryRef ref) const;
- void getTensor(EntryRef ref, vespalib::tensor::MutableDenseTensorView &tensor) const;
vespalib::eval::TypedCells get_typed_cells(EntryRef ref) const;
EntryRef setTensor(const vespalib::eval::Value &tensor);
// The following method is meant to be used only for unit tests.
diff --git a/searchlib/src/vespa/searchlib/tensor/direct_tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/direct_tensor_attribute.cpp
index 62beb25be22..8cda62682d0 100644
--- a/searchlib/src/vespa/searchlib/tensor/direct_tensor_attribute.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/direct_tensor_attribute.cpp
@@ -3,7 +3,7 @@
#include "direct_tensor_attribute.h"
#include "direct_tensor_saver.h"
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/value.h>
#include <vespa/fastlib/io/bufferedfile.h>
#include <vespa/searchlib/attribute/readerbase.h>
@@ -14,7 +14,7 @@
#include "tensor_deserialize.h"
#include "tensor_attribute.hpp"
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
namespace search::tensor {
@@ -73,7 +73,7 @@ DirectTensorAttribute::set_tensor(DocId lid, std::unique_ptr<vespalib::eval::Val
void
DirectTensorAttribute::setTensor(DocId lid, const vespalib::eval::Value &tensor)
{
- set_tensor(lid, EngineOrFactory::get().copy(tensor));
+ set_tensor(lid, FastValueBuilderFactory::get().copy(tensor));
}
std::unique_ptr<vespalib::eval::Value>
@@ -86,7 +86,7 @@ DirectTensorAttribute::getTensor(DocId docId) const
if (ref.valid()) {
auto ptr = _direct_store.get_tensor(ref);
if (ptr) {
- return EngineOrFactory::get().copy(*ptr);
+ return FastValueBuilderFactory::get().copy(*ptr);
}
}
std::unique_ptr<vespalib::eval::Value> empty;
diff --git a/searchlib/src/vespa/searchlib/tensor/direct_tensor_saver.cpp b/searchlib/src/vespa/searchlib/tensor/direct_tensor_saver.cpp
index e67d5d8202b..b4b41187c8f 100644
--- a/searchlib/src/vespa/searchlib/tensor/direct_tensor_saver.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/direct_tensor_saver.cpp
@@ -3,8 +3,7 @@
#include "direct_tensor_saver.h"
#include "direct_tensor_store.h"
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/serialization/typed_binary_format.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchlib/attribute/iattributesavetarget.h>
#include <vespa/searchlib/util/bufferwriter.h>
#include <vespa/vespalib/objects/nbostream.h>
@@ -39,7 +38,7 @@ DirectTensorAttributeSaver::onSave(IAttributeSaveTarget &saveTarget)
const vespalib::eval::Value *tensor = _tensorStore.get_tensor(_refs[lid]);
if (tensor) {
stream.clear();
- vespalib::eval::EngineOrFactory::get().encode(*tensor, stream);
+ encode_value(*tensor, stream);
uint32_t sz = stream.size();
datWriter->write(&sz, sizeof(sz));
datWriter->write(stream.peek(), stream.size());
diff --git a/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h b/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h
index c962e919d95..360250c869e 100644
--- a/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h
+++ b/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h
@@ -3,10 +3,8 @@
#pragma once
#include <memory>
+#include <vespa/eval/eval/typed_cells.h>
-namespace vespalib::tensor {
-class MutableDenseTensorView;
-}
namespace vespalib::eval { class ValueType; struct Value; }
namespace vespalib::slime { struct Inserter; }
@@ -21,9 +19,9 @@ public:
virtual ~ITensorAttribute() {}
virtual std::unique_ptr<vespalib::eval::Value> getTensor(uint32_t docId) const = 0;
virtual std::unique_ptr<vespalib::eval::Value> getEmptyTensor() const = 0;
- virtual void extract_dense_view(uint32_t docid, vespalib::tensor::MutableDenseTensorView& tensor) const = 0;
+ virtual vespalib::eval::TypedCells extract_cells_ref(uint32_t docid) const = 0;
virtual const vespalib::eval::Value& get_tensor_ref(uint32_t docid) const = 0;
- virtual bool supports_extract_dense_view() const = 0;
+ virtual bool supports_extract_cells_ref() const = 0;
virtual bool supports_get_tensor_ref() const = 0;
virtual const vespalib::eval::ValueType & getTensorType() const = 0;
diff --git a/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.cpp b/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.cpp
index 6a0dbfb9f48..79c8e5a663e 100644
--- a/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.cpp
@@ -48,10 +48,10 @@ ImportedTensorAttributeVectorReadGuard::getEmptyTensor() const
return _target_tensor_attribute.getEmptyTensor();
}
-void
-ImportedTensorAttributeVectorReadGuard::extract_dense_view(uint32_t docid, vespalib::tensor::MutableDenseTensorView& tensor) const
+vespalib::eval::TypedCells
+ImportedTensorAttributeVectorReadGuard::extract_cells_ref(uint32_t docid) const
{
- _target_tensor_attribute.extract_dense_view(getTargetLid(docid), tensor);
+ return _target_tensor_attribute.extract_cells_ref(getTargetLid(docid));
}
const vespalib::eval::Value&
diff --git a/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.h b/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.h
index a3ffc27b153..c55a922487f 100644
--- a/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.h
+++ b/searchlib/src/vespa/searchlib/tensor/imported_tensor_attribute_vector_read_guard.h
@@ -32,9 +32,9 @@ public:
std::unique_ptr<vespalib::eval::Value> getTensor(uint32_t docId) const override;
std::unique_ptr<vespalib::eval::Value> getEmptyTensor() const override;
- void extract_dense_view(uint32_t docid, vespalib::tensor::MutableDenseTensorView& tensor) const override;
+ vespalib::eval::TypedCells extract_cells_ref(uint32_t docid) const override;
const vespalib::eval::Value& get_tensor_ref(uint32_t docid) const override;
- bool supports_extract_dense_view() const override { return _target_tensor_attribute.supports_extract_dense_view(); }
+ bool supports_extract_cells_ref() const override { return _target_tensor_attribute.supports_extract_cells_ref(); }
bool supports_get_tensor_ref() const override { return _target_tensor_attribute.supports_get_tensor_ref(); }
const vespalib::eval::ValueType &getTensorType() const override;
void get_state(const vespalib::slime::Inserter& inserter) const override;
diff --git a/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.cpp
new file mode 100644
index 00000000000..6e1fb1a0a2f
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.cpp
@@ -0,0 +1,234 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "serialized_fast_value_attribute.h"
+#include "streamed_value_saver.h"
+#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/fast_value.hpp>
+#include <vespa/eval/streamed/streamed_value_utils.h>
+#include <vespa/fastlib/io/bufferedfile.h>
+#include <vespa/searchlib/attribute/readerbase.h>
+#include <vespa/searchlib/util/fileutil.h>
+#include <vespa/vespalib/util/rcuvector.hpp>
+#include <vespa/log/log.h>
+
+LOG_SETUP(".searchlib.tensor.serialized_fast_value_attribute");
+
+#include "blob_sequence_reader.h"
+#include "tensor_attribute.hpp"
+
+using namespace vespalib;
+using namespace vespalib::eval;
+
+namespace search::tensor {
+
+namespace {
+
+struct ValueBlock : LabelBlock {
+ TypedCells cells;
+};
+
+class ValueBlockStream {
+private:
+ const StreamedValueStore::DataFromType &_from_type;
+ LabelBlockStream _label_block_stream;
+ const char *_cells_ptr;
+
+ size_t dsss() const { return _from_type.dense_subspace_size; }
+ auto cell_type() const { return _from_type.cell_type; }
+public:
+ ValueBlock next_block() {
+ auto labels = _label_block_stream.next_block();
+ if (labels) {
+ TypedCells subspace_cells(_cells_ptr, cell_type(), dsss());
+ _cells_ptr += CellTypeUtils::mem_size(cell_type(), dsss());
+ return ValueBlock{labels, subspace_cells};
+ } else {
+ TypedCells none(nullptr, cell_type(), 0);
+ return ValueBlock{labels, none};
+ }
+ }
+
+ ValueBlockStream(const StreamedValueStore::DataFromType &from_type,
+ const StreamedValueStore::StreamedValueData &from_store)
+ : _from_type(from_type),
+ _label_block_stream(from_store.num_subspaces,
+ from_store.labels_buffer,
+ from_type.num_mapped_dimensions),
+ _cells_ptr((const char *)from_store.cells_ref.data)
+ {
+ _label_block_stream.reset();
+ }
+
+ ~ValueBlockStream();
+};
+
+ValueBlockStream::~ValueBlockStream() = default;
+
+void report_problematic_subspace(size_t idx,
+ const StreamedValueStore::DataFromType &from_type,
+ const StreamedValueStore::StreamedValueData &from_store)
+{
+ LOG(error, "PROBLEM: add_mapping returned same index=%zu twice", idx);
+ FastValueIndex temp_index(from_type.num_mapped_dimensions,
+ from_store.num_subspaces);
+ auto from_start = ValueBlockStream(from_type, from_store);
+ while (auto redo_block = from_start.next_block()) {
+ if (idx == temp_index.map.add_mapping(redo_block.address)) {
+ vespalib::string msg = "Block with address[ ";
+ for (vespalib::stringref ref : redo_block.address) {
+ msg.append("'").append(ref).append("' ");
+ }
+ msg.append("]");
+ LOG(error, "%s maps to subspace %zu", msg.c_str(), idx);
+ }
+ }
+}
+
+/**
+ * This Value implementation is almost exactly like FastValue, but
+ * instead of owning its type and cells it just has a reference to
+ * data stored elsewhere.
+ * XXX: we should find a better name for this, and move it
+ * (together with the helper classes above) to its own file,
+ * and add associated unit tests.
+ **/
+class OnlyFastValueIndex : public Value {
+private:
+ const ValueType &_type;
+ TypedCells _cells;
+ FastValueIndex my_index;
+public:
+ OnlyFastValueIndex(const ValueType &type,
+ const StreamedValueStore::DataFromType &from_type,
+ const StreamedValueStore::StreamedValueData &from_store)
+ : _type(type),
+ _cells(from_store.cells_ref),
+ my_index(from_type.num_mapped_dimensions,
+ from_store.num_subspaces)
+ {
+ assert(_type.cell_type() == _cells.type);
+ std::vector<vespalib::stringref> address(from_type.num_mapped_dimensions);
+ auto block_stream = ValueBlockStream(from_type, from_store);
+ size_t ss = 0;
+ while (auto block = block_stream.next_block()) {
+ size_t idx = my_index.map.add_mapping(block.address);
+ if (idx != ss) {
+ report_problematic_subspace(idx, from_type, from_store);
+ }
+ ++ss;
+ }
+ assert(ss == from_store.num_subspaces);
+ }
+
+
+ ~OnlyFastValueIndex();
+
+ const ValueType &type() const final override { return _type; }
+ TypedCells cells() const final override { return _cells; }
+ const Index &index() const final override { return my_index; }
+ vespalib::MemoryUsage get_memory_usage() const final override {
+ auto usage = self_memory_usage<OnlyFastValueIndex>();
+ usage.merge(my_index.map.estimate_extra_memory_usage());
+ return usage;
+ }
+};
+
+OnlyFastValueIndex::~OnlyFastValueIndex() = default;
+
+}
+
+SerializedFastValueAttribute::SerializedFastValueAttribute(stringref name, const Config &cfg)
+ : TensorAttribute(name, cfg, _streamedValueStore),
+ _tensor_type(cfg.tensorType()),
+ _streamedValueStore(_tensor_type),
+ _data_from_type(_tensor_type)
+{
+}
+
+
+SerializedFastValueAttribute::~SerializedFastValueAttribute()
+{
+ getGenerationHolder().clearHoldLists();
+ _tensorStore.clearHoldLists();
+}
+
+void
+SerializedFastValueAttribute::setTensor(DocId docId, const vespalib::eval::Value &tensor)
+{
+ checkTensorType(tensor);
+ EntryRef ref = _streamedValueStore.store_tensor(tensor);
+ assert(ref.valid());
+ setTensorRef(docId, ref);
+}
+
+std::unique_ptr<Value>
+SerializedFastValueAttribute::getTensor(DocId docId) const
+{
+ EntryRef ref;
+ if (docId < getCommittedDocIdLimit()) {
+ ref = _refVector[docId];
+ }
+ if (!ref.valid()) {
+ return {};
+ }
+ if (auto data_from_store = _streamedValueStore.get_tensor_data(ref)) {
+ return std::make_unique<OnlyFastValueIndex>(_tensor_type,
+ _data_from_type,
+ data_from_store);
+ }
+ return {};
+}
+
+bool
+SerializedFastValueAttribute::onLoad()
+{
+ BlobSequenceReader tensorReader(*this);
+ if (!tensorReader.hasData()) {
+ return false;
+ }
+ setCreateSerialNum(tensorReader.getCreateSerialNum());
+ assert(tensorReader.getVersion() == getVersion());
+ uint32_t numDocs(tensorReader.getDocIdLimit());
+ _refVector.reset();
+ _refVector.unsafe_reserve(numDocs);
+ vespalib::Array<char> buffer(1024);
+ for (uint32_t lid = 0; lid < numDocs; ++lid) {
+ uint32_t tensorSize = tensorReader.getNextSize();
+ if (tensorSize != 0) {
+ if (tensorSize > buffer.size()) {
+ buffer.resize(tensorSize + 1024);
+ }
+ tensorReader.readBlob(&buffer[0], tensorSize);
+ vespalib::nbostream source(&buffer[0], tensorSize);
+ EntryRef ref = _streamedValueStore.store_encoded_tensor(source);
+ _refVector.push_back(ref);
+ } else {
+ EntryRef invalid;
+ _refVector.push_back(invalid);
+ }
+ }
+ setNumDocs(numDocs);
+ setCommittedDocIdLimit(numDocs);
+ return true;
+}
+
+
+std::unique_ptr<AttributeSaver>
+SerializedFastValueAttribute::onInitSave(vespalib::stringref fileName)
+{
+ vespalib::GenerationHandler::Guard guard(getGenerationHandler().
+ takeGuard());
+ return std::make_unique<StreamedValueSaver>
+ (std::move(guard),
+ this->createAttributeHeader(fileName),
+ getRefCopy(),
+ _streamedValueStore);
+}
+
+void
+SerializedFastValueAttribute::compactWorst()
+{
+ doCompactWorst<StreamedValueStore::RefType>();
+}
+
+}
diff --git a/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.h b/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.h
new file mode 100644
index 00000000000..a8c1df4913a
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/serialized_fast_value_attribute.h
@@ -0,0 +1,33 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "tensor_attribute.h"
+#include "streamed_value_store.h"
+
+namespace search::tensor {
+
+/**
+ * Attribute vector class storing serialized tensors for all documents in memory.
+ *
+ * When fetching a tensor with getTensor(docId) the returned Value
+ * will have a FastValueIndex (constructed on the fly) for its sparse
+ * mapping, but refer to a common type, while cells() will refer to
+ * memory in the serialized store without copying.
+ *
+ */
+class SerializedFastValueAttribute : public TensorAttribute {
+ vespalib::eval::ValueType _tensor_type;
+ StreamedValueStore _streamedValueStore; // data store for serialized tensors
+ const StreamedValueStore::DataFromType _data_from_type;
+public:
+ SerializedFastValueAttribute(vespalib::stringref baseFileName, const Config &cfg);
+ virtual ~SerializedFastValueAttribute();
+ virtual void setTensor(DocId docId, const vespalib::eval::Value &tensor) override;
+ virtual std::unique_ptr<vespalib::eval::Value> getTensor(DocId docId) const override;
+ virtual bool onLoad() override;
+ virtual std::unique_ptr<AttributeSaver> onInitSave(vespalib::stringref fileName) override;
+ virtual void compactWorst() override;
+};
+
+}
diff --git a/searchlib/src/vespa/searchlib/tensor/serialized_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/serialized_tensor_store.cpp
index 2b3514fa352..7045c82935c 100644
--- a/searchlib/src/vespa/searchlib/tensor/serialized_tensor_store.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/serialized_tensor_store.cpp
@@ -2,8 +2,8 @@
#include "serialized_tensor_store.h"
#include "tensor_deserialize.h"
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/datastore/datastore.hpp>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -99,7 +99,7 @@ TensorStore::EntryRef
SerializedTensorStore::setTensor(const vespalib::eval::Value &tensor)
{
vespalib::nbostream stream;
- vespalib::eval::EngineOrFactory::get().encode(tensor, stream);
+ encode_value(tensor, stream);
auto raw = allocRawBuffer(stream.size());
memcpy(raw.data, stream.peek(), stream.size());
return raw.ref;
diff --git a/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.cpp b/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.cpp
new file mode 100644
index 00000000000..d4fd681f2cb
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.cpp
@@ -0,0 +1,48 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "streamed_value_saver.h"
+#include "streamed_value_store.h"
+
+#include <vespa/searchlib/attribute/iattributesavetarget.h>
+#include <vespa/searchlib/util/bufferwriter.h>
+#include <vespa/vespalib/objects/nbostream.h>
+
+using vespalib::GenerationHandler;
+
+namespace search::tensor {
+
+StreamedValueSaver::
+StreamedValueSaver(GenerationHandler::Guard &&guard,
+ const attribute::AttributeHeader &header,
+ RefCopyVector &&refs,
+ const StreamedValueStore &tensorStore)
+ : AttributeSaver(std::move(guard), header),
+ _refs(std::move(refs)),
+ _tensorStore(tensorStore)
+{
+}
+
+StreamedValueSaver::~StreamedValueSaver() = default;
+
+bool
+StreamedValueSaver::onSave(IAttributeSaveTarget &saveTarget)
+{
+ auto datWriter = saveTarget.datWriter().allocBufferWriter();
+ const uint32_t docIdLimit(_refs.size());
+ vespalib::nbostream stream;
+ for (uint32_t lid = 0; lid < docIdLimit; ++lid) {
+ if (_tensorStore.encode_tensor(_refs[lid], stream)) {
+ uint32_t sz = stream.size();
+ datWriter->write(&sz, sizeof(sz));
+ datWriter->write(stream.peek(), stream.size());
+ stream.clear();
+ } else {
+ uint32_t sz = 0;
+ datWriter->write(&sz, sizeof(sz));
+ }
+ }
+ datWriter->flush();
+ return true;
+}
+
+} // namespace search::tensor
diff --git a/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.h b/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.h
new file mode 100644
index 00000000000..71d56539679
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/streamed_value_saver.h
@@ -0,0 +1,35 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/searchlib/attribute/attributesaver.h>
+#include "tensor_attribute.h"
+
+namespace search::tensor {
+
+class StreamedValueStore;
+
+/*
+ * Class for saving a tensor attribute.
+ */
+class StreamedValueSaver : public AttributeSaver
+{
+public:
+ using RefCopyVector = TensorAttribute::RefCopyVector;
+private:
+ using GenerationHandler = vespalib::GenerationHandler;
+
+ RefCopyVector _refs;
+ const StreamedValueStore &_tensorStore;
+
+ bool onSave(IAttributeSaveTarget &saveTarget) override;
+public:
+ StreamedValueSaver(GenerationHandler::Guard &&guard,
+ const attribute::AttributeHeader &header,
+ RefCopyVector &&refs,
+ const StreamedValueStore &tensorStore);
+
+ virtual ~StreamedValueSaver();
+};
+
+} // namespace search::tensor
diff --git a/searchlib/src/vespa/searchlib/tensor/streamed_value_store.cpp b/searchlib/src/vespa/searchlib/tensor/streamed_value_store.cpp
new file mode 100644
index 00000000000..c4579880409
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/streamed_value_store.cpp
@@ -0,0 +1,220 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "streamed_value_store.h"
+#include "tensor_deserialize.h"
+#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/eval/streamed/streamed_value_builder_factory.h>
+#include <vespa/eval/streamed/streamed_value_view.h>
+#include <vespa/vespalib/datastore/datastore.hpp>
+#include <vespa/vespalib/objects/nbostream.h>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/log/log.h>
+
+LOG_SETUP(".searchlib.tensor.streamed_value_store");
+
+using vespalib::datastore::Handle;
+using namespace vespalib::eval;
+
+namespace search::tensor {
+
+namespace {
+
+constexpr size_t MIN_BUFFER_ARRAYS = 1024;
+
+struct CellsMemBlock {
+ uint32_t num;
+ uint32_t total_sz;
+ const char *ptr;
+ CellsMemBlock(TypedCells cells)
+ : num(cells.size),
+ total_sz(CellTypeUtils::mem_size(cells.type, num)),
+ ptr((const char *)cells.data)
+ {}
+};
+
+template<typename T>
+void check_alignment(T *ptr, size_t align)
+{
+ static_assert(sizeof(T) == 1);
+ size_t ptr_val = (size_t)ptr;
+ size_t unalign = ptr_val & (align - 1);
+ assert(unalign == 0);
+}
+
+} // namespace <unnamed>
+
+StreamedValueStore::StreamedValueStore(const ValueType &tensor_type)
+ : TensorStore(_concreteStore),
+ _concreteStore(),
+ _bufferType(RefType::align(1),
+ MIN_BUFFER_ARRAYS,
+ RefType::offsetSize() / RefType::align(1)),
+ _tensor_type(tensor_type),
+ _data_from_type(_tensor_type)
+{
+ _store.addType(&_bufferType);
+ _store.initActiveBuffers();
+ size_t align = CellTypeUtils::alignment(_data_from_type.cell_type);
+ // max alignment we can handle is 8:
+ assert(align <= 8);
+ // alignment must be a power of two:
+ assert((align & (align-1)) == 0);
+}
+
+StreamedValueStore::~StreamedValueStore()
+{
+ _store.dropBuffers();
+}
+
+std::pair<const char *, uint32_t>
+StreamedValueStore::getRawBuffer(RefType ref) const
+{
+ if (!ref.valid()) {
+ return std::make_pair(nullptr, 0u);
+ }
+ const char *buf = _store.getEntry<char>(ref);
+ uint32_t len = *reinterpret_cast<const uint32_t *>(buf);
+ return std::make_pair(buf + sizeof(uint32_t), len);
+}
+
+Handle<char>
+StreamedValueStore::allocRawBuffer(uint32_t size)
+{
+ if (size == 0) {
+ return Handle<char>();
+ }
+ size_t extSize = size + sizeof(uint32_t);
+ size_t bufSize = RefType::align(extSize);
+ auto result = _concreteStore.rawAllocator<char>(_typeId).alloc(bufSize);
+ *reinterpret_cast<uint32_t *>(result.data) = size;
+ char *padWritePtr = result.data + extSize;
+ for (size_t i = extSize; i < bufSize; ++i) {
+ *padWritePtr++ = 0;
+ }
+ // Hide length of buffer (first 4 bytes) from users of the buffer.
+ return Handle<char>(result.ref, result.data + sizeof(uint32_t));
+}
+
+void
+StreamedValueStore::holdTensor(EntryRef ref)
+{
+ if (!ref.valid()) {
+ return;
+ }
+ RefType iRef(ref);
+ const char *buf = _store.getEntry<char>(iRef);
+ uint32_t len = *reinterpret_cast<const uint32_t *>(buf);
+ _concreteStore.holdElem(ref, len + sizeof(uint32_t));
+}
+
+TensorStore::EntryRef
+StreamedValueStore::move(EntryRef ref)
+{
+ if (!ref.valid()) {
+ return RefType();
+ }
+ auto oldraw = getRawBuffer(ref);
+ auto newraw = allocRawBuffer(oldraw.second);
+ memcpy(newraw.data, oldraw.first, oldraw.second);
+ _concreteStore.holdElem(ref, oldraw.second + sizeof(uint32_t));
+ return newraw.ref;
+}
+
+StreamedValueStore::StreamedValueData
+StreamedValueStore::get_tensor_data(EntryRef ref) const
+{
+ StreamedValueData retval;
+ retval.valid = false;
+ auto raw = getRawBuffer(ref);
+ if (raw.second == 0u) {
+ return retval;
+ }
+ vespalib::nbostream source(raw.first, raw.second);
+ uint32_t num_cells = source.readValue<uint32_t>();
+ check_alignment(source.peek(), CellTypeUtils::alignment(_data_from_type.cell_type));
+ retval.cells_ref = TypedCells(source.peek(), _data_from_type.cell_type, num_cells);
+ source.adjustReadPos(CellTypeUtils::mem_size(_data_from_type.cell_type, num_cells));
+ assert((num_cells % _data_from_type.dense_subspace_size) == 0);
+ retval.num_subspaces = num_cells / _data_from_type.dense_subspace_size;
+ retval.labels_buffer = vespalib::ConstArrayRef<char>(source.peek(), source.size());
+ retval.valid = true;
+ return retval;
+}
+
+bool
+StreamedValueStore::encode_tensor(EntryRef ref, vespalib::nbostream &target) const
+{
+ if (auto data = get_tensor_data(ref)) {
+ StreamedValueView value(
+ _tensor_type, _data_from_type.num_mapped_dimensions,
+ data.cells_ref, data.num_subspaces, data.labels_buffer);
+ vespalib::eval::encode_value(value, target);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void
+StreamedValueStore::serialize_labels(const Value::Index &index,
+ vespalib::nbostream &target) const
+{
+ uint32_t num_subspaces = index.size();
+ uint32_t num_mapped_dims = _data_from_type.num_mapped_dimensions;
+ std::vector<vespalib::stringref> labels(num_mapped_dims * num_subspaces);
+ auto view = index.create_view({});
+ view->lookup({});
+ std::vector<vespalib::stringref> addr(num_mapped_dims);
+ std::vector<vespalib::stringref *> addr_refs;
+ for (auto & label : addr) {
+ addr_refs.push_back(&label);
+ }
+ size_t subspace;
+ for (size_t ss = 0; ss < num_subspaces; ++ss) {
+ bool ok = view->next_result(addr_refs, subspace);
+ assert(ok);
+ size_t idx = subspace * num_mapped_dims;
+ for (auto label : addr) {
+ labels[idx++] = label;
+ }
+ }
+ bool ok = view->next_result(addr_refs, subspace);
+ assert(!ok);
+ for (auto label : labels) {
+ target.writeSmallString(label);
+ }
+}
+
+TensorStore::EntryRef
+StreamedValueStore::store_tensor(const Value &tensor)
+{
+ assert(tensor.type() == _tensor_type);
+ CellsMemBlock cells_mem(tensor.cells());
+ vespalib::nbostream stream;
+ stream << uint32_t(cells_mem.num);
+ serialize_labels(tensor.index(), stream);
+ size_t mem_size = stream.size() + cells_mem.total_sz;
+ auto raw = allocRawBuffer(mem_size);
+ char *target = raw.data;
+ memcpy(target, stream.peek(), sizeof(uint32_t));
+ stream.adjustReadPos(sizeof(uint32_t));
+ target += sizeof(uint32_t);
+ check_alignment(target, CellTypeUtils::alignment(_data_from_type.cell_type));
+ memcpy(target, cells_mem.ptr, cells_mem.total_sz);
+ target += cells_mem.total_sz;
+ memcpy(target, stream.peek(), stream.size());
+ target += stream.size();
+ assert(target <= raw.data + mem_size);
+ return raw.ref;
+}
+
+TensorStore::EntryRef
+StreamedValueStore::store_encoded_tensor(vespalib::nbostream &encoded)
+{
+ const auto &factory = StreamedValueBuilderFactory::get();
+ auto val = vespalib::eval::decode_value(encoded, factory);
+ return store_tensor(*val);
+}
+
+}
diff --git a/searchlib/src/vespa/searchlib/tensor/streamed_value_store.h b/searchlib/src/vespa/searchlib/tensor/streamed_value_store.h
new file mode 100644
index 00000000000..de94dc043d3
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/tensor/streamed_value_store.h
@@ -0,0 +1,96 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "tensor_store.h"
+#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/value.h>
+#include <vespa/vespalib/objects/nbostream.h>
+#include <vespa/vespalib/util/typify.h>
+
+namespace search::tensor {
+
+/**
+ * Class for storing tensors in memory, with a special serialization
+ * format that can be used directly to make a StreamedValueView.
+ *
+ * The tensor type is owned by the store itself and will not be
+ * serialized at all.
+ *
+ * The parameters for serialization (see DataFromType) are:
+ * - number of mapped dimensions [MD]
+ * - dense subspace size [DS]
+ * - size of each cell [CS] - currently 4 (float) or 8 (double)
+ * - alignment for cells - currently 4 (float) or 8 (double)
+ * While the tensor value to be serialized has:
+ * - number of dense subspaces [ND]
+ * - labels for dense subspaces, ND * MD strings
+ * - cell values, ND * DS cells (each either float or double)
+ * The serialization format looks like:
+ *
+ * [bytes] : [format] : [description]
+ * 4 : n.b.o. uint32_ t : num cells = ND * DS
+ * CS * ND * DS : native float or double : cells
+ * (depends) : n.b.o. strings : ND * MD label strings
+ *
+ * Here, n.b.o. means network byte order, or more precisely
+ * it's the format vespalib::nbostream uses for the given data type,
+ * including strings (where exact format depends on the string length).
+ * Note that the only unpredictably-sized data (the labels) are kept
+ * last.
+ * If we ever make a "hbostream" which uses host byte order, we
+ * could switch to that instead since these data are only kept in
+ * memory.
+ */
+class StreamedValueStore : public TensorStore {
+public:
+ using RefType = vespalib::datastore::AlignedEntryRefT<22, 3>;
+ using DataStoreType = vespalib::datastore::DataStoreT<RefType>;
+
+ struct StreamedValueData {
+ bool valid;
+ vespalib::eval::TypedCells cells_ref;
+ size_t num_subspaces;
+ vespalib::ConstArrayRef<char> labels_buffer;
+ operator bool() const { return valid; }
+ };
+
+ struct DataFromType {
+ uint32_t num_mapped_dimensions;
+ uint32_t dense_subspace_size;
+ vespalib::eval::CellType cell_type;
+
+ DataFromType(const vespalib::eval::ValueType& type)
+ : num_mapped_dimensions(type.count_mapped_dimensions()),
+ dense_subspace_size(type.dense_subspace_size()),
+ cell_type(type.cell_type())
+ {}
+ };
+
+private:
+ DataStoreType _concreteStore;
+ vespalib::datastore::BufferType<char> _bufferType;
+ vespalib::eval::ValueType _tensor_type;
+ DataFromType _data_from_type;
+
+ void serialize_labels(const vespalib::eval::Value::Index &index,
+ vespalib::nbostream &target) const;
+
+ std::pair<const char *, uint32_t> getRawBuffer(RefType ref) const;
+ vespalib::datastore::Handle<char> allocRawBuffer(uint32_t size);
+public:
+ StreamedValueStore(const vespalib::eval::ValueType &tensor_type);
+ virtual ~StreamedValueStore();
+
+ virtual void holdTensor(EntryRef ref) override;
+ virtual EntryRef move(EntryRef ref) override;
+
+ StreamedValueData get_tensor_data(EntryRef ref) const;
+ bool encode_tensor(EntryRef ref, vespalib::nbostream &target) const;
+
+ EntryRef store_tensor(const vespalib::eval::Value &tensor);
+ EntryRef store_encoded_tensor(vespalib::nbostream &encoded);
+};
+
+
+}
diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp
index 0748329694c..e0b21290284 100644
--- a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.cpp
@@ -7,13 +7,14 @@
#include <vespa/vespalib/data/slime/cursor.h>
#include <vespa/vespalib/data/slime/inserter.h>
#include <vespa/vespalib/util/rcuvector.hpp>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value.h>
using document::TensorDataType;
using document::WrongTensorTypeException;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::TensorSpec;
using vespalib::eval::Value;
using vespalib::eval::ValueType;
@@ -31,9 +32,9 @@ constexpr size_t DEAD_SLACK = 0x10000u;
Value::UP
createEmptyTensor(const ValueType &type)
{
- auto engine = EngineOrFactory::get();
+ const auto &factory = FastValueBuilderFactory::get();
TensorSpec empty_spec(type.to_spec());
- return engine.from_spec(empty_spec);
+ return vespalib::eval::value_from_spec(empty_spec, factory);
}
vespalib::string makeWrongTensorTypeMsg(const ValueType &fieldTensorType, const ValueType &tensorType)
@@ -183,23 +184,19 @@ TensorAttribute::populate_state(vespalib::slime::Cursor& object) const
vespalib::eval::Value::UP
TensorAttribute::getEmptyTensor() const
{
- return EngineOrFactory::get().copy(*_emptyTensor);
+ return FastValueBuilderFactory::get().copy(*_emptyTensor);
}
-void
-TensorAttribute::extract_dense_view(uint32_t docid, vespalib::tensor::MutableDenseTensorView& tensor) const
+vespalib::eval::TypedCells
+TensorAttribute::extract_cells_ref(uint32_t /*docid*/) const
{
- (void) docid;
- (void) tensor;
notImplemented();
}
const vespalib::eval::Value&
-TensorAttribute::get_tensor_ref(uint32_t docid) const
+TensorAttribute::get_tensor_ref(uint32_t /*docid*/) const
{
- (void) docid;
notImplemented();
- abort(); // Needed to avoid compile error
}
const vespalib::eval::ValueType &
diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.h b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.h
index b88ffcf0f2c..7abfe66a2e4 100644
--- a/searchlib/src/vespa/searchlib/tensor/tensor_attribute.h
+++ b/searchlib/src/vespa/searchlib/tensor/tensor_attribute.h
@@ -47,9 +47,9 @@ public:
void onGenerationChange(generation_t generation) override;
bool addDoc(DocId &docId) override;
std::unique_ptr<vespalib::eval::Value> getEmptyTensor() const override;
- void extract_dense_view(uint32_t docid, vespalib::tensor::MutableDenseTensorView& tensor) const override;
+ vespalib::eval::TypedCells extract_cells_ref(uint32_t docid) const override;
const vespalib::eval::Value& get_tensor_ref(uint32_t docid) const override;
- bool supports_extract_dense_view() const override { return false; }
+ bool supports_extract_cells_ref() const override { return false; }
bool supports_get_tensor_ref() const override { return false; }
const vespalib::eval::ValueType & getTensorType() const override;
void get_state(const vespalib::slime::Inserter& inserter) const override;
diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.cpp b/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.cpp
index 83988a3af11..4fddd092451 100644
--- a/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.cpp
@@ -1,24 +1,30 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "tensor_deserialize.h"
#include <vespa/document/util/serializableexceptions.h>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/value.h>
-#include <vespa/vespalib/objects/nbostream.h>
using document::DeserializeException;
-using vespalib::eval::EngineOrFactory;
+using vespalib::eval::FastValueBuilderFactory;
using vespalib::eval::Value;
namespace search::tensor {
-std::unique_ptr<Value> deserialize_tensor(const void *data, size_t size)
+std::unique_ptr<Value> deserialize_tensor(vespalib::nbostream &buffer)
{
- vespalib::nbostream wrapStream(data, size);
- auto tensor = EngineOrFactory::get().decode(wrapStream);
- if (wrapStream.size() != 0) {
+ auto tensor = vespalib::eval::decode_value(buffer, FastValueBuilderFactory::get());
+ if (buffer.size() != 0) {
throw DeserializeException("Leftover bytes deserializing tensor attribute value.", VESPA_STRLOC);
}
return tensor;
}
+std::unique_ptr<Value> deserialize_tensor(const void *data, size_t size)
+{
+ vespalib::nbostream wrapStream(data, size);
+ return deserialize_tensor(wrapStream);
+}
+
} // namespace
diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.h b/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.h
index 18e166543d6..6f9521c1355 100644
--- a/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.h
+++ b/searchlib/src/vespa/searchlib/tensor/tensor_deserialize.h
@@ -1,10 +1,14 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/eval/eval/value.h>
+#include <vespa/vespalib/objects/nbostream.h>
namespace search::tensor {
extern std::unique_ptr<vespalib::eval::Value>
deserialize_tensor(const void *data, size_t size);
+extern std::unique_ptr<vespalib::eval::Value>
+deserialize_tensor(vespalib::nbostream &stream);
+
} // namespace
diff --git a/searchlib/src/vespa/searchlib/transactionlog/domainpart.cpp b/searchlib/src/vespa/searchlib/transactionlog/domainpart.cpp
index 830384ee538..9f7f39b7d5c 100644
--- a/searchlib/src/vespa/searchlib/transactionlog/domainpart.cpp
+++ b/searchlib/src/vespa/searchlib/transactionlog/domainpart.cpp
@@ -236,11 +236,8 @@ DomainPart::buildPacketMapping(bool allowTruncate)
_range.from(firstSerial);
}
_range.to(packet.range().to());
- _packets.insert(std::make_pair(firstSerial, std::move(packet)));
- {
- std::lock_guard guard(_lock);
- _skipList.push_back(SkipInfo(firstSerial, firstPos));
- }
+ // Called only from constructor so no need to hold lock
+ _skipList.emplace_back(firstSerial, firstPos);
} else {
fSize = transLog.GetSize();
}
@@ -259,7 +256,6 @@ DomainPart::DomainPart(const string & name, const string & baseDir, SerialNum s,
_range(s),
_sz(0),
_byteSize(0),
- _packets(),
_fileName(fmt("%s/%s-%016" PRIu64, baseDir.c_str(), name.c_str(), s)),
_transLog(std::make_unique<FastOS_File>(_fileName.c_str())),
_skipList(),
@@ -345,10 +341,6 @@ DomainPart::close()
throw runtime_error(fmt("Failed closing file '%s' of size %" PRId64 ".",
_transLog->GetFileName(), _transLog->GetSize()));
}
- {
- std::lock_guard guard(_lock);
- _packets.clear();
- }
return retval;
}
@@ -364,11 +356,9 @@ DomainPart::openAndFind(FastOS_FileInterface &file, const SerialNum &from)
if (retval) {
int64_t pos(_headerLen);
std::lock_guard guard(_lock);
- for(SkipList::const_iterator it(_skipList.begin()), mt(_skipList.end());
- (it < mt) && (it->id() <= from);
- it++)
- {
- pos = it->filePos();
+ for (const auto & skipInfo : _skipList) {
+ if (skipInfo.id() > from) break;
+ pos = skipInfo.filePos();
}
retval = file.SetPosition(pos);
}
@@ -419,20 +409,8 @@ DomainPart::commit(SerialNum firstSerial, const Packet &packet)
if ( ! chunk->getEntries().empty()) {
write(*_transLog, *chunk);
}
-
- bool merged(false);
std::lock_guard guard(_lock);
- if ( ! _packets.empty() ) {
- Packet & lastPacket = _packets.rbegin()->second;
- if (lastPacket.sizeBytes() < 0xf000) {
- lastPacket.merge(packet);
- merged = true;
- }
- }
- if (! merged ) {
- _packets.insert(std::make_pair(firstSerial, std::move(packet)));
- _skipList.push_back(SkipInfo(firstSerial, firstPos));
- }
+ _skipList.emplace_back(firstSerial, firstPos);
}
void
@@ -452,76 +430,6 @@ DomainPart::sync()
}
bool
-DomainPart::visit(SerialNumRange &r, Packet &packet)
-{
- bool retval(false);
- std::lock_guard guard(_lock);
- LOG(spam, "Visit r(%" PRIu64 ", %" PRIu64 "] Checking %" PRIu64 " packets",
- r.from(), r.to(), uint64_t(_packets.size()));
- if ( ! isClosed() ) {
- PacketList::const_iterator start(_packets.lower_bound(r.from() + 1));
- PacketList::const_iterator end(_packets.upper_bound(r.to()));
- if (start != _packets.end()) {
- if ( ! start->second.range().contains(r.from() + 1) &&
- (start != _packets.begin())) {
- PacketList::const_iterator prev(start);
- prev--;
- if (prev->second.range().contains(r.from() + 1)) {
- start--;
- }
- }
- } else {
- if (!_packets.empty())
- start--;
- }
- if ( start != _packets.end() && start->first <= r.to()) {
- PacketList::const_iterator next(start);
- next++;
- if ((r.from() < start->first) &&
- ((next != end) || ((next != _packets.end()) && ((r.to() + 1) == next->first))))
- {
- packet = start->second;
- LOG(spam, "Visit whole packet[%" PRIu64 ", %" PRIu64 "]", packet.range().from(), packet.range().to());
- if (next != _packets.end()) {
- r.from(next->first - 1);
- retval = true;
- } else {
- /// This is the very last package. Can safely finish.
- }
- } else {
- const nbostream & tmp = start->second.getHandle();
- nbostream_longlivedbuf h(tmp.data(), tmp.size());
- LOG(spam, "Visit partial[%" PRIu64 ", %" PRIu64 "] (%zd, %zd, %zd)",
- start->second.range().from(), start->second.range().to(), h.rp(), h.size(), h.capacity());
- Packet newPacket(h.size());
- for (; (h.size() > 0) && (r.from() < r.to()); ) {
- Packet::Entry e;
- e.deserialize(h);
- if (r.from() < e.serial()) {
- if (e.serial() <= r.to()) {
- LOG(spam, "Adding serial #%" PRIu64 ", of type %d and size %zd into packet of size %zu and %zu bytes",
- e.serial(), e.type(), e.data().size(), newPacket.size(), newPacket.sizeBytes());
- newPacket.add(e);
- r.from(e.serial());
- } else {
- // Force breakout on visiting empty interval.
- r.from(r.to());
- }
- }
- }
- packet = std::move(newPacket);
- retval = next != _packets.end();
- }
- }
- } else {
- /// File has been closed must continue from file.
- retval = true;
- }
- return retval;
-}
-
-
-bool
DomainPart::visit(FastOS_FileInterface &file, SerialNumRange &r, Packet &packet)
{
if ( ! file.IsOpened() && ! openAndFind(file, r.from() + 1)) {
diff --git a/searchlib/src/vespa/searchlib/transactionlog/domainpart.h b/searchlib/src/vespa/searchlib/transactionlog/domainpart.h
index a956932be19..f5a10cafe3e 100644
--- a/searchlib/src/vespa/searchlib/transactionlog/domainpart.h
+++ b/searchlib/src/vespa/searchlib/transactionlog/domainpart.h
@@ -27,7 +27,6 @@ public:
const vespalib::string &fileName() const { return _fileName; }
void commit(SerialNum firstSerial, const Packet &packet);
bool erase(SerialNum to);
- bool visit(SerialNumRange &r, Packet &packet);
bool visit(FastOS_FileInterface &file, SerialNumRange &r, Packet &packet);
bool close();
void sync();
@@ -56,22 +55,20 @@ private:
class SkipInfo
{
public:
- SkipInfo(SerialNum s, uint64_t p) : _id(s), _pos(p) {}
+ SkipInfo(SerialNum s, uint64_t p) noexcept : _id(s), _pos(p) {}
- bool operator ==(const SkipInfo &b) const { return cmp(b) == 0; }
- bool operator <(const SkipInfo &b) const { return cmp(b) < 0; }
- bool operator >(const SkipInfo &b) const { return cmp(b) > 0; }
- bool operator <=(const SkipInfo &b) const { return cmp(b) <= 0; }
- bool operator >=(const SkipInfo &b) const { return cmp(b) >= 0; }
- int64_t filePos() const { return _pos; }
- SerialNum id() const { return _id; }
+ bool operator ==(const SkipInfo &b) const noexcept { return cmp(b) == 0; }
+ bool operator <(const SkipInfo &b) const noexcept { return cmp(b) < 0; }
+ bool operator >(const SkipInfo &b) const noexcept { return cmp(b) > 0; }
+ bool operator <=(const SkipInfo &b) const noexcept { return cmp(b) <= 0; }
+ bool operator >=(const SkipInfo &b) const noexcept { return cmp(b) >= 0; }
+ int64_t filePos() const noexcept { return _pos; }
+ SerialNum id() const noexcept { return _id; }
private:
- int64_t cmp(const SkipInfo & b) const { return _id - b._id; }
+ int64_t cmp(const SkipInfo & b) const noexcept { return _id - b._id; }
SerialNum _id;
uint64_t _pos;
};
- typedef std::vector<SkipInfo> SkipList;
- typedef std::map<SerialNum, Packet> PacketList;
const Encoding _encoding;
const uint8_t _compressionLevel;
std::mutex _lock;
@@ -79,10 +76,9 @@ private:
SerialNumRange _range;
size_t _sz;
std::atomic<uint64_t> _byteSize;
- PacketList _packets;
vespalib::string _fileName;
std::unique_ptr<FastOS_FileInterface> _transLog;
- SkipList _skipList;
+ std::vector<SkipInfo> _skipList;
uint32_t _headerLen;
mutable std::mutex _writeLock;
// Protected by _writeLock
diff --git a/searchlib/src/vespa/searchlib/transactionlog/session.cpp b/searchlib/src/vespa/searchlib/transactionlog/session.cpp
index edfd7367a1f..022a891b3fc 100644
--- a/searchlib/src/vespa/searchlib/transactionlog/session.cpp
+++ b/searchlib/src/vespa/searchlib/transactionlog/session.cpp
@@ -33,12 +33,8 @@ Session::VisitTask::run()
bool
Session::visit(FastOS_FileInterface & file, DomainPart & dp) {
Packet packet(size_t(-1));
- bool more(false);
- if (dp.isClosed()) {
- more = dp.visit(file, _range, packet);
- } else {
- more = dp.visit(_range, packet);
- }
+ bool more = dp.visit(file, _range, packet);
+
if ( ! packet.getHandle().empty()) {
send(packet);
}
diff --git a/searchlib/src/vespa/searchlib/util/rawbuf.cpp b/searchlib/src/vespa/searchlib/util/rawbuf.cpp
index c4fb3dd72cc..0fcef353f33 100644
--- a/searchlib/src/vespa/searchlib/util/rawbuf.cpp
+++ b/searchlib/src/vespa/searchlib/util/rawbuf.cpp
@@ -220,7 +220,7 @@ RawBuf::operator+=(const RawBuf& buffer)
bool
-RawBuf::operator==(const RawBuf &buffer)
+RawBuf::operator==(const RawBuf &buffer) const
{
size_t nbytes = buffer.GetUsedLen();
if (nbytes != GetUsedLen())
diff --git a/searchlib/src/vespa/searchlib/util/rawbuf.h b/searchlib/src/vespa/searchlib/util/rawbuf.h
index ffebd035950..fd4ce8976a9 100644
--- a/searchlib/src/vespa/searchlib/util/rawbuf.h
+++ b/searchlib/src/vespa/searchlib/util/rawbuf.h
@@ -38,7 +38,7 @@ public:
void operator+=(const char *src);
void operator+=(const RawBuf& buffer);
- bool operator==(const RawBuf &buffer);
+ bool operator==(const RawBuf &buffer) const;
void addNum(size_t num, size_t fieldw, char fill);
void addNum32(int32_t num, size_t fieldw, char fill);
void addNum64(int64_t num, size_t fieldw, char fill);
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp
index dd1b6f95618..65b262a85f2 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp
+++ b/searchsummary/src/vespa/searchsummary/docsummary/attributedfw.cpp
@@ -3,8 +3,8 @@
#include "attributedfw.h"
#include "docsumstate.h"
#include "docsumwriter.h"
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/attribute/iattributecontext.h>
#include <vespa/searchlib/attribute/iattributemanager.h>
#include <vespa/searchlib/attribute/integerbase.h>
@@ -25,7 +25,6 @@ using search::attribute::IAttributeVector;
using vespalib::Memory;
using vespalib::slime::Cursor;
using vespalib::slime::Inserter;
-using vespalib::eval::EngineOrFactory;
using vespalib::eval::Value;
namespace search::docsummary {
@@ -106,7 +105,7 @@ SingleAttrDFW::insertField(uint32_t docid, GetDocsumsState * state, ResType type
const auto tensor = tv->getTensor(docid);
if (tensor) {
vespalib::nbostream str;
- EngineOrFactory::get().encode(*tensor, str);
+ encode_value(*tensor, str);
target.insertData(vespalib::Memory(str.peek(), str.size()));
}
}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/summaryfieldconverter.cpp b/searchsummary/src/vespa/searchsummary/docsummary/summaryfieldconverter.cpp
index 604e1b4c413..9df6328d4fe 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/summaryfieldconverter.cpp
+++ b/searchsummary/src/vespa/searchsummary/docsummary/summaryfieldconverter.cpp
@@ -24,6 +24,7 @@
#include <vespa/document/fieldvalue/annotationreferencefieldvalue.h>
#include <vespa/document/fieldvalue/tensorfieldvalue.h>
#include <vespa/document/fieldvalue/referencefieldvalue.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/common/schema.h>
#include <vespa/searchlib/util/url.h>
#include <vespa/vespalib/encoding/base64.h>
@@ -31,7 +32,6 @@
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/data/slime/slime.h>
-#include <vespa/eval/eval/engine_or_factory.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/searchlib/util/slime_output_raw_buf_adapter.h>
#include <vespa/vespalib/util/exceptions.h>
@@ -510,7 +510,7 @@ private:
const auto &tensor = value.getAsTensorPtr();
vespalib::nbostream s;
if (tensor) {
- vespalib::eval::EngineOrFactory::get().encode(*tensor, s);
+ encode_value(*tensor, s);
}
_inserter.insertData(vespalib::Memory(s.peek(), s.size()));
}
diff --git a/security-utils/src/main/java/com/yahoo/security/X509CertificateBuilder.java b/security-utils/src/main/java/com/yahoo/security/X509CertificateBuilder.java
index 4452a4a7604..d3907e09b3f 100644
--- a/security-utils/src/main/java/com/yahoo/security/X509CertificateBuilder.java
+++ b/security-utils/src/main/java/com/yahoo/security/X509CertificateBuilder.java
@@ -125,6 +125,11 @@ public class X509CertificateBuilder {
return this;
}
+ public X509CertificateBuilder addSubjectAlternativeName(SubjectAlternativeName.Type type, String value) {
+ this.subjectAlternativeNames.add(new SubjectAlternativeName(type, value));
+ return this;
+ }
+
public X509CertificateBuilder setBasicConstraints(boolean isCritical, boolean isCertAuthorityCertificate) {
this.basicConstraintsExtension = new BasicConstraintsExtension(isCritical, isCertAuthorityCertificate);
return this;
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
index a40813be96f..1d74f0a170f 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
@@ -17,6 +17,7 @@ import java.util.logging.Logger;
import static com.yahoo.security.SubjectAlternativeName.Type.DNS_NAME;
import static com.yahoo.security.SubjectAlternativeName.Type.IP_ADDRESS;
+import static com.yahoo.security.SubjectAlternativeName.Type.UNIFORM_RESOURCE_IDENTIFIER;
import static java.util.stream.Collectors.toList;
/**
@@ -59,6 +60,7 @@ public class PeerAuthorizer {
case CN:
return cn != null && requiredCredential.pattern().matches(cn);
case SAN_DNS:
+ case SAN_URI:
return sans.stream()
.anyMatch(san -> requiredCredential.pattern().matches(san));
default:
@@ -73,7 +75,7 @@ public class PeerAuthorizer {
private static List<String> getSubjectAlternativeNames(X509Certificate peerCertificate) {
return X509CertificateUtils.getSubjectAlternativeNames(peerCertificate).stream()
- .filter(san -> san.getType() == DNS_NAME || san.getType() == IP_ADDRESS)
+ .filter(san -> san.getType() == DNS_NAME || san.getType() == IP_ADDRESS || san.getType() == UNIFORM_RESOURCE_IDENTIFIER)
.map(SubjectAlternativeName::getValue)
.collect(toList());
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
index 83742950dbc..35eef68cef2 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
@@ -44,5 +44,5 @@ class TransportSecurityOptionsEntity {
@JsonProperty("must-match") String matchExpression;
}
- enum CredentialField { CN, SAN_DNS }
+ enum CredentialField { CN, SAN_DNS, SAN_URI }
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
index 4f6d9264f51..75134e20b68 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
@@ -8,7 +8,6 @@ import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.CredentialFiel
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.Files;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.RequiredCredential;
import com.yahoo.security.tls.policy.AuthorizedPeers;
-import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.Role;
@@ -119,13 +118,14 @@ public class TransportSecurityOptionsJsonSerializer {
if (requiredCredential.matchExpression == null) {
throw missingFieldException("must-match");
}
- return new RequiredPeerCredential(toField(requiredCredential.field), new HostGlobPattern(requiredCredential.matchExpression));
+ return RequiredPeerCredential.of(toField(requiredCredential.field), requiredCredential.matchExpression);
}
private static RequiredPeerCredential.Field toField(CredentialField field) {
switch (field) {
case CN: return RequiredPeerCredential.Field.CN;
case SAN_DNS: return RequiredPeerCredential.Field.SAN_DNS;
+ case SAN_URI: return RequiredPeerCredential.Field.SAN_URI;
default: throw new IllegalArgumentException("Invalid field type: " + field);
}
}
@@ -172,6 +172,7 @@ public class TransportSecurityOptionsJsonSerializer {
switch (field) {
case CN: return CredentialField.CN;
case SAN_DNS: return CredentialField.SAN_DNS;
+ case SAN_URI: return CredentialField.SAN_URI;
default: throw new IllegalArgumentException("Invalid field type: " + field);
}
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java
index c7acf5dfbeb..e8798686e05 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java
@@ -7,20 +7,22 @@ import java.util.regex.Pattern;
/**
* @author bjorncs
*/
-public class HostGlobPattern {
+class HostGlobPattern implements RequiredPeerCredential.Pattern {
private final String pattern;
private final Pattern regexPattern;
- public HostGlobPattern(String pattern) {
+ HostGlobPattern(String pattern) {
this.pattern = pattern;
this.regexPattern = toRegexPattern(pattern);
}
+ @Override
public String asString() {
return pattern;
}
+ @Override
public boolean matches(String hostString) {
return regexPattern.matcher(hostString).matches();
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java
index 4f028d8b1ab..3ae886fef61 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java
@@ -8,21 +8,37 @@ import java.util.Objects;
*/
public class RequiredPeerCredential {
- public enum Field { CN, SAN_DNS }
+ public enum Field { CN, SAN_DNS, SAN_URI }
private final Field field;
- private final HostGlobPattern pattern;
+ private final Pattern pattern;
- public RequiredPeerCredential(Field field, HostGlobPattern pattern) {
+ private RequiredPeerCredential(Field field, Pattern pattern) {
this.field = field;
this.pattern = pattern;
}
+ public static RequiredPeerCredential of(Field field, String pattern) {
+ return new RequiredPeerCredential(field, createPattern(field, pattern));
+ }
+
+ private static Pattern createPattern(Field field, String pattern) {
+ switch (field) {
+ case CN:
+ case SAN_DNS:
+ return new HostGlobPattern(pattern);
+ case SAN_URI:
+ return new UriPattern(pattern);
+ default:
+ throw new IllegalArgumentException("Unknown field: " + field);
+ }
+ }
+
public Field field() {
return field;
}
- public HostGlobPattern pattern() {
+ public Pattern pattern() {
return pattern;
}
@@ -47,4 +63,9 @@ public class RequiredPeerCredential {
public int hashCode() {
return Objects.hash(field, pattern);
}
+
+ public interface Pattern {
+ String asString();
+ boolean matches(String fieldValue);
+ }
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/UriPattern.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/UriPattern.java
new file mode 100644
index 00000000000..18f5c0ce2de
--- /dev/null
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/UriPattern.java
@@ -0,0 +1,46 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security.tls.policy;
+
+import java.util.Objects;
+
+/**
+ * Pattern used for matching URIs in X.509 certificate subject alternative names.
+ *
+ * @author bjorncs
+ */
+class UriPattern implements RequiredPeerCredential.Pattern {
+
+ private final String pattern;
+
+ UriPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override public String asString() { return pattern; }
+
+ @Override
+ public boolean matches(String fieldValue) {
+ // Only exact match is supported (unlike for host names)
+ return fieldValue.equals(pattern);
+ }
+
+ @Override
+ public String toString() {
+ return "UriPattern{" +
+ "pattern='" + pattern + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UriPattern that = (UriPattern) o;
+ return Objects.equals(pattern, that.pattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(pattern);
+ }
+}
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/DefaultTlsContextTest.java b/security-utils/src/test/java/com/yahoo/security/tls/DefaultTlsContextTest.java
index 00928187f55..59c9cf5c356 100644
--- a/security-utils/src/test/java/com/yahoo/security/tls/DefaultTlsContextTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/tls/DefaultTlsContextTest.java
@@ -4,7 +4,6 @@ package com.yahoo.security.tls;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.X509CertificateBuilder;
import com.yahoo.security.tls.policy.AuthorizedPeers;
-import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.Role;
@@ -43,7 +42,7 @@ public class DefaultTlsContextTest {
new PeerPolicy(
"dummy-policy",
singleton(new Role("dummy-role")),
- singletonList(new RequiredPeerCredential(RequiredPeerCredential.Field.CN, new HostGlobPattern("dummy"))))));
+ singletonList(RequiredPeerCredential.of(RequiredPeerCredential.Field.CN, "dummy")))));
DefaultTlsContext tlsContext =
new DefaultTlsContext(
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/authz/PeerAuthorizerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/authz/PeerAuthorizerTest.java
index ffda4fe3c2b..6fa7207cb9c 100644
--- a/security-utils/src/test/java/com/yahoo/security/tls/authz/PeerAuthorizerTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/tls/authz/PeerAuthorizerTest.java
@@ -3,9 +3,9 @@ package com.yahoo.security.tls.authz;
import com.yahoo.security.KeyAlgorithm;
import com.yahoo.security.KeyUtils;
+import com.yahoo.security.SubjectAlternativeName.Type;
import com.yahoo.security.X509CertificateBuilder;
import com.yahoo.security.tls.policy.AuthorizedPeers;
-import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.RequiredPeerCredential.Field;
@@ -19,12 +19,17 @@ import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
+import java.util.List;
import java.util.Set;
import static com.yahoo.security.SignatureAlgorithm.SHA256_WITH_ECDSA;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.CN;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.SAN_DNS;
+import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.SAN_URI;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
+import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertFalse;
@@ -44,14 +49,14 @@ public class PeerAuthorizerTest {
RequiredPeerCredential sanRequirement = createRequiredCredential(SAN_DNS, "*.matching.san");
PeerAuthorizer authorizer = createPeerAuthorizer(createPolicy(POLICY_1, createRoles(ROLE_1), cnRequirement, sanRequirement));
- AuthorizationResult result = authorizer.authorizePeer(createCertificate("foo.matching.cn", "foo.matching.san", "foo.invalid.san"));
+ AuthorizationResult result = authorizer.authorizePeer(createCertificate("foo.matching.cn", asList("foo.matching.san", "foo.invalid.san"), emptyList()));
assertAuthorized(result);
assertThat(result.assumedRoles()).extracting(Role::name).containsOnly(ROLE_1);
assertThat(result.matchedPolicies()).containsOnly(POLICY_1);
- assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.invalid.cn", "foo.matching.san")));
- assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.invalid.cn", "foo.matching.san", "foo.invalid.san")));
- assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.matching.cn", "foo.invalid.san")));
+ assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.invalid.cn", singletonList("foo.matching.san"), emptyList())));
+ assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.invalid.cn", asList("foo.matching.san", "foo.invalid.san"),emptyList())));
+ assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.matching.cn", singletonList("foo.invalid.san"), emptyList())));
}
@Test
@@ -64,7 +69,7 @@ public class PeerAuthorizerTest {
createPolicy(POLICY_2, createRoles(ROLE_2, ROLE_3), cnRequirement, sanRequirement));
AuthorizationResult result = peerAuthorizer
- .authorizePeer(createCertificate("foo.matching.cn", "foo.matching.san"));
+ .authorizePeer(createCertificate("foo.matching.cn", singletonList("foo.matching.san"), emptyList()));
assertAuthorized(result);
assertThat(result.assumedRoles()).extracting(Role::name).containsOnly(ROLE_1, ROLE_2, ROLE_3);
assertThat(result.matchedPolicies()).containsOnly(POLICY_1, POLICY_2);
@@ -76,7 +81,7 @@ public class PeerAuthorizerTest {
createPolicy(POLICY_1, createRoles(ROLE_1), createRequiredCredential(CN, "*.matching.cn")),
createPolicy(POLICY_2, createRoles(ROLE_1, ROLE_2), createRequiredCredential(SAN_DNS, "*.matching.san")));
- AuthorizationResult result = peerAuthorizer.authorizePeer(createCertificate("foo.invalid.cn", "foo.matching.san"));
+ AuthorizationResult result = peerAuthorizer.authorizePeer(createCertificate("foo.invalid.cn", singletonList("foo.matching.san"), emptyList()));
assertAuthorized(result);
assertThat(result.assumedRoles()).extracting(Role::name).containsOnly(ROLE_1, ROLE_2);
assertThat(result.matchedPolicies()).containsOnly(POLICY_2);
@@ -91,12 +96,26 @@ public class PeerAuthorizerTest {
PeerAuthorizer peerAuthorizer = createPeerAuthorizer(
createPolicy(POLICY_1, emptySet(), cnSuffixRequirement, cnPrefixRequirement, sanPrefixRequirement, sanSuffixRequirement));
- assertAuthorized(peerAuthorizer.authorizePeer(createCertificate("matching.prefix.matching.suffix.cn", "matching.prefix.matching.suffix.san")));
- assertUnauthorized(peerAuthorizer.authorizePeer(createCertificate("matching.prefix.matching.suffix.cn", "matching.prefix.invalid.suffix.san")));
- assertUnauthorized(peerAuthorizer.authorizePeer(createCertificate("invalid.prefix.matching.suffix.cn", "matching.prefix.matching.suffix.san")));
+ assertAuthorized(peerAuthorizer.authorizePeer(createCertificate("matching.prefix.matching.suffix.cn", singletonList("matching.prefix.matching.suffix.san"), emptyList())));
+ assertUnauthorized(peerAuthorizer.authorizePeer(createCertificate("matching.prefix.matching.suffix.cn", singletonList("matching.prefix.invalid.suffix.san"), emptyList())));
+ assertUnauthorized(peerAuthorizer.authorizePeer(createCertificate("invalid.prefix.matching.suffix.cn", singletonList("matching.prefix.matching.suffix.san"), emptyList())));
}
- private static X509Certificate createCertificate(String subjectCn, String... sanCns) {
+ @Test
+ public void can_exact_match_policy_with_san_uri_pattern() {
+ RequiredPeerCredential cnRequirement = createRequiredCredential(CN, "*.matching.cn");
+ RequiredPeerCredential sanUriRequirement = createRequiredCredential(SAN_URI, "myscheme://my/exact/uri");
+ PeerAuthorizer authorizer = createPeerAuthorizer(createPolicy(POLICY_1, createRoles(ROLE_1), cnRequirement, sanUriRequirement));
+
+ AuthorizationResult result = authorizer.authorizePeer(createCertificate("foo.matching.cn", singletonList("foo.irrelevant.san"), singletonList("myscheme://my/exact/uri")));
+ assertAuthorized(result);
+ assertThat(result.assumedRoles()).extracting(Role::name).containsOnly(ROLE_1);
+ assertThat(result.matchedPolicies()).containsOnly(POLICY_1);
+
+ assertUnauthorized(authorizer.authorizePeer(createCertificate("foo.matching.cn", emptyList(), singletonList("myscheme://my/nonmatching/uri"))));
+ }
+
+ private static X509Certificate createCertificate(String subjectCn, List<String> sanDns, List<String> sanUri) {
X509CertificateBuilder builder =
X509CertificateBuilder.fromKeypair(
KEY_PAIR,
@@ -105,14 +124,13 @@ public class PeerAuthorizerTest {
Instant.EPOCH.plus(100000, ChronoUnit.DAYS),
SHA256_WITH_ECDSA,
BigInteger.ONE);
- for (String sanCn : sanCns) {
- builder.addSubjectAlternativeName(sanCn);
- }
+ sanDns.forEach(san -> builder.addSubjectAlternativeName(Type.DNS_NAME, san));
+ sanUri.forEach(san -> builder.addSubjectAlternativeName(Type.UNIFORM_RESOURCE_IDENTIFIER, san));
return builder.build();
}
private static RequiredPeerCredential createRequiredCredential(Field field, String pattern) {
- return new RequiredPeerCredential(field, new HostGlobPattern(pattern));
+ return RequiredPeerCredential.of(field, pattern);
}
private static Set<Role> createRoles(String... roleNames) {
@@ -124,7 +142,7 @@ public class PeerAuthorizerTest {
}
private static PeerPolicy createPolicy(String name, Set<Role> roles, RequiredPeerCredential... requiredCredentials) {
- return new PeerPolicy(name, roles, Arrays.asList(requiredCredentials));
+ return new PeerPolicy(name, roles, asList(requiredCredentials));
}
private static void assertAuthorized(AuthorizationResult result) {
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
index d996b21442a..ee1fa12b15f 100644
--- a/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
@@ -3,7 +3,6 @@ package com.yahoo.security.tls.json;
import com.yahoo.security.tls.TransportSecurityOptions;
import com.yahoo.security.tls.policy.AuthorizedPeers;
-import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.Role;
@@ -25,6 +24,7 @@ import java.util.HashSet;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.CN;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.SAN_DNS;
+import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.SAN_URI;
import static com.yahoo.test.json.JsonTestHelper.assertJsonEquals;
import static java.util.Collections.singleton;
import static org.junit.Assert.assertEquals;
@@ -39,7 +39,7 @@ public class TransportSecurityOptionsJsonSerializerTest {
private static final Path TEST_CONFIG_FILE = Paths.get("src/test/resources/transport-security-options.json");
@Test
- public void can_serialize_and_deserialize_transport_security_options() {
+ public void can_serialize_and_deserialize_transport_security_options() throws IOException {
TransportSecurityOptions options = new TransportSecurityOptions.Builder()
.withCaCertificates(Paths.get("/path/to/ca-certs.pem"))
.withCertificates(Paths.get("/path/to/cert.pem"), Paths.get("/path/to/key.pem"))
@@ -48,9 +48,10 @@ public class TransportSecurityOptionsJsonSerializerTest {
new AuthorizedPeers(
new HashSet<>(Arrays.asList(
new PeerPolicy("cfgserver", "cfgserver policy description", singleton(new Role("myrole")), Arrays.asList(
- new RequiredPeerCredential(CN, new HostGlobPattern("mycfgserver")),
- new RequiredPeerCredential(SAN_DNS, new HostGlobPattern("*.suffix.com")))),
- new PeerPolicy("node", singleton(new Role("anotherrole")), Collections.singletonList(new RequiredPeerCredential(CN, new HostGlobPattern("hostname"))))))))
+ RequiredPeerCredential.of(CN, "mycfgserver"),
+ RequiredPeerCredential.of(SAN_DNS, "*.suffix.com"),
+ RequiredPeerCredential.of(SAN_URI, "myscheme://resource/path/"))),
+ new PeerPolicy("node", singleton(new Role("anotherrole")), Collections.singletonList(RequiredPeerCredential.of(CN, "hostname")))))))
.build();
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -58,6 +59,8 @@ public class TransportSecurityOptionsJsonSerializerTest {
serializer.serialize(out, options);
TransportSecurityOptions deserializedOptions = serializer.deserialize(new ByteArrayInputStream(out.toByteArray()));
assertEquals(options, deserializedOptions);
+ Path expectedJsonFile = Paths.get("src/test/resources/transport-security-options-with-authz-rules.json");
+ assertJsonEquals(new String(Files.readAllBytes(expectedJsonFile)), out.toString());
}
@Test
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/policy/AuthorizedPeersTest.java b/security-utils/src/test/java/com/yahoo/security/tls/policy/AuthorizedPeersTest.java
index ce8249b9c6c..7581d7771a2 100644
--- a/security-utils/src/test/java/com/yahoo/security/tls/policy/AuthorizedPeersTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/tls/policy/AuthorizedPeersTest.java
@@ -18,7 +18,7 @@ public class AuthorizedPeersTest {
@Test(expected = IllegalArgumentException.class)
public void throws_exception_on_peer_policies_with_duplicate_names() {
- List<RequiredPeerCredential> requiredPeerCredential = singletonList(new RequiredPeerCredential(CN, new HostGlobPattern("mycfgserver")));
+ List<RequiredPeerCredential> requiredPeerCredential = singletonList(RequiredPeerCredential.of(CN, "mycfgserver"));
PeerPolicy peerPolicy1 = new PeerPolicy("duplicate-name", singleton(new Role("role")), requiredPeerCredential);
PeerPolicy peerPolicy2 = new PeerPolicy("duplicate-name", singleton(new Role("anotherrole")), requiredPeerCredential);
new AuthorizedPeers(new HashSet<>(asList(peerPolicy1, peerPolicy2)));
diff --git a/security-utils/src/test/resources/transport-security-options-with-authz-rules.json b/security-utils/src/test/resources/transport-security-options-with-authz-rules.json
new file mode 100644
index 00000000000..ea0bee38c8a
--- /dev/null
+++ b/security-utils/src/test/resources/transport-security-options-with-authz-rules.json
@@ -0,0 +1,29 @@
+{
+ "files" : {
+ "private-key" : "/path/to/key.pem",
+ "certificates" : "/path/to/cert.pem",
+ "ca-certificates" : "/path/to/ca-certs.pem"
+ },
+ "authorized-peers" : [ {
+ "required-credentials" : [ {
+ "field" : "CN",
+ "must-match" : "mycfgserver"
+ }, {
+ "field" : "SAN_DNS",
+ "must-match" : "*.suffix.com"
+ }, {
+ "field" : "SAN_URI",
+ "must-match" : "myscheme://resource/path/"
+ } ],
+ "name" : "cfgserver",
+ "description" : "cfgserver policy description",
+ "roles" : [ "myrole" ]
+ }, {
+ "required-credentials" : [ {
+ "field" : "CN",
+ "must-match" : "hostname"
+ } ],
+ "name" : "node",
+ "roles" : [ "anotherrole" ]
+ } ]
+} \ No newline at end of file
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java
index 48e20fb5989..97b9313a06a 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java
@@ -1,6 +1,7 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.duper;
+import com.yahoo.config.ConfigInstance;
import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.HostInfo;
@@ -22,6 +23,7 @@ import java.util.Set;
* @author hakon
*/
public class HostsModel implements Model {
+
private final Collection<HostInfo> hosts;
public HostsModel(List<HostInfo> hosts) {
@@ -34,11 +36,17 @@ public class HostsModel implements Model {
}
@Override
+ @SuppressWarnings("deprecation") // yes, this is needed
public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition configDefinition) {
throw new UnsupportedOperationException();
}
@Override
+ public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition configDefinition) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Set<ConfigKey<?>> allConfigsProduced() {
throw new UnsupportedOperationException();
}
@@ -72,4 +80,5 @@ public class HostsModel implements Model {
public boolean skipOldConfigModels(Instant now) {
throw new UnsupportedOperationException();
}
+
}
diff --git a/simplemetrics/src/main/java/com/yahoo/metrics/simple/MetricUpdater.java b/simplemetrics/src/main/java/com/yahoo/metrics/simple/MetricUpdater.java
index 06d048c5211..848132c9bea 100644
--- a/simplemetrics/src/main/java/com/yahoo/metrics/simple/MetricUpdater.java
+++ b/simplemetrics/src/main/java/com/yahoo/metrics/simple/MetricUpdater.java
@@ -6,7 +6,7 @@ import com.yahoo.concurrent.ThreadLocalDirectory.Updater;
/**
* The link between each single thread and the central data store.
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
*/
class MetricUpdater implements Updater<Bucket, Sample> {
diff --git a/slobrok/src/apps/slobrok/slobrok.cpp b/slobrok/src/apps/slobrok/slobrok.cpp
index b89449e6779..5d650fafc96 100644
--- a/slobrok/src/apps/slobrok/slobrok.cpp
+++ b/slobrok/src/apps/slobrok/slobrok.cpp
@@ -1,5 +1,4 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/fnet.h>
#include <vespa/slobrok/server/sbenv.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/vespalib/util/exceptions.h>
diff --git a/staging_vespalib/src/tests/objectselection/objectselection.cpp b/staging_vespalib/src/tests/objectselection/objectselection.cpp
index 0b670dd56f9..edf0a6b6a9f 100644
--- a/staging_vespalib/src/tests/objectselection/objectselection.cpp
+++ b/staging_vespalib/src/tests/objectselection/objectselection.cpp
@@ -48,11 +48,14 @@ struct ObjectType : public ObjectPredicate
struct ObjectCollect : public ObjectOperation
{
std::vector<Identifiable*> nodes;
+ ~ObjectCollect() override;
void execute(Identifiable &obj) override {
nodes.push_back(&obj);
}
};
+ObjectCollect::~ObjectCollect() = default;
+
TEST_SETUP(Test);
int
diff --git a/staging_vespalib/src/tests/sequencedtaskexecutor/foregroundtaskexecutor_test.cpp b/staging_vespalib/src/tests/sequencedtaskexecutor/foregroundtaskexecutor_test.cpp
index 03ec64b771e..6df3b83f90f 100644
--- a/staging_vespalib/src/tests/sequencedtaskexecutor/foregroundtaskexecutor_test.cpp
+++ b/staging_vespalib/src/tests/sequencedtaskexecutor/foregroundtaskexecutor_test.cpp
@@ -61,7 +61,7 @@ public:
wait(int wantDone)
{
std::unique_lock<std::mutex> guard(_m);
- _cv.wait(guard, [=] { return this->_done >= wantDone; });
+ _cv.wait(guard, [this, wantDone] { return this->_done >= wantDone; });
}
};
diff --git a/staging_vespalib/src/tests/sequencedtaskexecutor/sequencedtaskexecutor_test.cpp b/staging_vespalib/src/tests/sequencedtaskexecutor/sequencedtaskexecutor_test.cpp
index 21674b4e2d0..d36664d3b1f 100644
--- a/staging_vespalib/src/tests/sequencedtaskexecutor/sequencedtaskexecutor_test.cpp
+++ b/staging_vespalib/src/tests/sequencedtaskexecutor/sequencedtaskexecutor_test.cpp
@@ -63,7 +63,7 @@ public:
wait(int wantDone)
{
std::unique_lock<std::mutex> guard(_m);
- _cv.wait(guard, [=] { return this->_done >= wantDone; });
+ _cv.wait(guard, [this, wantDone] { return this->_done >= wantDone; });
}
};
diff --git a/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.cpp b/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.cpp
index 407129199e3..e4b64b19739 100644
--- a/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.cpp
+++ b/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.cpp
@@ -334,4 +334,11 @@ AdaptiveSequencedExecutor::getStats()
return stats;
}
+AdaptiveSequencedExecutor::Config
+AdaptiveSequencedExecutor::get_config() const
+{
+ auto guard = std::lock_guard(_mutex);
+ return _cfg;
+}
+
}
diff --git a/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.h b/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.h
index c52b9b22245..ed2209d130a 100644
--- a/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.h
+++ b/staging_vespalib/src/vespa/vespalib/util/adaptive_sequenced_executor.h
@@ -123,7 +123,7 @@ private:
};
std::unique_ptr<ThreadTools> _thread_tools;
- std::mutex _mutex;
+ mutable std::mutex _mutex;
std::vector<Strand> _strands;
vespalib::ArrayQueue<Strand*> _wait_queue;
vespalib::ArrayQueue<Worker*> _worker_stack;
@@ -149,6 +149,7 @@ public:
void sync() override;
void setTaskLimit(uint32_t task_limit) override;
vespalib::ExecutorStats getStats() override;
+ Config get_config() const;
};
}
diff --git a/staging_vespalib/src/vespa/vespalib/util/foreground_thread_executor.h b/staging_vespalib/src/vespa/vespalib/util/foreground_thread_executor.h
index ff523b1e35d..1862de910ab 100644
--- a/staging_vespalib/src/vespa/vespalib/util/foreground_thread_executor.h
+++ b/staging_vespalib/src/vespa/vespalib/util/foreground_thread_executor.h
@@ -26,6 +26,7 @@ public:
return ExecutorStats(ExecutorStats::QueueSizeT(), _accepted.load(std::memory_order_relaxed), 0);
}
void setTaskLimit(uint32_t taskLimit) override { (void) taskLimit; }
+ uint32_t getTaskLimit() const override { return std::numeric_limits<uint32_t>::max(); }
void wakeup() override { }
};
diff --git a/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.cpp b/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.cpp
index d1c6b1aba53..b0c67e14c5b 100644
--- a/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.cpp
+++ b/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.cpp
@@ -123,4 +123,13 @@ SequencedTaskExecutor::getExecutorId(uint64_t componentId) const {
return ExecutorId(executorId);
}
+const vespalib::SyncableThreadExecutor*
+SequencedTaskExecutor::first_executor() const
+{
+ if (_executors->empty()) {
+ return nullptr;
+ }
+ return _executors->front().get();
+}
+
} // namespace search
diff --git a/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.h b/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.h
index 050b00ef011..496b183af8a 100644
--- a/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.h
+++ b/staging_vespalib/src/vespa/vespalib/util/sequencedtaskexecutor.h
@@ -41,6 +41,8 @@ public:
*/
uint32_t getComponentHashSize() const { return _component2Id.size(); }
uint32_t getComponentEffectiveHashSize() const { return _nextId; }
+ const vespalib::SyncableThreadExecutor* first_executor() const;
+
private:
explicit SequencedTaskExecutor(std::unique_ptr<std::vector<std::unique_ptr<vespalib::SyncableThreadExecutor>>> executor);
diff --git a/staging_vespalib/src/vespa/vespalib/util/singleexecutor.h b/staging_vespalib/src/vespa/vespalib/util/singleexecutor.h
index 58cec52b2b0..721df3bf881 100644
--- a/staging_vespalib/src/vespa/vespalib/util/singleexecutor.h
+++ b/staging_vespalib/src/vespa/vespalib/util/singleexecutor.h
@@ -26,7 +26,9 @@ public:
SingleExecutor & sync() override;
void wakeup() override;
size_t getNumThreads() const override;
- uint32_t getTaskLimit() const { return _taskLimit.load(std::memory_order_relaxed); }
+ uint32_t getTaskLimit() const override { return _taskLimit.load(std::memory_order_relaxed); }
+ uint32_t get_watermark() const { return _watermark; }
+ duration get_reaction_time() const { return _reactionTime; }
Stats getStats() override;
SingleExecutor & shutdown() override;
private:
diff --git a/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java
index d65b41c11c7..e9d8dbd3642 100644
--- a/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java
+++ b/standalone-container/src/main/java/com/yahoo/container/standalone/StandaloneSubscriberFactory.java
@@ -20,6 +20,7 @@ import java.util.Set;
* @author ollivir
*/
public class StandaloneSubscriberFactory implements SubscriberFactory {
+
private final VespaModel root;
public StandaloneSubscriberFactory(VespaModel root) {
@@ -36,9 +37,6 @@ public class StandaloneSubscriberFactory implements SubscriberFactory {
}
@Override
- public boolean internalRedeploy() { return false; }
-
- @Override
public boolean configChanged() {
return generation == 0;
}
@@ -60,7 +58,7 @@ public class StandaloneSubscriberFactory implements SubscriberFactory {
}
@Override
- public long waitNextGeneration() {
+ public long waitNextGeneration(boolean isInitializing) {
generation++;
if (generation != 0) {
diff --git a/storage/src/tests/bucketdb/bucketmanagertest.cpp b/storage/src/tests/bucketdb/bucketmanagertest.cpp
index 8a508a2169d..89d82df62bd 100644
--- a/storage/src/tests/bucketdb/bucketmanagertest.cpp
+++ b/storage/src/tests/bucketdb/bucketmanagertest.cpp
@@ -14,6 +14,7 @@
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageapi/message/state.h>
#include <vespa/storageapi/message/bucketsplitting.h>
+#include <vespa/metrics/updatehook.h>
#include <tests/common/teststorageapp.h>
#include <tests/common/dummystoragelink.h>
#include <tests/common/testhelper.h>
diff --git a/storage/src/tests/common/CMakeLists.txt b/storage/src/tests/common/CMakeLists.txt
index 9e18a3ca7ca..400255964d6 100644
--- a/storage/src/tests/common/CMakeLists.txt
+++ b/storage/src/tests/common/CMakeLists.txt
@@ -12,6 +12,7 @@ vespa_add_library(storage_testcommon TEST
vespa_add_executable(storage_common_gtest_runner_app TEST
SOURCES
+ bucket_utils_test.cpp
global_bucket_space_distribution_converter_test.cpp
gtest_runner.cpp
metricstest.cpp
diff --git a/storage/src/tests/common/bucket_utils_test.cpp b/storage/src/tests/common/bucket_utils_test.cpp
new file mode 100644
index 00000000000..7cf6ee0af9f
--- /dev/null
+++ b/storage/src/tests/common/bucket_utils_test.cpp
@@ -0,0 +1,30 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/storage/common/bucket_utils.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using document::BucketId;
+using storage::get_super_bucket_key;
+constexpr uint8_t MUB = storage::spi::BucketLimits::MinUsedBits;
+
+TEST(SuperBucketKeyTest, super_bucket_key_is_min_used_bits_of_msb_of_bucket_id_key)
+{
+ // Note that bits are reversed when creating a key from the bucket id
+ EXPECT_EQ(0x0F, get_super_bucket_key(BucketId(MUB, 0x1F0)));
+ EXPECT_EQ(0x0F, get_super_bucket_key(BucketId(MUB + 1, 0x1F0)));
+ EXPECT_EQ(0x0F, get_super_bucket_key(BucketId(MUB, 0x2F0)));
+ EXPECT_EQ(0x0F, get_super_bucket_key(BucketId(MUB + 1, 0x2F0)));
+
+ EXPECT_EQ(0xF4, get_super_bucket_key(BucketId(MUB, 0x12F)));
+ EXPECT_EQ(0xF4, get_super_bucket_key(BucketId(MUB + 1, 0x12F)));
+ EXPECT_EQ(0xF4, get_super_bucket_key(BucketId(MUB, 0x22F)));
+ EXPECT_EQ(0xF4, get_super_bucket_key(BucketId(MUB + 1, 0x22F)));
+}
+
+TEST(SuperBucketKeyTest, super_bucket_key_is_zero_when_bucket_id_is_zero)
+{
+ EXPECT_EQ(0, get_super_bucket_key(BucketId()));
+ EXPECT_EQ(0, get_super_bucket_key(BucketId(0)));
+}
+
diff --git a/storage/src/tests/common/metricstest.cpp b/storage/src/tests/common/metricstest.cpp
index fa46fce5e93..3f7e1036c08 100644
--- a/storage/src/tests/common/metricstest.cpp
+++ b/storage/src/tests/common/metricstest.cpp
@@ -5,6 +5,7 @@
#include <vespa/storage/bucketdb/bucketmanager.h>
#include <vespa/storage/common/statusmetricconsumer.h>
#include <vespa/storage/persistence/filestorage/filestormanager.h>
+#include <vespa/storage/persistence/filestorage/filestormetrics.h>
#include <vespa/storage/visiting/visitormetrics.h>
#include <tests/common/teststorageapp.h>
#include <tests/common/testhelper.h>
@@ -79,8 +80,7 @@ void MetricsTest::SetUp() {
} catch (config::InvalidConfigException& e) {
fprintf(stderr, "%s\n", e.what());
}
- _metricManager = std::make_unique<metrics::MetricManager>(
- std::make_unique<MetricClock>(*_clock));
+ _metricManager = std::make_unique<metrics::MetricManager>(std::make_unique<MetricClock>(*_clock));
_topSet.reset(new metrics::MetricSet("vds", {}, ""));
{
metrics::MetricLockGuard guard(_metricManager->getMetricLock());
@@ -92,17 +92,15 @@ void MetricsTest::SetUp() {
*_metricManager,
"status");
- documentapi::LoadTypeSet::SP loadTypes(_node->getLoadTypes());
-
- _filestorMetrics = std::make_shared<FileStorMetrics>(_node->getLoadTypes()->getMetricLoadTypes());
- _filestorMetrics->initDiskMetrics(loadTypes->getMetricLoadTypes(), 1, 1);
+ _filestorMetrics = std::make_shared<FileStorMetrics>();
+ _filestorMetrics->initDiskMetrics(1, 1);
_topSet->registerMetric(*_filestorMetrics);
_bucketManagerMetrics = std::make_shared<BucketManagerMetrics>(_node->getComponentRegister().getBucketSpaceRepo());
_topSet->registerMetric(*_bucketManagerMetrics);
_visitorMetrics = std::make_shared<VisitorMetrics>();
- _visitorMetrics->initThreads(4, loadTypes->getMetricLoadTypes());
+ _visitorMetrics->initThreads(4);
_topSet->registerMetric(*_visitorMetrics);
_metricManager->init(_config->getConfigId(), _node->getThreadPool());
}
@@ -136,31 +134,29 @@ void MetricsTest::createFakeLoad()
{
FileStorDiskMetrics& disk(*_filestorMetrics->disk);
disk.queueSize.addValue(4 * n);
- //disk.averageQueueWaitingTime[documentapi::LoadType::DEFAULT].addValue(10 * n);
+ disk.averageQueueWaitingTime.addValue(10 * n);
disk.pendingMerges.addValue(4 * n);
for (uint32_t j=0; j<disk.threads.size(); ++j) {
FileStorThreadMetrics& thread(*disk.threads[j]);
thread.operations.inc(120 * n);
thread.failedOperations.inc(2 * n);
- using documentapi::LoadType;
-
- thread.put[LoadType::DEFAULT].count.inc(10 * n);
- thread.put[LoadType::DEFAULT].latency.addValue(5 * n);
- thread.get[LoadType::DEFAULT].count.inc(12 * n);
- thread.get[LoadType::DEFAULT].notFound.inc(2 * n);
- thread.get[LoadType::DEFAULT].latency.addValue(3 * n);
- thread.remove[LoadType::DEFAULT].count.inc(6 * n);
- thread.remove[LoadType::DEFAULT].notFound.inc(1 * n);
- thread.remove[LoadType::DEFAULT].latency.addValue(2 * n);
- thread.update[LoadType::DEFAULT].count.inc(2 * n);
- thread.update[LoadType::DEFAULT].notFound.inc(1 * n);
- thread.update[LoadType::DEFAULT].latencyRead.addValue(2 * n);
- thread.update[LoadType::DEFAULT].latency.addValue(7 * n);
- thread.revert[LoadType::DEFAULT].count.inc(2 * n);
- thread.revert[LoadType::DEFAULT].notFound.inc(n / 2);
- thread.revert[LoadType::DEFAULT].latency.addValue(2 * n);
- thread.visit[LoadType::DEFAULT].count.inc(6 * n);
+ thread.put.count.inc(10 * n);
+ thread.put.latency.addValue(5 * n);
+ thread.get.count.inc(12 * n);
+ thread.get.notFound.inc(2 * n);
+ thread.get.latency.addValue(3 * n);
+ thread.remove.count.inc(6 * n);
+ thread.remove.notFound.inc(1 * n);
+ thread.remove.latency.addValue(2 * n);
+ thread.update.count.inc(2 * n);
+ thread.update.notFound.inc(1 * n);
+ thread.update.latencyRead.addValue(2 * n);
+ thread.update.latency.addValue(7 * n);
+ thread.revert.count.inc(2 * n);
+ thread.revert.notFound.inc(n / 2);
+ thread.revert.latency.addValue(2 * n);
+ thread.visit.count.inc(6 * n);
thread.deleteBuckets.count.inc(1 * n);
thread.repairs.count.inc(3 * n);
@@ -186,12 +182,12 @@ void MetricsTest::createFakeLoad()
for (uint32_t i=0; i<_visitorMetrics->threads.size(); ++i) {
VisitorThreadMetrics& thread(*_visitorMetrics->threads[i]);
thread.queueSize.addValue(2);
- thread.averageQueueWaitingTime[documentapi::LoadType::DEFAULT].addValue(10);
- thread.averageVisitorLifeTime[documentapi::LoadType::DEFAULT].addValue(1000);
- thread.createdVisitors[documentapi::LoadType::DEFAULT].inc(5 * n);
- thread.abortedVisitors[documentapi::LoadType::DEFAULT].inc(1 * n);
- thread.completedVisitors[documentapi::LoadType::DEFAULT].inc(4 * n);
- thread.failedVisitors[documentapi::LoadType::DEFAULT].inc(2 * n);
+ thread.averageQueueWaitingTime.addValue(10);
+ thread.averageVisitorLifeTime.addValue(1000);
+ thread.createdVisitors.inc(5 * n);
+ thread.abortedVisitors.inc(1 * n);
+ thread.completedVisitors.inc(4 * n);
+ thread.failedVisitors.inc(2 * n);
}
_clock->addSecondsToTime(60);
_metricManager->timeChangedNotification();
@@ -241,8 +237,7 @@ TEST_F(MetricsTest, snapshot_presenting) {
LOG(debug, "Adding to get metric");
- using documentapi::LoadType;
- thread0.get[LoadType::DEFAULT].count.inc(1);
+ thread0.get.count.inc(1);
LOG(debug, "Waiting for 5 minute snapshot to be taken");
// Wait until active metrics have been added to 5 min snapshot and reset
@@ -258,7 +253,7 @@ TEST_F(MetricsTest, snapshot_presenting) {
}
LOG(debug, "5 minute snapshot should have been taken. Adding put count");
- thread0.put[LoadType::DEFAULT].count.inc(1);
+ thread0.put.count.inc(1);
// Verify that active metrics have set put count but not get count
ASSERT_METRIC(-2, "vds.filestor.alldisks.allthreads.put.sum.count", 1);
diff --git a/storage/src/tests/common/teststorageapp.cpp b/storage/src/tests/common/teststorageapp.cpp
index e904f690bde..04dc1a03dd3 100644
--- a/storage/src/tests/common/teststorageapp.cpp
+++ b/storage/src/tests/common/teststorageapp.cpp
@@ -41,13 +41,13 @@ TestStorageApp::TestStorageApp(StorageComponentRegisterImpl::UP compReg,
_docMan(),
_nodeStateUpdater(type),
_configId(configId),
+ _node_identity("test_cluster", type, index),
_initialized(false)
{
// Use config to adjust values
vespalib::string clusterName = "mycluster";
uint32_t redundancy = 2;
uint32_t nodeCount = 10;
- documentapi::LoadTypeSet::SP loadTypes;
if (!configId.empty()) {
config::ConfigUri uri(configId);
std::unique_ptr<vespa::config::content::core::StorServerConfig> serverConfig = config::ConfigGetter<vespa::config::content::core::StorServerConfig>::getConfig(uri.getConfigId(), uri.getContext());
@@ -55,15 +55,8 @@ TestStorageApp::TestStorageApp(StorageComponentRegisterImpl::UP compReg,
if (index == 0xffff) index = serverConfig->nodeIndex;
redundancy = config::ConfigGetter<vespa::config::content::StorDistributionConfig>::getConfig(uri.getConfigId(), uri.getContext())->redundancy;
nodeCount = config::ConfigGetter<vespa::config::content::FleetcontrollerConfig>::getConfig(uri.getConfigId(), uri.getContext())->totalStorageCount;
- _compReg.setPriorityConfig(
- *config::ConfigGetter<StorageComponent::PriorityConfig>
- ::getConfig(uri.getConfigId(), uri.getContext()));
- loadTypes = std::make_shared<documentapi::LoadTypeSet>(
- *config::ConfigGetter<vespa::config::content::LoadTypeConfig>
- ::getConfig(uri.getConfigId(), uri.getContext()));
} else {
if (index == 0xffff) index = 0;
- loadTypes.reset(new documentapi::LoadTypeSet);
}
if (index >= nodeCount) nodeCount = index + 1;
if (redundancy > nodeCount) redundancy = nodeCount;
@@ -71,7 +64,6 @@ TestStorageApp::TestStorageApp(StorageComponentRegisterImpl::UP compReg,
_compReg.setNodeInfo(clusterName, type, index);
_compReg.setNodeStateUpdater(_nodeStateUpdater);
_compReg.setDocumentTypeRepo(_docMan.getTypeRepoSP());
- _compReg.setLoadTypes(loadTypes);
_compReg.setBucketIdFactory(document::BucketIdFactory());
auto distr = std::make_shared<lib::Distribution>(
lib::Distribution::getDefaultDistributionConfig(redundancy, nodeCount));
diff --git a/storage/src/tests/common/teststorageapp.h b/storage/src/tests/common/teststorageapp.h
index dffe1da7a9a..4a49b5d7953 100644
--- a/storage/src/tests/common/teststorageapp.h
+++ b/storage/src/tests/common/teststorageapp.h
@@ -18,17 +18,17 @@
#pragma once
#include "testnodestateupdater.h"
+#include <vespa/document/base/testdocman.h>
+#include <vespa/document/bucket/fixed_bucket_spaces.h>
+#include <vespa/persistence/spi/persistenceprovider.h>
#include <vespa/storage/bucketdb/storbucketdb.h>
#include <vespa/storage/common/doneinitializehandler.h>
+#include <vespa/storage/common/node_identity.h>
#include <vespa/storage/common/nodestateupdater.h>
-#include <vespa/storage/storageserver/framework.h>
#include <vespa/storage/frameworkimpl/component/distributorcomponentregisterimpl.h>
#include <vespa/storage/frameworkimpl/component/servicelayercomponentregisterimpl.h>
#include <vespa/storageframework/defaultimplementation/clock/realclock.h>
#include <vespa/storageframework/defaultimplementation/component/testcomponentregister.h>
-#include <vespa/persistence/spi/persistenceprovider.h>
-#include <vespa/document/bucket/fixed_bucket_spaces.h>
-#include <vespa/document/base/testdocman.h>
#include <vespa/vespalib/util/sequencedtaskexecutor.h>
#include <atomic>
@@ -50,6 +50,7 @@ protected:
document::TestDocMan _docMan;
TestNodeStateUpdater _nodeStateUpdater;
vespalib::string _configId;
+ NodeIdentity _node_identity;
std::atomic<bool> _initialized;
public:
@@ -81,12 +82,11 @@ public:
const document::BucketIdFactory& getBucketIdFactory()
{ return _compReg.getBucketIdFactory(); }
TestNodeStateUpdater& getStateUpdater() { return _nodeStateUpdater; }
- documentapi::LoadTypeSet::SP getLoadTypes()
- { return _compReg.getLoadTypes(); }
lib::Distribution::SP getDistribution()
{ return _compReg.getDistribution(); }
TestNodeStateUpdater& getNodeStateUpdater() { return _nodeStateUpdater; }
uint16_t getIndex() const { return _compReg.getIndex(); }
+ const NodeIdentity& node_identity() const noexcept { return _node_identity; }
// The storage app also implements the done initializer interface, so it can
// be sent to components needing this.
diff --git a/storage/src/tests/distributor/CMakeLists.txt b/storage/src/tests/distributor/CMakeLists.txt
index 1e70b6a4881..810ffb550bf 100644
--- a/storage/src/tests/distributor/CMakeLists.txt
+++ b/storage/src/tests/distributor/CMakeLists.txt
@@ -10,6 +10,7 @@ vespa_add_executable(storage_distributor_gtest_runner_app TEST
bucketdbupdatertest.cpp
bucketgctimecalculatortest.cpp
bucketstateoperationtest.cpp
+ distributor_bucket_space_test.cpp
distributor_host_info_reporter_test.cpp
distributor_message_sender_stub.cpp
distributortest.cpp
@@ -31,6 +32,7 @@ vespa_add_executable(storage_distributor_gtest_runner_app TEST
pendingmessagetrackertest.cpp
persistence_metrics_set_test.cpp
putoperationtest.cpp
+ read_for_write_visitor_operation_test.cpp
removebucketoperationtest.cpp
removelocationtest.cpp
removeoperationtest.cpp
diff --git a/storage/src/tests/distributor/blockingoperationstartertest.cpp b/storage/src/tests/distributor/blockingoperationstartertest.cpp
index 9a9e04f0f33..5203fec2462 100644
--- a/storage/src/tests/distributor/blockingoperationstartertest.cpp
+++ b/storage/src/tests/distributor/blockingoperationstartertest.cpp
@@ -2,6 +2,7 @@
#include <vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h>
#include <vespa/storage/distributor/blockingoperationstarter.h>
#include <vespa/storage/distributor/pendingmessagetracker.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
#include <tests/distributor/maintenancemocks.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/vespalib/gtest/gtest.h>
@@ -26,6 +27,7 @@ struct BlockingOperationStarterTest : Test {
std::unique_ptr<MockOperationStarter> _starterImpl;
std::unique_ptr<StorageComponentRegisterImpl> _compReg;
std::unique_ptr<PendingMessageTracker> _messageTracker;
+ std::unique_ptr<OperationSequencer> _operation_sequencer;
std::unique_ptr<BlockingOperationStarter> _operationStarter;
void SetUp() override;
@@ -39,7 +41,8 @@ BlockingOperationStarterTest::SetUp()
_compReg->setClock(_clock);
_clock.setAbsoluteTimeInSeconds(1);
_messageTracker = std::make_unique<PendingMessageTracker>(*_compReg);
- _operationStarter = std::make_unique<BlockingOperationStarter>(*_messageTracker, *_starterImpl);
+ _operation_sequencer = std::make_unique<OperationSequencer>();
+ _operationStarter = std::make_unique<BlockingOperationStarter>(*_messageTracker, *_operation_sequencer, *_starterImpl);
}
TEST_F(BlockingOperationStarterTest, operation_not_blocked_when_no_messages_pending) {
diff --git a/storage/src/tests/distributor/bucketdatabasetest.cpp b/storage/src/tests/distributor/bucketdatabasetest.cpp
index 7f9825d32fc..6aadc6c01e1 100644
--- a/storage/src/tests/distributor/bucketdatabasetest.cpp
+++ b/storage/src/tests/distributor/bucketdatabasetest.cpp
@@ -625,6 +625,22 @@ struct InsertAtEndMergingProcessor : BucketDatabase::MergingProcessor {
}
};
+struct EntryUpdateProcessor : BucketDatabase::EntryUpdateProcessor {
+ using Entry = BucketDatabase::Entry;
+ std::function<bool(Entry&)> _func;
+ EntryUpdateProcessor(std::function<bool(Entry&)> func)
+ : _func(std::move(func))
+ {
+ }
+ ~EntryUpdateProcessor() override = default;
+ BucketDatabase::Entry create_entry(const document::BucketId& bucket) const override {
+ return BucketDatabase::Entry(bucket, BucketInfo());
+ }
+ bool process_entry(Entry& entry) const override {
+ return(_func(entry));
+ }
+};
+
}
TEST_P(BucketDatabaseTest, merge_keep_unchanged_result_does_not_alter_db_contents) {
@@ -704,6 +720,25 @@ TEST_P(BucketDatabaseTest, merge_can_insert_entry_at_end) {
"node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n");
}
+TEST_P(BucketDatabaseTest, process_update)
+{
+ using Entry = BucketDatabase::Entry;
+ document::BucketId bucket(16, 2);
+ EXPECT_EQ(dump_db(db()), "");
+ auto update_entry = [](Entry& entry) { entry->addNode(BC(0), toVector<uint16_t>(0)); return true; };
+ EntryUpdateProcessor update_processor(update_entry);
+ db().process_update(bucket, update_processor, false);
+ EXPECT_EQ(dump_db(db()), "");
+ db().process_update(bucket, update_processor, true);
+ EXPECT_EQ(dump_db(db()),
+ "BucketId(0x4000000000000002) : "
+ "node(idx=0,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n");
+ auto remove_entry = [](Entry&) noexcept { return false; };
+ EntryUpdateProcessor remove_processor(remove_entry);
+ db().process_update(bucket, remove_processor, false);
+ EXPECT_EQ(dump_db(db()), "");
+}
+
TEST_P(BucketDatabaseTest, DISABLED_benchmark_const_iteration) {
constexpr uint32_t superbuckets = 1u << 16u;
constexpr uint32_t sub_buckets = 14;
diff --git a/storage/src/tests/distributor/bucketdbmetricupdatertest.cpp b/storage/src/tests/distributor/bucketdbmetricupdatertest.cpp
index e0c3cf161bb..6b8a6608c34 100644
--- a/storage/src/tests/distributor/bucketdbmetricupdatertest.cpp
+++ b/storage/src/tests/distributor/bucketdbmetricupdatertest.cpp
@@ -23,14 +23,11 @@ struct BucketDBMetricUpdaterTest : Test {
using NodeToReplicasMap = std::unordered_map<uint16_t, uint32_t>;
NodeToReplicasMap replicaStatsOf(BucketDBMetricUpdater& metricUpdater);
- metrics::LoadTypeSet _loadTypes;
-
BucketDBMetricUpdaterTest();
};
BucketDBMetricUpdaterTest::BucketDBMetricUpdaterTest()
{
- _loadTypes.push_back(metrics::LoadType(0, "foo"));
}
namespace {
@@ -65,7 +62,7 @@ makeInfo(uint32_t copy0Crc, uint32_t copy1Crc)
TEST_F(BucketDBMetricUpdaterTest, doc_and_byte_counts_are_updated) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
EXPECT_FALSE(metricUpdater.hasCompletedRound());
@@ -104,7 +101,7 @@ TEST_F(BucketDBMetricUpdaterTest, doc_and_byte_counts_are_updated) {
TEST_F(BucketDBMetricUpdaterTest, bucket_db_memory_usage_metrics_are_updated) {
BucketDBMetricUpdater metric_updater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
vespalib::MemoryUsage mem_usage;
mem_usage.incAllocatedBytes(1000);
@@ -138,7 +135,7 @@ TEST_F(BucketDBMetricUpdaterTest, bucket_db_memory_usage_metrics_are_updated) {
TEST_F(BucketDBMetricUpdaterTest, buckets_with_too_few_and_too_many_copies) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
metricUpdater.completeRound();
metricUpdater.getLastCompleteStats().propagateMetrics(ims, dms);
@@ -186,7 +183,7 @@ TEST_F(BucketDBMetricUpdaterTest, buckets_with_too_few_and_too_many_copies) {
TEST_F(BucketDBMetricUpdaterTest, buckets_with_varying_trustedness) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
metricUpdater.completeRound(false);
metricUpdater.getLastCompleteStats().propagateMetrics(ims, dms);
@@ -222,7 +219,7 @@ TEST_F(BucketDBMetricUpdaterTest, buckets_with_varying_trustedness) {
TEST_F(BucketDBMetricUpdaterTest, pick_counts_from_trusted_copy) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
// First copy added is implicitly trusted, but it is not the largest.
BucketDatabase::Entry e(document::BucketId(16, 2), makeInfo(100, 200));
@@ -237,7 +234,7 @@ TEST_F(BucketDBMetricUpdaterTest, pick_counts_from_trusted_copy) {
TEST_F(BucketDBMetricUpdaterTest, pick_largest_copy_if_no_trusted) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
// No trusted copies, so must pick second copy.
BucketInfo info(makeInfo(100, 200));
@@ -254,7 +251,7 @@ TEST_F(BucketDBMetricUpdaterTest, pick_largest_copy_if_no_trusted) {
TEST_F(BucketDBMetricUpdaterTest, complete_round_clears_working_state) {
BucketDBMetricUpdater metricUpdater;
IdealStateMetricSet ims;
- DistributorMetricSet dms(_loadTypes);
+ DistributorMetricSet dms;
{
BucketDatabase::Entry e(document::BucketId(16, 1), makeInfo(10));
diff --git a/storage/src/tests/distributor/bucketdbupdatertest.cpp b/storage/src/tests/distributor/bucketdbupdatertest.cpp
index fa540669b4b..22d9c945262 100644
--- a/storage/src/tests/distributor/bucketdbupdatertest.cpp
+++ b/storage/src/tests/distributor/bucketdbupdatertest.cpp
@@ -144,8 +144,7 @@ public:
api::RequestBucketInfoReply::EntryVector &vec = sreply->getBucketInfo();
for (uint32_t i=0; i<bucketCount + invalidBucketCount; i++) {
- if (!getBucketDBUpdater().getDistributorComponent()
- .ownsBucketInState(state, makeDocumentBucket(document::BucketId(16, i)))) {
+ if (!getDistributorBucketSpace().owns_bucket_in_state(state, document::BucketId(16, i))) {
continue;
}
@@ -392,7 +391,8 @@ public:
}
api::StorageMessageAddress storageAddress(uint16_t node) {
- return api::StorageMessageAddress("storage", lib::NodeType::STORAGE, node);
+ static vespalib::string _storage("storage");
+ return api::StorageMessageAddress(&_storage, lib::NodeType::STORAGE, node);
}
std::string getSentNodes(const std::string& oldClusterState,
@@ -1778,8 +1778,7 @@ TEST_F(BucketDBUpdaterTest, no_db_resurrection_for_bucket_not_owned_in_current_s
uint32_t expectedMsgs = messageCount(2), dummyBucketsToReturn = 1;
ASSERT_NO_FATAL_FAILURE(setAndEnableClusterState(stateAfter, expectedMsgs, dummyBucketsToReturn));
}
- EXPECT_FALSE(getBucketDBUpdater().getDistributorComponent()
- .ownsBucketInCurrentState(makeDocumentBucket(bucket)));
+ EXPECT_FALSE(getDistributorBucketSpace().get_bucket_ownership_flags(bucket).owned_in_current_state());
ASSERT_NO_FATAL_FAILURE(sendFakeReplyForSingleBucketRequest(*rbi));
@@ -1805,10 +1804,8 @@ TEST_F(BucketDBUpdaterTest, no_db_resurrection_for_bucket_not_owned_in_pending_s
lib::ClusterState stateAfter("distributor:3 storage:3");
// Set, but _don't_ enable cluster state. We want it to be pending.
setSystemState(stateAfter);
- EXPECT_TRUE(getBucketDBUpdater().getDistributorComponent()
- .ownsBucketInCurrentState(makeDocumentBucket(bucket)));
- EXPECT_FALSE(getBucketDBUpdater()
- .checkOwnershipInPendingState(makeDocumentBucket(bucket)).isOwned());
+ EXPECT_TRUE(getDistributorBucketSpace().get_bucket_ownership_flags(bucket).owned_in_current_state());
+ EXPECT_FALSE(getDistributorBucketSpace().get_bucket_ownership_flags(bucket).owned_in_pending_state());
ASSERT_NO_FATAL_FAILURE(sendFakeReplyForSingleBucketRequest(*rbi));
@@ -1928,8 +1925,7 @@ TEST_F(BucketDBUpdaterTest, changed_distribution_config_does_not_elide_bucket_db
setDistribution(getDistConfig6Nodes2Groups());
getBucketDatabase().forEach(*func_processor([&](const auto& e) {
- EXPECT_TRUE(getBucketDBUpdater()
- .checkOwnershipInPendingState(makeDocumentBucket(e.getBucketId())).isOwned());
+ EXPECT_TRUE(getDistributorBucketSpace().get_bucket_ownership_flags(e.getBucketId()).owned_in_pending_state());
}));
}
@@ -2389,8 +2385,7 @@ TEST_F(BucketDBUpdaterTest, non_owned_buckets_moved_to_read_only_db_on_ownership
std::unordered_set<Bucket, Bucket::hash> buckets_not_owned_in_pending_state;
for_each_bucket(mutable_repo(), [&](const auto& space, const auto& entry) {
- if (!getBucketDBUpdater().getDistributorComponent()
- .ownsBucketInState(pending_state, makeDocumentBucket(entry.getBucketId()))) {
+ if (!getDistributorBucketSpace().owns_bucket_in_state(pending_state, entry.getBucketId())) {
buckets_not_owned_in_pending_state.insert(Bucket(space, entry.getBucketId()));
}
});
diff --git a/storage/src/tests/distributor/bucketstateoperationtest.cpp b/storage/src/tests/distributor/bucketstateoperationtest.cpp
index c62d0a62ed3..4abf47cd210 100644
--- a/storage/src/tests/distributor/bucketstateoperationtest.cpp
+++ b/storage/src/tests/distributor/bucketstateoperationtest.cpp
@@ -5,6 +5,7 @@
#include <vespa/storage/distributor/distributor.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using namespace ::testing;
@@ -39,7 +40,7 @@ TEST_F(BucketStateOperationTest, activate_single_node) {
BucketAndNodes bucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(0));
std::vector<uint16_t> active;
active.push_back(0);
- SetBucketStateOperation op("storage", bucketAndNodes, active);
+ SetBucketStateOperation op(dummy_cluster_context, bucketAndNodes, active);
op.setIdealStateManager(&getIdealStateManager());
op.start(_sender, framework::MilliSecTime(0));
@@ -48,8 +49,7 @@ TEST_F(BucketStateOperationTest, activate_single_node) {
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SETBUCKETSTATE);
- EXPECT_EQ(api::StorageMessageAddress(
- "storage", lib::NodeType::STORAGE, 0).toString(),
+ EXPECT_EQ(api::StorageMessageAddress(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 0).toString(),
msg->getAddress()->toString());
auto& cmd = dynamic_cast<const api::SetBucketStateCommand&>(*msg);
@@ -76,7 +76,7 @@ TEST_F(BucketStateOperationTest, activate_and_deactivate_nodes) {
BucketAndNodes bucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(0, 1));
std::vector<uint16_t> active;
active.push_back(1);
- SetBucketStateOperation op("storage", bucketAndNodes, active);
+ SetBucketStateOperation op(dummy_cluster_context, bucketAndNodes, active);
op.setIdealStateManager(&getIdealStateManager());
op.start(_sender, framework::MilliSecTime(0));
@@ -85,8 +85,7 @@ TEST_F(BucketStateOperationTest, activate_and_deactivate_nodes) {
{
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SETBUCKETSTATE);
- EXPECT_EQ(api::StorageMessageAddress(
- "storage", lib::NodeType::STORAGE, 1).toString(),
+ EXPECT_EQ(api::StorageMessageAddress(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 1).toString(),
msg->getAddress()->toString());
auto& cmd = dynamic_cast<const api::SetBucketStateCommand&>(*msg);
@@ -101,8 +100,8 @@ TEST_F(BucketStateOperationTest, activate_and_deactivate_nodes) {
{
std::shared_ptr<api::StorageCommand> msg = _sender.command(1);
ASSERT_EQ(msg->getType(), api::MessageType::SETBUCKETSTATE);
- EXPECT_EQ(api::StorageMessageAddress(
- "storage", lib::NodeType::STORAGE, 0).toString(),
+ EXPECT_EQ(api::StorageMessageAddress(dummy_cluster_context.cluster_name_ptr(),
+ lib::NodeType::STORAGE, 0).toString(),
msg->getAddress()->toString());
auto& cmd = dynamic_cast<const api::SetBucketStateCommand&>(*msg);
@@ -133,7 +132,7 @@ TEST_F(BucketStateOperationTest, do_not_deactivate_if_activate_fails) {
BucketAndNodes bucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(0, 1));
std::vector<uint16_t> active;
active.push_back(1);
- SetBucketStateOperation op("storage", bucketAndNodes, active);
+ SetBucketStateOperation op(dummy_cluster_context, bucketAndNodes, active);
op.setIdealStateManager(&getIdealStateManager());
op.start(_sender, framework::MilliSecTime(0));
@@ -142,8 +141,8 @@ TEST_F(BucketStateOperationTest, do_not_deactivate_if_activate_fails) {
{
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SETBUCKETSTATE);
- EXPECT_EQ(api::StorageMessageAddress(
- "storage", lib::NodeType::STORAGE, 1).toString(),
+ EXPECT_EQ(api::StorageMessageAddress(dummy_cluster_context.cluster_name_ptr(),
+ lib::NodeType::STORAGE, 1).toString(),
msg->getAddress()->toString());
auto& cmd = dynamic_cast<const api::SetBucketStateCommand&>(*msg);
@@ -176,7 +175,7 @@ TEST_F(BucketStateOperationTest, bucket_db_not_updated_on_failure) {
BucketAndNodes bucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(0));
std::vector<uint16_t> active;
active.push_back(0);
- SetBucketStateOperation op("storage", bucketAndNodes, active);
+ SetBucketStateOperation op(dummy_cluster_context, bucketAndNodes, active);
op.setIdealStateManager(&getIdealStateManager());
op.start(_sender, framework::MilliSecTime(0));
@@ -185,8 +184,8 @@ TEST_F(BucketStateOperationTest, bucket_db_not_updated_on_failure) {
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SETBUCKETSTATE);
- EXPECT_EQ(api::StorageMessageAddress(
- "storage", lib::NodeType::STORAGE, 0).toString(),
+ EXPECT_EQ(api::StorageMessageAddress(dummy_cluster_context.cluster_name_ptr(),
+ lib::NodeType::STORAGE, 0).toString(),
msg->getAddress()->toString());
std::shared_ptr<api::StorageReply> reply(msg->makeReply().release());
diff --git a/storage/src/tests/distributor/distributor_bucket_space_test.cpp b/storage/src/tests/distributor/distributor_bucket_space_test.cpp
new file mode 100644
index 00000000000..8db7955b8a7
--- /dev/null
+++ b/storage/src/tests/distributor/distributor_bucket_space_test.cpp
@@ -0,0 +1,200 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/storage/distributor/distributor_bucket_space.h>
+#include <vespa/storage/distributor/distributor_bucket_space_repo.h>
+#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vdslib/state/clusterstate.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using document::BucketId;
+using storage::lib::ClusterState;
+using storage::lib::Distribution;
+
+namespace storage::distributor {
+
+namespace {
+
+std::shared_ptr<ClusterState> stable_state(std::make_shared<ClusterState>("distributor:4 storage:4 bits:8"));
+std::shared_ptr<ClusterState> node_1_down_state(std::make_shared<ClusterState>("distributor:4 .1.s:d storage:4 .1.s:d bits:8"));
+std::shared_ptr<ClusterState> node_1_retired_state(std::make_shared<ClusterState>("distributor:4 .1.s:d storage:4 .1.s:r bits:8"));
+std::shared_ptr<ClusterState> node_1_maintenance_state(std::make_shared<ClusterState>("distributor:4 .1.s:d storage:4 .1.s:m bits:8"));
+std::shared_ptr<Distribution> distribution_r1(std::make_shared<Distribution>(Distribution::getDefaultDistributionConfig(1, 4)));
+std::shared_ptr<Distribution> distribution_r2(std::make_shared<Distribution>(Distribution::getDefaultDistributionConfig(2, 4)));
+
+}
+
+struct DistributorBucketSpaceTest : public ::testing::Test
+{
+ using CountVector = std::vector<uint32_t>;
+
+ DistributorBucketSpace bucket_space;
+
+ DistributorBucketSpaceTest()
+ : ::testing::Test(),
+ bucket_space(0u)
+ {
+ }
+ ~DistributorBucketSpaceTest() = default;
+
+ // make normal buckets
+ std::vector<BucketId> make_normal_buckets();
+
+ // make deep split buckets. Ideal service layer nodes for a bucket changes for each split level when bucket used bits > 33.
+ std::vector<BucketId> make_deep_split_buckets(std::function<bool(BucketId)> owned);
+
+ // Count normal buckets using this distributor
+ uint32_t count_distributor_buckets(const std::vector<BucketId>& buckets);
+ // Count normal buckets using service layer node 0.
+ CountVector count_service_layer_buckets(const std::vector<BucketId>& buckets);
+ // Count normal buckets using this distributor and service layer node 0
+ CountVector count_buckets();
+ // Count deep split buckets using this distributor and service layer node 0.
+ CountVector count_deep_split_buckets();
+};
+
+std::vector<BucketId>
+DistributorBucketSpaceTest::make_normal_buckets()
+{
+ std::vector<BucketId> buckets;
+ uint16_t distribution_bits = bucket_space.getClusterState().getDistributionBitCount();
+ for (uint32_t i = 0; i < (1u << distribution_bits); ++i) {
+ buckets.emplace_back(distribution_bits, i);
+ }
+ return buckets;
+}
+
+std::vector<BucketId>
+DistributorBucketSpaceTest::make_deep_split_buckets(std::function<bool(BucketId)> owned)
+{
+ std::vector<BucketId> buckets;
+ uint16_t distribution_bits = bucket_space.getClusterState().getDistributionBitCount();
+ uint32_t bias = 0;
+ uint32_t bias_max = std::min(1u << distribution_bits, 1000u);
+ for (; bias < bias_max; ++bias) {
+ BucketId bucket(distribution_bits, bias);
+ if (owned(bucket)) {
+ break;
+ }
+ }
+ assert(bias < bias_max);
+ for (uint32_t i = 0; i < 100; ++i) {
+ buckets.emplace_back(42u, i * (1ul << 32) + bias);
+ }
+ return buckets;
+}
+
+uint32_t
+DistributorBucketSpaceTest::count_distributor_buckets(const std::vector<BucketId>& buckets)
+{
+ uint32_t owned_buckets = 0;
+ for (auto& bucket : buckets) {
+ bool owned = bucket_space.check_ownership_in_pending_and_current_state(bucket).isOwned();
+ if (owned) {
+ ++owned_buckets;
+ }
+ }
+ return owned_buckets;
+}
+
+DistributorBucketSpaceTest::CountVector
+DistributorBucketSpaceTest::count_service_layer_buckets(const std::vector<BucketId>& buckets)
+{
+ CountVector result(3);
+ std::vector<uint16_t> ideal_nodes;
+ for (auto& bucket : buckets) {
+ auto &ideal_nodes_bundle = bucket_space.get_ideal_service_layer_nodes_bundle(bucket);
+ for (uint32_t i = 0; i < 3; ++i) {
+ switch (i) {
+ case 0:
+ ideal_nodes = ideal_nodes_bundle.get_available_nodes();
+ break;
+ case 1:
+ ideal_nodes = ideal_nodes_bundle.get_available_nonretired_nodes();
+ break;
+ case 2:
+ ideal_nodes = ideal_nodes_bundle.get_available_nonretired_or_maintenance_nodes();
+ break;
+ default:
+ ;
+ }
+ for (auto node : ideal_nodes) {
+ if (node == 0u) {
+ ++result[i];
+ }
+ }
+ }
+ }
+ return result;
+}
+
+DistributorBucketSpaceTest::CountVector
+DistributorBucketSpaceTest::count_buckets()
+{
+ CountVector result;
+ auto buckets = make_normal_buckets();
+ result.push_back(count_distributor_buckets(buckets));
+ auto service_layer_result = count_service_layer_buckets(buckets);
+ result.insert(result.end(), service_layer_result.cbegin(), service_layer_result.cend());
+ return result;
+}
+
+DistributorBucketSpaceTest::CountVector
+DistributorBucketSpaceTest::count_deep_split_buckets()
+{
+ CountVector result;
+ auto buckets = make_deep_split_buckets([this](BucketId bucket) { return bucket_space.check_ownership_in_pending_and_current_state(bucket).isOwned(); });
+ result.push_back(count_distributor_buckets(buckets));
+ auto service_layer_result = count_service_layer_buckets(buckets);
+ result.insert(result.end(), service_layer_result.cbegin(), service_layer_result.cend());
+ return result;
+}
+
+TEST_F(DistributorBucketSpaceTest, check_owned_buckets)
+{
+ bucket_space.setDistribution(distribution_r1);
+ bucket_space.setClusterState(stable_state);
+ EXPECT_EQ((CountVector{64u, 64u, 64u, 64u}), count_buckets());
+ bucket_space.set_pending_cluster_state(node_1_down_state);
+ EXPECT_EQ((CountVector{64u, 64u, 64u, 64u}), count_buckets());
+ bucket_space.setClusterState(node_1_down_state);
+ bucket_space.set_pending_cluster_state({});
+ EXPECT_EQ((CountVector{86u, 86u, 86u, 86u}), count_buckets());
+ bucket_space.set_pending_cluster_state(stable_state);
+ EXPECT_EQ((CountVector{64u, 86u, 86u, 86u}), count_buckets());
+ bucket_space.setClusterState(stable_state);
+ bucket_space.set_pending_cluster_state({});
+ EXPECT_EQ((CountVector{64u, 64u, 64u, 64u}), count_buckets());
+ bucket_space.setDistribution(distribution_r2);
+ EXPECT_EQ((CountVector{64u, 125u, 125u, 125u}), count_buckets());
+ bucket_space.setClusterState(node_1_maintenance_state);
+ bucket_space.setDistribution(distribution_r1);
+ EXPECT_EQ((CountVector{86u, 86u, 86u, 64u}), count_buckets());
+ bucket_space.setClusterState(node_1_retired_state);
+ EXPECT_EQ((CountVector{86u, 64u, 86u, 86u}), count_buckets());
+}
+
+TEST_F(DistributorBucketSpaceTest, check_available_nodes)
+{
+ bucket_space.setDistribution(distribution_r1);
+ bucket_space.setClusterState(stable_state);
+ EXPECT_EQ((std::vector<bool>{true, true, true, true}), bucket_space.get_available_nodes());
+ bucket_space.set_pending_cluster_state(node_1_down_state);
+ EXPECT_EQ((std::vector<bool>{true, false, true, true}), bucket_space.get_available_nodes());
+ bucket_space.setClusterState(node_1_down_state);
+ bucket_space.set_pending_cluster_state({});
+ EXPECT_EQ((std::vector<bool>{true, false, true, true}), bucket_space.get_available_nodes());
+ bucket_space.set_pending_cluster_state(stable_state);
+ EXPECT_EQ((std::vector<bool>{true, false, true, true}), bucket_space.get_available_nodes());
+ bucket_space.setClusterState(stable_state);
+ bucket_space.set_pending_cluster_state({});
+ EXPECT_EQ((std::vector<bool>{true, true, true, true}), bucket_space.get_available_nodes());
+}
+
+TEST_F(DistributorBucketSpaceTest, check_owned_deep_split_buckets)
+{
+ bucket_space.setDistribution(distribution_r1);
+ bucket_space.setClusterState(stable_state);
+ EXPECT_EQ((CountVector{100u, 19u, 19u, 19u}), count_deep_split_buckets());
+}
+
+}
diff --git a/storage/src/tests/distributor/distributor_message_sender_stub.cpp b/storage/src/tests/distributor/distributor_message_sender_stub.cpp
index df894f1bb2c..bb0079744c2 100644
--- a/storage/src/tests/distributor/distributor_message_sender_stub.cpp
+++ b/storage/src/tests/distributor/distributor_message_sender_stub.cpp
@@ -11,8 +11,8 @@ namespace storage {
DistributorMessageSenderStub::DistributorMessageSenderStub()
: _stub_impl(),
- _cluster_name("storage"),
- _pending_message_tracker(nullptr)
+ _pending_message_tracker(nullptr),
+ _operation_sequencer(nullptr)
{}
DistributorMessageSenderStub::~DistributorMessageSenderStub() = default;
diff --git a/storage/src/tests/distributor/distributor_message_sender_stub.h b/storage/src/tests/distributor/distributor_message_sender_stub.h
index 440dee70d48..3791839f3fe 100644
--- a/storage/src/tests/distributor/distributor_message_sender_stub.h
+++ b/storage/src/tests/distributor/distributor_message_sender_stub.h
@@ -6,13 +6,14 @@
#include <tests/common/message_sender_stub.h>
#include <cassert>
#include <string>
+#include "dummy_cluster_context.h"
namespace storage {
class DistributorMessageSenderStub : public distributor::DistributorMessageSender {
MessageSenderStub _stub_impl;
- std::string _cluster_name;
distributor::PendingMessageTracker* _pending_message_tracker;
+ distributor::OperationSequencer* _operation_sequencer;
public:
DistributorMessageSenderStub();
@@ -82,8 +83,8 @@ public:
return 0;
}
- const std::string& getClusterName() const override {
- return _cluster_name;
+ const ClusterContext& cluster_context() const override {
+ return dummy_cluster_context;
}
const distributor::PendingMessageTracker& getPendingMessageTracker() const override {
@@ -94,6 +95,15 @@ public:
void setPendingMessageTracker(distributor::PendingMessageTracker& tracker) {
_pending_message_tracker = &tracker;
}
+
+ const distributor::OperationSequencer& operation_sequencer() const noexcept override {
+ assert(_operation_sequencer);
+ return *_operation_sequencer;
+ }
+
+ void set_operation_sequencer(distributor::OperationSequencer& op_seq) {
+ _operation_sequencer = &op_seq;
+ }
};
}
diff --git a/storage/src/tests/distributor/distributortest.cpp b/storage/src/tests/distributor/distributortest.cpp
index 542ad3c0752..928373d516b 100644
--- a/storage/src/tests/distributor/distributortest.cpp
+++ b/storage/src/tests/distributor/distributortest.cpp
@@ -13,8 +13,10 @@
#include <vespa/document/test/make_bucket_space.h>
#include <vespa/storage/config/config-stor-distributormanager.h>
#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/distributor_bucket_space.h>
#include <vespa/storage/distributor/distributormetricsset.h>
#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/metrics/updatehook.h>
#include <thread>
#include <vespa/vespalib/gtest/gtest.h>
#include <gmock/gmock.h>
@@ -119,14 +121,14 @@ struct DistributorTest : Test, DistributorTestUtil {
}
}
- getExternalOperationHandler().removeNodesFromDB(makeDocumentBucket(document::BucketId(16, 1)), removedNodes);
+ distributor_component().removeNodesFromDB(makeDocumentBucket(document::BucketId(16, 1)), removedNodes);
uint32_t flags(DatabaseUpdate::CREATE_IF_NONEXISTING
| (resetTrusted ? DatabaseUpdate::RESET_TRUSTED : 0));
- getExternalOperationHandler().updateBucketDatabase(makeDocumentBucket(document::BucketId(16, 1)),
- changedNodes,
- flags);
+ distributor_component().updateBucketDatabase(makeDocumentBucket(document::BucketId(16, 1)),
+ changedNodes,
+ flags);
}
std::string retVal = dumpBucket(document::BucketId(16, 1));
@@ -452,7 +454,7 @@ TEST_F(DistributorTest, metric_update_hook_updates_pending_maintenance_metrics)
// Force trigger update hook
std::mutex l;
- distributor_metric_update_hook().updateMetrics(std::unique_lock(l));
+ distributor_metric_update_hook().updateMetrics(metrics::MetricLockGuard(l));
// Metrics should now be updated to the last complete working state
{
const IdealStateMetricSet& metrics(getIdealStateManager().getMetrics());
@@ -481,7 +483,7 @@ TEST_F(DistributorTest, bucket_db_memory_usage_metrics_only_updated_at_fixed_tim
tickDistributorNTimes(10);
std::mutex l;
- distributor_metric_update_hook().updateMetrics(std::unique_lock(l));
+ distributor_metric_update_hook().updateMetrics(metrics::MetricLockGuard(l));
auto* m = getDistributor().getMetrics().mutable_dbs.memory_usage.getMetric("used_bytes");
ASSERT_TRUE(m != nullptr);
auto last_used = m->getLongValue("last");
@@ -495,7 +497,7 @@ TEST_F(DistributorTest, bucket_db_memory_usage_metrics_only_updated_at_fixed_tim
const auto sample_interval_sec = db_sample_interval_sec(getDistributor());
getClock().setAbsoluteTimeInSeconds(1000 + sample_interval_sec - 1); // Not there yet.
tickDistributorNTimes(50);
- distributor_metric_update_hook().updateMetrics(std::unique_lock(l));
+ distributor_metric_update_hook().updateMetrics(metrics::MetricLockGuard(l));
m = getDistributor().getMetrics().mutable_dbs.memory_usage.getMetric("used_bytes");
auto now_used = m->getLongValue("last");
@@ -503,7 +505,7 @@ TEST_F(DistributorTest, bucket_db_memory_usage_metrics_only_updated_at_fixed_tim
getClock().setAbsoluteTimeInSeconds(1000 + sample_interval_sec + 1);
tickDistributorNTimes(10);
- distributor_metric_update_hook().updateMetrics(std::unique_lock(l));
+ distributor_metric_update_hook().updateMetrics(metrics::MetricLockGuard(l));
m = getDistributor().getMetrics().mutable_dbs.memory_usage.getMetric("used_bytes");
now_used = m->getLongValue("last");
@@ -556,15 +558,13 @@ TEST_F(DistributorTest, no_db_resurrection_for_bucket_not_owned_in_pending_state
getBucketDBUpdater().onSetSystemState(stateCmd);
document::BucketId nonOwnedBucket(16, 3);
- EXPECT_FALSE(getBucketDBUpdater().checkOwnershipInPendingState(makeDocumentBucket(nonOwnedBucket)).isOwned());
- EXPECT_FALSE(getBucketDBUpdater().getDistributorComponent()
- .checkOwnershipInPendingAndCurrentState(makeDocumentBucket(nonOwnedBucket))
- .isOwned());
+ EXPECT_FALSE(getDistributorBucketSpace().get_bucket_ownership_flags(nonOwnedBucket).owned_in_pending_state());
+ EXPECT_FALSE(getDistributorBucketSpace().check_ownership_in_pending_and_current_state(nonOwnedBucket).isOwned());
std::vector<BucketCopy> copies;
copies.emplace_back(1234, 0, api::BucketInfo(0x567, 1, 2));
- getExternalOperationHandler().updateBucketDatabase(makeDocumentBucket(nonOwnedBucket), copies,
- DatabaseUpdate::CREATE_IF_NONEXISTING);
+ distributor_component().updateBucketDatabase(makeDocumentBucket(nonOwnedBucket), copies,
+ DatabaseUpdate::CREATE_IF_NONEXISTING);
EXPECT_EQ("NONEXISTING", dumpBucket(nonOwnedBucket));
}
@@ -576,8 +576,8 @@ TEST_F(DistributorTest, added_db_buckets_without_gc_timestamp_implicitly_get_cur
std::vector<BucketCopy> copies;
copies.emplace_back(1234, 0, api::BucketInfo(0x567, 1, 2));
- getExternalOperationHandler().updateBucketDatabase(makeDocumentBucket(bucket), copies,
- DatabaseUpdate::CREATE_IF_NONEXISTING);
+ distributor_component().updateBucketDatabase(makeDocumentBucket(bucket), copies,
+ DatabaseUpdate::CREATE_IF_NONEXISTING);
BucketDatabase::Entry e(getBucket(bucket));
EXPECT_EQ(101234, e->getLastGarbageCollectionTime());
}
diff --git a/storage/src/tests/distributor/distributortestutil.cpp b/storage/src/tests/distributor/distributortestutil.cpp
index 3c26ea01c19..2d2038b7cd0 100644
--- a/storage/src/tests/distributor/distributortestutil.cpp
+++ b/storage/src/tests/distributor/distributortestutil.cpp
@@ -1,11 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "distributortestutil.h"
+#include <vespa/config-stor-distribution.h>
+#include <vespa/document/test/make_bucket_space.h>
+#include <vespa/document/test/make_document_bucket.h>
#include <vespa/storage/distributor/distributor.h>
#include <vespa/storage/distributor/distributor_bucket_space.h>
-#include <vespa/config-stor-distribution.h>
+#include <vespa/storage/distributor/distributorcomponent.h>
#include <vespa/vespalib/text/stringtokenizer.h>
-#include <vespa/document/test/make_document_bucket.h>
-#include <vespa/document/test/make_bucket_space.h>
using document::test::makeBucketSpace;
using document::test::makeDocumentBucket;
@@ -26,6 +27,7 @@ DistributorTestUtil::createLinks()
_threadPool = framework::TickingThreadPool::createDefault("distributor");
_distributor.reset(new Distributor(
_node->getComponentRegister(),
+ _node->node_identity(),
*_threadPool,
*this,
true,
@@ -133,7 +135,7 @@ DistributorTestUtil::getNodes(document::BucketId id)
std::string
DistributorTestUtil::getIdealStr(document::BucketId id, const lib::ClusterState& state)
{
- if (!getExternalOperationHandler().ownsBucketInState(state, makeDocumentBucket(id))) {
+ if (!getDistributorBucketSpace().owns_bucket_in_state(state, id)) {
return id.toString();
}
@@ -244,7 +246,7 @@ DistributorTestUtil::removeFromBucketDB(const document::BucketId& id)
void
DistributorTestUtil::addIdealNodes(const document::BucketId& id)
{
- addIdealNodes(*getExternalOperationHandler().getClusterStateBundle().getBaselineClusterState(), id);
+ addIdealNodes(*distributor_component().getClusterStateBundle().getBaselineClusterState(), id);
}
void
@@ -276,7 +278,7 @@ DistributorTestUtil::insertBucketInfo(document::BucketId id,
if (active) {
info2.setActive();
}
- BucketCopy copy(getExternalOperationHandler().getUniqueTimestamp(), node, info2);
+ BucketCopy copy(distributor_component().getUniqueTimestamp(), node, info2);
entry->addNode(copy.setTrusted(trusted), toVector<uint16_t>(0));
@@ -336,6 +338,11 @@ DistributorTestUtil::getExternalOperationHandler() {
return _distributor->_externalOperationHandler;
}
+storage::distributor::DistributorComponent&
+DistributorTestUtil::distributor_component() {
+ return _distributor->_component;
+}
+
bool
DistributorTestUtil::tick() {
framework::ThreadWaitInfo res(
diff --git a/storage/src/tests/distributor/distributortestutil.h b/storage/src/tests/distributor/distributortestutil.h
index 3dc71bcb433..1bdb6e33512 100644
--- a/storage/src/tests/distributor/distributortestutil.h
+++ b/storage/src/tests/distributor/distributortestutil.h
@@ -2,14 +2,14 @@
#pragma once
#include "distributor_message_sender_stub.h"
-#include <tests/common/teststorageapp.h>
-#include <tests/common/testhelper.h>
#include <tests/common/dummystoragelink.h>
+#include <tests/common/testhelper.h>
+#include <tests/common/teststorageapp.h>
#include <vespa/storage/common/hostreporter/hostinfo.h>
#include <vespa/storage/frameworkimpl/component/distributorcomponentregisterimpl.h>
#include <vespa/storage/storageutil/utils.h>
-#include <vespa/storageframework/defaultimplementation/clock/fakeclock.h>
#include <vespa/storageapi/message/state.h>
+#include <vespa/storageframework/defaultimplementation/clock/fakeclock.h>
namespace storage {
@@ -21,6 +21,7 @@ class BucketDBUpdater;
class Distributor;
class DistributorBucketSpace;
class DistributorBucketSpaceRepo;
+class DistributorComponent;
class IdealStateManager;
class ExternalOperationHandler;
class Operation;
@@ -111,6 +112,7 @@ public:
BucketDBUpdater& getBucketDBUpdater();
IdealStateManager& getIdealStateManager();
ExternalOperationHandler& getExternalOperationHandler();
+ storage::distributor::DistributorComponent& distributor_component();
Distributor& getDistributor() {
return *_distributor;
@@ -175,6 +177,9 @@ public:
BucketDatabase::Entry getBucket(const document::BucketId& bId) const;
std::vector<document::BucketSpace> getBucketSpaces() const;
+
+ DistributorMessageSenderStub& sender() noexcept { return _sender; }
+ const DistributorMessageSenderStub& sender() const noexcept { return _sender; }
protected:
vdstestlib::DirConfig _config;
std::unique_ptr<TestDistributorApp> _node;
diff --git a/storage/src/tests/distributor/dummy_cluster_context.h b/storage/src/tests/distributor/dummy_cluster_context.h
new file mode 100644
index 00000000000..783038daf7d
--- /dev/null
+++ b/storage/src/tests/distributor/dummy_cluster_context.h
@@ -0,0 +1,13 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/storage/common/cluster_context.h>
+
+namespace storage {
+namespace {
+
+SimpleClusterContext dummy_cluster_context("storage");
+
+} // namespace <unnamed>
+} // namespace storage
diff --git a/storage/src/tests/distributor/externaloperationhandlertest.cpp b/storage/src/tests/distributor/externaloperationhandlertest.cpp
index 1f0fba90200..e566f16dcdd 100644
--- a/storage/src/tests/distributor/externaloperationhandlertest.cpp
+++ b/storage/src/tests/distributor/externaloperationhandlertest.cpp
@@ -3,9 +3,13 @@
#include <tests/distributor/distributortestutil.h>
#include <vespa/storage/distributor/externaloperationhandler.h>
#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/distributor_bucket_space.h>
#include <vespa/storage/distributor/distributormetricsset.h>
#include <vespa/storage/distributor/operations/external/getoperation.h>
+#include <vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h>
+#include <vespa/storage/common/reindexing_constants.h>
#include <vespa/storageapi/message/persistence.h>
+#include <vespa/storageapi/message/visitor.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/update/documentupdate.h>
#include <vespa/document/fieldset/fieldsets.h>
@@ -43,23 +47,21 @@ struct ExternalOperationHandlerTest : Test, DistributorTestUtil {
void start_operation_verify_rejected(std::shared_ptr<api::StorageCommand> cmd);
int64_t safe_time_not_reached_metric_count(
- const metrics::LoadMetric<PersistenceOperationMetricSet>& metrics) const {
- return metrics[documentapi::LoadType::DEFAULT].failures
- .safe_time_not_reached.getLongValue("count");
+ const PersistenceOperationMetricSet & metrics) const {
+ return metrics.failures.safe_time_not_reached.getLongValue("count");
}
- int64_t safe_time_not_reached_metric_count(const metrics::LoadMetric<UpdateMetricSet>& metrics) const {
- return metrics[documentapi::LoadType::DEFAULT].failures.safe_time_not_reached.getLongValue("count");
+ int64_t safe_time_not_reached_metric_count(const UpdateMetricSet & metrics) const {
+ return metrics.failures.safe_time_not_reached.getLongValue("count");
}
int64_t concurrent_mutatations_metric_count(
- const metrics::LoadMetric<PersistenceOperationMetricSet>& metrics) const {
- return metrics[documentapi::LoadType::DEFAULT].failures
- .concurrent_mutations.getLongValue("count");
+ const PersistenceOperationMetricSet& metrics) const {
+ return metrics.failures.concurrent_mutations.getLongValue("count");
}
- int64_t concurrent_mutatations_metric_count(const metrics::LoadMetric<UpdateMetricSet>& metrics) const {
- return metrics[documentapi::LoadType::DEFAULT].failures.concurrent_mutations.getLongValue("count");
+ int64_t concurrent_mutatations_metric_count(const UpdateMetricSet & metrics) const {
+ return metrics.failures.concurrent_mutations.getLongValue("count");
}
void set_up_distributor_for_sequencing_test();
@@ -93,19 +95,19 @@ TEST_F(ExternalOperationHandlerTest, bucket_split_mask) {
getDirConfig().getConfig("stor-distributormanager").set("minsplitcount", "16");
EXPECT_EQ(document::BucketId(16, 0xffff),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0xffff))
).stripUnused());
EXPECT_EQ(document::BucketId(16, 0),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0x10000))
).stripUnused());
EXPECT_EQ(document::BucketId(16, 0xffff),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0xffff))
).stripUnused());
EXPECT_EQ(document::BucketId(16, 0x100),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0x100))
).stripUnused());
close();
@@ -114,11 +116,11 @@ TEST_F(ExternalOperationHandlerTest, bucket_split_mask) {
getDirConfig().getConfig("stor-distributormanager").set("minsplitcount", "20");
createLinks();
EXPECT_EQ(document::BucketId(20, 0x11111),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0x111111))
).stripUnused());
EXPECT_EQ(document::BucketId(20, 0x22222),
- getExternalOperationHandler().getBucketId(document::DocumentId(
+ distributor_component().getBucketId(document::DocumentId(
vespalib::make_string("id:ns:test:n=%d::", 0x222222))
).stripUnused());
}
@@ -131,7 +133,7 @@ ExternalOperationHandlerTest::findNonOwnedUserBucketInState(
lib::ClusterState state(statestr);
for (uint64_t i = 1; i < 1000; ++i) {
document::BucketId bucket(32, i);
- if (!getExternalOperationHandler().ownsBucketInState(state, makeDocumentBucket(bucket))) {
+ if (!getDistributorBucketSpace().owns_bucket_in_state(state, bucket)) {
return bucket;
}
}
@@ -147,8 +149,8 @@ ExternalOperationHandlerTest::findOwned1stNotOwned2ndInStates(
lib::ClusterState state2(statestr2);
for (uint64_t i = 1; i < 1000; ++i) {
document::BucketId bucket(32, i);
- if (getExternalOperationHandler().ownsBucketInState(state1, makeDocumentBucket(bucket))
- && !getExternalOperationHandler().ownsBucketInState(state2, makeDocumentBucket(bucket)))
+ if (getDistributorBucketSpace().owns_bucket_in_state(state1, bucket)
+ && !getDistributorBucketSpace().owns_bucket_in_state(state2, bucket))
{
return bucket;
}
@@ -562,6 +564,88 @@ TEST_F(ExternalOperationHandlerTest, gets_are_sent_with_weak_consistency_if_conf
do_test_get_weak_consistency_is_propagated(true);
}
+struct OperationHandlerSequencingTest : ExternalOperationHandlerTest {
+ void SetUp() override {
+ set_up_distributor_for_sequencing_test();
+ }
+
+ static documentapi::TestAndSetCondition bucket_lock_bypass_tas_condition(const vespalib::string& token) {
+ return documentapi::TestAndSetCondition(
+ vespalib::make_string("%s=%s", reindexing_bucket_lock_bypass_prefix(), token.c_str()));
+ }
+};
+
+TEST_F(OperationHandlerSequencingTest, put_not_allowed_through_locked_bucket_if_special_tas_token_not_present) {
+ auto put = makePutCommand("testdoctype1", "id:foo:testdoctype1:n=1:bar");
+ auto bucket = makeDocumentBucket(document::BucketId(16, 1));
+ auto bucket_handle = getExternalOperationHandler().operation_sequencer().try_acquire(bucket, "foo");
+ ASSERT_TRUE(bucket_handle.valid());
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_rejected(put));
+}
+
+TEST_F(OperationHandlerSequencingTest, put_allowed_through_locked_bucket_if_special_tas_token_present) {
+ set_up_distributor_for_sequencing_test();
+
+ auto put = makePutCommand("testdoctype1", "id:foo:testdoctype1:n=1:bar");
+ put->setCondition(bucket_lock_bypass_tas_condition("foo"));
+
+ auto bucket = makeDocumentBucket(document::BucketId(16, 1));
+ auto bucket_handle = getExternalOperationHandler().operation_sequencer().try_acquire(bucket, "foo");
+ ASSERT_TRUE(bucket_handle.valid());
+
+ Operation::SP op;
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_not_rejected(put, op));
+}
+
+TEST_F(OperationHandlerSequencingTest, put_not_allowed_through_locked_bucket_if_tas_token_mismatches_current_lock_tkoen) {
+ auto put = makePutCommand("testdoctype1", "id:foo:testdoctype1:n=1:bar");
+ put->setCondition(bucket_lock_bypass_tas_condition("bar"));
+ auto bucket = makeDocumentBucket(document::BucketId(16, 1));
+ auto bucket_handle = getExternalOperationHandler().operation_sequencer().try_acquire(bucket, "foo");
+ ASSERT_TRUE(bucket_handle.valid());
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_rejected(put));
+}
+
+TEST_F(OperationHandlerSequencingTest, put_with_bucket_lock_tas_token_is_rejected_if_no_bucket_lock_present) {
+ auto put = makePutCommand("testdoctype1", "id:foo:testdoctype1:n=1:bar");
+ put->setCondition(bucket_lock_bypass_tas_condition("foo"));
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_rejected(put));
+ EXPECT_EQ("ReturnCode(TEST_AND_SET_CONDITION_FAILED, Operation expects a read-for-write bucket "
+ "lock to be present, but none currently exists)",
+ _sender.reply(0)->getResult().toString());
+}
+
+// This test is a variation of the above, but whereas it tests the case where _no_ lock is
+// present, this tests the case where a lock is present but it's not a bucket-level lock.
+TEST_F(OperationHandlerSequencingTest, put_with_bucket_lock_tas_token_is_rejected_if_document_lock_present) {
+ auto put = makePutCommand("testdoctype1", _dummy_id);
+ put->setCondition(bucket_lock_bypass_tas_condition("foo"));
+ Operation::SP op;
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_not_rejected(makeUpdateCommand("testdoctype1", _dummy_id), op));
+ ASSERT_NO_FATAL_FAILURE(start_operation_verify_rejected(std::move(put)));
+ EXPECT_EQ("ReturnCode(TEST_AND_SET_CONDITION_FAILED, Operation expects a read-for-write bucket "
+ "lock to be present, but none currently exists)",
+ _sender.reply(0)->getResult().toString());
+}
+
+TEST_F(OperationHandlerSequencingTest, reindexing_visitor_creates_read_for_write_operation) {
+ auto cmd = std::make_shared<api::CreateVisitorCommand>(
+ document::FixedBucketSpaces::default_space(), "reindexingvisitor", "foo", "");
+ Operation::SP op;
+ getExternalOperationHandler().handleMessage(cmd, op);
+ ASSERT_TRUE(op.get() != nullptr);
+ ASSERT_TRUE(dynamic_cast<ReadForWriteVisitorOperationStarter*>(op.get()) != nullptr);
+}
+
+TEST_F(OperationHandlerSequencingTest, reindexing_visitor_library_check_is_case_insensitive) {
+ auto cmd = std::make_shared<api::CreateVisitorCommand>(
+ document::FixedBucketSpaces::default_space(), "ReIndexingVisitor", "foo", "");
+ Operation::SP op;
+ getExternalOperationHandler().handleMessage(cmd, op);
+ ASSERT_TRUE(op.get() != nullptr);
+ ASSERT_TRUE(dynamic_cast<ReadForWriteVisitorOperationStarter*>(op.get()) != nullptr);
+}
+
// TODO support sequencing of RemoveLocation? It's a mutating operation, but supporting it with
// the current approach is not trivial. A RemoveLocation operation covers the _entire_ bucket
// sub tree under a given location, while the sequencer works on individual GIDs. Mapping the
diff --git a/storage/src/tests/distributor/garbagecollectiontest.cpp b/storage/src/tests/distributor/garbagecollectiontest.cpp
index 776cfc14d84..751269fe586 100644
--- a/storage/src/tests/distributor/garbagecollectiontest.cpp
+++ b/storage/src/tests/distributor/garbagecollectiontest.cpp
@@ -8,6 +8,7 @@
#include <vespa/storage/distributor/distributor.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using namespace ::testing;
@@ -29,7 +30,7 @@ struct GarbageCollectionOperationTest : Test, DistributorTestUtil {
std::shared_ptr<GarbageCollectionOperation> create_op() {
auto op = std::make_shared<GarbageCollectionOperation>(
- "storage",BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
+ dummy_cluster_context, BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(0, 1)));
op->setIdealStateManager(&getIdealStateManager());
return op;
diff --git a/storage/src/tests/distributor/getoperationtest.cpp b/storage/src/tests/distributor/getoperationtest.cpp
index 09e4f41d275..fe87de5f18a 100644
--- a/storage/src/tests/distributor/getoperationtest.cpp
+++ b/storage/src/tests/distributor/getoperationtest.cpp
@@ -45,7 +45,7 @@ struct GetOperationTest : Test, DistributorTestUtil {
createLinks();
docId = document::DocumentId("id:ns:text/html::uri");
- bucketId = getExternalOperationHandler().getBucketId(docId);
+ bucketId = distributor_component().getBucketId(docId);
};
void TearDown() override {
@@ -56,9 +56,9 @@ struct GetOperationTest : Test, DistributorTestUtil {
void sendGet(api::InternalReadConsistency consistency = api::InternalReadConsistency::Strong) {
auto msg = std::make_shared<api::GetCommand>(makeDocumentBucket(BucketId(0)), docId, document::AllFields::NAME);
op = std::make_unique<GetOperation>(
- getExternalOperationHandler(), getDistributorBucketSpace(),
+ distributor_component(), getDistributorBucketSpace(),
getDistributorBucketSpace().getBucketDatabase().acquire_read_guard(),
- msg, getDistributor().getMetrics(). gets[msg->getLoadType()],
+ msg, getDistributor().getMetrics().gets,
consistency);
op->start(_sender, framework::MilliSecTime(0));
}
@@ -414,8 +414,7 @@ TEST_F(GetOperationTest, not_found) {
"timestamp 0) ReturnCode(NONE)",
_sender.getLastReply());
- EXPECT_EQ(1, getDistributor().getMetrics().gets[documentapi::LoadType::DEFAULT].
- failures.notfound.getValue());
+ EXPECT_EQ(1, getDistributor().getMetrics().gets.failures.notfound.getValue());
EXPECT_FALSE(op->any_replicas_failed()); // "Not found" is not a failure.
EXPECT_TRUE(last_reply_had_consistent_replicas());
EXPECT_TRUE(op->newest_replica().has_value());
diff --git a/storage/src/tests/distributor/idealstatemanagertest.cpp b/storage/src/tests/distributor/idealstatemanagertest.cpp
index fc26a8c9cce..51284307fa8 100644
--- a/storage/src/tests/distributor/idealstatemanagertest.cpp
+++ b/storage/src/tests/distributor/idealstatemanagertest.cpp
@@ -4,6 +4,7 @@
#include <vespa/storage/distributor/bucketdbupdater.h>
#include <vespa/storage/distributor/distributor.h>
#include <vespa/storage/distributor/operations/idealstate/mergeoperation.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
#include <vespa/storageapi/message/stat.h>
#include <vespa/storageapi/message/visitor.h>
#include <vespa/storageapi/message/bucketsplitting.h>
@@ -12,6 +13,7 @@
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/document/test/make_bucket_space.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using document::test::makeBucketSpace;
@@ -41,16 +43,18 @@ struct IdealStateManagerTest : Test, DistributorTestUtil {
bool checkBlock(const IdealStateOperation& op,
const document::Bucket& bucket,
- const PendingMessageTracker& tracker) const
+ const PendingMessageTracker& tracker,
+ const OperationSequencer& op_seq) const
{
- return op.checkBlock(bucket, tracker);
+ return op.checkBlock(bucket, tracker, op_seq);
}
bool checkBlockForAllNodes(const IdealStateOperation& op,
const document::Bucket& bucket,
- const PendingMessageTracker& tracker) const
+ const PendingMessageTracker& tracker,
+ const OperationSequencer& op_seq) const
{
- return op.checkBlockForAllNodes(bucket, tracker);
+ return op.checkBlockForAllNodes(bucket, tracker, op_seq);
}
std::vector<document::BucketSpace> _bucketSpaces;
@@ -170,10 +174,12 @@ TEST_F(IdealStateManagerTest, recheck_when_active) {
}
TEST_F(IdealStateManagerTest, block_ideal_state_ops_on_full_request_bucket_info) {
+
setupDistributor(2, 10, "distributor:1 storage:2");
framework::defaultimplementation::FakeClock clock;
PendingMessageTracker tracker(_node->getComponentRegister());
+ OperationSequencer op_seq;
document::BucketId bid(16, 1234);
std::vector<document::BucketId> buckets;
@@ -182,34 +188,34 @@ TEST_F(IdealStateManagerTest, block_ideal_state_ops_on_full_request_bucket_info)
// sent to the entire node. It will then use a null bucketid.
{
auto msg = std::make_shared<api::RequestBucketInfoCommand>(makeBucketSpace(), buckets);
- msg->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 4));
+ msg->setAddress(api::StorageMessageAddress::create(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 4));
tracker.insert(msg);
}
{
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(3, 4)));
- EXPECT_TRUE(op.isBlocked(tracker));
+ EXPECT_TRUE(op.isBlocked(tracker, op_seq));
}
{
// Don't trigger on requests to other nodes.
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(3, 5)));
- EXPECT_FALSE(op.isBlocked(tracker));
+ EXPECT_FALSE(op.isBlocked(tracker, op_seq));
}
// Don't block on null-bucket messages that aren't RequestBucketInfo.
{
auto msg = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "foo", "bar", "baz");
- msg->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 7));
+ msg->setAddress(api::StorageMessageAddress::create(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 7));
tracker.insert(msg);
}
{
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(7)));
- EXPECT_FALSE(op.isBlocked(tracker));
+ EXPECT_FALSE(op.isBlocked(tracker, op_seq));
}
}
@@ -217,21 +223,42 @@ TEST_F(IdealStateManagerTest, block_check_for_all_operations_to_specific_bucket)
setupDistributor(2, 10, "distributor:1 storage:2");
framework::defaultimplementation::FakeClock clock;
PendingMessageTracker tracker(_node->getComponentRegister());
+ OperationSequencer op_seq;
document::BucketId bid(16, 1234);
{
auto msg = std::make_shared<api::JoinBucketsCommand>(makeDocumentBucket(bid));
- msg->setAddress(
- api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 4));
+ msg->setAddress(api::StorageMessageAddress::create(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 4));
tracker.insert(msg);
}
{
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(bid), toVector<uint16_t>(7)));
// Not blocked for exact node match.
- EXPECT_FALSE(checkBlock(op, makeDocumentBucket(bid), tracker));
+ EXPECT_FALSE(checkBlock(op, makeDocumentBucket(bid), tracker, op_seq));
// But blocked for bucket match!
- EXPECT_TRUE(checkBlockForAllNodes(op, makeDocumentBucket(bid), tracker));
+ EXPECT_TRUE(checkBlockForAllNodes(op, makeDocumentBucket(bid), tracker, op_seq));
+ }
+}
+
+TEST_F(IdealStateManagerTest, block_operations_with_locked_buckets) {
+ setupDistributor(2, 10, "distributor:1 storage:2");
+ framework::defaultimplementation::FakeClock clock;
+ PendingMessageTracker tracker(_node->getComponentRegister());
+ OperationSequencer op_seq;
+ const auto bucket = makeDocumentBucket(document::BucketId(16, 1234));
+
+ {
+ auto msg = std::make_shared<api::JoinBucketsCommand>(bucket);
+ msg->setAddress(api::StorageMessageAddress::create(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 1));
+ tracker.insert(msg);
+ }
+ auto token = op_seq.try_acquire(bucket, "foo");
+ EXPECT_TRUE(token.valid());
+ {
+ RemoveBucketOperation op(dummy_cluster_context, BucketAndNodes(bucket, toVector<uint16_t>(0)));
+ EXPECT_TRUE(checkBlock(op, bucket, tracker, op_seq));
+ EXPECT_TRUE(checkBlockForAllNodes(op, bucket, tracker, op_seq));
}
}
diff --git a/storage/src/tests/distributor/joinbuckettest.cpp b/storage/src/tests/distributor/joinbuckettest.cpp
index a918a29c609..9382648e881 100644
--- a/storage/src/tests/distributor/joinbuckettest.cpp
+++ b/storage/src/tests/distributor/joinbuckettest.cpp
@@ -6,6 +6,7 @@
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <gmock/gmock.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using namespace ::testing;
@@ -36,7 +37,7 @@ TEST_F(JoinOperationTest, simple) {
enableDistributorClusterState("distributor:1 storage:1");
- JoinOperation op("storage",
+ JoinOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(32, 0)),
toVector<uint16_t>(0)),
toVector(document::BucketId(33, 1),
@@ -91,7 +92,7 @@ TEST_F(JoinOperationTest, send_sparse_joins_to_nodes_without_both_source_buckets
enableDistributorClusterState("distributor:1 storage:2");
- JoinOperation op("storage",
+ JoinOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(32, 0)),
toVector<uint16_t>(0, 1)),
toVector(document::BucketId(33, 1),
diff --git a/storage/src/tests/distributor/maintenancemocks.h b/storage/src/tests/distributor/maintenancemocks.h
index c88e477e90e..2bfb4ebb40f 100644
--- a/storage/src/tests/distributor/maintenancemocks.h
+++ b/storage/src/tests/distributor/maintenancemocks.h
@@ -51,7 +51,7 @@ public:
}
void onStart(DistributorMessageSender&) override {}
void onReceive(DistributorMessageSender&, const std::shared_ptr<api::StorageReply>&) override {}
- bool isBlocked(const PendingMessageTracker&) const override {
+ bool isBlocked(const PendingMessageTracker&, const OperationSequencer&) const override {
return _shouldBlock;
}
void setShouldBlock(bool shouldBlock) {
@@ -64,7 +64,7 @@ class MockMaintenanceOperationGenerator
{
public:
MaintenanceOperation::SP generate(const document::Bucket&bucket) const override {
- return MaintenanceOperation::SP(new MockOperation(bucket));
+ return std::make_shared<MockOperation>(bucket);
}
std::vector<MaintenanceOperation::SP> generateAll(
@@ -73,7 +73,7 @@ public:
{
(void) tracker;
std::vector<MaintenanceOperation::SP> ret;
- ret.push_back(MaintenanceOperation::SP(new MockOperation(bucket)));
+ ret.emplace_back(std::make_shared<MockOperation>(bucket));
return ret;
}
diff --git a/storage/src/tests/distributor/mergeoperationtest.cpp b/storage/src/tests/distributor/mergeoperationtest.cpp
index 75faddbe667..90fcf40b3fe 100644
--- a/storage/src/tests/distributor/mergeoperationtest.cpp
+++ b/storage/src/tests/distributor/mergeoperationtest.cpp
@@ -6,6 +6,7 @@
#include <vespa/storage/distributor/operations/idealstate/mergeoperation.h>
#include <vespa/storage/distributor/bucketdbupdater.h>
#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
#include <tests/distributor/distributortestutil.h>
#include <vespa/vespalib/text/stringtokenizer.h>
#include <vespa/vespalib/gtest/gtest.h>
@@ -17,11 +18,13 @@ namespace storage::distributor {
struct MergeOperationTest : Test, DistributorTestUtil {
std::unique_ptr<PendingMessageTracker> _pendingTracker;
+ OperationSequencer _operation_sequencer;
void SetUp() override {
createLinks();
_pendingTracker = std::make_unique<PendingMessageTracker>(getComponentRegister());
_sender.setPendingMessageTracker(*_pendingTracker);
+ _sender.set_operation_sequencer(_operation_sequencer);
}
void TearDown() override {
@@ -250,7 +253,8 @@ TEST_F(MergeOperationTest, do_not_remove_copies_with_pending_messages) {
// at will.
auto msg = std::make_shared<api::SetBucketStateCommand>(
makeDocumentBucket(bucket), api::SetBucketStateCommand::ACTIVE);
- msg->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 1));
+ vespalib::string storage("storage");
+ msg->setAddress(api::StorageMessageAddress::create(&storage, lib::NodeType::STORAGE, 1));
_pendingTracker->insert(msg);
sendReply(op);
@@ -396,18 +400,31 @@ TEST_F(MergeOperationTest, merge_operation_is_blocked_by_any_busy_target_node) {
// Should not block on nodes _not_ included in operation node set
_pendingTracker->getNodeInfo().setBusy(3, std::chrono::seconds(10));
- EXPECT_FALSE(op.isBlocked(*_pendingTracker));
+ EXPECT_FALSE(op.isBlocked(*_pendingTracker, _operation_sequencer));
// Node 1 is included in operation node set and should cause a block
_pendingTracker->getNodeInfo().setBusy(0, std::chrono::seconds(10));
- EXPECT_TRUE(op.isBlocked(*_pendingTracker));
+ EXPECT_TRUE(op.isBlocked(*_pendingTracker, _operation_sequencer));
getClock().addSecondsToTime(11);
- EXPECT_FALSE(op.isBlocked(*_pendingTracker)); // No longer busy
+ EXPECT_FALSE(op.isBlocked(*_pendingTracker, _operation_sequencer)); // No longer busy
// Should block on other operation nodes than the first listed as well
_pendingTracker->getNodeInfo().setBusy(1, std::chrono::seconds(10));
- EXPECT_TRUE(op.isBlocked(*_pendingTracker));
+ EXPECT_TRUE(op.isBlocked(*_pendingTracker, _operation_sequencer));
+}
+
+TEST_F(MergeOperationTest, merge_operation_is_blocked_by_locked_bucket) {
+ getClock().setAbsoluteTimeInSeconds(10);
+ addNodesToBucketDB(document::BucketId(16, 1), "0=10/1/1/t,1=20/1/1,2=10/1/1/t");
+ enableDistributorClusterState("distributor:1 storage:3");
+ MergeOperation op(BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)), toVector<uint16_t>(0, 1, 2)));
+ op.setIdealStateManager(&getIdealStateManager());
+
+ EXPECT_FALSE(op.isBlocked(*_pendingTracker, _operation_sequencer));
+ auto token = _operation_sequencer.try_acquire(makeDocumentBucket(document::BucketId(16, 1)), "foo");
+ EXPECT_TRUE(token.valid());
+ EXPECT_TRUE(op.isBlocked(*_pendingTracker, _operation_sequencer));
}
TEST_F(MergeOperationTest, missing_replica_is_included_in_limited_node_list) {
diff --git a/storage/src/tests/distributor/operation_sequencer_test.cpp b/storage/src/tests/distributor/operation_sequencer_test.cpp
index b3674ee2126..968d41dd98b 100644
--- a/storage/src/tests/distributor/operation_sequencer_test.cpp
+++ b/storage/src/tests/distributor/operation_sequencer_test.cpp
@@ -1,46 +1,107 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/document/base/documentid.h>
+#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/storage/distributor/operation_sequencer.h>
#include <vespa/vespalib/gtest/gtest.h>
namespace storage::distributor {
using document::DocumentId;
+using namespace ::testing;
-TEST(OperationSequencerTest, can_get_sequencing_handle_for_id_without_existing_handle) {
+namespace {
+
+constexpr document::BucketSpace default_space() {
+ return document::FixedBucketSpaces::default_space();
+}
+
+constexpr document::BucketSpace global_space() {
+ return document::FixedBucketSpaces::global_space();
+}
+
+}
+
+struct OperationSequencerTest : Test {
OperationSequencer sequencer;
- auto handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
+};
+
+TEST_F(OperationSequencerTest, can_get_sequencing_handle_for_id_without_existing_handle) {
+ auto handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
EXPECT_TRUE(handle.valid());
+ EXPECT_FALSE(handle.is_blocked());
}
-TEST(OperationSequencerTest, cannot_get_sequencing_handle_for_id_with_existing_handle) {
- OperationSequencer sequencer;
- auto first_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
- auto second_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
+TEST_F(OperationSequencerTest, cannot_get_sequencing_handle_for_id_with_existing_handle) {
+ auto first_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
+ auto second_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
EXPECT_FALSE(second_handle.valid());
+ ASSERT_TRUE(second_handle.is_blocked());
+ EXPECT_TRUE(second_handle.is_blocked_by_pending_operation());
+ EXPECT_FALSE(second_handle.is_blocked_by_bucket());
}
-TEST(OperationSequencerTest, can_get_sequencing_handle_for_different_ids) {
- OperationSequencer sequencer;
- auto first_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
- auto second_handle = sequencer.try_acquire(DocumentId("id:foo:test::efgh"));
+TEST_F(OperationSequencerTest, can_get_sequencing_handle_for_different_ids) {
+ auto first_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
+ auto second_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::efgh"));
EXPECT_TRUE(first_handle.valid());
EXPECT_TRUE(second_handle.valid());
}
-TEST(OperationSequencerTest, releasing_handle_allows_for_getting_new_handles_for_id) {
- OperationSequencer sequencer;
- auto first_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
+TEST_F(OperationSequencerTest, releasing_handle_allows_for_getting_new_handles_for_id) {
+ auto first_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
// Explicit release
first_handle.release();
{
- auto second_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
+ auto second_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
EXPECT_TRUE(second_handle.valid());
// Implicit release by scope exit
}
- auto third_handle = sequencer.try_acquire(DocumentId("id:foo:test::abcd"));
+ auto third_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test::abcd"));
EXPECT_TRUE(third_handle.valid());
}
+TEST_F(OperationSequencerTest, cannot_get_handle_for_gid_contained_in_locked_bucket) {
+ const auto bucket = document::Bucket(default_space(), document::BucketId(16, 1));
+ EXPECT_FALSE(sequencer.is_blocked(bucket));
+ auto bucket_handle = sequencer.try_acquire(bucket, "foo");
+ EXPECT_TRUE(bucket_handle.valid());
+ EXPECT_TRUE(sequencer.is_blocked(bucket));
+ auto doc_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test:n=1:abcd"));
+ EXPECT_FALSE(doc_handle.valid());
+ ASSERT_TRUE(doc_handle.is_blocked());
+ ASSERT_TRUE(doc_handle.is_blocked_by_bucket());
+ EXPECT_TRUE(doc_handle.is_bucket_blocked_with_token("foo"));
+ EXPECT_FALSE(doc_handle.is_bucket_blocked_with_token("bar"));
+}
+
+TEST_F(OperationSequencerTest, can_get_handle_for_gid_not_contained_in_active_bucket) {
+ auto bucket_handle = sequencer.try_acquire(document::Bucket(default_space(), document::BucketId(16, 1)), "foo");
+ EXPECT_TRUE(bucket_handle.valid());
+ // Note: different sub-bucket than the lock
+ auto doc_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test:n=2:abcd"));
+ EXPECT_TRUE(doc_handle.valid());
+}
+
+TEST_F(OperationSequencerTest, releasing_bucket_lock_allows_gid_handles_to_be_acquired) {
+ const auto bucket = document::Bucket(default_space(), document::BucketId(16, 1));
+ auto bucket_handle = sequencer.try_acquire(bucket, "foo");
+ bucket_handle.release();
+ auto doc_handle = sequencer.try_acquire(default_space(), DocumentId("id:foo:test:n=1:abcd"));
+ EXPECT_TRUE(doc_handle.valid());
+ EXPECT_FALSE(sequencer.is_blocked(bucket));
+}
+
+TEST_F(OperationSequencerTest, can_get_handle_for_gid_when_locked_bucket_is_in_separate_bucket_space) {
+ auto bucket_handle = sequencer.try_acquire(document::Bucket(default_space(), document::BucketId(16, 1)), "foo");
+ EXPECT_TRUE(bucket_handle.valid());
+ auto doc_handle = sequencer.try_acquire(global_space(), DocumentId("id:foo:test:n=1:abcd"));
+ EXPECT_TRUE(doc_handle.valid());
+}
+
+TEST_F(OperationSequencerTest, is_blocked_is_bucket_space_aware) {
+ auto bucket_handle = sequencer.try_acquire(document::Bucket(default_space(), document::BucketId(16, 1)), "foo");
+ EXPECT_FALSE(sequencer.is_blocked(document::Bucket(global_space(), document::BucketId(16, 1))));
+}
+
} // storage::distributor
diff --git a/storage/src/tests/distributor/operationtargetresolvertest.cpp b/storage/src/tests/distributor/operationtargetresolvertest.cpp
index da0206cf0a4..721809d4515 100644
--- a/storage/src/tests/distributor/operationtargetresolvertest.cpp
+++ b/storage/src/tests/distributor/operationtargetresolvertest.cpp
@@ -115,12 +115,12 @@ OperationTargetResolverTest::getInstances(const BucketId& id,
bool stripToRedundancy)
{
lib::IdealNodeCalculatorImpl idealNodeCalc;
- auto &bucketSpaceRepo(getExternalOperationHandler().getBucketSpaceRepo());
+ auto &bucketSpaceRepo(distributor_component().getBucketSpaceRepo());
auto &distributorBucketSpace(bucketSpaceRepo.get(makeBucketSpace()));
idealNodeCalc.setDistribution(distributorBucketSpace.getDistribution());
idealNodeCalc.setClusterState(distributorBucketSpace.getClusterState());
OperationTargetResolverImpl resolver(
- distributorBucketSpace.getBucketDatabase(), idealNodeCalc, 16,
+ distributorBucketSpace, distributorBucketSpace.getBucketDatabase(), 16,
distributorBucketSpace.getDistribution().getRedundancy(),
makeBucketSpace());
if (stripToRedundancy) {
@@ -144,7 +144,7 @@ TEST_F(OperationTargetResolverTest, simple) {
TEST_F(OperationTargetResolverTest, multiple_nodes) {
setupDistributor(1, 2, "storage:2 distributor:1");
- auto &bucketSpaceRepo(getExternalOperationHandler().getBucketSpaceRepo());
+ auto &bucketSpaceRepo(distributor_component().getBucketSpaceRepo());
auto &distributorBucketSpace(bucketSpaceRepo.get(makeBucketSpace()));
for (int i = 0; i < 100; ++i) {
addNodesToBucketDB(BucketId(16, i), "0=0,1=0");
diff --git a/storage/src/tests/distributor/pendingmessagetrackertest.cpp b/storage/src/tests/distributor/pendingmessagetrackertest.cpp
index e1bca1a1890..72365c61597 100644
--- a/storage/src/tests/distributor/pendingmessagetrackertest.cpp
+++ b/storage/src/tests/distributor/pendingmessagetrackertest.cpp
@@ -1,13 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/document/base/testdocman.h>
+#include <vespa/document/test/make_document_bucket.h>
#include <vespa/storage/distributor/pendingmessagetracker.h>
#include <vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h>
-#include <vespa/storageapi/message/bucket.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageframework/defaultimplementation/clock/fakeclock.h>
#include <tests/common/dummystoragelink.h>
-#include <vespa/document/test/make_document_bucket.h>
+#include <vespa/vespalib/util/lambdatask.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <gmock/gmock.h>
@@ -49,6 +49,12 @@ public:
std::chrono::milliseconds atTime() const { return _atTime; }
};
+api::StorageMessageAddress
+makeStorageAddress(uint16_t node) {
+ static vespalib::string _storage("storage");
+ return {&_storage, lib::NodeType::STORAGE, node};
+}
+
class Fixture
{
StorageComponentRegisterImpl _compReg;
@@ -77,6 +83,26 @@ public:
_tracker->reply(*putReply);
}
+ std::shared_ptr<api::PutCommand> createPutToNode(uint16_t node) const {
+ document::BucketId bucket(16, 1234);
+ auto cmd = std::make_shared<api::PutCommand>(
+ makeDocumentBucket(bucket),
+ createDummyDocumentForBucket(bucket),
+ api::Timestamp(123456));
+ cmd->setAddress(makeStorageAddress(node));
+ return cmd;
+ }
+
+ std::shared_ptr<api::GetCommand> create_get_to_node(uint16_t node) const {
+ document::BucketId bucket(16, 1234);
+ auto cmd = std::make_shared<api::GetCommand>(
+ makeDocumentBucket(bucket),
+ document::DocumentId("id::testdoctype1:n=1234:foo"),
+ "[all]");
+ cmd->setAddress(makeStorageAddress(node));
+ return cmd;
+ }
+
PendingMessageTracker& tracker() { return *_tracker; }
auto& clock() { return _clock; }
@@ -87,25 +113,9 @@ private:
return id.str();
}
- document::Document::SP createDummyDocumentForBucket(
- const document::BucketId& bucket) const
+ document::Document::SP createDummyDocumentForBucket(const document::BucketId& bucket) const
{
- return _testDocMan.createDocument("foobar",
- createDummyIdString(bucket));
- }
-
- api::StorageMessageAddress makeStorageAddress(uint16_t node) const {
- return {"storage", lib::NodeType::STORAGE, node};
- }
-
- std::shared_ptr<api::PutCommand> createPutToNode(uint16_t node) const {
- document::BucketId bucket(16, 1234);
- auto cmd = std::make_shared<api::PutCommand>(
- makeDocumentBucket(bucket),
- createDummyDocumentForBucket(bucket),
- api::Timestamp(123456));
- cmd->setAddress(makeStorageAddress(node));
- return cmd;
+ return _testDocMan.createDocument("foobar", createDummyIdString(bucket));
}
std::shared_ptr<api::RemoveCommand> createRemoveToNode(
@@ -151,7 +161,7 @@ TEST_F(PendingMessageTrackerTest, simple) {
auto remove = std::make_shared<api::RemoveCommand>(
makeDocumentBucket(document::BucketId(16, 1234)),
document::DocumentId("id:footype:testdoc:n=1234:foo"), 1001);
- remove->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0));
+ remove->setAddress(makeStorageAddress(0));
tracker.insert(remove);
{
@@ -186,7 +196,7 @@ PendingMessageTrackerTest::insertMessages(PendingMessageTracker& tracker)
auto remove = std::make_shared<api::RemoveCommand>(
makeDocumentBucket(document::BucketId(16, 1234)),
document::DocumentId(ost.str()), 1000 + i);
- remove->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, i % 2));
+ remove->setAddress(makeStorageAddress(i % 2));
tracker.insert(remove);
}
@@ -194,7 +204,7 @@ PendingMessageTrackerTest::insertMessages(PendingMessageTracker& tracker)
std::ostringstream ost;
ost << "id:footype:testdoc:n=4567:" << i;
auto remove = std::make_shared<api::RemoveCommand>(makeDocumentBucket(document::BucketId(16, 4567)), document::DocumentId(ost.str()), 2000 + i);
- remove->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, i % 2));
+ remove->setAddress(makeStorageAddress(i % 2));
tracker.insert(remove);
}
}
@@ -323,7 +333,7 @@ TEST_F(PendingMessageTrackerTest, get_pending_message_types) {
auto remove = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bid),
document::DocumentId("id:footype:testdoc:n=1234:foo"), 1001);
- remove->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0));
+ remove->setAddress(makeStorageAddress(0));
tracker.insert(remove);
{
@@ -358,7 +368,7 @@ TEST_F(PendingMessageTrackerTest, has_pending_message) {
{
auto remove = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bid),
document::DocumentId("id:footype:testdoc:n=1234:foo"), 1001);
- remove->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 1));
+ remove->setAddress(makeStorageAddress(1));
tracker.insert(remove);
}
@@ -436,4 +446,75 @@ TEST_F(PendingMessageTrackerTest, busy_node_duration_can_be_adjusted) {
EXPECT_FALSE(f.tracker().getNodeInfo().isBusy(0));
}
+namespace {
+
+document::BucketId bucket_of(const document::DocumentId& id) {
+ return document::BucketId(16, id.getGlobalId().convertToBucketId().getId());
+}
+
+}
+
+TEST_F(PendingMessageTrackerTest, start_deferred_task_immediately_if_no_pending_write_ops) {
+ Fixture f;
+ auto cmd = f.createPutToNode(0);
+ auto bucket_id = bucket_of(cmd->getDocumentId());
+ auto state = TaskRunState::Aborted;
+ f.tracker().run_once_no_pending_for_bucket(makeDocumentBucket(bucket_id), make_deferred_task([&](TaskRunState s){
+ state = s;
+ }));
+ EXPECT_EQ(state, TaskRunState::OK);
+}
+
+TEST_F(PendingMessageTrackerTest, start_deferred_task_immediately_if_only_pending_read_ops) {
+ Fixture f;
+ auto cmd = f.create_get_to_node(0);
+ f.tracker().insert(cmd);
+ auto bucket_id = bucket_of(cmd->getDocumentId());
+ auto state = TaskRunState::Aborted;
+ f.tracker().run_once_no_pending_for_bucket(makeDocumentBucket(bucket_id), make_deferred_task([&](TaskRunState s){
+ state = s;
+ }));
+ EXPECT_EQ(state, TaskRunState::OK);
+}
+
+TEST_F(PendingMessageTrackerTest, deferred_task_not_started_before_pending_ops_completed) {
+ Fixture f;
+ auto cmd = f.sendPut(RequestBuilder().toNode(0));
+ auto bucket_id = bucket_of(cmd->getDocumentId());
+ auto state = TaskRunState::Aborted;
+ f.tracker().run_once_no_pending_for_bucket(makeDocumentBucket(bucket_id), make_deferred_task([&](TaskRunState s){
+ state = s;
+ }));
+ EXPECT_EQ(state, TaskRunState::Aborted);
+ f.sendPutReply(*cmd, RequestBuilder()); // Deferred task should be run as part of this.
+ EXPECT_EQ(state, TaskRunState::OK);
+}
+
+TEST_F(PendingMessageTrackerTest, deferred_task_can_be_started_with_pending_read_op) {
+ Fixture f;
+ auto cmd = f.sendPut(RequestBuilder().toNode(0));
+ auto bucket_id = bucket_of(cmd->getDocumentId());
+ auto state = TaskRunState::Aborted;
+ f.tracker().run_once_no_pending_for_bucket(makeDocumentBucket(bucket_id), make_deferred_task([&](TaskRunState s){
+ state = s;
+ }));
+ EXPECT_EQ(state, TaskRunState::Aborted);
+ f.tracker().insert(f.create_get_to_node(0)); // Concurrent Get and Put
+ f.sendPutReply(*cmd, RequestBuilder()); // Deferred task should be allowed to run
+ EXPECT_EQ(state, TaskRunState::OK);
+}
+
+TEST_F(PendingMessageTrackerTest, abort_invokes_deferred_tasks_with_aborted_status) {
+ Fixture f;
+ auto cmd = f.sendPut(RequestBuilder().toNode(0));
+ auto bucket_id = bucket_of(cmd->getDocumentId());
+ auto state = TaskRunState::OK;
+ f.tracker().run_once_no_pending_for_bucket(makeDocumentBucket(bucket_id), make_deferred_task([&](TaskRunState s){
+ state = s;
+ }));
+ EXPECT_EQ(state, TaskRunState::OK);
+ f.tracker().abort_deferred_tasks();
+ EXPECT_EQ(state, TaskRunState::Aborted);
+}
+
}
diff --git a/storage/src/tests/distributor/putoperationtest.cpp b/storage/src/tests/distributor/putoperationtest.cpp
index 16d5dcf3b25..9838bd9be01 100644
--- a/storage/src/tests/distributor/putoperationtest.cpp
+++ b/storage/src/tests/distributor/putoperationtest.cpp
@@ -3,6 +3,7 @@
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/storage/distributor/operations/external/putoperation.h>
#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/distributor_bucket_space.h>
#include <vespa/storageapi/message/bucket.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageapi/message/state.h>
@@ -72,11 +73,12 @@ public:
}
void sendPut(std::shared_ptr<api::PutCommand> msg) {
- op = std::make_unique<PutOperation>(getExternalOperationHandler(),
+ op = std::make_unique<PutOperation>(distributor_component(),
+ distributor_component(),
getDistributorBucketSpace(),
msg,
getDistributor().getMetrics().
- puts[msg->getLoadType()]);
+ puts);
op->start(_sender, framework::MilliSecTime(0));
}
@@ -101,7 +103,7 @@ document::BucketId
PutOperationTest::createAndSendSampleDocument(vespalib::duration timeout) {
auto doc = std::make_shared<Document>(doc_type(), DocumentId("id:test:testdoctype1::"));
- document::BucketId id = getExternalOperationHandler().getBucketId(doc->getId());
+ document::BucketId id = distributor_component().getBucketId(doc->getId());
addIdealNodes(id);
auto msg = std::make_shared<api::PutCommand>(makeDocumentBucket(document::BucketId(0)), doc, 0);
@@ -147,7 +149,7 @@ TEST_F(PutOperationTest, bucket_database_gets_special_entry_when_CreateBucket_se
// Database updated before CreateBucket is sent
ASSERT_EQ("BucketId(0x4000000000008f09) : "
"node(idx=0,crc=0x1,docs=0/0,bytes=0/0,trusted=true,active=true,ready=false)",
- dumpBucket(getExternalOperationHandler().getBucketId(doc->getId())));
+ dumpBucket(distributor_component().getBucketId(doc->getId())));
ASSERT_EQ("Create bucket => 0,Put => 0", _sender.getCommands(true));
}
@@ -194,7 +196,7 @@ TEST_F(PutOperationTest, return_success_if_op_acked_on_all_replicas_even_if_buck
"id:test:testdoctype1::, timestamp 100, size 45) => 1",
_sender.getCommands(true, true));
- getExternalOperationHandler().removeNodeFromDB(makeDocumentBucket(document::BucketId(16, 0x1dd4)), 0);
+ distributor_component().removeNodeFromDB(makeDocumentBucket(document::BucketId(16, 0x1dd4)), 0);
// If we get an ACK from the backend nodes, the operation has been persisted OK.
// Even if the bucket has been removed from the DB in the meantime (usually would
@@ -246,7 +248,7 @@ TEST_F(PutOperationTest, multiple_copies) {
"node(idx=3,crc=0x1,docs=2/4,bytes=3/5,trusted=true,active=false,ready=false), "
"node(idx=2,crc=0x1,docs=2/4,bytes=3/5,trusted=true,active=false,ready=false), "
"node(idx=1,crc=0x1,docs=2/4,bytes=3/5,trusted=true,active=false,ready=false)",
- dumpBucket(getExternalOperationHandler().getBucketId(doc->getId())));
+ dumpBucket(distributor_component().getBucketId(doc->getId())));
}
TEST_F(PutOperationTest, multiple_copies_early_return_primary_required) {
@@ -399,7 +401,7 @@ TEST_F(PutOperationTest, do_not_send_CreateBucket_if_already_pending) {
// Manually shove sent messages into pending message tracker, since
// this isn't done automatically.
for (size_t i = 0; i < _sender.commands().size(); ++i) {
- getExternalOperationHandler().getDistributor().getPendingMessageTracker()
+ distributor_component().getDistributor().getPendingMessageTracker()
.insert(_sender.command(i));
}
@@ -474,7 +476,7 @@ parseBucketInfoString(const std::string& nodeList) {
std::string
PutOperationTest::getNodes(const std::string& infoString) {
Document::SP doc(createDummyDocument("test", "uri"));
- document::BucketId bid(getExternalOperationHandler().getBucketId(doc->getId()));
+ document::BucketId bid(distributor_component().getBucketId(doc->getId()));
BucketInfo entry = parseBucketInfoString(infoString);
@@ -482,7 +484,7 @@ PutOperationTest::getNodes(const std::string& infoString) {
std::vector<uint16_t> targetNodes;
std::vector<uint16_t> createNodes;
- PutOperation::getTargetNodes(getExternalOperationHandler().getIdealNodes(makeDocumentBucket(bid)),
+ PutOperation::getTargetNodes(getDistributorBucketSpace().get_ideal_service_layer_nodes_bundle(bid).get_available_nodes(),
targetNodes, createNodes, entry, 2);
ost << "target( ";
@@ -516,7 +518,7 @@ TEST_F(PutOperationTest, replica_not_resurrected_in_db_when_node_down_in_active_
setupDistributor(Redundancy(3), NodeCount(3), "distributor:1 storage:3");
Document::SP doc(createDummyDocument("test", "uri"));
- document::BucketId bId = getExternalOperationHandler().getBucketId(doc->getId());
+ document::BucketId bId = distributor_component().getBucketId(doc->getId());
addNodesToBucketDB(bId, "0=1/2/3/t,1=1/2/3/t,2=1/2/3/t");
@@ -533,14 +535,14 @@ TEST_F(PutOperationTest, replica_not_resurrected_in_db_when_node_down_in_active_
ASSERT_EQ("BucketId(0x4000000000000593) : "
"node(idx=0,crc=0x7,docs=8/8,bytes=9/9,trusted=true,active=false,ready=false)",
- dumpBucket(getExternalOperationHandler().getBucketId(doc->getId())));
+ dumpBucket(distributor_component().getBucketId(doc->getId())));
}
TEST_F(PutOperationTest, replica_not_resurrected_in_db_when_node_down_in_pending_state) {
setupDistributor(Redundancy(3), NodeCount(4), "version:1 distributor:1 storage:3");
auto doc = createDummyDocument("test", "uri");
- auto bucket = getExternalOperationHandler().getBucketId(doc->getId());
+ auto bucket = distributor_component().getBucketId(doc->getId());
addNodesToBucketDB(bucket, "0=1/2/3/t,1=1/2/3/t,2=1/2/3/t");
sendPut(createPut(doc));
@@ -574,7 +576,7 @@ TEST_F(PutOperationTest, replica_not_resurrected_in_db_when_node_down_in_pending
TEST_F(PutOperationTest, put_is_failed_with_busy_if_target_down_in_pending_state) {
setupDistributor(Redundancy(3), NodeCount(4), "version:1 distributor:1 storage:3");
auto doc = createDummyDocument("test", "test");
- auto bucket = getExternalOperationHandler().getBucketId(doc->getId());
+ auto bucket = distributor_component().getBucketId(doc->getId());
addNodesToBucketDB(bucket, "0=1/2/3/t,1=1/2/3/t,2=1/2/3/t");
getBucketDBUpdater().onSetSystemState(
std::make_shared<api::SetSystemStateCommand>(
@@ -594,7 +596,7 @@ TEST_F(PutOperationTest, send_to_retired_nodes_if_no_up_nodes_available) {
"distributor:1 storage:2 .0.s:r .1.s:r");
Document::SP doc(createDummyDocument("test", "uri"));
document::BucketId bucket(
- getExternalOperationHandler().getBucketId(doc->getId()));
+ distributor_component().getBucketId(doc->getId()));
addNodesToBucketDB(bucket, "0=1/2/3/t,1=1/2/3/t");
sendPut(createPut(doc));
diff --git a/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp b/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp
new file mode 100644
index 00000000000..33c3b747015
--- /dev/null
+++ b/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp
@@ -0,0 +1,221 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/document/base/testdocman.h>
+#include <vespa/document/bucket/fixed_bucket_spaces.h>
+#include <vespa/document/repo/documenttyperepo.h>
+#include <vespa/document/update/documentupdate.h>
+#include <vespa/storage/common/reindexing_constants.h>
+#include <vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h>
+#include <vespa/storage/distributor/operations/external/visitoroperation.h>
+#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/distributormetricsset.h>
+#include <vespa/storage/distributor/pendingmessagetracker.h>
+#include <vespa/storage/distributor/uuid_generator.h>
+#include <vespa/storageapi/message/bucket.h>
+#include <vespa/storageapi/message/persistence.h>
+#include <vespa/storageapi/message/visitor.h>
+#include <tests/distributor/distributortestutil.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace ::testing;
+using document::Bucket;
+using document::BucketId;
+
+namespace storage::distributor {
+
+namespace {
+
+Bucket default_bucket(BucketId id) {
+ return Bucket(document::FixedBucketSpaces::default_space(), id);
+}
+
+api::StorageMessageAddress make_storage_address(uint16_t node) {
+ static vespalib::string _storage("storage");
+ return {&_storage, lib::NodeType::STORAGE, node};
+}
+
+struct MockUuidGenerator : UuidGenerator {
+ vespalib::string _uuid;
+ MockUuidGenerator() : _uuid("a-very-random-id") {}
+
+ vespalib::string generate_uuid() const override {
+ return _uuid;
+ }
+};
+
+}
+
+struct ReadForWriteVisitorOperationStarterTest : Test, DistributorTestUtil {
+ document::TestDocMan _test_doc_man;
+ VisitorOperation::Config _default_config;
+ std::unique_ptr<OperationOwner> _op_owner;
+ BucketId _superbucket;
+ BucketId _sub_bucket;
+ MockUuidGenerator _mock_uuid_generator;
+
+ ReadForWriteVisitorOperationStarterTest()
+ : _test_doc_man(),
+ _default_config(100, 100),
+ _op_owner(),
+ _superbucket(16, 4),
+ _sub_bucket(17, 4),
+ _mock_uuid_generator()
+ {}
+
+ void SetUp() override {
+ createLinks();
+ setupDistributor(1, 1, "version:1 distributor:1 storage:1");
+ _op_owner = std::make_unique<OperationOwner>(_sender, getClock());
+ _sender.setPendingMessageTracker(getDistributor().getPendingMessageTracker());
+
+ addNodesToBucketDB(_sub_bucket, "0=1/2/3/t");
+ }
+
+ void TearDown() override {
+ close();
+ }
+
+ std::shared_ptr<VisitorOperation> create_nested_visitor_op(bool valid_command = true) {
+ auto cmd = std::make_shared<api::CreateVisitorCommand>(
+ document::FixedBucketSpaces::default_space(), "reindexingvisitor", "foo", "");
+ if (valid_command) {
+ cmd->addBucketToBeVisited(_superbucket);
+ cmd->addBucketToBeVisited(BucketId()); // Will be inferred to first sub-bucket in DB
+ }
+ return std::make_shared<VisitorOperation>(
+ distributor_component(), distributor_component(),
+ getDistributorBucketSpace(), cmd, _default_config,
+ getDistributor().getMetrics().visits);
+ }
+
+ OperationSequencer& operation_sequencer() {
+ return getExternalOperationHandler().operation_sequencer();
+ }
+
+ std::shared_ptr<ReadForWriteVisitorOperationStarter> create_rfw_op(std::shared_ptr<VisitorOperation> visitor_op) {
+ return std::make_shared<ReadForWriteVisitorOperationStarter>(
+ std::move(visitor_op), operation_sequencer(),
+ *_op_owner, getDistributor().getPendingMessageTracker(),
+ _mock_uuid_generator);
+ }
+};
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_that_fails_precondition_checks_is_immediately_failed) {
+ auto op = create_rfw_op(create_nested_visitor_op(false));
+ _op_owner->start(op, OperationStarter::Priority(120));
+ ASSERT_EQ("", _sender.getCommands(true));
+ EXPECT_EQ("CreateVisitorReply(last=BucketId(0x0000000000000000)) "
+ "ReturnCode(ILLEGAL_PARAMETERS, No buckets in CreateVisitorCommand for visitor 'foo')",
+ _sender.getLastReply());
+}
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_immediately_started_if_no_pending_ops_to_bucket) {
+ auto op = create_rfw_op(create_nested_visitor_op(true));
+ _op_owner->start(op, OperationStarter::Priority(120));
+ ASSERT_EQ("Visitor Create => 0", _sender.getCommands(true));
+}
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_is_bounced_if_merge_pending_for_bucket) {
+ auto op = create_rfw_op(create_nested_visitor_op(true));
+ std::vector<api::MergeBucketCommand::Node> nodes({{0, false}, {1, false}});
+ auto merge = std::make_shared<api::MergeBucketCommand>(default_bucket(_sub_bucket),
+ std::move(nodes),
+ api::Timestamp(123456));
+ merge->setAddress(make_storage_address(0));
+ getDistributor().getPendingMessageTracker().insert(merge);
+ _op_owner->start(op, OperationStarter::Priority(120));
+ ASSERT_EQ("", _sender.getCommands(true));
+ EXPECT_EQ("CreateVisitorReply(last=BucketId(0x0000000000000000)) "
+ "ReturnCode(BUSY, A merge operation is pending for this bucket)",
+ _sender.getLastReply());
+}
+
+namespace {
+
+struct ConcurrentMutationFixture {
+ ReadForWriteVisitorOperationStarterTest& _test;
+ std::shared_ptr<api::StorageCommand> _mutation;
+
+ explicit ConcurrentMutationFixture(ReadForWriteVisitorOperationStarterTest& test) : _test(test) {}
+
+ void block_bucket_with_mutation() {
+ // Pending mutating op to same bucket, prevents visitor from starting
+ auto update = std::make_shared<document::DocumentUpdate>(
+ _test._test_doc_man.getTypeRepo(),
+ *_test._test_doc_man.getTypeRepo().getDocumentType("testdoctype1"),
+ document::DocumentId("id::testdoctype1:n=4:foo"));
+ auto update_cmd = std::make_shared<api::UpdateCommand>(
+ default_bucket(document::BucketId(0)), std::move(update), api::Timestamp(0));
+
+ Operation::SP mutating_op;
+ _test.getExternalOperationHandler().handleMessage(update_cmd, mutating_op);
+ ASSERT_TRUE(mutating_op);
+ _test._op_owner->start(mutating_op, OperationStarter::Priority(120));
+ ASSERT_EQ("Update(BucketId(0x4400000000000004), id::testdoctype1:n=4:foo, timestamp 1) => 0",
+ _test.sender().getCommands(true, true));
+ _mutation = _test.sender().command(0);
+ // Since pending message tracking normally happens in the distributor itself during sendUp,
+ // we have to emulate this and explicitly insert the sent message into the pending mapping.
+ _test.getDistributor().getPendingMessageTracker().insert(_mutation);
+ }
+
+ void unblock_bucket() {
+ // Pretend update operation completed
+ auto update_reply = std::shared_ptr<api::StorageReply>(_mutation->makeReply());
+ _test.getDistributor().getPendingMessageTracker().reply(*update_reply);
+ _test._op_owner->handleReply(update_reply);
+ }
+};
+
+}
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_start_deferred_if_pending_ops_to_bucket) {
+ ConcurrentMutationFixture f(*this);
+ auto op = create_rfw_op(create_nested_visitor_op(true));
+ ASSERT_NO_FATAL_FAILURE(f.block_bucket_with_mutation());
+
+ _op_owner->start(op, OperationStarter::Priority(120));
+ // Nothing started yet
+ ASSERT_EQ("", _sender.getCommands(true, false, 1));
+ ASSERT_NO_FATAL_FAILURE(f.unblock_bucket());
+
+ // Visitor should now be started!
+ ASSERT_EQ("Visitor Create => 0", _sender.getCommands(true, false, 1));
+}
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_bounced_if_bucket_removed_from_db_before_deferred_start) {
+ ConcurrentMutationFixture f(*this);
+ auto op = create_rfw_op(create_nested_visitor_op(true));
+ ASSERT_NO_FATAL_FAILURE(f.block_bucket_with_mutation());
+
+ _op_owner->start(op, OperationStarter::Priority(120));
+ // Nothing started yet
+ ASSERT_EQ("", _sender.getCommands(true, false, 1));
+
+ // Simulate that ownership of bucket has changed, or replica has gone down.
+ removeFromBucketDB(_sub_bucket);
+ ASSERT_NO_FATAL_FAILURE(f.unblock_bucket());
+
+ // No visitor should be sent to the content node
+ ASSERT_EQ("", _sender.getCommands(true, false, 1));
+ // Instead, we should get a "bucket not found" transient error bounce back to the client.
+ EXPECT_EQ("CreateVisitorReply(last=BucketId(0x0000000000000000)) "
+ "ReturnCode(BUCKET_NOT_FOUND),"
+ "UpdateReply(id::testdoctype1:n=4:foo, BucketId(0x0000000000000000), "
+ "timestamp 1, timestamp of updated doc: 0) ReturnCode(NONE)",
+ _sender.getReplies(false, true));
+}
+
+TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_locks_bucket_with_random_token_with_parameter_propagation) {
+ _mock_uuid_generator._uuid = "fritjof";
+ auto op = create_rfw_op(create_nested_visitor_op(true));
+ _op_owner->start(op, OperationStarter::Priority(120));
+ ASSERT_EQ("Visitor Create => 0", _sender.getCommands(true));
+ auto cmd = dynamic_pointer_cast<api::CreateVisitorCommand>(_sender.command(0));
+ ASSERT_TRUE(cmd);
+ EXPECT_EQ(cmd->getParameters().get(reindexing_bucket_lock_visitor_parameter_key(),
+ vespalib::stringref("not found :I")),
+ "fritjof");
+}
+
+}
diff --git a/storage/src/tests/distributor/removebucketoperationtest.cpp b/storage/src/tests/distributor/removebucketoperationtest.cpp
index e2bf867ad11..c670e89b065 100644
--- a/storage/src/tests/distributor/removebucketoperationtest.cpp
+++ b/storage/src/tests/distributor/removebucketoperationtest.cpp
@@ -9,6 +9,7 @@
#include <tests/distributor/distributortestutil.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using namespace ::testing;
@@ -33,7 +34,7 @@ TEST_F(RemoveBucketOperationTest, simple) {
setRedundancy(1);
enableDistributorClusterState("distributor:1 storage:3");
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(1,2)));
op.setIdealStateManager(&getIdealStateManager());
@@ -65,7 +66,7 @@ TEST_F(RemoveBucketOperationTest, bucket_info_mismatch_failure) {
enableDistributorClusterState("distributor:1 storage:2");
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(1)));
op.setIdealStateManager(&getIdealStateManager());
@@ -100,7 +101,7 @@ TEST_F(RemoveBucketOperationTest, fail_with_invalid_bucket_info) {
enableDistributorClusterState("distributor:1 storage:2");
- RemoveBucketOperation op("storage",
+ RemoveBucketOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(1)));
op.setIdealStateManager(&getIdealStateManager());
diff --git a/storage/src/tests/distributor/removelocationtest.cpp b/storage/src/tests/distributor/removelocationtest.cpp
index 74daba3d098..779d6f60be0 100644
--- a/storage/src/tests/distributor/removelocationtest.cpp
+++ b/storage/src/tests/distributor/removelocationtest.cpp
@@ -27,11 +27,13 @@ struct RemoveLocationOperationTest : Test, DistributorTestUtil {
auto msg = std::make_shared<api::RemoveLocationCommand>(selection, makeDocumentBucket(document::BucketId(0)));
op = std::make_unique<RemoveLocationOperation>(
- getExternalOperationHandler(),
+ distributor_component(),
+ distributor_component(),
+ distributor_component(),
getDistributorBucketSpace(),
msg,
getDistributor().getMetrics().
- removelocations[msg->getLoadType()]);
+ removelocations);
op->start(_sender, framework::MilliSecTime(0));
}
diff --git a/storage/src/tests/distributor/removeoperationtest.cpp b/storage/src/tests/distributor/removeoperationtest.cpp
index c3fcda30bf5..cc5452e2bfe 100644
--- a/storage/src/tests/distributor/removeoperationtest.cpp
+++ b/storage/src/tests/distributor/removeoperationtest.cpp
@@ -23,7 +23,7 @@ struct RemoveOperationTest : Test, DistributorTestUtil {
createLinks();
docId = document::DocumentId("id:test:test::uri");
- bucketId = getExternalOperationHandler().getBucketId(docId);
+ bucketId = distributor_component().getBucketId(docId);
enableDistributorClusterState("distributor:1 storage:4");
};
@@ -35,11 +35,12 @@ struct RemoveOperationTest : Test, DistributorTestUtil {
auto msg = std::make_shared<api::RemoveCommand>(makeDocumentBucket(document::BucketId(0)), dId, 100);
op = std::make_unique<RemoveOperation>(
- getExternalOperationHandler(),
+ distributor_component(),
+ distributor_component(),
getDistributorBucketSpace(),
msg,
getDistributor().getMetrics().
- removes[msg->getLoadType()]);
+ removes);
op->start(_sender, framework::MilliSecTime(0));
}
diff --git a/storage/src/tests/distributor/simplemaintenancescannertest.cpp b/storage/src/tests/distributor/simplemaintenancescannertest.cpp
index b21a10c319e..58dc2430041 100644
--- a/storage/src/tests/distributor/simplemaintenancescannertest.cpp
+++ b/storage/src/tests/distributor/simplemaintenancescannertest.cpp
@@ -36,7 +36,7 @@ void
SimpleMaintenanceScannerTest::SetUp()
{
_priorityGenerator = std::make_unique<MockMaintenancePriorityGenerator>();
- _bucketSpaceRepo = std::make_unique<DistributorBucketSpaceRepo>();
+ _bucketSpaceRepo = std::make_unique<DistributorBucketSpaceRepo>(0u);
_priorityDb = std::make_unique<SimpleBucketPriorityDatabase>();
_scanner = std::make_unique<SimpleMaintenanceScanner>(*_priorityDb, *_priorityGenerator, *_bucketSpaceRepo);
}
diff --git a/storage/src/tests/distributor/splitbuckettest.cpp b/storage/src/tests/distributor/splitbuckettest.cpp
index d88b02b332e..527fc7bfa2a 100644
--- a/storage/src/tests/distributor/splitbuckettest.cpp
+++ b/storage/src/tests/distributor/splitbuckettest.cpp
@@ -1,14 +1,16 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <tests/common/dummystoragelink.h>
-#include <vespa/storageapi/message/bucketsplitting.h>
-#include <vespa/storage/distributor/operations/idealstate/splitoperation.h>
#include <vespa/document/base/documentid.h>
-#include <vespa/storageapi/message/persistence.h>
-#include <vespa/storage/distributor/idealstatemanager.h>
-#include <tests/distributor/distributortestutil.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/storage/distributor/distributor.h>
+#include <vespa/storage/distributor/idealstatemanager.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
+#include <vespa/storage/distributor/operations/idealstate/splitoperation.h>
+#include <vespa/storageapi/message/bucketsplitting.h>
+#include <vespa/storageapi/message/persistence.h>
+#include <tests/common/dummystoragelink.h>
+#include <tests/distributor/distributortestutil.h>
#include <vespa/vespalib/gtest/gtest.h>
+#include "dummy_cluster_context.h"
using document::test::makeDocumentBucket;
using namespace document;
@@ -44,13 +46,17 @@ SplitOperationTest::SplitOperationTest()
{
}
+namespace {
+ api::StorageMessageAddress _Storage0Address(dummy_cluster_context.cluster_name_ptr(), lib::NodeType::STORAGE, 0);
+}
+
TEST_F(SplitOperationTest, simple) {
enableDistributorClusterState("distributor:1 storage:1");
insertBucketInfo(document::BucketId(16, 1), 0, 0xabc, 1000,
tooLargeBucketSize, 250);
- SplitOperation op("storage",
+ SplitOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(0)),
maxSplitBits,
@@ -65,7 +71,7 @@ TEST_F(SplitOperationTest, simple) {
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SPLITBUCKET);
- EXPECT_EQ(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0).toString(),
+ EXPECT_EQ(_Storage0Address.toString(),
msg->getAddress()->toString());
std::shared_ptr<api::StorageReply> reply(msg->makeReply().release());
@@ -119,7 +125,7 @@ TEST_F(SplitOperationTest, multi_node_failure) {
enableDistributorClusterState("distributor:1 storage:2");
- SplitOperation op("storage",
+ SplitOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(document::BucketId(16, 1)),
toVector<uint16_t>(0,1)),
maxSplitBits,
@@ -135,7 +141,7 @@ TEST_F(SplitOperationTest, multi_node_failure) {
{
std::shared_ptr<api::StorageCommand> msg = _sender.command(0);
ASSERT_EQ(msg->getType(), api::MessageType::SPLITBUCKET);
- EXPECT_EQ(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0).toString(),
+ EXPECT_EQ(_Storage0Address.toString(),
msg->getAddress()->toString());
auto* sreply = static_cast<api::SplitBucketReply*>(msg->makeReply().release());
@@ -204,7 +210,7 @@ TEST_F(SplitOperationTest, copy_trusted_status_not_carried_over_after_split) {
addNodesToBucketDB(sourceBucket, "0=150/20/30000000/t,1=450/50/60000/u,"
"2=550/60/70000");
- SplitOperation op("storage",
+ SplitOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(sourceBucket), toVector<uint16_t>(0, 1)),
maxSplitBits,
splitCount,
@@ -255,6 +261,7 @@ TEST_F(SplitOperationTest, operation_blocked_by_pending_join) {
compReg.setClock(clock);
clock.setAbsoluteTimeInSeconds(1);
PendingMessageTracker tracker(compReg);
+ OperationSequencer op_seq;
enableDistributorClusterState("distributor:1 storage:2");
@@ -264,31 +271,52 @@ TEST_F(SplitOperationTest, operation_blocked_by_pending_join) {
};
auto joinCmd = std::make_shared<api::JoinBucketsCommand>(makeDocumentBucket(joinTarget));
joinCmd->getSourceBuckets() = joinSources;
- joinCmd->setAddress(
- api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0));
+ joinCmd->setAddress(_Storage0Address);
tracker.insert(joinCmd);
insertBucketInfo(joinTarget, 0, 0xabc, 1000, 1234, true);
- SplitOperation op("storage",
+ SplitOperation op(dummy_cluster_context,
BucketAndNodes(makeDocumentBucket(joinTarget), toVector<uint16_t>(0)),
maxSplitBits,
splitCount,
splitByteSize);
- EXPECT_TRUE(op.isBlocked(tracker));
+ EXPECT_TRUE(op.isBlocked(tracker, op_seq));
// Now, pretend there's a join for another node in the same bucket. This
// will happen when a join is partially completed.
tracker.clearMessagesForNode(0);
- EXPECT_FALSE(op.isBlocked(tracker));
+ EXPECT_FALSE(op.isBlocked(tracker, op_seq));
- joinCmd->setAddress(
- api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 1));
+ joinCmd->setAddress(api::StorageMessageAddress::create(dummy_cluster_context.cluster_name_ptr(),
+ lib::NodeType::STORAGE, 1));
tracker.insert(joinCmd);
- EXPECT_TRUE(op.isBlocked(tracker));
+ EXPECT_TRUE(op.isBlocked(tracker, op_seq));
+}
+
+TEST_F(SplitOperationTest, split_is_blocked_by_locked_bucket) {
+ StorageComponentRegisterImpl compReg;
+ framework::defaultimplementation::FakeClock clock;
+ compReg.setClock(clock);
+ clock.setAbsoluteTimeInSeconds(1);
+ PendingMessageTracker tracker(compReg);
+ OperationSequencer op_seq;
+
+ enableDistributorClusterState("distributor:1 storage:2");
+
+ document::BucketId source_bucket(16, 1);
+ insertBucketInfo(source_bucket, 0, 0xabc, 1000, tooLargeBucketSize, 250);
+
+ SplitOperation op(dummy_cluster_context, BucketAndNodes(makeDocumentBucket(source_bucket), toVector<uint16_t>(0)),
+ maxSplitBits, splitCount, splitByteSize);
+
+ EXPECT_FALSE(op.isBlocked(tracker, op_seq));
+ auto token = op_seq.try_acquire(makeDocumentBucket(source_bucket), "foo");
+ EXPECT_TRUE(token.valid());
+ EXPECT_TRUE(op.isBlocked(tracker, op_seq));
}
} // storage::distributor
diff --git a/storage/src/tests/distributor/statecheckerstest.cpp b/storage/src/tests/distributor/statecheckerstest.cpp
index f66aab26dc9..00c1c7bb403 100644
--- a/storage/src/tests/distributor/statecheckerstest.cpp
+++ b/storage/src/tests/distributor/statecheckerstest.cpp
@@ -238,7 +238,7 @@ struct StateCheckersTest : Test, DistributorTestUtil {
tick(); // Trigger command processing and pending state setup.
}
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(),
+ StateChecker::Context c(distributor_component(),
getBucketSpaceRepo().get(params._bucket_space),
statsTracker,
bucket);
@@ -290,7 +290,7 @@ std::string StateCheckersTest::testSplit(uint32_t splitCount,
SplitBucketStateChecker checker;
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
getConfig().setSplitSize(splitSize);
getConfig().setSplitCount(splitCount);
getConfig().setMinimalBucketSplit(minSplitBits);
@@ -375,7 +375,7 @@ StateCheckersTest::testInconsistentSplit(const document::BucketId& bid,
{
SplitInconsistentStateChecker checker;
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, true,
PendingMessage(), includePriority);
}
@@ -433,7 +433,7 @@ StateCheckersTest::testJoin(uint32_t joinCount,
getConfig().setMinimalBucketSplit(minSplitBits);
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, true, blocker, includePriority);
}
@@ -586,7 +586,7 @@ StateCheckersTest::testSynchronizeAndMove(const std::string& bucketInfo,
enableDistributorClusterState(clusterState);
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, false, blocker, includePriority);
}
@@ -820,7 +820,7 @@ StateCheckersTest::testDeleteExtraCopies(
}
DeleteExtraCopiesStateChecker checker;
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, false, blocker, includePriority);
}
@@ -937,7 +937,7 @@ std::string StateCheckersTest::testBucketState(
BucketStateStateChecker checker;
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, false, PendingMessage(),
includePriority);
}
@@ -1104,7 +1104,7 @@ std::string StateCheckersTest::testBucketStatePerGroup(
BucketStateStateChecker checker;
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket(bid));
return testStateChecker(checker, c, false, PendingMessage(),
includePriority);
}
@@ -1231,7 +1231,7 @@ std::string StateCheckersTest::testGarbageCollection(
getConfig().setGarbageCollection("music", std::chrono::seconds(checkInterval));
getConfig().setLastGarbageCollectionChangeTime(vespalib::steady_time(std::chrono::seconds(lastChangeTime)));
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker,
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker,
makeDocumentBucket(e.getBucketId()));
getClock().setAbsoluteTimeInSeconds(nowTimestamp);
return testStateChecker(checker, c, false, PendingMessage(),
@@ -1304,7 +1304,7 @@ TEST_F(StateCheckersTest, gc_inhibited_when_ideal_node_in_maintenance) {
getConfig().setGarbageCollection("music", 3600s);
getConfig().setLastGarbageCollectionChangeTime(vespalib::steady_time(vespalib::duration::zero()));
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker,
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker,
makeDocumentBucket(bucket));
getClock().setAbsoluteTimeInSeconds(4000);
// Would normally (in a non-maintenance case) trigger GC due to having
@@ -1448,7 +1448,7 @@ TEST_F(StateCheckersTest, context_populates_ideal_state_containers) {
setupDistributor(2, 100, "distributor:1 storage:4");
NodeMaintenanceStatsTracker statsTracker;
- StateChecker::Context c(getExternalOperationHandler(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket({17, 0}));
+ StateChecker::Context c(distributor_component(), getDistributorBucketSpace(), statsTracker, makeDocumentBucket({17, 0}));
ASSERT_THAT(c.idealState, ElementsAre(1, 3));
// TODO replace with UnorderedElementsAre once we can build gmock without issues
@@ -1491,7 +1491,7 @@ public:
// NOTE: resets the bucket database!
void runFor(const document::BucketId& bid) {
Checker checker;
- StateChecker::Context c(_fixture.getExternalOperationHandler(), _fixture.getDistributorBucketSpace(), _statsTracker, makeDocumentBucket(bid));
+ StateChecker::Context c(_fixture.distributor_component(), _fixture.getDistributorBucketSpace(), _statsTracker, makeDocumentBucket(bid));
_result = _fixture.testStateChecker(
checker, c, false, StateCheckersTest::PendingMessage(), false);
}
diff --git a/storage/src/tests/distributor/statoperationtest.cpp b/storage/src/tests/distributor/statoperationtest.cpp
index 53ea0ec5efa..a80eb9533bb 100644
--- a/storage/src/tests/distributor/statoperationtest.cpp
+++ b/storage/src/tests/distributor/statoperationtest.cpp
@@ -32,7 +32,6 @@ TEST_F(StatOperationTest, bucket_info) {
addNodesToBucketDB(document::BucketId(16, 5), "0=4/2/100,1=4/2/100");
StatBucketOperation op(
- getExternalOperationHandler(),
getDistributorBucketSpace(),
std::make_shared<api::StatBucketCommand>(
makeDocumentBucket(document::BucketId(16, 5)), ""));
@@ -74,7 +73,7 @@ TEST_F(StatOperationTest, bucket_list) {
StatBucketListOperation op(
getDistributorBucketSpace().getBucketDatabase(),
getIdealStateManager(),
- getExternalOperationHandler().getIndex(),
+ distributor_component().getIndex(),
msg);
op.start(_sender, framework::MilliSecTime(0));
diff --git a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp
index 635e5b9883b..1518c8594aa 100644
--- a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp
+++ b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp
@@ -302,7 +302,7 @@ TwoPhaseUpdateOperationTest::sendUpdate(const std::string& bucketState,
}
update->setCreateIfNonExistent(options._createIfNonExistent);
- document::BucketId id = getExternalOperationHandler().getBucketId(update->getId());
+ document::BucketId id = distributor_component().getBucketId(update->getId());
document::BucketId id2 = document::BucketId(id.getUsedBits() + 1, id.getRawId());
if (bucketState.length()) {
@@ -325,9 +325,9 @@ TwoPhaseUpdateOperationTest::sendUpdate(const std::string& bucketState,
msg->setCondition(options._condition);
msg->setTransportContext(std::make_unique<DummyTransportContext>());
- ExternalOperationHandler& handler = getExternalOperationHandler();
+ auto& comp = distributor_component();
return std::make_shared<TwoPhaseUpdateOperation>(
- handler, getDistributorBucketSpace(), msg, getDistributor().getMetrics());
+ comp, comp, comp, getDistributorBucketSpace(), msg, getDistributor().getMetrics());
}
TEST_F(TwoPhaseUpdateOperationTest, simple) {
@@ -1002,7 +1002,7 @@ TEST_F(TwoPhaseUpdateOperationTest, safe_path_consistent_get_reply_timestamps_re
"ReturnCode(NONE)",
_sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(1, metrics.fast_path_restarts.getValue());
}
@@ -1021,7 +1021,7 @@ TEST_F(TwoPhaseUpdateOperationTest, safe_path_consistent_get_reply_timestamps_do
// Should _not_ be restarted with fast path, as it has been config disabled
ASSERT_EQ("Put => 1,Put => 0", _sender.getCommands(true, false, 2));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(0, metrics.fast_path_restarts.getValue());
}
@@ -1116,7 +1116,7 @@ TEST_F(ThreePhaseUpdateTest, full_document_get_sent_to_replica_with_highest_time
reply_to_metadata_get(*cb, _sender, 0, 1000U);
reply_to_metadata_get(*cb, _sender, 1, 2000U);
- auto& metrics = getDistributor().getMetrics().update_metadata_gets[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().update_metadata_gets;
EXPECT_EQ(1, metrics.ok.getValue()); // Technically tracks an entire operation covering multiple Gets.
// Node 1 has newest document version at ts=2000
@@ -1137,7 +1137,7 @@ TEST_F(ThreePhaseUpdateTest, puts_are_sent_after_receiving_full_document_get) {
replyToGet(*cb, _sender, 2, 2000U);
ASSERT_EQ("Put => 1,Put => 0", _sender.getCommands(true, false, 3));
- auto& metrics = getDistributor().getMetrics().update_gets[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().update_gets;
EXPECT_EQ(1, metrics.ok.getValue());
}
@@ -1158,7 +1158,7 @@ TEST_F(ThreePhaseUpdateTest, consistent_meta_get_timestamps_can_restart_in_fast_
"ReturnCode(NONE)",
_sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(1, metrics.fast_path_restarts.getValue());
}
@@ -1178,7 +1178,7 @@ TEST_F(ThreePhaseUpdateTest, no_document_found_on_any_replicas_is_considered_con
reply_to_metadata_get(*cb, _sender, 1, no_document_timestamp);
ASSERT_EQ("Update => 0,Update => 1", _sender.getCommands(true, false, 2));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(1, metrics.fast_path_restarts.getValue());
}
diff --git a/storage/src/tests/distributor/updateoperationtest.cpp b/storage/src/tests/distributor/updateoperationtest.cpp
index 844cf80e6b6..d3a8b270ad0 100644
--- a/storage/src/tests/distributor/updateoperationtest.cpp
+++ b/storage/src/tests/distributor/updateoperationtest.cpp
@@ -59,16 +59,16 @@ UpdateOperationTest::sendUpdate(const std::string& bucketState, bool create_if_m
document::DocumentId("id:ns:" + _html_type->getName() + "::1"));
update->setCreateIfNonExistent(create_if_missing);
- _bId = getExternalOperationHandler().getBucketId(update->getId());
+ _bId = distributor_component().getBucketId(update->getId());
addNodesToBucketDB(_bId, bucketState);
auto msg = std::make_shared<api::UpdateCommand>(makeDocumentBucket(document::BucketId(0)), update, 100);
- ExternalOperationHandler& handler = getExternalOperationHandler();
+ auto& comp = distributor_component();
return std::make_shared<UpdateOperation>(
- handler, getDistributorBucketSpace(), msg,
- getDistributor().getMetrics().updates[msg->getLoadType()]);
+ comp, comp, getDistributorBucketSpace(), msg, std::vector<BucketDatabase::Entry>(),
+ getDistributor().getMetrics().updates);
}
void
@@ -101,7 +101,7 @@ TEST_F(UpdateOperationTest, simple) {
"timestamp 100, timestamp of updated doc: 90) ReturnCode(NONE)",
sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(0, metrics.diverging_timestamp_updates.getValue());
}
@@ -141,7 +141,7 @@ TEST_F(UpdateOperationTest, multi_node) {
"node(idx=0,crc=0x2,docs=4/4,bytes=6/6,trusted=true,active=false,ready=false)",
dumpBucket(_bId));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(0, metrics.diverging_timestamp_updates.getValue());
}
@@ -161,7 +161,7 @@ TEST_F(UpdateOperationTest, multi_node_inconsistent_timestamp) {
"(best node 1)) ReturnCode(NONE)",
sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(1, metrics.diverging_timestamp_updates.getValue());
}
@@ -179,7 +179,7 @@ TEST_F(UpdateOperationTest, test_and_set_failures_increment_tas_metric) {
"ReturnCode(TEST_AND_SET_CONDITION_FAILED, bork bork)",
sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(1, metrics.failures.test_and_set_failed.getValue());
}
@@ -212,7 +212,7 @@ TEST_F(UpdateOperationTest, create_if_missing_update_sentinel_timestamp_is_treat
"timestamp 100, timestamp of updated doc: 0) ReturnCode(NONE)",
sender.getLastReply(true));
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
EXPECT_EQ(0, metrics.diverging_timestamp_updates.getValue());
}
@@ -236,7 +236,7 @@ TEST_F(UpdateOperationTest, inconsistent_create_if_missing_updates_picks_largest
EXPECT_NE(newest.first, BucketId());
EXPECT_EQ(newest.second, 1);
- auto& metrics = getDistributor().getMetrics().updates[documentapi::LoadType::DEFAULT];
+ auto& metrics = getDistributor().getMetrics().updates;
// Implementation detail: since we get diverging results from nodes 2 and 1, these are
// counted as separate diverging updates.
EXPECT_EQ(2, metrics.diverging_timestamp_updates.getValue());
diff --git a/storage/src/tests/distributor/visitoroperationtest.cpp b/storage/src/tests/distributor/visitoroperationtest.cpp
index 8a9d8063525..c4f72c312c7 100644
--- a/storage/src/tests/distributor/visitoroperationtest.cpp
+++ b/storage/src/tests/distributor/visitoroperationtest.cpp
@@ -4,6 +4,7 @@
#include <vespa/storageapi/message/datagram.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageapi/message/state.h>
+#include <vespa/storage/common/reindexing_constants.h>
#include <vespa/storage/distributor/operations/external/visitoroperation.h>
#include <vespa/storage/distributor/operations/external/visitororder.h>
#include <vespa/storage/distributor/distributormetricsset.h>
@@ -94,7 +95,7 @@ struct VisitorOperationTest : Test, DistributorTestUtil {
}
VisitorMetricSet& defaultVisitorMetrics() {
- return getDistributor().getMetrics().visits[documentapi::LoadType::DEFAULT];
+ return getDistributor().getMetrics().visits;
}
std::unique_ptr<VisitorOperation> createOpWithConfig(
@@ -102,15 +103,15 @@ struct VisitorOperationTest : Test, DistributorTestUtil {
const VisitorOperation::Config& config)
{
return std::make_unique<VisitorOperation>(
- getExternalOperationHandler(),
+ distributor_component(),
+ distributor_component(),
getDistributorBucketSpace(),
msg,
config,
- getDistributor().getMetrics().visits[msg->getLoadType()]);
+ getDistributor().getMetrics().visits);
}
- std::unique_ptr<VisitorOperation> createOpWithDefaultConfig(
- api::CreateVisitorCommand::SP msg)
+ std::unique_ptr<VisitorOperation> createOpWithDefaultConfig(api::CreateVisitorCommand::SP msg)
{
return createOpWithConfig(std::move(msg), defaultConfig);
}
@@ -126,21 +127,17 @@ struct VisitorOperationTest : Test, DistributorTestUtil {
}
const std::vector<BucketId>& getBucketsFromLastCommand() {
- const auto& cvc = dynamic_cast<const CreateVisitorCommand&>(
- *_sender.commands().back());
+ const auto& cvc = dynamic_cast<const CreateVisitorCommand&>(*_sender.commands().back());
return cvc.getBuckets();
}
std::pair<std::string, std::string>
- runVisitor(document::BucketId id,
- document::BucketId lastId,
- uint32_t maxBuckets);
+ runVisitor(document::BucketId id, document::BucketId lastId, uint32_t maxBuckets);
void doStandardVisitTest(const std::string& clusterState);
- std::unique_ptr<VisitorOperation> startOperationWith2StorageNodeVisitors(
- bool inconsistent);
+ std::unique_ptr<VisitorOperation> startOperationWith2StorageNodeVisitors(bool inconsistent);
void do_visitor_roundtrip_with_statistics(const api::ReturnCode& result);
};
@@ -1092,4 +1089,21 @@ TEST_F(VisitorOperationTest, statistical_metrics_not_updated_on_wrong_distributi
EXPECT_DOUBLE_EQ(0.0, defaultVisitorMetrics().latency.getCount());
}
+TEST_F(VisitorOperationTest, assigning_put_lock_access_token_sets_special_visitor_parameter) {
+ document::BucketId id(0x400000000000007bULL);
+ enableDistributorClusterState("distributor:1 storage:1");
+ addNodesToBucketDB(id, "0=1/1/1/t");
+
+ auto op = createOpWithDefaultConfig(createVisitorCommand("metricstats", id, nullId));
+ op->assign_put_lock_access_token("its-a me, mario");
+
+ op->start(_sender, framework::MilliSecTime(0));
+ ASSERT_EQ("Visitor Create => 0", _sender.getCommands(true));
+ auto cmd = std::dynamic_pointer_cast<api::CreateVisitorCommand>(_sender.command(0));
+ ASSERT_TRUE(cmd);
+ EXPECT_EQ(cmd->getParameters().get(reindexing_bucket_lock_visitor_parameter_key(),
+ vespalib::stringref("")),
+ "its-a me, mario");
+}
+
}
diff --git a/storage/src/tests/persistence/common/filestortestfixture.cpp b/storage/src/tests/persistence/common/filestortestfixture.cpp
index 079abd6df06..57c63747ece 100644
--- a/storage/src/tests/persistence/common/filestortestfixture.cpp
+++ b/storage/src/tests/persistence/common/filestortestfixture.cpp
@@ -83,9 +83,11 @@ FileStorTestFixture::TestFileStorComponents::TestFileStorComponents(
top.open();
}
+vespalib::string _Storage("storage");
+
api::StorageMessageAddress
FileStorTestFixture::makeSelfAddress() {
- return api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0);
+ return api::StorageMessageAddress(&_Storage, lib::NodeType::STORAGE, 0);
}
void
diff --git a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp
index 3cac188cb17..3bd92d31ca7 100644
--- a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp
+++ b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp
@@ -56,7 +56,11 @@ namespace storage {
namespace {
-metrics::LoadType defaultLoadType(0, "default");
+vespalib::string _Cluster("cluster");
+vespalib::string _Storage("storage");
+api::StorageMessageAddress _Storage2(&_Storage, lib::NodeType::STORAGE, 2);
+api::StorageMessageAddress _Storage3(&_Storage, lib::NodeType::STORAGE, 3);
+api::StorageMessageAddress _Cluster1(&_Cluster, lib::NodeType::STORAGE, 1);
struct TestFileStorComponents;
@@ -250,7 +254,6 @@ struct FileStorHandlerComponents {
DummyStorageLink top;
DummyStorageLink* dummyManager;
ForwardingMessageSender messageSender;
- documentapi::LoadTypeSet loadTypes;
FileStorMetrics metrics;
std::unique_ptr<FileStorHandler> filestorHandler;
@@ -258,14 +261,13 @@ struct FileStorHandlerComponents {
: top(),
dummyManager(new DummyStorageLink),
messageSender(*dummyManager),
- loadTypes("raw:"),
- metrics(loadTypes.getMetricLoadTypes()),
+ metrics(),
filestorHandler()
{
top.push_back(std::unique_ptr<StorageLink>(dummyManager));
top.open();
- metrics.initDiskMetrics(loadTypes.getMetricLoadTypes(), 1, threadsPerDisk);
+ metrics.initDiskMetrics(1, threadsPerDisk);
filestorHandler = std::make_unique<FileStorHandlerImpl>(messageSender, metrics, test._node->getComponentRegister());
filestorHandler->setGetNextMessageTimeout(50ms);
@@ -322,7 +324,6 @@ struct FileStorManagerTest : public FileStorTestBase {
TEST_F(FileStorManagerTest, header_only_put) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
// Creating a document to test with
Document::SP doc(createDocument(
"some content", "id:crawler:testdoctype1:n=4000:foo").release());
@@ -334,7 +335,7 @@ TEST_F(FileStorManagerTest, header_only_put) {
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -349,7 +350,7 @@ TEST_F(FileStorManagerTest, header_only_put) {
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 124);
cmd->setUpdateTimestamp(105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -361,7 +362,7 @@ TEST_F(FileStorManagerTest, header_only_put) {
// Getting it
{
auto cmd = std::make_shared<api::GetCommand>(makeDocumentBucket(bid), doc->getId(), document::AllFields::NAME);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -385,7 +386,6 @@ TEST_F(FileStorManagerTest, header_only_put) {
TEST_F(FileStorManagerTest, put) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
// Creating a document to test with
Document::SP doc(createDocument(
"some content", "id:crawler:testdoctype1:n=4000:foo").release());
@@ -397,7 +397,7 @@ TEST_F(FileStorManagerTest, put) {
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -422,7 +422,6 @@ TEST_F(FileStorManagerTest, state_change) {
TEST_F(FileStorManagerTest, flush) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
// Creating a document to test with
document::DocumentId docId("id:ns:testdoctype1::crawler:http://www.ntnu.no/");
@@ -435,7 +434,7 @@ TEST_F(FileStorManagerTest, flush) {
std::vector<std::shared_ptr<api::StorageCommand> > _commands;
for (uint32_t i=0; i<msgCount; ++i) {
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, i+1);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
_commands.push_back(cmd);
}
for (uint32_t i=0; i<msgCount; ++i) {
@@ -462,8 +461,7 @@ TEST_F(FileStorManagerTest, handler_priority) {
// Populate bucket with the given data
for (uint32_t i = 1; i < 6; i++) {
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100);
- auto address = std::make_shared<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(i * 15);
filestorHandler.schedule(cmd);
}
@@ -588,8 +586,7 @@ TEST_F(FileStorManagerTest, handler_pause) {
// Populate bucket with the given data
for (uint32_t i = 1; i < 6; i++) {
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(i * 15);
filestorHandler.schedule(cmd);
}
@@ -665,8 +662,7 @@ TEST_F(FileStorManagerTest, handler_timeout) {
// Populate bucket with the given data
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(0);
cmd->setTimeout(50ms);
filestorHandler.schedule(cmd);
@@ -674,8 +670,7 @@ TEST_F(FileStorManagerTest, handler_timeout) {
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(200);
cmd->setTimeout(10000ms);
filestorHandler.schedule(cmd);
@@ -738,8 +733,7 @@ TEST_F(FileStorManagerTest, priority) {
document::BucketId bucket(16, factory.getBucketId(documents[i]->getId()).getRawId());
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(i * 2);
filestorHandler.schedule(cmd);
}
@@ -755,9 +749,7 @@ TEST_F(FileStorManagerTest, priority) {
ASSERT_LT(count, 10000);
for (uint32_t i = 0; i < documents.size(); i++) {
- std::shared_ptr<api::PutReply> reply(
- std::dynamic_pointer_cast<api::PutReply>(
- c.top.getReply(i)));
+ std::shared_ptr<api::PutReply> reply(std::dynamic_pointer_cast<api::PutReply>(c.top.getReply(i)));
ASSERT_TRUE(reply.get());
EXPECT_EQ(ReturnCode(ReturnCode::OK), reply->getResult());
}
@@ -799,8 +791,7 @@ TEST_F(FileStorManagerTest, split1) {
_node->getPersistenceProvider().createBucket(makeSpiBucket(bucket), context);
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
cmd->setSourceIndex(0);
filestorHandler.schedule(cmd);
@@ -814,9 +805,8 @@ TEST_F(FileStorManagerTest, split1) {
// Delete every 5th document to have delete entries in file too
if (i % 5 == 0) {
- auto rcmd = std::make_shared<api::RemoveCommand>(
- makeDocumentBucket(bucket), documents[i]->getId(), 1000000 + 100 + i);
- rcmd->setAddress(*address);
+ auto rcmd = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bucket), documents[i]->getId(), 1000000 + 100 + i);
+ rcmd->setAddress(_Storage3);
filestorHandler.schedule(rcmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -842,12 +832,9 @@ TEST_F(FileStorManagerTest, split1) {
// Test that the documents have gotten into correct parts.
for (uint32_t i=0; i<documents.size(); ++i) {
- document::BucketId bucket(
- 17, i % 3 == 0 ? 0x10001 : 0x0100001);
- auto cmd = std::make_shared<api::GetCommand>(
- makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(address);
+ document::BucketId bucket(17, i % 3 == 0 ? 0x10001 : 0x0100001);
+ auto cmd = std::make_shared<api::GetCommand>(makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -859,8 +846,7 @@ TEST_F(FileStorManagerTest, split1) {
// Keep splitting location 1 until we gidsplit
for (int i=17; i<=32; ++i) {
- auto cmd = std::make_shared<api::SplitBucketCommand>(
- makeDocumentBucket(document::BucketId(i, 0x0100001)));
+ auto cmd = std::make_shared<api::SplitBucketCommand>(makeDocumentBucket(document::BucketId(i, 0x0100001)));
cmd->setSourceIndex(0);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
@@ -877,13 +863,10 @@ TEST_F(FileStorManagerTest, split1) {
if (i % 3 == 0) {
bucket = document::BucketId(17, 0x10001);
} else {
- bucket = document::BucketId(33, factory.getBucketId(
- documents[i]->getId()).getRawId());
+ bucket = document::BucketId(33, factory.getBucketId(documents[i]->getId()).getRawId());
}
- auto cmd = std::make_shared<api::GetCommand>(
- makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(address);
+ auto cmd = std::make_shared<api::GetCommand>(makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -932,8 +915,7 @@ TEST_F(FileStorManagerTest, split_single_group) {
_node->getPersistenceProvider().createBucket(makeSpiBucket(bucket), context);
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -958,10 +940,8 @@ TEST_F(FileStorManagerTest, split_single_group) {
// Test that the documents are all still there
for (uint32_t i=0; i<documents.size(); ++i) {
document::BucketId bucket(17, state ? 0x10001 : 0x00001);
- auto cmd = std::make_shared<api::GetCommand>
- (makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(address);
+ auto cmd = std::make_shared<api::GetCommand>(makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -982,7 +962,6 @@ FileStorTestBase::putDoc(DummyStorageLink& top,
const document::BucketId& target,
uint32_t docNum)
{
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
spi::Context context(spi::Priority(0), spi::Trace::TraceLevel(0));
document::BucketIdFactory factory;
document::DocumentId docId(vespalib::make_string("id:ns:testdoctype1:n=%" PRIu64 ":%d", target.getId(), docNum));
@@ -991,7 +970,7 @@ FileStorTestBase::putDoc(DummyStorageLink& top,
_node->getPersistenceProvider().createBucket(makeSpiBucket(target), context);
Document::SP doc(new Document(*_testdoctype1, docId));
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(target), doc, docNum+1);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
cmd->setPriority(120);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
@@ -1012,8 +991,6 @@ TEST_F(FileStorManagerTest, split_empty_target_with_remapped_ops) {
document::BucketId source(16, 0x10001);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
-
for (uint32_t i=0; i<10; ++i) {
ASSERT_NO_FATAL_FAILURE(putDoc(top, filestorHandler, source, i));
}
@@ -1034,7 +1011,7 @@ TEST_F(FileStorManagerTest, split_empty_target_with_remapped_ops) {
vespalib::make_string("id:ns:testdoctype1:n=%d:1234", 0x100001));
auto doc = std::make_shared<Document>(*_testdoctype1, docId);
auto putCmd = std::make_shared<api::PutCommand>(makeDocumentBucket(source), doc, 1001);
- putCmd->setAddress(address);
+ putCmd->setAddress(_Storage3);
putCmd->setPriority(120);
filestorHandler.schedule(splitCmd);
@@ -1115,8 +1092,7 @@ TEST_F(FileStorManagerTest, join) {
for (uint32_t i=0; i<documents.size(); ++i) {
document::BucketId bucket(17, factory.getBucketId(documents[i]->getId()).getRawId());
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i);
- auto address = std::make_unique<api::StorageMessageAddress>("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(*address);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -1128,7 +1104,7 @@ TEST_F(FileStorManagerTest, join) {
if ((i % 5) == 0) {
auto rcmd = std::make_shared<api::RemoveCommand>(
makeDocumentBucket(bucket), documents[i]->getId(), 1000000 + 100 + i);
- rcmd->setAddress(*address);
+ rcmd->setAddress(_Storage3);
filestorHandler.schedule(rcmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -1157,8 +1133,7 @@ TEST_F(FileStorManagerTest, join) {
document::BucketId bucket(16, 1);
auto cmd = std::make_shared<api::GetCommand>(
makeDocumentBucket(bucket), documents[i]->getId(), document::AllFields::NAME);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
filestorHandler.schedule(cmd);
filestorHandler.flush(true);
ASSERT_EQ(1, top.getNumReplies());
@@ -1320,7 +1295,6 @@ TEST_F(FileStorManagerTest, visiting) {
TEST_F(FileStorManagerTest, remove_location) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
document::BucketId bid(8, 0);
createBucket(bid);
@@ -1331,7 +1305,7 @@ TEST_F(FileStorManagerTest, remove_location) {
docid << "id:ns:testdoctype1:n=" << (i << 8) << ":foo";
Document::SP doc(createDocument("some content", docid.str()));
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 1000 + i);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1344,7 +1318,7 @@ TEST_F(FileStorManagerTest, remove_location) {
// Issuing remove location command
{
auto cmd = std::make_shared<api::RemoveLocationCommand>("id.user % 512 == 0", makeDocumentBucket(bid));
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1359,7 +1333,6 @@ TEST_F(FileStorManagerTest, remove_location) {
TEST_F(FileStorManagerTest, delete_bucket) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 2);
// Creating a document to test with
document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/");
auto doc = std::make_shared<Document>(*_testdoctype1, docId);
@@ -1371,7 +1344,7 @@ TEST_F(FileStorManagerTest, delete_bucket) {
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1387,7 +1360,7 @@ TEST_F(FileStorManagerTest, delete_bucket) {
// Delete bucket
{
auto cmd = std::make_shared<api::DeleteBucketCommand>(makeDocumentBucket(bid));
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
cmd->setBucketInfo(bucketInfo);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
@@ -1401,7 +1374,6 @@ TEST_F(FileStorManagerTest, delete_bucket) {
TEST_F(FileStorManagerTest, delete_bucket_rejects_outdated_bucket_info) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 2);
// Creating a document to test with
document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/");
Document::SP doc(new Document(*_testdoctype1, docId));
@@ -1414,7 +1386,7 @@ TEST_F(FileStorManagerTest, delete_bucket_rejects_outdated_bucket_info) {
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1431,7 +1403,7 @@ TEST_F(FileStorManagerTest, delete_bucket_rejects_outdated_bucket_info) {
{
auto cmd = std::make_shared<api::DeleteBucketCommand>(makeDocumentBucket(bid));
cmd->setBucketInfo(api::BucketInfo(0xf000baaa, 1, 123, 1, 456));
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1449,7 +1421,6 @@ TEST_F(FileStorManagerTest, delete_bucket_rejects_outdated_bucket_info) {
TEST_F(FileStorManagerTest, delete_bucket_with_invalid_bucket_info){
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 2);
// Creating a document to test with
document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/");
auto doc = std::make_shared<Document>(*_testdoctype1, docId);
@@ -1460,7 +1431,7 @@ TEST_F(FileStorManagerTest, delete_bucket_with_invalid_bucket_info){
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1474,7 +1445,7 @@ TEST_F(FileStorManagerTest, delete_bucket_with_invalid_bucket_info){
// Attempt to delete bucket with invalid bucketinfo
{
auto cmd = std::make_shared<api::DeleteBucketCommand>(makeDocumentBucket(bid));
- cmd->setAddress(address);
+ cmd->setAddress(_Storage2);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1488,8 +1459,6 @@ TEST_F(FileStorManagerTest, delete_bucket_with_invalid_bucket_info){
TEST_F(FileStorManagerTest, no_timestamps) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address(
- "storage", lib::NodeType::STORAGE, 3);
// Creating a document to test with
Document::SP doc(createDocument(
"some content", "id:ns:testdoctype1::crawler:http://www.ntnu.no/").release());
@@ -1500,7 +1469,7 @@ TEST_F(FileStorManagerTest, no_timestamps) {
// Putting it
{
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 0);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
EXPECT_EQ(api::Timestamp(0), cmd->getTimestamp());
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
@@ -1513,7 +1482,7 @@ TEST_F(FileStorManagerTest, no_timestamps) {
// Removing it
{
auto cmd = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bid), doc->getId(), 0);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
EXPECT_EQ(api::Timestamp(0), cmd->getTimestamp());
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
@@ -1528,7 +1497,6 @@ TEST_F(FileStorManagerTest, no_timestamps) {
TEST_F(FileStorManagerTest, equal_timestamps) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
// Creating a document to test with
document::BucketId bid(16, 4000);
@@ -1539,7 +1507,7 @@ TEST_F(FileStorManagerTest, equal_timestamps) {
Document::SP doc(createDocument(
"some content", "id:crawler:testdoctype1:n=4000:http://www.ntnu.no/"));
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 100);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1556,7 +1524,7 @@ TEST_F(FileStorManagerTest, equal_timestamps) {
Document::SP doc(createDocument(
"some content", "id:crawler:testdoctype1:n=4000:http://www.ntnu.no/"));
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 100);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1571,7 +1539,7 @@ TEST_F(FileStorManagerTest, equal_timestamps) {
Document::SP doc(createDocument(
"some content", "id:crawler:testdoctype1:n=4000:http://www.ntnu.nu/"));
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 100);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1585,8 +1553,6 @@ TEST_F(FileStorManagerTest, equal_timestamps) {
TEST_F(FileStorManagerTest, get_iter) {
TestFileStorComponents c(*this);
auto& top = c.top;
- api::StorageMessageAddress address(
- "storage", lib::NodeType::STORAGE, 3);
document::BucketId bid(16, 4000);
createBucket(bid);
@@ -1605,7 +1571,7 @@ TEST_F(FileStorManagerTest, get_iter) {
// Putting all docs to have something to visit
for (uint32_t i=0; i<docs.size(); ++i) {
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), docs[i], 100 + i);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1659,7 +1625,6 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) {
TestFileStorComponents c(*this);
auto& top = c.top;
setClusterState("storage:4 distributor:1");
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
document::BucketId bid(16, 4000);
@@ -1668,9 +1633,8 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) {
EXPECT_FALSE(provider.isActive(makeSpiBucket(bid)));
{
- auto cmd = std::make_shared<api::SetBucketStateCommand>(
- makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE);
- cmd->setAddress(address);
+ auto cmd = std::make_shared<api::SetBucketStateCommand>(makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1682,9 +1646,7 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) {
EXPECT_TRUE(provider.isActive(makeSpiBucket(bid)));
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
EXPECT_TRUE(entry->info.isActive());
}
// Trigger bucket info to be read back into the database
@@ -1699,16 +1661,14 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) {
}
// Should not have lost active flag
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
EXPECT_TRUE(entry->info.isActive());
}
{
auto cmd = std::make_shared<api::SetBucketStateCommand>(
makeDocumentBucket(bid), api::SetBucketStateCommand::INACTIVE);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
top.sendDown(cmd);
top.waitForMessages(1, _waitTime);
ASSERT_EQ(1, top.getNumReplies());
@@ -1720,9 +1680,7 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) {
EXPECT_FALSE(provider.isActive(makeSpiBucket(bid)));
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
EXPECT_FALSE(entry->info.isActive());
}
}
@@ -1736,9 +1694,8 @@ TEST_F(FileStorManagerTest, notify_owner_distributor_on_outdated_set_bucket_stat
ASSERT_NE(bid.getRawId(), 0);
createBucket(bid);
- auto cmd = std::make_shared<api::SetBucketStateCommand>(
- makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE);
- cmd->setAddress(api::StorageMessageAddress("cluster", lib::NodeType::STORAGE, 1));
+ auto cmd = std::make_shared<api::SetBucketStateCommand>(makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE);
+ cmd->setAddress(_Cluster1);
cmd->setSourceIndex(0);
top.sendDown(cmd);
@@ -1773,7 +1730,7 @@ TEST_F(FileStorManagerTest, GetBucketDiff_implicitly_creates_bucket) {
std::vector<api::MergeBucketCommand::Node> nodes = {1, 0};
auto cmd = std::make_shared<api::GetBucketDiffCommand>(makeDocumentBucket(bid), nodes, Timestamp(1000));
- cmd->setAddress(api::StorageMessageAddress("cluster", lib::NodeType::STORAGE, 1));
+ cmd->setAddress(_Cluster1);
cmd->setSourceIndex(0);
top.sendDown(cmd);
@@ -1781,9 +1738,7 @@ TEST_F(FileStorManagerTest, GetBucketDiff_implicitly_creates_bucket) {
ASSERT_SINGLE_REPLY(api::GetBucketDiffReply, reply, top, _waitTime);
EXPECT_EQ(api::ReturnCode(api::ReturnCode::OK), reply->getResult());
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
ASSERT_TRUE(entry.exist());
EXPECT_TRUE(entry->info.isReady());
}
@@ -1799,16 +1754,14 @@ TEST_F(FileStorManagerTest, merge_bucket_implicitly_creates_bucket) {
std::vector<api::MergeBucketCommand::Node> nodes = {1, 2};
auto cmd = std::make_shared<api::MergeBucketCommand>(makeDocumentBucket(bid), nodes, Timestamp(1000));
- cmd->setAddress(api::StorageMessageAddress("cluster", lib::NodeType::STORAGE, 1));
+ cmd->setAddress(_Cluster1);
cmd->setSourceIndex(0);
top.sendDown(cmd);
api::GetBucketDiffCommand* diffCmd;
ASSERT_SINGLE_REPLY(api::GetBucketDiffCommand, diffCmd, top, _waitTime);
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
ASSERT_TRUE(entry.exist());
EXPECT_TRUE(entry->info.isReady());
}
@@ -1822,7 +1775,7 @@ TEST_F(FileStorManagerTest, newly_created_bucket_is_ready) {
document::BucketId bid(16, 4000);
auto cmd = std::make_shared<api::CreateBucketCommand>(makeDocumentBucket(bid));
- cmd->setAddress(api::StorageMessageAddress("cluster", lib::NodeType::STORAGE, 1));
+ cmd->setAddress(_Cluster1);
cmd->setSourceIndex(0);
top.sendDown(cmd);
@@ -1830,9 +1783,7 @@ TEST_F(FileStorManagerTest, newly_created_bucket_is_ready) {
ASSERT_SINGLE_REPLY(api::CreateBucketReply, reply, top, _waitTime);
EXPECT_EQ(api::ReturnCode(api::ReturnCode::OK), reply->getResult());
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
ASSERT_TRUE(entry.exist());
EXPECT_TRUE(entry->info.isReady());
EXPECT_FALSE(entry->info.isActive());
@@ -1844,10 +1795,8 @@ TEST_F(FileStorManagerTest, create_bucket_sets_active_flag_in_database_and_reply
setClusterState("storage:2 distributor:1");
document::BucketId bid(16, 4000);
- std::shared_ptr<api::CreateBucketCommand> cmd(
- new api::CreateBucketCommand(makeDocumentBucket(bid)));
- cmd->setAddress(api::StorageMessageAddress(
- "cluster", lib::NodeType::STORAGE, 1));
+ auto cmd = std::make_shared<api::CreateBucketCommand>(makeDocumentBucket(bid));
+ cmd->setAddress(_Cluster1);
cmd->setSourceIndex(0);
cmd->setActive(true);
c.top.sendDown(cmd);
@@ -1856,9 +1805,7 @@ TEST_F(FileStorManagerTest, create_bucket_sets_active_flag_in_database_and_reply
ASSERT_SINGLE_REPLY(api::CreateBucketReply, reply, c.top, _waitTime);
EXPECT_EQ(api::ReturnCode(api::ReturnCode::OK), reply->getResult());
{
- StorBucketDatabase::WrappedEntry entry(
- _node->getStorageBucketDatabase().get(
- bid, "foo"));
+ StorBucketDatabase::WrappedEntry entry(_node->getStorageBucketDatabase().get(bid, "foo"));
ASSERT_TRUE(entry.exist());
EXPECT_TRUE(entry->info.isReady());
EXPECT_TRUE(entry->info.isActive());
@@ -1867,9 +1814,8 @@ TEST_F(FileStorManagerTest, create_bucket_sets_active_flag_in_database_and_reply
template <typename Metric>
void FileStorTestBase::assert_request_size_set(TestFileStorComponents& c, std::shared_ptr<api::StorageMessage> cmd, const Metric& metric) {
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
cmd->setApproxByteSize(54321);
- cmd->setAddress(address);
+ cmd->setAddress(_Storage3);
c.top.sendDown(cmd);
c.top.waitForMessages(1, _waitTime);
EXPECT_EQ(static_cast<int64_t>(cmd->getApproxByteSize()), metric.request_size.getLast());
@@ -1882,7 +1828,7 @@ TEST_F(FileStorManagerTest, put_command_size_is_added_to_metric) {
auto cmd = std::make_shared<api::PutCommand>(
makeDocumentBucket(bucket), _node->getTestDocMan().createRandomDocument(), api::Timestamp(12345));
- assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->put[defaultLoadType]);
+ assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->put);
}
TEST_F(FileStorManagerTest, update_command_size_is_added_to_metric) {
@@ -1896,7 +1842,7 @@ TEST_F(FileStorManagerTest, update_command_size_is_added_to_metric) {
auto cmd = std::make_shared<api::UpdateCommand>(
makeDocumentBucket(bucket), std::move(update), api::Timestamp(123456));
- assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->update[defaultLoadType]);
+ assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->update);
}
TEST_F(FileStorManagerTest, remove_command_size_is_added_to_metric) {
@@ -1906,7 +1852,7 @@ TEST_F(FileStorManagerTest, remove_command_size_is_added_to_metric) {
auto cmd = std::make_shared<api::RemoveCommand>(
makeDocumentBucket(bucket), document::DocumentId("id:foo:testdoctype1::bar"), api::Timestamp(123456));
- assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->remove[defaultLoadType]);
+ assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->remove);
}
TEST_F(FileStorManagerTest, get_command_size_is_added_to_metric) {
@@ -1916,7 +1862,7 @@ TEST_F(FileStorManagerTest, get_command_size_is_added_to_metric) {
auto cmd = std::make_shared<api::GetCommand>(
makeDocumentBucket(bucket), document::DocumentId("id:foo:testdoctype1::bar"), document::AllFields::NAME);
- assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->get[defaultLoadType]);
+ assert_request_size_set(c, std::move(cmd), thread_metrics_of(*c.manager)->get);
}
TEST_F(FileStorManagerTest, test_and_set_condition_mismatch_not_counted_as_failure) {
@@ -1926,14 +1872,14 @@ TEST_F(FileStorManagerTest, test_and_set_condition_mismatch_not_counted_as_failu
createBucket(bucket);
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), std::move(doc), api::Timestamp(12345));
cmd->setCondition(TestAndSetCondition("not testdoctype1"));
- cmd->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 3));
+ cmd->setAddress(_Storage3);
c.top.sendDown(cmd);
api::PutReply* reply;
ASSERT_SINGLE_REPLY(api::PutReply, reply, c.top, _waitTime);
EXPECT_EQ(reply->getResult().getResult(), api::ReturnCode::TEST_AND_SET_CONDITION_FAILED);
- auto& metrics = thread_metrics_of(*c.manager)->put[defaultLoadType];
+ auto& metrics = thread_metrics_of(*c.manager)->put;
EXPECT_EQ(metrics.failed.getValue(), 0);
EXPECT_EQ(metrics.test_and_set_failed.getValue(), 1);
EXPECT_EQ(thread_metrics_of(*c.manager)->failedOperations.getValue(), 0);
diff --git a/storage/src/tests/persistence/filestorage/mergeblockingtest.cpp b/storage/src/tests/persistence/filestorage/mergeblockingtest.cpp
index 8b38083b33d..2710d766f5d 100644
--- a/storage/src/tests/persistence/filestorage/mergeblockingtest.cpp
+++ b/storage/src/tests/persistence/filestorage/mergeblockingtest.cpp
@@ -32,7 +32,8 @@ namespace {
api::StorageMessageAddress
makeAddress() {
- return api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 0);
+ static vespalib::string _storage("storage");
+ return api::StorageMessageAddress(&_storage, lib::NodeType::STORAGE, 0);
}
void
diff --git a/storage/src/tests/persistence/filestorage/operationabortingtest.cpp b/storage/src/tests/persistence/filestorage/operationabortingtest.cpp
index 95e2d8e2c43..e0ccc175c11 100644
--- a/storage/src/tests/persistence/filestorage/operationabortingtest.cpp
+++ b/storage/src/tests/persistence/filestorage/operationabortingtest.cpp
@@ -72,8 +72,6 @@ public:
}
};
-metrics::LoadType defaultLoadType(0, "default");
-
}
struct OperationAbortingTest : FileStorTestFixture {
diff --git a/storage/src/tests/persistence/mergehandlertest.cpp b/storage/src/tests/persistence/mergehandlertest.cpp
index c1da8e9ec06..7e810c0fff4 100644
--- a/storage/src/tests/persistence/mergehandlertest.cpp
+++ b/storage/src/tests/persistence/mergehandlertest.cpp
@@ -158,11 +158,11 @@ struct MergeHandlerTest : SingleDiskPersistenceTestUtils {
MergeHandler createHandler(size_t maxChunkSize = 0x400000) {
return MergeHandler(getEnv(), getPersistenceProvider(),
- getEnv()._component.getClusterName(), getEnv()._component.getClock(), maxChunkSize);
+ getEnv()._component.cluster_context(), getEnv()._component.getClock(), maxChunkSize);
}
MergeHandler createHandler(spi::PersistenceProvider & spi) {
return MergeHandler(getEnv(), spi,
- getEnv()._component.getClusterName(), getEnv()._component.getClock());
+ getEnv()._component.cluster_context(), getEnv()._component.getClock());
}
};
diff --git a/storage/src/tests/persistence/persistencequeuetest.cpp b/storage/src/tests/persistence/persistencequeuetest.cpp
index 61c6e446517..61719b569d6 100644
--- a/storage/src/tests/persistence/persistencequeuetest.cpp
+++ b/storage/src/tests/persistence/persistencequeuetest.cpp
@@ -3,6 +3,7 @@
#include <vespa/persistence/dummyimpl/dummypersistence.h>
#include <tests/persistence/common/filestortestfixture.h>
#include <tests/persistence/filestorage/forwardingmessagesender.h>
+#include <vespa/storage/persistence/filestorage/filestormetrics.h>
#include <vespa/document/test/make_document_bucket.h>
#include <vespa/document/fieldset/fieldsets.h>
#include <vespa/log/log.h>
@@ -26,7 +27,6 @@ public:
DummyStorageLink top;
std::unique_ptr<DummyStorageLink> dummyManager;
ForwardingMessageSender messageSender;
- documentapi::LoadTypeSet loadTypes;
FileStorMetrics metrics;
std::unique_ptr<FileStorHandler> filestorHandler;
uint32_t stripeId;
@@ -41,14 +41,13 @@ PersistenceQueueTest::Fixture::Fixture(FileStorTestFixture& parent_)
top(),
dummyManager(std::make_unique<DummyStorageLink>()),
messageSender(*dummyManager),
- loadTypes("raw:"),
- metrics(loadTypes.getMetricLoadTypes()),
+ metrics(),
stripeId(0)
{
top.push_back(std::move(dummyManager));
top.open();
- metrics.initDiskMetrics(loadTypes.getMetricLoadTypes(), 1, 1);
+ metrics.initDiskMetrics(1, 1);
filestorHandler = std::make_unique<FileStorHandlerImpl>(messageSender, metrics,
parent._node->getComponentRegister());
diff --git a/storage/src/tests/persistence/persistencetestutils.cpp b/storage/src/tests/persistence/persistencetestutils.cpp
index 278cb36b50c..9e779c5904b 100644
--- a/storage/src/tests/persistence/persistencetestutils.cpp
+++ b/storage/src/tests/persistence/persistencetestutils.cpp
@@ -52,10 +52,10 @@ PersistenceTestEnvironment::PersistenceTestEnvironment(const std::string & rootO
_messageKeeper(),
_node(NodeIndex(0), _config.getConfigId()),
_component(_node.getComponentRegister(), "persistence test env"),
- _metrics(_component.getLoadTypes()->getMetricLoadTypes())
+ _metrics()
{
_node.setupDummyPersistence();
- _metrics.initDiskMetrics(_node.getLoadTypes()->getMetricLoadTypes(), 1, 1);
+ _metrics.initDiskMetrics(1, 1);
_handler = std::make_unique<FileStorHandlerImpl>(_messageKeeper, _metrics, _node.getComponentRegister());
_diskEnv = std::make_unique<PersistenceUtil>(_component, *_handler,
*_metrics.disk->threads[0], _node.getPersistenceProvider());
diff --git a/storage/src/tests/persistence/processalltest.cpp b/storage/src/tests/persistence/processalltest.cpp
index a19abbfb1c6..7ac9c01dabd 100644
--- a/storage/src/tests/persistence/processalltest.cpp
+++ b/storage/src/tests/persistence/processalltest.cpp
@@ -16,7 +16,7 @@ class ProcessAllHandlerTest : public SingleDiskPersistenceTestUtils {
};
TEST_F(ProcessAllHandlerTest, change_of_repos_is_reflected) {
- EXPECT_EQ(3u, getComponent().getGeneration());
+ EXPECT_EQ(2u, getComponent().getGeneration());
auto old = getComponent().getTypeRepo()->documentTypeRepo;
auto old2 = &getEnv().getDocumentTypeRepo();
EXPECT_EQ(old.get(), old2);
@@ -24,7 +24,7 @@ TEST_F(ProcessAllHandlerTest, change_of_repos_is_reflected) {
auto newDocRepo = std::make_shared<document::DocumentTypeRepo>(*old->getDocumentType("testdoctype1"));
getComponent().setDocumentTypeRepo(newDocRepo);
- EXPECT_EQ(4u, getComponent().getGeneration());
+ EXPECT_EQ(3u, getComponent().getGeneration());
EXPECT_EQ(newDocRepo.get(), getComponent().getTypeRepo()->documentTypeRepo.get());
EXPECT_EQ(newDocRepo.get(), &getEnv().getDocumentTypeRepo());
}
diff --git a/storage/src/tests/persistence/splitbitdetectortest.cpp b/storage/src/tests/persistence/splitbitdetectortest.cpp
index 4982383685a..e1a1b6cf11b 100644
--- a/storage/src/tests/persistence/splitbitdetectortest.cpp
+++ b/storage/src/tests/persistence/splitbitdetectortest.cpp
@@ -7,7 +7,6 @@
#include <vespa/persistence/spi/test.h>
#include <vespa/document/base/testdocman.h>
#include <vespa/document/bucket/bucketidfactory.h>
-#include <vespa/metrics/loadmetric.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <algorithm>
diff --git a/storage/src/tests/storageserver/communicationmanagertest.cpp b/storage/src/tests/storageserver/communicationmanagertest.cpp
index 1431c49559c..b352c06d1d0 100644
--- a/storage/src/tests/storageserver/communicationmanagertest.cpp
+++ b/storage/src/tests/storageserver/communicationmanagertest.cpp
@@ -24,6 +24,8 @@ using namespace ::testing;
namespace storage {
+vespalib::string _Storage("storage");
+
struct CommunicationManagerTest : Test {
static constexpr uint32_t MESSAGE_WAIT_TIME_SEC = 60;
@@ -36,7 +38,7 @@ struct CommunicationManagerTest : Test {
auto cmd = std::make_shared<api::GetCommand>(makeDocumentBucket(document::BucketId(0)),
document::DocumentId("id:ns:mytype::mydoc"),
document::AllFields::NAME);
- cmd->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 1));
+ cmd->setAddress(api::StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
cmd->setPriority(priority);
return cmd;
}
@@ -72,7 +74,7 @@ TEST_F(CommunicationManagerTest, simple) {
// Send a message through from distributor to storage
auto cmd = std::make_shared<api::GetCommand>(
makeDocumentBucket(document::BucketId(0)), document::DocumentId("id:ns:mytype::mydoc"), document::AllFields::NAME);
- cmd->setAddress(api::StorageMessageAddress("storage", lib::NodeType::STORAGE, 1));
+ cmd->setAddress(api::StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
distributorLink->sendUp(cmd);
storageLink->waitForMessages(1, MESSAGE_WAIT_TIME_SEC);
ASSERT_GT(storageLink->getNumCommands(), 0);
diff --git a/storage/src/tests/storageserver/mergethrottlertest.cpp b/storage/src/tests/storageserver/mergethrottlertest.cpp
index 0271af85fef..d8156b21333 100644
--- a/storage/src/tests/storageserver/mergethrottlertest.cpp
+++ b/storage/src/tests/storageserver/mergethrottlertest.cpp
@@ -29,6 +29,8 @@ namespace storage {
namespace {
+vespalib::string _Storage("storage");
+
struct MergeBuilder {
document::BucketId _bucket;
api::Timestamp _maxTimestamp;
@@ -104,8 +106,7 @@ struct MergeBuilder {
auto cmd = std::make_shared<MergeBucketCommand>(
makeDocumentBucket(_bucket), n, _maxTimestamp,
_clusterStateVersion, _chain);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, _nodes[0]);
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, _nodes[0]));
return cmd;
}
};
@@ -115,8 +116,7 @@ MergeBuilder::~MergeBuilder() = default;
std::shared_ptr<api::SetSystemStateCommand>
makeSystemStateCmd(const std::string& state)
{
- return std::make_shared<api::SetSystemStateCommand>(
- lib::ClusterState(state));
+ return std::make_shared<api::SetSystemStateCommand>(lib::ClusterState(state));
}
} // anon ns
@@ -266,8 +266,7 @@ TEST_F(MergeThrottlerTest, chain) {
auto cmd = std::make_shared<MergeBucketCommand>(bucket, nodes, UINT_MAX, 123);
cmd->setPriority(7);
cmd->setTimeout(54321ms);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 0));
const uint16_t distributorIndex = 123;
cmd->setSourceIndex(distributorIndex); // Dummy distributor index that must be forwarded
@@ -404,15 +403,13 @@ TEST_F(MergeThrottlerTest, chain) {
TEST_F(MergeThrottlerTest, with_source_only_node) {
BucketId bid(14, 0x1337);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
-
std::vector<MergeBucketCommand::Node> nodes;
nodes.push_back(0);
nodes.push_back(2);
nodes.push_back(MergeBucketCommand::Node(1, true));
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, UINT_MAX, 123);
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 0));
_topLinks[0]->sendDown(cmd);
_topLinks[0]->waitForMessage(MessageType::MERGEBUCKET, _messageWaitTime);
@@ -460,9 +457,7 @@ TEST_F(MergeThrottlerTest, legacy_42_distributor_behavior) {
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, 1234);
// Send to node 1, which is not the lowest index
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 1);
-
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
_topLinks[1]->sendDown(cmd);
_bottomLinks[1]->waitForMessage(MessageType::MERGEBUCKET, _messageWaitTime);
@@ -500,9 +495,7 @@ TEST_F(MergeThrottlerTest, legacy_42_distributor_behavior_does_not_take_ownershi
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, 1234);
// Send to node 1, which is not the lowest index
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 1);
-
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
_topLinks[1]->sendDown(cmd);
_bottomLinks[1]->waitForMessage(MessageType::MERGEBUCKET, _messageWaitTime);
@@ -554,9 +547,7 @@ TEST_F(MergeThrottlerTest, end_of_chain_execution_does_not_take_ownership) {
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, 1234, 1, chain);
// Send to last node, which is not the lowest index
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 3);
-
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 3));
_topLinks[2]->sendDown(cmd);
_bottomLinks[2]->waitForMessage(MessageType::MERGEBUCKET, _messageWaitTime);
@@ -604,9 +595,7 @@ TEST_F(MergeThrottlerTest, resend_handling) {
nodes.push_back(2);
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, 1234);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 1);
-
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
_topLinks[0]->sendDown(cmd);
_topLinks[0]->waitForMessage(MessageType::MERGEBUCKET, _messageWaitTime);
@@ -1008,9 +997,8 @@ TEST_F(MergeThrottlerTest, unseen_merge_with_node_in_chain) {
auto cmd = std::make_shared<MergeBucketCommand>(
makeDocumentBucket(BucketId(32, 0xdeadbeef)), nodes, 1234, 1, chain);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 9);
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 9));
_topLinks[0]->sendDown(cmd);
// First, test that we get rejected when processing merge immediately
@@ -1218,9 +1206,7 @@ TEST_F(MergeThrottlerTest, unknown_merge_with_self_in_chain) {
chain.push_back(0);
auto cmd = std::make_shared<MergeBucketCommand>(makeDocumentBucket(bid), nodes, 1234, 1, chain);
- StorageMessageAddress address("storage", lib::NodeType::STORAGE, 1);
-
- cmd->setAddress(address);
+ cmd->setAddress(StorageMessageAddress::create(&_Storage, lib::NodeType::STORAGE, 1));
_topLinks[0]->sendDown(cmd);
_topLinks[0]->waitForMessage(MessageType::MERGEBUCKET_REPLY, _messageWaitTime);
diff --git a/storage/src/tests/storageserver/rpc/caching_rpc_target_resolver_test.cpp b/storage/src/tests/storageserver/rpc/caching_rpc_target_resolver_test.cpp
index 6291a8ad0dd..8f8eb84b0f2 100644
--- a/storage/src/tests/storageserver/rpc/caching_rpc_target_resolver_test.cpp
+++ b/storage/src/tests/storageserver/rpc/caching_rpc_target_resolver_test.cpp
@@ -49,6 +49,8 @@ public:
}
};
+vespalib::string _my_cluster("my_cluster");
+
class CachingRpcTargetResolverTest : public ::testing::Test {
public:
MockMirror mirror;
@@ -66,8 +68,8 @@ public:
: mirror(),
factory(),
resolver(mirror, factory, 2),
- address_0("my_cluster", NodeType::STORAGE, 5),
- address_1("my_cluster", NodeType::DISTRIBUTOR, 7),
+ address_0(&_my_cluster, NodeType::STORAGE, 5),
+ address_1(&_my_cluster, NodeType::DISTRIBUTOR, 7),
spec_0("tcp/my:41"),
spec_1("tcp/my:42"),
bucket_id_0(3),
diff --git a/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp b/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp
index 8b009e02f28..a39ee819f64 100644
--- a/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp
+++ b/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp
@@ -57,7 +57,7 @@ struct FixtureBase {
config.getConfig("stor-server").set("node_index", "1");
addSlobrokConfig(config, slobrok);
- shared_rpc_resources = std::make_unique<SharedRpcResources>(config.getConfigId(), 0, 1);
+ shared_rpc_resources = std::make_unique<SharedRpcResources>(config.getConfigId(), 0, 1, 1);
cc_service = std::make_unique<ClusterControllerApiRpcService>(dispatcher, *shared_rpc_resources);
shared_rpc_resources->start_server_and_register_slobrok("my_cool_rpc_test");
}
diff --git a/storage/src/tests/storageserver/rpc/message_codec_provider_test.cpp b/storage/src/tests/storageserver/rpc/message_codec_provider_test.cpp
index 0d4e3b8df93..67474f86df0 100644
--- a/storage/src/tests/storageserver/rpc/message_codec_provider_test.cpp
+++ b/storage/src/tests/storageserver/rpc/message_codec_provider_test.cpp
@@ -2,7 +2,6 @@
#include <vespa/storage/storageserver/rpc/message_codec_provider.h>
#include <vespa/storageapi/mbusprot/protocolserialization7.h>
#include <vespa/document/base/testdocman.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace ::testing;
@@ -12,17 +11,13 @@ namespace storage::rpc {
struct MessageCodecProviderTest : Test {
std::shared_ptr<const document::DocumentTypeRepo> _repo1;
std::shared_ptr<const document::DocumentTypeRepo> _repo2;
- std::shared_ptr<const documentapi::LoadTypeSet> _load_types1;
- std::shared_ptr<const documentapi::LoadTypeSet> _load_types2;
MessageCodecProvider _provider;
// We don't care about repo/set contents, just their pointer identities
MessageCodecProviderTest()
: _repo1(document::TestDocRepo().getTypeRepoSp()),
_repo2(document::TestDocRepo().getTypeRepoSp()),
- _load_types1(std::make_shared<documentapi::LoadTypeSet>()),
- _load_types2(std::make_shared<documentapi::LoadTypeSet>()),
- _provider(_repo1, _load_types1)
+ _provider(_repo1)
{}
~MessageCodecProviderTest() override;
};
@@ -32,15 +27,13 @@ MessageCodecProviderTest::~MessageCodecProviderTest() = default;
TEST_F(MessageCodecProviderTest, initially_provides_constructed_repos) {
auto wrapped = _provider.wrapped_codec();
EXPECT_EQ(&wrapped->codec().type_repo(), _repo1.get());
- EXPECT_EQ(&wrapped->codec().load_type_set(), _load_types1.get());
}
TEST_F(MessageCodecProviderTest, updated_repos_reflected_in_new_wrapped_codec) {
- _provider.update_atomically(_repo2, _load_types2);
+ _provider.update_atomically(_repo2);
auto wrapped = _provider.wrapped_codec();
EXPECT_EQ(&wrapped->codec().type_repo(), _repo2.get());
- EXPECT_EQ(&wrapped->codec().load_type_set(), _load_types2.get());
}
}
diff --git a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp
index 69d5a827272..0b33da39c41 100644
--- a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp
+++ b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp
@@ -1,22 +1,21 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <tests/common/testhelper.h>
#include <vespa/document/base/testdocman.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/test/make_document_bucket.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/messagebus/testlib/slobrok.h>
#include <vespa/slobrok/sbmirror.h>
-#include <vespa/storage/storageserver/rpc/storage_api_rpc_service.h>
-#include <vespa/storage/storageserver/rpc/shared_rpc_resources.h>
-#include <vespa/storage/storageserver/rpc/message_codec_provider.h>
-#include <vespa/storage/storageserver/rpc/caching_rpc_target_resolver.h>
#include <vespa/storage/storageserver/communicationmanager.h>
-#include <vespa/storage/storageserver/rpcrequestwrapper.h>
#include <vespa/storage/storageserver/message_dispatcher.h>
+#include <vespa/storage/storageserver/rpc/caching_rpc_target_resolver.h>
+#include <vespa/storage/storageserver/rpc/message_codec_provider.h>
+#include <vespa/storage/storageserver/rpc/shared_rpc_resources.h>
+#include <vespa/storage/storageserver/rpc/storage_api_rpc_service.h>
+#include <vespa/storage/storageserver/rpcrequestwrapper.h>
#include <vespa/storageapi/message/persistence.h>
-#include <tests/common/testhelper.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
@@ -90,7 +89,8 @@ LockingMockOperationDispatcher::LockingMockOperationDispatcher() = default;
LockingMockOperationDispatcher::~LockingMockOperationDispatcher() = default;
api::StorageMessageAddress make_address(uint16_t node_index, bool is_distributor) {
- return {"coolcluster", (is_distributor ? lib::NodeType::DISTRIBUTOR : lib::NodeType::STORAGE), node_index};
+ static vespalib::string _coolcluster("coolcluster");
+ return {&_coolcluster, (is_distributor ? lib::NodeType::DISTRIBUTOR : lib::NodeType::STORAGE), node_index};
}
vespalib::string to_slobrok_id(const api::StorageMessageAddress& address) {
@@ -102,7 +102,6 @@ class RpcNode {
protected:
vdstestlib::DirConfig _config;
std::shared_ptr<const document::DocumentTypeRepo> _doc_type_repo;
- std::shared_ptr<const documentapi::LoadTypeSet> _load_type_set;
LockingMockOperationDispatcher _messages;
std::unique_ptr<MessageCodecProvider> _codec_provider;
std::unique_ptr<SharedRpcResources> _shared_rpc_resources;
@@ -112,7 +111,6 @@ public:
RpcNode(uint16_t node_index, bool is_distributor, const mbus::Slobrok& slobrok)
: _config(getStandardConfig(true)),
_doc_type_repo(document::TestDocRepo().getTypeRepoSp()),
- _load_type_set(std::make_shared<documentapi::LoadTypeSet>()),
_node_address(make_address(node_index, is_distributor)),
_slobrok_id(to_slobrok_id(_node_address))
{
@@ -121,9 +119,9 @@ public:
cfg.set("is_distributor", is_distributor ? "true" : "false");
addSlobrokConfig(_config, slobrok);
- _shared_rpc_resources = std::make_unique<SharedRpcResources>(_config.getConfigId(), 0, 1);
+ _shared_rpc_resources = std::make_unique<SharedRpcResources>(_config.getConfigId(), 0, 1, 1);
// TODO make codec provider into interface so we can test decode-failures more easily?
- _codec_provider = std::make_unique<MessageCodecProvider>(_doc_type_repo, _load_type_set);
+ _codec_provider = std::make_unique<MessageCodecProvider>(_doc_type_repo);
}
~RpcNode();
diff --git a/storage/src/tests/storageserver/statereportertest.cpp b/storage/src/tests/storageserver/statereportertest.cpp
index c67598dc37b..121195ba033 100644
--- a/storage/src/tests/storageserver/statereportertest.cpp
+++ b/storage/src/tests/storageserver/statereportertest.cpp
@@ -2,6 +2,7 @@
#include <vespa/storageframework/defaultimplementation/clock/fakeclock.h>
#include <vespa/storage/persistence/filestorage/filestormanager.h>
+#include <vespa/storage/persistence/filestorage/filestormetrics.h>
#include <vespa/storage/storageserver/applicationgenerationfetcher.h>
#include <vespa/storage/storageserver/statereporter.h>
#include <vespa/metrics/metricmanager.h>
@@ -89,10 +90,8 @@ void StateReporterTest::SetUp() {
_generationFetcher,
"status");
- documentapi::LoadTypeSet::SP loadTypes(_node->getLoadTypes());
-
- _filestorMetrics = std::make_shared<FileStorMetrics>(_node->getLoadTypes()->getMetricLoadTypes());
- _filestorMetrics->initDiskMetrics(loadTypes->getMetricLoadTypes(), 1, 1);
+ _filestorMetrics = std::make_shared<FileStorMetrics>();
+ _filestorMetrics->initDiskMetrics(1, 1);
_topSet->registerMetric(*_filestorMetrics);
_metricManager->init(_config->getConfigId(), _node->getThreadPool());
@@ -222,8 +221,7 @@ TEST_F(StateReporterTest, report_metrics) {
LOG(debug, "Adding to get metric");
- using documentapi::LoadType;
- thread0.get[LoadType::DEFAULT].count.inc(1);
+ thread0.get.count.inc(1);
LOG(debug, "Waiting for 5 minute snapshot to be taken");
// Wait until active metrics have been added to 5 min snapshot and reset
@@ -239,7 +237,7 @@ TEST_F(StateReporterTest, report_metrics) {
}
LOG(debug, "5 minute snapshot should have been taken. Adding put count");
- thread0.put[LoadType::DEFAULT].count.inc(1);
+ thread0.put.count.inc(1);
const int pathCount = 2;
const char* paths[pathCount] = {
diff --git a/storage/src/tests/visiting/visitormanagertest.cpp b/storage/src/tests/visiting/visitormanagertest.cpp
index 7943790f13d..d5c558c5a0d 100644
--- a/storage/src/tests/visiting/visitormanagertest.cpp
+++ b/storage/src/tests/visiting/visitormanagertest.cpp
@@ -36,7 +36,8 @@ namespace storage {
namespace {
using msg_ptr_vector = std::vector<api::StorageMessage::SP>;
-
+vespalib::string _Storage("storage");
+api::StorageMessageAddress _Address(&_Storage, lib::NodeType::STORAGE, 0);
}
struct VisitorManagerTest : Test {
@@ -101,7 +102,6 @@ VisitorManagerTest::initializeTest()
_top->open();
// Adding some documents so database isn't empty
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
std::string content(
"To be, or not to be: that is the question:\n"
"Whether 'tis nobler in the mind to suffer\n"
@@ -152,7 +152,7 @@ VisitorManagerTest::initializeTest()
document::BucketId bid(16, i);
auto cmd = std::make_shared<api::CreateBucketCommand>(makeDocumentBucket(bid));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setSourceIndex(0);
_top->sendDown(cmd);
_top->waitForMessages(1, 60);
@@ -167,7 +167,7 @@ VisitorManagerTest::initializeTest()
document::BucketId bid(16, i);
auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), _documents[i], i+1);
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
_top->waitForMessages(1, 60);
const msg_ptr_vector replies = _top->getRepliesOnce();
@@ -182,13 +182,12 @@ void
VisitorManagerTest::addSomeRemoves(bool removeAll)
{
framework::defaultimplementation::FakeClock clock;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
for (uint32_t i=0; i<docCount; i += (removeAll ? 1 : 4)) {
// Add it to the database
document::BucketId bid(16, i % 10);
auto cmd = std::make_shared<api::RemoveCommand>(
makeDocumentBucket(bid), _documents[i]->getId(), clock.getTimeInMicros().getTime() + docCount + i + 1);
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
_top->waitForMessages(1, 60);
const msg_ptr_vector replies = _top->getRepliesOnce();
@@ -345,10 +344,9 @@ int getTotalSerializedSize(const std::vector<document::Document::SP>& docs)
TEST_F(VisitorManagerTest, normal_usage) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setControlDestination("foo/bar");
_top->sendDown(cmd);
std::vector<document::Document::SP > docs;
@@ -369,10 +367,9 @@ TEST_F(VisitorManagerTest, normal_usage) {
TEST_F(VisitorManagerTest, resending) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setControlDestination("foo/bar");
_top->sendDown(cmd);
std::vector<document::Document::SP > docs;
@@ -416,11 +413,10 @@ TEST_F(VisitorManagerTest, resending) {
TEST_F(VisitorManagerTest, visit_empty_bucket) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
addSomeRemoves(true);
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
// All data has been replied to, expecting to get a create visitor reply
@@ -429,12 +425,11 @@ TEST_F(VisitorManagerTest, visit_empty_bucket) {
TEST_F(VisitorManagerTest, multi_bucket_visit) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
for (uint32_t i=0; i<10; ++i) {
cmd->addBucketToBeVisited(document::BucketId(16, i));
}
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setDataDestination("fooclient.0");
_top->sendDown(cmd);
std::vector<document::Document::SP> docs;
@@ -451,10 +446,9 @@ TEST_F(VisitorManagerTest, multi_bucket_visit) {
TEST_F(VisitorManagerTest, no_buckets) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
// Should get one reply; a CreateVisitorReply with error since no
@@ -472,9 +466,8 @@ TEST_F(VisitorManagerTest, no_buckets) {
TEST_F(VisitorManagerTest, visit_puts_and_removes) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
addSomeRemoves();
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setVisitRemoves();
for (uint32_t i=0; i<10; ++i) {
cmd->addBucketToBeVisited(document::BucketId(16, i));
@@ -496,14 +489,13 @@ TEST_F(VisitorManagerTest, visit_puts_and_removes) {
TEST_F(VisitorManagerTest, visit_with_timeframe_and_selection) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "testdoctype1.headerval < 2");
cmd->setFromTime(3);
cmd->setToTime(8);
for (uint32_t i=0; i<10; ++i) {
cmd->addBucketToBeVisited(document::BucketId(16, i));
}
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
std::vector<document::Document::SP> docs;
std::vector<document::DocumentId> docIds;
@@ -525,7 +517,6 @@ TEST_F(VisitorManagerTest, visit_with_timeframe_and_selection) {
TEST_F(VisitorManagerTest, visit_with_timeframe_and_bogus_selection) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis",
"DocType(testdoctype1---///---) XXX BAD Field(headerval) < 2");
cmd->setFromTime(3);
@@ -533,7 +524,7 @@ TEST_F(VisitorManagerTest, visit_with_timeframe_and_bogus_selection) {
for (uint32_t i=0; i<10; ++i) {
cmd->addBucketToBeVisited(document::BucketId(16, i));
}
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
_top->waitForMessages(1, 60);
@@ -566,11 +557,10 @@ TEST_F(VisitorManagerTest, visit_with_timeframe_and_bogus_selection) {
TEST_F(VisitorManagerTest, visitor_callbacks) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
std::ostringstream replydata;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "TestVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
cmd->addBucketToBeVisited(document::BucketId(16, 5));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
_top->sendDown(cmd);
// Wait until we have started the visitor
@@ -607,7 +597,6 @@ TEST_F(VisitorManagerTest, visitor_callbacks) {
TEST_F(VisitorManagerTest, visitor_cleanup) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
// Start a bunch of invalid visitors
for (uint32_t i=0; i<10; ++i) {
@@ -615,7 +604,7 @@ TEST_F(VisitorManagerTest, visitor_cleanup) {
ost << "testvis" << i;
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "InvalidVisitor", ost.str(), "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
_top->sendDown(cmd);
_top->waitForMessages(i+1, 60);
@@ -627,7 +616,7 @@ TEST_F(VisitorManagerTest, visitor_cleanup) {
ost << "testvis" << (i + 10);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", ost.str(), "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
_top->sendDown(cmd);
}
@@ -696,7 +685,7 @@ TEST_F(VisitorManagerTest, visitor_cleanup) {
ost << "testvis" << (i + 24);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", ost.str(), "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
_top->sendDown(cmd);
}
@@ -723,12 +712,11 @@ TEST_F(VisitorManagerTest, visitor_cleanup) {
TEST_F(VisitorManagerTest, abort_on_failed_visitor_info) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
{
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
_top->sendDown(cmd);
}
@@ -757,13 +745,12 @@ TEST_F(VisitorManagerTest, abort_on_failed_visitor_info) {
TEST_F(VisitorManagerTest, abort_on_field_path_error) {
initializeTest();
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
// Use bogus field path to force error to happen
auto cmd = std::make_shared<api::CreateVisitorCommand>(
makeBucketSpace(), "DumpVisitor", "testvis", "testdoctype1.headerval{bogus} == 1234");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
_top->sendDown(cmd);
@@ -772,7 +759,6 @@ TEST_F(VisitorManagerTest, abort_on_field_path_error) {
TEST_F(VisitorManagerTest, visitor_queue_timeout) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
_manager->enforceQueueUsage();
{
@@ -780,7 +766,7 @@ TEST_F(VisitorManagerTest, visitor_queue_timeout) {
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(1ms);
cmd->setTimeout(100 * 1000 * 1000ms);
_top->sendDown(cmd);
@@ -801,11 +787,10 @@ TEST_F(VisitorManagerTest, visitor_queue_timeout) {
TEST_F(VisitorManagerTest, visitor_processing_timeout) {
ASSERT_NO_FATAL_FAILURE(initializeTest());
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(0ms);
cmd->setTimeout(100ms);
_top->sendDown(cmd);
@@ -827,10 +812,9 @@ api::StorageMessage::Id
sendCreateVisitor(vespalib::duration timeout, DummyStorageLink& top, uint8_t priority = 127) {
std::ostringstream ost;
ost << "testvis" << ++nextVisitor;
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(makeBucketSpace(), "DumpVisitor", ost.str(), "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
- cmd->setAddress(address);
+ cmd->setAddress(_Address);
cmd->setQueueTimeout(timeout);
cmd->setPriority(priority);
top.sendDown(cmd);
diff --git a/storage/src/tests/visiting/visitortest.cpp b/storage/src/tests/visiting/visitortest.cpp
index f727cdf8eb2..a8c317655ca 100644
--- a/storage/src/tests/visiting/visitortest.cpp
+++ b/storage/src/tests/visiting/visitortest.cpp
@@ -1,21 +1,22 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/config/common/exceptions.h>
#include <vespa/document/fieldvalue/intfieldvalue.h>
#include <vespa/document/fieldvalue/stringfieldvalue.h>
#include <vespa/document/test/make_bucket_space.h>
-#include <vespa/storageapi/message/datagram.h>
-#include <vespa/storageapi/message/persistence.h>
+#include <vespa/documentapi/messagebus/messages/putdocumentmessage.h>
+#include <vespa/documentapi/messagebus/messages/removedocumentmessage.h>
+#include <vespa/documentapi/messagebus/messages/visitor.h>
+#include <vespa/storage/common/reindexing_constants.h>
#include <vespa/storage/persistence/filestorage/filestormanager.h>
#include <vespa/storage/visiting/visitormanager.h>
+#include <vespa/storageapi/message/datagram.h>
+#include <vespa/storageapi/message/persistence.h>
#include <tests/common/testhelper.h>
#include <tests/common/teststorageapp.h>
#include <tests/common/dummystoragelink.h>
#include <tests/storageserver/testvisitormessagesession.h>
-#include <vespa/documentapi/messagebus/messages/putdocumentmessage.h>
-#include <vespa/documentapi/messagebus/messages/removedocumentmessage.h>
-#include <vespa/documentapi/messagebus/messages/visitor.h>
#include <vespa/vespalib/io/fileutil.h>
-#include <vespa/config/common/exceptions.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <thread>
#include <sys/stat.h>
@@ -127,8 +128,7 @@ protected:
// come in and wipe our accumulated failure metrics.
// Only 1 visitor thread running, so we know it has the metrics.
const auto& metrics = _manager->getThread(0).getMetrics();
- auto loadType = documentapi::LoadType::DEFAULT;
- return metrics.visitorDestinationFailureReplies[loadType].getCount();
+ return metrics.visitorDestinationFailureReplies.getCount();
}
};
@@ -440,7 +440,8 @@ VisitorTest::fetchSingleCommand(DummyStorageLink& link, std::shared_ptr<T>& msg_
std::shared_ptr<api::CreateVisitorCommand>
VisitorTest::makeCreateVisitor(const VisitorOptions& options)
{
- api::StorageMessageAddress address("storage", lib::NodeType::STORAGE, 0);
+ static vespalib::string _storage("storage");
+ api::StorageMessageAddress address(&_storage, lib::NodeType::STORAGE, 0);
auto cmd = std::make_shared<api::CreateVisitorCommand>(
makeBucketSpace(), options.visitorType, "testvis", "");
cmd->addBucketToBeVisited(document::BucketId(16, 3));
@@ -681,8 +682,7 @@ VisitorTest::sendInitialCreateVisitorAndGetIterRound()
{
GetIterCommand::SP getIterCmd;
ASSERT_NO_FATAL_FAILURE(fetchSingleCommand<GetIterCommand>(*_bottom, getIterCmd));
- sendGetIterReply(*getIterCmd, api::ReturnCode(api::ReturnCode::OK),
- 1, true);
+ sendGetIterReply(*getIterCmd, api::ReturnCode(api::ReturnCode::OK), 1, true);
}
}
@@ -729,8 +729,7 @@ TEST_F(VisitorTest, no_visitor_notification_for_transient_failures) {
}
TEST_F(VisitorTest, notification_sent_if_transient_error_retried_many_times) {
- constexpr size_t retries(
- Visitor::TRANSIENT_ERROR_RETRIES_BEFORE_NOTIFY);
+ constexpr size_t retries = Visitor::TRANSIENT_ERROR_RETRIES_BEFORE_NOTIFY;
ASSERT_NO_FATAL_FAILURE(initializeTest());
sendInitialCreateVisitorAndGetIterRound();
@@ -765,7 +764,6 @@ VisitorTest::doCompleteVisitingSession(
const std::shared_ptr<api::CreateVisitorCommand>& cmd,
std::shared_ptr<api::CreateVisitorReply>& reply_out)
{
- initializeTest();
_top->sendDown(cmd);
sendCreateIteratorReply();
@@ -795,6 +793,7 @@ VisitorTest::doCompleteVisitingSession(
}
TEST_F(VisitorTest, no_mbus_tracing_if_trace_level_is_zero) {
+ ASSERT_NO_FATAL_FAILURE(initializeTest());
std::shared_ptr<api::CreateVisitorCommand> cmd(makeCreateVisitor());
cmd->getTrace().setLevel(0);
std::shared_ptr<api::CreateVisitorReply> reply;
@@ -803,6 +802,7 @@ TEST_F(VisitorTest, no_mbus_tracing_if_trace_level_is_zero) {
}
TEST_F(VisitorTest, reply_contains_trace_if_trace_level_above_zero) {
+ ASSERT_NO_FATAL_FAILURE(initializeTest());
std::shared_ptr<api::CreateVisitorCommand> cmd(makeCreateVisitor());
cmd->getTrace().setLevel(1);
cmd->getTrace().trace(1,"at least one trace.");
@@ -887,4 +887,65 @@ TEST_F(VisitorTest, test_visitor_invokes_weak_read_consistency_iteration) {
"testvisitor", spi::ReadConsistency::WEAK);
}
+struct ReindexingVisitorTest : VisitorTest {
+ void respond_with_docs_from_persistence() {
+ sendCreateIteratorReply();
+ GetIterCommand::SP get_iter_cmd;
+ // Reply to GetIter with a single doc and bucket completed
+ ASSERT_NO_FATAL_FAILURE(fetchSingleCommand<GetIterCommand>(*_bottom, get_iter_cmd));
+ sendGetIterReply(*get_iter_cmd, api::ReturnCode(api::ReturnCode::OK), 1, true);
+ }
+
+ void respond_to_client_put(api::ReturnCode::Result result) {
+ // Reply to the Put from "client" back to the visitor
+ std::vector<document::Document::SP> docs;
+ std::vector<document::DocumentId> doc_ids;
+ std::vector<std::string> info_messages;
+ getMessagesAndReply(1, getSession(0), docs, doc_ids, info_messages, result);
+ }
+
+ void complete_visitor() {
+ DestroyIteratorCommand::SP destroy_iter_cmd;
+ ASSERT_NO_FATAL_FAILURE(fetchSingleCommand<DestroyIteratorCommand>(*_bottom, destroy_iter_cmd));
+ }
+};
+
+TEST_F(ReindexingVisitorTest, puts_are_sent_with_tas_condition) {
+ ASSERT_NO_FATAL_FAILURE(initializeTest());
+ auto cmd = makeCreateVisitor(VisitorOptions().withVisitorType("reindexingvisitor"));
+ cmd->getParameters().set(reindexing_bucket_lock_visitor_parameter_key(), "foobar");
+ _top->sendDown(cmd);
+
+ ASSERT_NO_FATAL_FAILURE(respond_with_docs_from_persistence());
+ auto& session = getSession(0);
+ session.waitForMessages(1);
+
+ ASSERT_EQ(session.sentMessages.size(), 1u);
+ auto* put_cmd = dynamic_cast<documentapi::PutDocumentMessage*>(session.sentMessages.front().get());
+ ASSERT_TRUE(put_cmd);
+ auto token_str = vespalib::make_string("%s=foobar", reindexing_bucket_lock_bypass_prefix());
+ EXPECT_EQ(put_cmd->getCondition().getSelection(), token_str);
+
+ ASSERT_NO_FATAL_FAILURE(respond_to_client_put(api::ReturnCode::OK));
+ ASSERT_NO_FATAL_FAILURE(complete_visitor());
+
+ ASSERT_NO_FATAL_FAILURE(verifyCreateVisitorReply(api::ReturnCode::OK));
+ ASSERT_TRUE(waitUntilNoActiveVisitors());
+}
+
+
+TEST_F(ReindexingVisitorTest, tas_responses_fail_the_visitor_and_are_rewritten_to_aborted) {
+ ASSERT_NO_FATAL_FAILURE(initializeTest());
+ auto cmd = makeCreateVisitor(VisitorOptions().withVisitorType("reindexingvisitor"));
+ cmd->getParameters().set(reindexing_bucket_lock_visitor_parameter_key(), "foobar");
+ _top->sendDown(cmd);
+
+ ASSERT_NO_FATAL_FAILURE(respond_with_docs_from_persistence());
+ ASSERT_NO_FATAL_FAILURE(respond_to_client_put(api::ReturnCode::TEST_AND_SET_CONDITION_FAILED));
+ ASSERT_NO_FATAL_FAILURE(complete_visitor());
+
+ ASSERT_NO_FATAL_FAILURE(verifyCreateVisitorReply(api::ReturnCode::ABORTED, -1, -1));
+ ASSERT_TRUE(waitUntilNoActiveVisitors());
+}
+
} // namespace storage
diff --git a/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp b/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp
index d547830d765..be02db70d9e 100644
--- a/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp
+++ b/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp
@@ -139,6 +139,12 @@ void BTreeBucketDatabase::update(const Entry& newEntry) {
_impl->update(newEntry.getBucketId(), newEntry);
}
+void
+BTreeBucketDatabase::process_update(const document::BucketId& bucket, EntryUpdateProcessor &processor, bool create_if_nonexisting)
+{
+ _impl->process_update(bucket, processor, create_if_nonexisting);
+}
+
// TODO need snapshot read with guarding
// FIXME semantics of for-each in judy and bit tree DBs differ, former expects lbound, latter ubound..!
// FIXME but bit-tree code says "lowerBound" in impl and "after" in declaration???
diff --git a/storage/src/vespa/storage/bucketdb/btree_bucket_database.h b/storage/src/vespa/storage/bucketdb/btree_bucket_database.h
index 2821e360792..e0955651209 100644
--- a/storage/src/vespa/storage/bucketdb/btree_bucket_database.h
+++ b/storage/src/vespa/storage/bucketdb/btree_bucket_database.h
@@ -43,6 +43,7 @@ public:
void getAll(const document::BucketId& bucket,
std::vector<Entry>& entries) const override;
void update(const Entry& newEntry) override;
+ void process_update(const document::BucketId& bucket, EntryUpdateProcessor &processor, bool create_if_nonexisting) override;
void forEach(EntryProcessor&, const document::BucketId& after) const override;
Entry upperBound(const document::BucketId& value) const override;
uint64_t size() const override;
diff --git a/storage/src/vespa/storage/bucketdb/bucketdatabase.h b/storage/src/vespa/storage/bucketdb/bucketdatabase.h
index cd94a698358..9ca231a26d2 100644
--- a/storage/src/vespa/storage/bucketdb/bucketdatabase.h
+++ b/storage/src/vespa/storage/bucketdb/bucketdatabase.h
@@ -57,6 +57,21 @@ public:
virtual bool process(const ConstEntryRef& e) = 0;
};
+ /*
+ * Interface class used by process_update() for updating an entry
+ * with a single call to the bucket database.
+ */
+ struct EntryUpdateProcessor {
+ virtual ~EntryUpdateProcessor() = default;
+ virtual Entry create_entry(const document::BucketId& bucket) const = 0;
+ /*
+ * Modifies entry.
+ * returns true if modified entry should be kept.
+ * returns false if entry should be removed.
+ */
+ virtual bool process_entry(Entry &entry) const = 0;
+ };
+
~BucketDatabase() override = default;
virtual Entry get(const document::BucketId& bucket) const = 0;
@@ -82,6 +97,8 @@ public:
*/
virtual void update(const Entry& newEntry) = 0;
+ virtual void process_update(const document::BucketId& bucket, EntryUpdateProcessor &processor, bool create_if_nonexisting) = 0;
+
virtual void forEach(
EntryProcessor&,
const document::BucketId& after = document::BucketId()) const = 0;
diff --git a/storage/src/vespa/storage/bucketdb/bucketmanager.cpp b/storage/src/vespa/storage/bucketdb/bucketmanager.cpp
index 7b934af4bdd..5be6f310c71 100644
--- a/storage/src/vespa/storage/bucketdb/bucketmanager.cpp
+++ b/storage/src/vespa/storage/bucketdb/bucketmanager.cpp
@@ -169,12 +169,11 @@ namespace {
Count() : docs(0), bytes(0), buckets(0), active(0), ready(0) {}
};
- uint16_t diskCount;
- std::vector<Count> disk;
+ Count count;
uint32_t lowestUsedBit;
- explicit MetricsUpdater(uint16_t diskCnt)
- : diskCount(diskCnt), disk(diskCnt), lowestUsedBit(58) {}
+ MetricsUpdater()
+ : count(), lowestUsedBit(58) {}
void operator()(document::BucketId::Type bucketId,
const StorBucketDatabase::Entry& data)
@@ -183,15 +182,15 @@ namespace {
document::BucketId::keyToBucketId(bucketId));
if (data.valid()) {
- ++disk[0].buckets;
+ ++count.buckets;
if (data.getBucketInfo().isActive()) {
- ++disk[0].active;
+ ++count.active;
}
if (data.getBucketInfo().isReady()) {
- ++disk[0].ready;
+ ++count.ready;
}
- disk[0].docs += data.getBucketInfo().getDocumentCount();
- disk[0].bytes += data.getBucketInfo().getTotalDocumentSize();
+ count.docs += data.getBucketInfo().getDocumentCount();
+ count.bytes += data.getBucketInfo().getTotalDocumentSize();
if (bucket.getUsedBits() < lowestUsedBit) {
lowestUsedBit = bucket.getUsedBits();
@@ -200,16 +199,13 @@ namespace {
};
void add(const MetricsUpdater& rhs) {
- assert(diskCount == rhs.diskCount);
- for (uint16_t i = 0; i < diskCount; i++) {
- auto& d = disk[i];
- auto& s = rhs.disk[i];
- d.buckets += s.buckets;
- d.docs += s.docs;
- d.bytes += s.bytes;
- d.ready += s.ready;
- d.active += s.active;
- }
+ auto& d = count;
+ auto& s = rhs.count;
+ d.buckets += s.buckets;
+ d.docs += s.docs;
+ d.bytes += s.bytes;
+ d.ready += s.ready;
+ d.active += s.active;
}
};
@@ -230,29 +226,26 @@ BucketManager::updateMetrics(bool updateDocCount)
updateDocCount ? "" : ", minusedbits only",
_doneInitialized ? "" : ", server is not done initializing");
- const uint16_t diskCount = 1;
if (!updateDocCount || _doneInitialized) {
- MetricsUpdater total(diskCount);
+ MetricsUpdater total;
for (auto& space : _component.getBucketSpaceRepo()) {
- MetricsUpdater m(diskCount);
+ MetricsUpdater m;
auto guard = space.second->bucketDatabase().acquire_read_guard();
guard->for_each(std::ref(m));
total.add(m);
if (updateDocCount) {
auto bm = _metrics->bucket_spaces.find(space.first);
assert(bm != _metrics->bucket_spaces.end());
- // No system with multiple bucket spaces has more than 1 "disk"
- // TODO remove disk concept entirely as it's a VDS relic
- bm->second->buckets_total.set(m.disk[0].buckets);
- bm->second->docs.set(m.disk[0].docs);
- bm->second->bytes.set(m.disk[0].bytes);
- bm->second->active_buckets.set(m.disk[0].active);
- bm->second->ready_buckets.set(m.disk[0].ready);
+ bm->second->buckets_total.set(m.count.buckets);
+ bm->second->docs.set(m.count.docs);
+ bm->second->bytes.set(m.count.bytes);
+ bm->second->active_buckets.set(m.count.active);
+ bm->second->ready_buckets.set(m.count.ready);
}
}
if (updateDocCount) {
auto & dest = *_metrics->disk;
- const auto & src = total.disk[0];
+ const auto & src = total.count;
dest.buckets.addValue(src.buckets);
dest.docs.addValue(src.docs);
dest.bytes.addValue(src.bytes);
@@ -273,7 +266,7 @@ void BucketManager::update_bucket_db_memory_usage_metrics() {
void BucketManager::updateMinUsedBits()
{
- MetricsUpdater m(1);
+ MetricsUpdater m;
_component.getBucketSpaceRepo().for_each_bucket(std::ref(m));
// When going through to get sizes, we also record min bits
MinimumUsedBitsTracker& bitTracker(_component.getMinUsedBitsTracker());
diff --git a/storage/src/vespa/storage/bucketdb/bucketmanagermetrics.h b/storage/src/vespa/storage/bucketdb/bucketmanagermetrics.h
index e475252f23a..e2d8dc69f9b 100644
--- a/storage/src/vespa/storage/bucketdb/bucketmanagermetrics.h
+++ b/storage/src/vespa/storage/bucketdb/bucketmanagermetrics.h
@@ -3,8 +3,8 @@
#pragma once
#include <vespa/document/bucket/bucketspace.h>
-#include <vespa/metrics/metrics.h>
#include <vespa/metrics/common/memory_usage_metrics.h>
+#include <vespa/metrics/summetric.h>
#include <unordered_map>
#include <memory>
diff --git a/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.h b/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.h
index ea6d47f26bb..f9d9f4f7861 100644
--- a/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.h
+++ b/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.h
@@ -99,6 +99,8 @@ public:
// Returns true if bucket pre-existed in the DB, false otherwise
bool update(const document::BucketId& bucket, const ValueType& new_entry);
bool update_by_raw_key(uint64_t bucket_key, const ValueType& new_entry);
+ template <typename EntryUpdateProcessor>
+ void process_update(const document::BucketId &bucket, EntryUpdateProcessor& processor, bool create_if_nonexisting);
template <typename IterValueExtractor, typename Func>
void find_parents_and_self(const document::BucketId& bucket, Func func) const;
diff --git a/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.hpp b/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.hpp
index 839efae4c1b..aafb4286d7d 100644
--- a/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.hpp
+++ b/storage/src/vespa/storage/bucketdb/generic_btree_bucket_database.hpp
@@ -342,6 +342,40 @@ bool GenericBTreeBucketDatabase<DataStoreTraitsT>::update(const BucketId& bucket
return update_by_raw_key(bucket.toKey(), new_entry);
}
+template <typename DataStoreTraitsT>
+template <typename EntryUpdateProcessor>
+void
+GenericBTreeBucketDatabase<DataStoreTraitsT>::process_update(const BucketId& bucket, EntryUpdateProcessor& processor, bool create_if_nonexisting)
+{
+ uint64_t bucket_key = bucket.toKey();
+ auto iter = _tree.lowerBound(bucket_key);
+ bool found = true;
+ if (!iter.valid() || bucket_key < iter.getKey()) {
+ if (!create_if_nonexisting) {
+ return;
+ }
+ found = false;
+ }
+ ValueType entry(found ? entry_from_iterator(iter) : processor.create_entry(bucket));
+ bool keep = processor.process_entry(entry);
+ if (found) {
+ DataStoreTraitsT::remove_by_wrapped_value(_store, iter.getData());
+ if (keep) {
+ const auto new_value = DataStoreTraitsT::wrap_and_store_value(_store, entry);
+ std::atomic_thread_fence(std::memory_order_release);
+ iter.writeData(new_value);
+ } else {
+ _tree.remove(iter);
+ }
+ } else {
+ if (keep) {
+ const auto new_value = DataStoreTraitsT::wrap_and_store_value(_store, entry);
+ _tree.insert(iter, bucket_key, new_value);
+ }
+ }
+ commit_tree_changes();
+}
+
/*
* Returns the bucket ID which, based on the buckets already existing in the DB,
* is the most specific location in the tree in which it should reside. This may
diff --git a/storage/src/vespa/storage/common/CMakeLists.txt b/storage/src/vespa/storage/common/CMakeLists.txt
index 81c6486eaeb..741d97f78ef 100644
--- a/storage/src/vespa/storage/common/CMakeLists.txt
+++ b/storage/src/vespa/storage/common/CMakeLists.txt
@@ -2,19 +2,20 @@
vespa_add_library(storage_common OBJECT
SOURCES
bucketmessages.cpp
- bucketoperationlogger.cpp
content_bucket_space.cpp
content_bucket_space_repo.cpp
distributorcomponent.cpp
global_bucket_space_distribution_converter.cpp
messagebucket.cpp
messagesender.cpp
+ node_identity.cpp
+ reindexing_constants.cpp
servicelayercomponent.cpp
statusmessages.cpp
statusmetricconsumer.cpp
+ storage_chain_builder.cpp
storagecomponent.cpp
storagelink.cpp
storagelinkqueued.cpp
- storage_chain_builder.cpp
DEPENDS
)
diff --git a/storage/src/vespa/storage/common/bucket_utils.h b/storage/src/vespa/storage/common/bucket_utils.h
new file mode 100644
index 00000000000..019cb7e1c5b
--- /dev/null
+++ b/storage/src/vespa/storage/common/bucket_utils.h
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/persistence/spi/bucket_limits.h>
+#include <cassert>
+
+namespace storage {
+
+/**
+ * Returns the super bucket key of the given bucket id key based on the minimum used bits allowed.
+ *
+ * For a bucket id that is explicit zero, the super bucket key is zero as well.
+ */
+inline uint64_t get_super_bucket_key(const document::BucketId& bucket_id) noexcept {
+ if (bucket_id == document::BucketId(0)) {
+ return 0;
+ }
+ assert(bucket_id.getUsedBits() >= spi::BucketLimits::MinUsedBits);
+ // Since bucket keys have count-bits at the LSB positions, we want to look at the MSBs instead.
+ return (bucket_id.toKey() >> (64 - spi::BucketLimits::MinUsedBits));
+}
+
+}
diff --git a/storage/src/vespa/storage/common/bucketmessages.cpp b/storage/src/vespa/storage/common/bucketmessages.cpp
index 51c6af8ea5f..796d07ad9ef 100644
--- a/storage/src/vespa/storage/common/bucketmessages.cpp
+++ b/storage/src/vespa/storage/common/bucketmessages.cpp
@@ -104,54 +104,5 @@ std::unique_ptr<api::StorageReply> ReadBucketInfo::makeReply() {
return std::make_unique<ReadBucketInfoReply>(*this);
}
-InternalBucketJoinCommand::InternalBucketJoinCommand(const document::Bucket &bucket,
- uint16_t keepOnDisk, uint16_t joinFromDisk)
- : api::InternalCommand(ID),
- _bucket(bucket),
- _keepOnDisk(keepOnDisk),
- _joinFromDisk(joinFromDisk)
-{
- setPriority(HIGH); // To not get too many pending of these, prioritize
- // them higher than getting more bucket info lists.
-}
-
-InternalBucketJoinCommand::~InternalBucketJoinCommand() = default;
-
-void
-InternalBucketJoinCommand::print(std::ostream& out, bool verbose, const std::string& indent) const {
- out << "InternalBucketJoinCommand()";
-
- if (verbose) {
- out << " : ";
- InternalCommand::print(out, true, indent);
- }
-}
-
-InternalBucketJoinReply::InternalBucketJoinReply(const InternalBucketJoinCommand& cmd,
- const api::BucketInfo& info)
- : api::InternalReply(ID, cmd),
- _bucket(cmd.getBucket()),
- _bucketInfo(info)
-{ }
-
-InternalBucketJoinReply::~InternalBucketJoinReply() = default;
-
-void
-InternalBucketJoinReply::print(std::ostream& out, bool verbose, const std::string& indent) const
-{
- out << "InternalBucketJoinReply()";
-
- if (verbose) {
- out << " : ";
- InternalReply::print(out, true, indent);
- }
-}
-
-std::unique_ptr<api::StorageReply>
-InternalBucketJoinCommand::makeReply()
-{
- return std::make_unique<InternalBucketJoinReply>(*this);
-}
-
} // storage
diff --git a/storage/src/vespa/storage/common/bucketmessages.h b/storage/src/vespa/storage/common/bucketmessages.h
index 428b5268293..3b152c60447 100644
--- a/storage/src/vespa/storage/common/bucketmessages.h
+++ b/storage/src/vespa/storage/common/bucketmessages.h
@@ -11,7 +11,7 @@ namespace storage {
* @class ReadBucketList
* @ingroup common
*
- * @brief List buckets existing on a partition.
+ * @brief List buckets existing in a bucket space.
*/
class ReadBucketList : public api::InternalCommand {
document::BucketSpace _bucketSpace;
@@ -107,60 +107,4 @@ public:
void print(std::ostream& out, bool verbose, const std::string& indent) const override;
};
-/**
- * @class InternalBucketJoinCommand
- * @ingroup common
- *
- * @brief Joins multiple versions of the same bucket.
- *
- * In case disks are reintroduced, we might have several copies of the same
- * bucket on multiple disks. In such cases we should join these buckets during
- * initialization as we cannot cope with multiple versions of the same bucket
- * while storage is running.
- */
-class InternalBucketJoinCommand : public api::InternalCommand {
- document::Bucket _bucket;
- uint16_t _keepOnDisk;
- uint16_t _joinFromDisk;
-
-public:
- static const uint32_t ID = 2015;
-
- InternalBucketJoinCommand(const document::Bucket &bucket, uint16_t keepOnDisk, uint16_t joinFromDisk);
- ~InternalBucketJoinCommand();
-
- document::Bucket getBucket() const override { return _bucket; }
- bool hasSingleBucketId() const override { return true; }
-
- uint16_t getDiskOfInstanceToKeep() const { return _keepOnDisk; }
- uint16_t getDiskOfInstanceToJoin() const { return _joinFromDisk; }
-
- std::unique_ptr<api::StorageReply> makeReply() override;
-
- void print(std::ostream& out, bool verbose, const std::string& indent) const override;
-};
-
-/**
- * @class InternalBucketJoinReply
- * @ingroup common
- */
-class InternalBucketJoinReply : public api::InternalReply {
- document::Bucket _bucket;
- api::BucketInfo _bucketInfo;
-
-public:
- static const uint32_t ID = 2016;
-
- InternalBucketJoinReply(const InternalBucketJoinCommand& cmd,
- const api::BucketInfo& info = api::BucketInfo());
- ~InternalBucketJoinReply();
-
- document::Bucket getBucket() const override { return _bucket; }
- bool hasSingleBucketId() const override { return true; }
-
- const api::BucketInfo& getBucketInfo() const { return _bucketInfo; }
-
- void print(std::ostream& out, bool verbose, const std::string& indent) const override;
-};
-
} // storage
diff --git a/storage/src/vespa/storage/common/bucketoperationlogger.cpp b/storage/src/vespa/storage/common/bucketoperationlogger.cpp
deleted file mode 100644
index 905b704409f..00000000000
--- a/storage/src/vespa/storage/common/bucketoperationlogger.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "bucketoperationlogger.h"
-#include <vespa/storage/bucketdb/storbucketdb.h>
-#include <vespa/storage/bucketdb/bucketcopy.h>
-
-#include <vespa/storageapi/buckets/bucketinfo.h>
-#include <vespa/storageframework/defaultimplementation/clock/realclock.h>
-#include <vespa/vespalib/util/backtrace.h>
-#include <vespa/vespalib/stllike/asciistream.h>
-
-#ifdef ENABLE_BUCKET_OPERATION_LOGGING
-#include <vespa/log/log.h>
-LOG_SETUP(".debuglogger");
-
-namespace storage {
-
-namespace debug {
-
-BucketOperationLogger opLogger;
-
-void
-BucketOperationLogger::log(const document::BucketId& id,
- const vespalib::string& text,
- bool requireLock,
- State::LockUpdate lockUpdate)
-{
- LogEntry entry;
- framework::defaultimplementation::RealClock rclock;
- entry._frameCount = vespalib::getStackTraceFrames(entry._stackFrames, MAX_STACK_FRAMES);
- entry._text = text;
- entry._timestamp = rclock.getTimeInMicros();
- entry._threadId = FastOS_Thread::GetCurrentThreadId() & 0xffff;
- uint32_t lockedByThread = 0;
- bool hasError = false;
-
- {
- std::lock_guard<std:.mutex> guard(_logLock);
- BucketMapType::iterator i = _bucketMap.lower_bound(id);
- if (i != _bucketMap.end() && i->first == id) {
- if (i->second._history.size() >= MAX_ENTRIES) {
- i->second._history.pop_front();
- }
- i->second._history.push_back(entry);
- if (lockUpdate == State::BUCKET_LOCKED) {
- if (i->second._lockedByThread != 0) {
- LOG(warning, "Attempting to acquire lock, but lock "
- "is already held by thread %u", i->second._lockedByThread);
- hasError = true;
- }
- i->second._lockedByThread = entry._threadId;
- }
- lockedByThread = i->second._lockedByThread;
- if (lockUpdate == State::BUCKET_UNLOCKED) {
- if (i->second._lockedByThread == 0) {
- LOG(warning, "Attempting to release lock, but lock "
- "is not held");
- hasError = true;
- }
- i->second._lockedByThread = 0;
- }
- } else {
- State addState;
- addState._lockedByThread = 0;
- addState._history.push_back(entry);
- if (lockUpdate == State::BUCKET_LOCKED) {
- addState._lockedByThread = entry._threadId;
- } else if (lockUpdate == State::BUCKET_UNLOCKED) {
- LOG(warning, "Attempting to release lock, but lock "
- "is not held");
- hasError = true;
- }
- _bucketMap.insert(i, BucketMapType::value_type(id, addState));
- }
- }
-
- if (requireLock && !lockedByThread) {
- LOG(warning, "Operation '%s' requires lock, but lock is "
- "not registered as held", text.c_str());
- hasError = true;
- }
- if (hasError) {
- LOG(warning, "%s", getHistory(id).c_str());
- }
-}
-
-namespace {
-
-// Must hold logger lock
-template <typename LineHandler>
-void
-processHistory(const BucketOperationLogger& opLogger,
- const document::BucketId& id, LineHandler& handler)
-{
- BucketOperationLogger::BucketMapType::const_iterator i(
- opLogger._bucketMap.find(id));
- if (i == opLogger._bucketMap.end()) {
- vespalib::asciistream ss;
- ss << "No history recorded for bucket '"
- << id.toString() << "'";
- handler(ss.str());
- return;
- }
-
- {
- vespalib::asciistream ss;
- ss << "Showing last " << i->second._history.size() << " operations on "
- << "bucket " << id.toString() << " (newest first):";
- handler(ss.str());
- }
- for (BucketOperationLogger::State::LogEntryListType::const_reverse_iterator j(
- i->second._history.rbegin()), end(i->second._history.rend());
- j != end; ++j)
- {
- vespalib::asciistream ss;
- ss << storage::framework::getTimeString(
- j->_timestamp.getTime(),
- storage::framework::DATETIME_WITH_MICROS)
- << " " << j->_threadId << " "
- << j->_text << ". "
- << vespalib::getStackTrace(1, j->_stackFrames, j->_frameCount);
- handler(ss.str());
- }
-}
-
-struct LogWarnAppender
-{
- void operator()(const vespalib::string& line)
- {
- LOG(warning, "%s", line.c_str());
- }
-};
-
-struct LogStringBuilder
-{
- vespalib::asciistream ss;
- void operator()(const vespalib::string& line)
- {
- ss << line << "\n";
- }
-};
-
-}
-
-void
-BucketOperationLogger::dumpHistoryToLog(const document::BucketId& id) const
-{
- LogWarnAppender handler;
- std::lock_guard<std::mutex> guard(_logLock);
- processHistory(*this, id, handler);
-}
-
-vespalib::string
-BucketOperationLogger::getHistory(const document::BucketId& id) const
-{
- LogStringBuilder handler;
- std::lock_guard<std::mutex> lock(_logLock);
- processHistory(*this, id, handler);
- return handler.ss.str();
-}
-
-vespalib::string
-BucketOperationLogger::searchBucketHistories(
- const vespalib::string& sub,
- const vespalib::string& urlPrefix) const
-{
- vespalib::asciistream ss;
- ss << "<ul>\n";
- // This may block for a while... Assuming such searches run when system
- // is otherwise idle.
- std::lock_guard<std::mutex> guard(_logLock);
- for (BucketMapType::const_iterator
- bIt(_bucketMap.begin()), bEnd(_bucketMap.end());
- bIt != bEnd; ++bIt)
- {
- for (State::LogEntryListType::const_iterator
- sIt(bIt->second._history.begin()),
- sEnd(bIt->second._history.end());
- sIt != sEnd; ++sIt)
- {
- if (sIt->_text.find(sub.c_str()) != vespalib::string::npos) {
- ss << "<li><a href=\"" << urlPrefix
- << "0x" << vespalib::hex << bIt->first.getId()
- << vespalib::dec << "\">" << bIt->first.toString()
- << "</a>:\n";
- ss << sIt->_text << "</li>\n";
- }
- }
- }
- ss << "</ul>\n";
- return ss.str();
-}
-
-BucketOperationLogger&
-BucketOperationLogger::getInstance()
-{
- return opLogger;
-}
-
-// Storage node
-void logBucketDbInsert(uint64_t key, const bucketdb::StorageBucketInfo& entry)
-{
- LOG_BUCKET_OPERATION_NO_LOCK(
- document::BucketId(document::BucketId::keyToBucketId(key)),
- vespalib::make_string(
- "bucketdb insert Bucket(crc=%x, docs=%u, size=%u, "
- "metacount=%u, usedfilesize=%u, ready=%s, "
- "active=%s, lastModified=%zu) disk=%u",
- entry.info.getChecksum(),
- entry.info.getDocumentCount(),
- entry.info.getTotalDocumentSize(),
- entry.info.getMetaCount(),
- entry.info.getUsedFileSize(),
- (entry.info.isReady() ? "true" : "false"),
- (entry.info.isActive() ? "true" : "false"),
- entry.info.getLastModified(),
- entry.disk));
-}
-
-void logBucketDbErase(uint64_t key, const TypeTag<bucketdb::StorageBucketInfo>&)
-{
- LOG_BUCKET_OPERATION_NO_LOCK(
- document::BucketId(document::BucketId::keyToBucketId(key)),
- "bucketdb erase");
-}
-
-// Distributor
-void
-checkAllConsistentNodesImpliesTrusted(
- const document::BucketId& bucket,
- const BucketInfo& entry)
-{
- // If all copies are consistent, they should also be trusted
- if (entry.validAndConsistent() && entry.getNodeCount() > 1) {
- for (std::size_t i = 0; i < entry.getNodeCount(); ++i) {
- const BucketCopy& copy = entry.getNodeRef(i);
- if (copy.trusted() == false) {
- LOG(warning, "Bucket DB entry %s for %s is consistent, but "
- "contains non-trusted copy %s", entry.toString().c_str(),
- bucket.toString().c_str(), copy.toString().c_str());
- DUMP_LOGGED_BUCKET_OPERATIONS(bucket);
- }
- }
- }
-}
-
-std::size_t
-firstTrustedNode(const BucketInfo& entry)
-{
- for (std::size_t i = 0; i < entry.getNodeCount(); ++i) {
- const distributor::BucketCopy& copy = entry.getNodeRef(i);
- if (copy.trusted()) {
- return i;
- }
- }
- return std::numeric_limits<std::size_t>::max();
-}
-
-void
-checkNotInSyncImpliesNotTrusted(
- const document::BucketId& bucket,
- const BucketInfo& entry)
-{
- // If there are copies out of sync, different copies should not
- // be set to trusted
- std::size_t trustedNode = firstTrustedNode(entry);
- if (trustedNode != std::numeric_limits<std::size_t>::max()) {
- // Ensure all other trusted copies match the metadata of the
- // first trusted bucket
- const BucketCopy& trustedCopy = entry.getNodeRef(trustedNode);
- for (std::size_t i = 0; i < entry.getNodeCount(); ++i) {
- if (i == trustedNode) {
- continue;
- }
- const BucketCopy& copy = entry.getNodeRef(i);
- const api::BucketInfo& copyInfo = copy.getBucketInfo();
- const api::BucketInfo& trustedInfo = trustedCopy.getBucketInfo();
- if (copy.trusted()
- && ((copyInfo.getChecksum() != trustedInfo.getChecksum())))
- //|| (copyInfo.getTotalDocumentSize() != trustedInfo.getTotalDocumentSize())))
- {
- LOG(warning, "Bucket DB entry %s for %s has trusted node copy "
- "with differing metadata %s", entry.toString().c_str(),
- bucket.toString().c_str(), copy.toString().c_str());
- DUMP_LOGGED_BUCKET_OPERATIONS(bucket);
- }
- }
- }
-}
-
-void
-checkInvalidImpliesNotTrusted(
- const document::BucketId& bucket,
- const BucketInfo& entry)
-{
- for (std::size_t i = 0; i < entry.getNodeCount(); ++i) {
- const BucketCopy& copy = entry.getNodeRef(i);
- if (!copy.valid() && copy.trusted()) {
- LOG(warning, "Bucket DB entry %s for %s has invalid copy %s "
- "marked as trusted", entry.toString().c_str(),
- bucket.toString().c_str(), copy.toString().c_str());
- DUMP_LOGGED_BUCKET_OPERATIONS(bucket);
- }
- }
-}
-
-void
-logBucketDbInsert(uint64_t key, const BucketInfo& entry)
-{
- document::BucketId bucket(document::BucketId::keyToBucketId(key));
- LOG_BUCKET_OPERATION_NO_LOCK(
- bucket, vespalib::make_string(
- "bucketdb insert of %s", entry.toString().c_str()));
- // Do some sanity checking of the inserted entry
- checkAllConsistentNodesImpliesTrusted(bucket, entry);
- checkNotInSyncImpliesNotTrusted(bucket, entry);
- checkInvalidImpliesNotTrusted(bucket, entry);
-}
-
-void
-logBucketDbErase(uint64_t key, const TypeTag<BucketInfo>&)
-{
- document::BucketId bucket(document::BucketId::keyToBucketId(key));
- LOG_BUCKET_OPERATION_NO_LOCK(bucket, "bucketdb erase");
-}
-
-} // namespace debug
-
-} // namespace storage
-
-#endif // ENABLE_BUCKET_OPERATION_LOGGING
diff --git a/storage/src/vespa/storage/common/bucketoperationlogger.h b/storage/src/vespa/storage/common/bucketoperationlogger.h
deleted file mode 100644
index af4b539a4c8..00000000000
--- a/storage/src/vespa/storage/common/bucketoperationlogger.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-#include <vespa/document/bucket/bucketid.h>
-#include <map>
-#include <list>
-#include <mutex>
-
-/**
- * Enable this to log most slotfile operations (such as all mutations) as
- * well as common bucket operations such as splitting, joining and bucket db
- * updates. Each log entry contains the stack frames for the logging callsite,
- * a timestamp, the ID of the thread performing the operation as well as a
- * message. The stack trace is cheaply acquired and does thus not affect runtime
- * performance to a great degree. Expect some overhead from the logging itself
- * since it requires a global mutex around the log state.
- *
- * All relevant bucket/slotfile operations are checked to ensure that the
- * filestor lock is held during the operation and that the thread performing
- * it is the same as the one that acquired the lock.
- *
- * Similarly, code has been added to distributor bucket database and ideal
- * state handling to log these.
- *
- * In the case of an invariant violation (such as a locking bug), the last
- * BUCKET_OPERATION_LOG_ENTRIES log entries will be dumped to the vespalog.
- * Code may also dump the logged history for a bucket by calling
- * DUMP_LOGGED_BUCKET_OPERATIONS(bucketid)
- */
-//#define ENABLE_BUCKET_OPERATION_LOGGING
-#define BUCKET_OPERATION_LOG_ENTRIES 40
-
-#ifdef ENABLE_BUCKET_OPERATION_LOGGING
-#define LOG_BUCKET_OPERATION_NO_LOCK(bucket, string) \
-debug::BucketOperationLogger::getInstance().log( \
- (bucket), (string), false)
-
-#define LOG_BUCKET_OPERATION(bucket, string) \
-debug::BucketOperationLogger::getInstance().log( \
- (bucket), (string), true)
-
-#define LOG_BUCKET_OPERATION_SPECIFY_LOCKED(bucket, string, require_locked) \
-debug::BucketOperationLogger::getInstance().log( \
- (bucket), (string), (require_locked))
-
-#define LOG_BUCKET_OPERATION_SET_LOCK_STATE(bucket, string, require_locked, new_state) \
-debug::BucketOperationLogger::getInstance().log( \
- (bucket), (string), (require_locked), (new_state))
-
-#define DUMP_LOGGED_BUCKET_OPERATIONS(bucket) \
- debug::BucketOperationLogger::getInstance().dumpHistoryToLog(bucket)
-
-namespace storage {
-
-// Debug stuff for tracking the last n operations to buckets
-namespace debug {
-
-struct BucketOperationLogger
-{
- static const std::size_t MAX_ENTRIES = BUCKET_OPERATION_LOG_ENTRIES;
- static const std::size_t MAX_STACK_FRAMES = 25;
-
- struct LogEntry
- {
- void* _stackFrames[MAX_STACK_FRAMES];
- vespalib::string _text;
- framework::MicroSecTime _timestamp;
- int _frameCount;
- int32_t _threadId;
- };
-
- struct State
- {
- typedef std::list<LogEntry> LogEntryListType;
- enum LockUpdate
- {
- NO_UPDATE = 0,
- BUCKET_LOCKED = 1,
- BUCKET_UNLOCKED = 2
- };
- LogEntryListType _history;
- uint32_t _lockedByThread;
- };
-
- typedef std::map<document::BucketId, State> BucketMapType;
-
- std::mutex _logLock;
- BucketMapType _bucketMap;
-
- void log(const document::BucketId& id,
- const vespalib::string& text,
- bool requireLock = true,
- State::LockUpdate update = State::NO_UPDATE);
-
- vespalib::string getHistory(const document::BucketId& id) const;
- void dumpHistoryToLog(const document::BucketId& id) const;
- //void dumpAllBucketHistoriesToFile(const vespalib::string& filename) const;
- /**
- * Search through all bucket history entry descriptions to find substring,
- * creating a itemized list of buckets containing it as well as a preview.
- * @param sub the exact substring to search for.
- * @param urlPrefix the URL used for creating bucket links.
- */
- vespalib::string searchBucketHistories(const vespalib::string& sub,
- const vespalib::string& urlPrefix) const;
- static BucketOperationLogger& getInstance();
-};
-
-}
-
-}
-
-#else
-
-#define LOG_BUCKET_OPERATION_NO_LOCK(bucket, string)
-#define LOG_BUCKET_OPERATION(bucket, string)
-#define LOG_BUCKET_OPERATION_SPECIFY_LOCKED(bucket, string, require_locked)
-#define DUMP_LOGGED_BUCKET_OPERATIONS(bucket)
-#define LOG_BUCKET_OPERATION_SET_LOCK_STATE(bucket, string, require_locked, new_state)
-
-#endif
-
diff --git a/storage/src/vespa/storage/common/cluster_context.h b/storage/src/vespa/storage/common/cluster_context.h
new file mode 100644
index 00000000000..a7d8ab0a2e5
--- /dev/null
+++ b/storage/src/vespa/storage/common/cluster_context.h
@@ -0,0 +1,46 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/stllike/string.h>
+
+namespace storage {
+
+/**
+ * Cluster ontext common to all storage components.
+ * For now just the cluster name, but we can consider
+ * moving other global context into this API.
+ **/
+struct ClusterContext {
+protected:
+ virtual ~ClusterContext() = default;
+public:
+ // Returns a pointer to the cluster name.
+ // Must be a valid pointer to a constant string for the
+ // lifetime of all the components that may ask for it.
+ // This API is for the benefit of StorageMessageAddress
+ // which wants to contain the pointer returned here.
+ virtual const vespalib::string * cluster_name_ptr() const noexcept = 0;
+
+ // convenience method
+ const vespalib::string &cluster_name() const noexcept {
+ return *cluster_name_ptr();
+ }
+};
+
+/**
+ * Simple ClusterContext with an exposed string.
+ **/
+struct SimpleClusterContext : ClusterContext {
+ vespalib::string my_cluster_name;
+ const vespalib::string * cluster_name_ptr() const noexcept override {
+ return &my_cluster_name;
+ }
+ SimpleClusterContext() : my_cluster_name("") {}
+ explicit SimpleClusterContext(const vespalib::string& value)
+ : my_cluster_name(value)
+ {}
+ ~SimpleClusterContext() override = default;
+};
+
+} // namespace
diff --git a/storage/src/vespa/storage/common/messagebucket.cpp b/storage/src/vespa/storage/common/messagebucket.cpp
index 6cc94e2a732..61283fd3d04 100644
--- a/storage/src/vespa/storage/common/messagebucket.cpp
+++ b/storage/src/vespa/storage/common/messagebucket.cpp
@@ -64,8 +64,6 @@ getStorageMessageBucket(const api::StorageMessage& msg)
return static_cast<const ReadBucketList&>(msg).getBucket();
case ReadBucketInfo::ID:
return static_cast<const ReadBucketInfo&>(msg).getBucket();
- case InternalBucketJoinCommand::ID:
- return static_cast<const InternalBucketJoinCommand&>(msg).getBucket();
case RecheckBucketInfoCommand::ID:
return static_cast<const RecheckBucketInfoCommand&>(msg).getBucket();
default:
diff --git a/storage/src/vespa/storage/common/messagesender.h b/storage/src/vespa/storage/common/messagesender.h
index 48020bf053e..839dbcb91dc 100644
--- a/storage/src/vespa/storage/common/messagesender.h
+++ b/storage/src/vespa/storage/common/messagesender.h
@@ -43,4 +43,13 @@ struct ChainedMessageSender {
virtual void sendDown(const std::shared_ptr<api::StorageMessage>&) = 0;
};
+/**
+ * Interface to send messages "up" that bypasses message tracking.
+ */
+class NonTrackingMessageSender {
+public:
+ virtual ~NonTrackingMessageSender() = default;
+ virtual void send_up_without_tracking(const std::shared_ptr<api::StorageMessage>&) = 0;
+};
+
} // storage
diff --git a/storage/src/vespa/storage/common/node_identity.cpp b/storage/src/vespa/storage/common/node_identity.cpp
new file mode 100644
index 00000000000..2ad940b7b20
--- /dev/null
+++ b/storage/src/vespa/storage/common/node_identity.cpp
@@ -0,0 +1,16 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "node_identity.h"
+
+namespace storage {
+
+NodeIdentity::NodeIdentity(vespalib::stringref cluster_name_in,
+ const lib::NodeType& node_type_in,
+ uint16_t node_index_in)
+ : _cluster_name(cluster_name_in),
+ _node_type(node_type_in),
+ _node_index(node_index_in)
+{
+}
+
+}
diff --git a/storage/src/vespa/storage/common/node_identity.h b/storage/src/vespa/storage/common/node_identity.h
new file mode 100644
index 00000000000..ea2edb98cdd
--- /dev/null
+++ b/storage/src/vespa/storage/common/node_identity.h
@@ -0,0 +1,28 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vdslib/state/nodetype.h>
+#include <vespa/vespalib/stllike/string.h>
+
+namespace storage {
+
+/**
+ * Class that represents the identity of a storage or distributor node.
+ */
+class NodeIdentity {
+private:
+ vespalib::string _cluster_name;
+ const lib::NodeType& _node_type;
+ uint16_t _node_index;
+
+public:
+ NodeIdentity(vespalib::stringref cluster_name_in,
+ const lib::NodeType& node_type_in,
+ uint16_t node_index_in);
+ const vespalib::string& cluster_name() const { return _cluster_name; }
+ const lib::NodeType& node_type() const { return _node_type; }
+ uint16_t node_index() const { return _node_index; }
+};
+
+}
diff --git a/storage/src/vespa/storage/common/reindexing_constants.cpp b/storage/src/vespa/storage/common/reindexing_constants.cpp
new file mode 100644
index 00000000000..1c72f9a9d64
--- /dev/null
+++ b/storage/src/vespa/storage/common/reindexing_constants.cpp
@@ -0,0 +1,16 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "reindexing_constants.h"
+
+namespace storage {
+
+const char* reindexing_bucket_lock_bypass_prefix() noexcept {
+ // This is by design a string that will fail to parse as a valid document selection in the backend.
+ // It's only used to bypass the read-for-write visitor bucket lock.
+ return "@@__vespa_internal_allow_through_bucket_lock";
+}
+
+const char* reindexing_bucket_lock_visitor_parameter_key() noexcept {
+ return "__vespa_internal_reindexing_bucket_token";
+}
+
+}
diff --git a/storage/src/vespa/storage/common/reindexing_constants.h b/storage/src/vespa/storage/common/reindexing_constants.h
new file mode 100644
index 00000000000..7552ab332b1
--- /dev/null
+++ b/storage/src/vespa/storage/common/reindexing_constants.h
@@ -0,0 +1,10 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+namespace storage {
+
+const char* reindexing_bucket_lock_bypass_prefix() noexcept;
+
+const char* reindexing_bucket_lock_visitor_parameter_key() noexcept;
+
+}
diff --git a/storage/src/vespa/storage/common/statusmetricconsumer.cpp b/storage/src/vespa/storage/common/statusmetricconsumer.cpp
index 553ab7f77ca..3dfa96cb0df 100644
--- a/storage/src/vespa/storage/common/statusmetricconsumer.cpp
+++ b/storage/src/vespa/storage/common/statusmetricconsumer.cpp
@@ -1,13 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "statusmetricconsumer.h"
-#include <vespa/storageframework/generic/status/htmlstatusreporter.h>
-#include <boost/assign.hpp>
#include <boost/lexical_cast.hpp>
-#include <vespa/metrics/printutils.h>
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/textwriter.h>
#include <vespa/metrics/xmlwriter.h>
+#include <vespa/metrics/metricmanager.h>
#include <vespa/storageapi/messageapi/storagemessage.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/xmlstream.h>
@@ -47,7 +45,7 @@ vespalib::string
StatusMetricConsumer::getReportContentType(const framework::HttpUrlPath& path) const
{
if (!path.hasAttribute("format")) {
- return "text/html";
+ return "text/plain";
}
if (path.getAttribute("format") == "xml") {
@@ -62,85 +60,7 @@ StatusMetricConsumer::getReportContentType(const framework::HttpUrlPath& path) c
return "application/json";
}
- return "text/html";
-}
-
-namespace {
- void addSnapshotAsTableRow(const metrics::MetricSnapshot& snapshot,
- const metrics::MetricSnapshotSet* building,
- std::ostream& out,
- int32_t interval = -3)
- {
- if (interval == -3) interval = snapshot.getPeriod();
- std::string name(snapshot.getName());
- if (interval == -1) {
- name = "Clone of total metrics with active metrics added";
- }
- std::vector<char> buffer(40);
- out << " <tr>\n"
- << " <td>" << name << "</td>\n";
- //if (snapshot.getToTime() != 0 || interval < 0 || building != 0)
- for (uint32_t format=0; format<4; ++format) {
- // 0 XML - 1 HTML - 2 text, 3 JSON
- out << " <td>";
- bool linked = false;
- for (uint32_t tmp=0; tmp<2; ++tmp) { // 0 last - 1 temp
- if (tmp == 1) {
- if (building == 0 || !building->hasTemporarySnapshot()
- || building->getBuilderCount() == 0)
- {
- continue;
- }
- } else {
- if ((snapshot.getToTime() == 0 && interval >= 0)
- || snapshot.getToTime() == snapshot.getFromTime())
- {
- continue;
- }
- }
- if (tmp == 1) out << "&nbsp;&nbsp;";
-
- const char* formatStr = "xml";
- const char* consumer = "status";
- switch (format) {
- case 0:
- formatStr = "xml";
- break;
- case 1:
- formatStr = "html";
- break;
- case 2:
- formatStr = "text";
- break;
- case 3:
- formatStr = "json";
- consumer = "yamas";
- break;
- }
-
- linked = true;
- out << "<a href=\""
- << "?interval=" << interval
- << "&format=" << formatStr
- << "&consumer=" << consumer
- << "&verbosity=0"
- << "&pattern=.*"
- << "&callsnapshothooks=0"
- << "&tmpsnapshot=" << tmp
- << "\">"
- << (tmp == 0 ? (interval > 0 ? "Last complete"
- : "Current")
- : "Building")
- << "</a>";
- }
- if (!linked) {
- out << "None taken yet";
- }
- out << "</td>\n";
- }
- out << "</tr>\n";
- }
-
+ return "text/plain";
}
bool
@@ -155,160 +75,76 @@ StatusMetricConsumer::reportStatus(std::ostream& out,
updateSnapshotHooks ? ", calling snapshot hooks too" : ".");
_manager.updateMetrics(updateSnapshotHooks);
} else {
- LOG(debug, "Not calling update hooks as dontcallupdatehooks option "
- "has been given");
+ LOG(debug, "Not calling update hooks as dontcallupdatehooks option has been given");
}
framework::SecondTime currentTime(_component.getClock().getTimeInSeconds());
- bool html = (!path.hasAttribute("format")
- || path.getAttribute("format") == "html");
- bool xml = (!html && path.getAttribute("format") == "xml");
- bool json = (!html && path.getAttribute("format") == "json");
+ bool xml = (path.getAttribute("format") == "xml");
+ bool json = (path.getAttribute("format") == "json");
int verbosity(path.get("verbosity", 0));
// We have to copy unset values if using HTML as HTML version gathers
// metrics for calculations and thus needs unset values.
- bool copyUnset = (html || verbosity >= 2);
+ bool copyUnset = (verbosity >= 2);
bool temporarySnap = (path.get("tmpsnapshot", 0) == 1);
- framework::PartlyHtmlStatusReporter htmlReporter(*this);
- if (html) {
- htmlReporter.reportHtmlHeader(out, path);
- }
-
if (path.hasAttribute("task") && path.getAttribute("task") == "reset") {
- {
- std::lock_guard guard(_lock);
- _manager.reset(currentTime.getTime());
- }
- if (html) {
- out << "<p>Metrics reset at " << currentTime << ".</p>\n";
- }
- }
-
- if (html) {
- out << "<p><div align=\"right\"><a href=\"?task=reset\">"
- << "Reset all metrics</a></div></p>\n"
- << "<p>Metrics available at " << framework::SecondTime(currentTime)
- << "</p>\n"
- << "<table border=\"1\" cellspacing=\"3\">\n"
- << " <tr><td>Display metrics from</td>\n"
- << " <td>XML raw data</td>\n"
- << " <td>HTML presentation</td>\n"
- << " <td>Text output</td>\n"
- << " <td>JSON output</td></tr>\n";
-
- metrics::MetricLockGuard metricLock(_manager.getMetricLock());
- std::vector<uint32_t> intervals(
- _manager.getSnapshotPeriods(metricLock));
- addSnapshotAsTableRow(
- _manager.getActiveMetrics(metricLock), 0, out, -2);
- for (uint32_t i=0; i<intervals.size(); ++i) {
- addSnapshotAsTableRow(
- _manager.getMetricSnapshot(metricLock, intervals[i]),
- &_manager.getMetricSnapshotSet(metricLock, intervals[i]),
- out);
- }
- addSnapshotAsTableRow(
- _manager.getTotalMetricSnapshot(metricLock), 0, out);
- addSnapshotAsTableRow(
- _manager.getTotalMetricSnapshot(metricLock), 0, out, -1);
- out << "</table>\n";
-
- out << "<h3>Metrics explanation</h3>\n"
- << "<p>\n"
- << "The active metrics are currently being updated. The snapshots "
- << "update at given time intervals, such that you can always view "
- << "activity for a full time window. A total snapshot is also "
- << "available. It is updated each time the shortest interval "
- << "snapshot is updated. In addition it is possible to view a "
- << "truly total metric set for all metrics since start, but this "
- << "is a bit more expensive as we need to take a copy of the total "
- << "snapshot to add the active metrics to it.\n"
- << "</p><p>\n"
- << "The XML view has a verbosity option that can be adjusted to "
- << "control the amount of detail shown. With the default verbosity "
- << "only the critical parts are shown. Currently, verbosity 1 adds "
- << "descriptions. Verbosity 2 adds unused metrics and total values "
- << "for value metrics. Verbosity 3 add tags.\n"
- << "</p><p>\n"
- << "The Text view uses a pattern that has a regular expression. "
- << "Only metrics whose name path matches the regular expression "
- << "will be shown.\n"
- << "</p><p>\n"
- << "Both XML, json and text view use consumer identifiers to detect "
- << "what metrics to show. The default status consumer hides "
- << "metrics that are part of sums and shows everything else. Use an "
- << "empty consumer string to see all metrics. The 'log' consumer "
- << "can be used to see metrics logged. JSON uses the yamas consumer as "
- << "default.\n"
- << "</p>\n";
+ std::lock_guard guard(_lock);
+ _manager.reset(currentTime.getTime());
}
if (path.hasAttribute("interval")) {
// Grab the snapshot we want to view more of
- int32_t interval(
- boost::lexical_cast<int32_t>(path.getAttribute("interval")));
+ int32_t interval(boost::lexical_cast<int32_t>(path.getAttribute("interval")));
metrics::MetricLockGuard metricLock(_manager.getMetricLock());
std::unique_ptr<metrics::MetricSnapshot> generated;
const metrics::MetricSnapshot* snapshot;
if (interval == -2) {
snapshot = &_manager.getActiveMetrics(metricLock);
- _manager.getActiveMetrics(metricLock).setToTime(
- currentTime.getTime());
+ _manager.getActiveMetrics(metricLock).setToTime(currentTime.getTime());
} else if (interval == -1) {
// "Prime" the metric structure by first fetching the set of active
// metrics (complete with structure) and resetting these. This
// leaves us with an empty metrics set to which we can (in order)
// add the total and the active metrics. If this is not done, non-
// written metrics won't be included even if copyUnset is true.
- generated.reset(new metrics::MetricSnapshot(
+ generated = std::make_unique<metrics::MetricSnapshot>(
"Total metrics from start until current time", 0,
_manager.getActiveMetrics(metricLock).getMetrics(),
- copyUnset));
+ copyUnset);
generated->reset(0);
- _manager.getTotalMetricSnapshot(metricLock).addToSnapshot(
- *generated, currentTime.getTime());
- _manager.getActiveMetrics(metricLock).addToSnapshot(
- *generated, currentTime.getTime());
- generated->setFromTime(
- _manager.getTotalMetricSnapshot(metricLock).getFromTime());
+ _manager.getTotalMetricSnapshot(metricLock).addToSnapshot(*generated, currentTime.getTime());
+ _manager.getActiveMetrics(metricLock).addToSnapshot(*generated, currentTime.getTime());
+ generated->setFromTime(_manager.getTotalMetricSnapshot(metricLock).getFromTime());
snapshot = generated.get();
} else if (interval == 0) {
if (copyUnset) {
- generated.reset(new metrics::MetricSnapshot(
+ generated = std::make_unique<metrics::MetricSnapshot>(
_manager.getTotalMetricSnapshot(metricLock).getName(),
0,
_manager.getActiveMetrics(metricLock).getMetrics(),
- true));
+ true);
generated->reset(0);
- _manager.getTotalMetricSnapshot(metricLock).addToSnapshot(
- *generated, currentTime.getTime());
+ _manager.getTotalMetricSnapshot(metricLock).addToSnapshot(*generated, currentTime.getTime());
snapshot = generated.get();
} else {
snapshot = &_manager.getTotalMetricSnapshot(metricLock);
}
} else {
if (copyUnset) {
- generated.reset(new metrics::MetricSnapshot(
- _manager.getMetricSnapshot(metricLock, interval)
- .getName(), 0,
- _manager.getActiveMetrics(metricLock).getMetrics(),
- true));
+ generated = std::make_unique<metrics::MetricSnapshot>(
+ _manager.getMetricSnapshot(metricLock, interval).getName(), 0,
+ _manager.getActiveMetrics(metricLock).getMetrics(), true);
generated->reset(0);
_manager.getMetricSnapshot(metricLock, interval, temporarySnap)
.addToSnapshot(*generated, currentTime.getTime());
snapshot = generated.get();
} else {
- snapshot = &_manager.getMetricSnapshot(
- metricLock, interval, temporarySnap);
+ snapshot = &_manager.getMetricSnapshot(metricLock, interval, temporarySnap);
}
}
std::string consumer = path.getAttribute("consumer", "");
- if (html) {
- printHtmlMetricsReport(out, *snapshot,
- path.hasAttribute("includenotused"));
- } else if (xml) {
+ if (xml) {
out << "<?xml version=\"1.0\"?>\n";
vespalib::XmlOutputStream xos(out);
metrics::XmlWriter xmlWriter(xos, snapshot->getPeriod(), verbosity);
@@ -325,711 +161,12 @@ StatusMetricConsumer::reportStatus(std::ostream& out,
out << jsonStreamData.str();
} else {
std::string pattern = path.getAttribute("pattern", ".*");
- metrics::TextWriter textWriter(out, snapshot->getPeriod(),
- pattern, verbosity > 0);
+ metrics::TextWriter textWriter(out, snapshot->getPeriod(), pattern, verbosity > 0);
_manager.visit(metricLock, *snapshot, textWriter, consumer);
}
}
- if (html) {
- htmlReporter.reportHtmlFooter(out, path);
- }
- return true;
-}
-
-void
-StatusMetricConsumer::writeXmlTags(std::ostream& out,
- const vespalib::StringTokenizer& name,
- std::vector<std::string>& xmlTags) const
-{
- // Find how many common elements exist.
- uint32_t equalUpToIndex = 0;
- if (name.size() != 0) {
- uint32_t n = std::min((size_t)name.size() - 1, xmlTags.size());
- while (equalUpToIndex < n &&
- name[equalUpToIndex] == xmlTags[equalUpToIndex])
- {
- ++equalUpToIndex;
- }
- }
-
- // End old tags that aren't common.
- for (uint32_t i=0, n=xmlTags.size() - equalUpToIndex; i<n; ++i) {
- for (uint32_t j=0; j<xmlTags.size(); ++j) out << " ";
- std::string xmlname(xmlTags.back());
- std::replace(xmlname.begin(), xmlname.end(), ' ', '_');
- out << "</" << xmlname << ">\n";
- xmlTags.pop_back();
- }
-
- // Create new tags that aren't common.
- for (uint32_t i=equalUpToIndex; i + 1 <name.size(); ++i) {
- std::string xmlname(name[i]);
- if (xmlname.size() > 0) {
- for (uint32_t j=0; j<=xmlTags.size(); ++j) out << " ";
- xmlTags.push_back(xmlname);
- std::replace(xmlname.begin(), xmlname.end(), ' ', '_');
- out << "<" << xmlname << ">\n";
- }
- }
-}
-
-namespace {
- struct UnusedMetricPrinter : public metrics::MetricVisitor {
- const std::map<metrics::Metric::String, metrics::Metric::SP>& _usedMetrics;
- std::ostream& _out;
-
- UnusedMetricPrinter(const std::map<metrics::Metric::String, metrics::Metric::SP>& used,
- std::ostream& out)
- : _usedMetrics(used), _out(out) {}
-
- bool visitMetric(const metrics::Metric& metric, bool) override {
- std::map<metrics::Metric::String,
- metrics::Metric::SP>::const_iterator it(
- _usedMetrics.find(metric.getPath()));
- if (it == _usedMetrics.end()) {
- std::string result = metric.toString();
- std::string::size_type pos1 = result.find(' ');
- std::string::size_type pos2 = result.rfind('"');
- _out << metric.getPath() << result.substr(pos1, pos2 + 1 - pos1)
- << "\n";
- }
- return true;
- }
- };
-}
-
-void
-StatusMetricConsumer::printHtmlMetricsReport(
- std::ostream& out, const metrics::MetricSnapshot& data,
- bool includeNotUsed) const
-{
- std::map<String, Metric::SP> usedMetrics;
-
- out << "<h2>Metrics report for the last "
- << framework::SecondTime(data.getLength())
- .toString(framework::DIFFERENCE)
- << ", from " << framework::SecondTime(data.getFromTime()) << " to "
- << framework::SecondTime(data.getFromTime() + data.getLength())
- << "</h2>\n";
-
- out << "<p>\n"
- << "Note that min/max values are currently always from start of "
- << "process, as current procedure for gathering data doesn't let us "
- << "know min/max for windows.\n"
- << "</p>\n";
-
- // Storage node metrics
- if (_component.getNodeType() == lib::NodeType::STORAGE) {
- printStorageHtmlReport(out, usedMetrics, data);
- printOperationHtmlReport(out, usedMetrics, data);
- printMaintOpHtmlReport(out, usedMetrics, data);
- out << "<br>\n"
- << "<table cellpadding=\"0\" cellspacing=\"0\">\n"
- << "<td valign=\"top\">\n";
- out << "</td><td>&nbsp;&nbsp;</td>\n"
- << "<td valign=\"top\">\n";
- out << "</td></table><br>\n";
- printMergeHtmlReport(out, usedMetrics, data);
- printVisitHtmlReport(out, usedMetrics, data);
- }
-
- if (includeNotUsed) {
- out << "<h2>Metrics not used by user friendly overview above</h2>\n";
- out << "<pre>\n";
- UnusedMetricPrinter metricPrinter(usedMetrics, out);
- data.getMetrics().visit(metricPrinter);
- out << "</pre>\n";
- }
-}
-
-void
-StatusMetricConsumer::printStorageHtmlReport(
- std::ostream& out,
- std::map<metrics::Metric::String, metrics::Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const
-{
- using namespace boost::assign;
- using namespace metrics::printutils;
-
- MetricSource ms(snapshot, "vds.datastored", &usedMetrics);
- HttpTable table("Disk storage utilization", "Disk");
- table.colNames += "Stored data", "Document count";
-
- std::vector<std::string> diskMetrics(ms.getPathsMatchingPrefix("disk_"));
- std::map<uint32_t, std::string> indexMap;
- for(std::vector<std::string>::const_iterator it = diskMetrics.begin();
- it != diskMetrics.end(); ++it)
- {
- std::string::size_type pos = it->find('_');
- indexMap[boost::lexical_cast<uint32_t>(it->substr(pos + 1))] = *it;
- }
-
- std::map<uint32_t, std::string>::const_iterator it = indexMap.begin();
- for (uint32_t i=0; i<indexMap.size(); ++i) {
- std::ostringstream ost;
- ost << it->first;
- table.rowNames += ost.str();
- table[i][0] = getByteValueString(
- getLongMetric(it->second + ".bytes.value", ms));
- table[i][1] = getValueString(
- getLongMetric(it->second + ".docs.value", ms));
- ++it;
- }
- table.rowNames += "Total";
- table[diskMetrics.size()][0] = getByteValueString(
- getLongMetric("alldisks.bytes.value", ms));
- table[diskMetrics.size()][1] = getValueString(
- getLongMetric("alldisks.docs.value", ms));
-
- table.print(out);
-}
-
-void
-StatusMetricConsumer::printOperationHtmlReport(
- std::ostream& out,
- std::map<metrics::Metric::String, metrics::Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const
-{
- using namespace boost::assign;
- using namespace metrics::printutils;
-
- LVW timePeriod(snapshot.getLength());
-
- MetricSource ms(snapshot, "vds.filestor.alldisks.allthreads", &usedMetrics);
- HttpTable table("External load", "Operation");
- table.colNames += "Ops/s", "Ops", "Failed", "Not found",
- "Min latency", "Avg latency", "Max latency";
- LongValue failed;
-
- table.rowNames += "Put";
- table[0][0] = getValueString(
- DVW(1.0) * getLongMetric("put.sum.count.count", ms) / timePeriod,
- "%'3.2f");
- table[0][1] = getValueString(getLongMetric("put.sum.count.count", ms));
- LongValue failedPuts = getLongMetric("put.sum.count.count", ms)
- - getLongMetric("put.sum.latency.count", ms);
- table[0][2] = getValueString(failedPuts) + getValueString(
- DVW(100) * failedPuts / getLongMetric("put.sum.count.count", ms),
- " (%'3.2f %%)");
- table[0][4] = getValueString(
- getDoubleMetric("put.sum.latency.min", ms), "%'3.2f ms");
- table[0][5] = getValueString(
- getDoubleMetric("put.sum.latency.average", ms), "%'3.2f ms");
- table[0][6] = getValueString(
- getDoubleMetric("put.sum.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Update";
- table[1][0] = getValueString(
- DVW(1.0) * getLongMetric("update.sum.count.count", ms) / LVW(timePeriod),
- "%'3.2f");
- table[1][1] = getValueString(getLongMetric("update.sum.count.count", ms));
- LongValue failedUpdates = getLongMetric("update.sum.count.count", ms)
- - getLongMetric("update.sum.latency.count", ms);
- table[1][2] = getValueString(failedUpdates) + getValueString(
- DVW(100) * failedUpdates / getLongMetric("update.sum.count.count", ms),
- " (%'3.2f %%)");
- LongValue notFoundUpdates = getLongMetric("update.sum.not_found.count", ms);
- table[1][3] = getValueString(notFoundUpdates) + getValueString(
- DVW(100) * notFoundUpdates / getLongMetric("update.sum.count.count", ms),
- " (%'3.2f %%)");
- table[1][4] = getValueString(
- getDoubleMetric("update.sum.latency.min", ms), "%'3.2f ms");
- table[1][5] = getValueString(
- getDoubleMetric("update.sum.latency.average", ms), "%'3.2f ms");
- table[1][6] = getValueString(
- getDoubleMetric("update.sum.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Remove";
- table[2][0] = getValueString(
- DVW(1.0) * getLongMetric("remove.sum.count.count", ms) / LVW(timePeriod),
- "%'3.2f");
- table[2][1] = getValueString(getLongMetric("remove.sum.count.count", ms));
- LongValue failedRemoves = getLongMetric("remove.sum.count.count", ms)
- - getLongMetric("remove.sum.latency.count", ms);
- table[2][2] = getValueString(failedRemoves) + getValueString(
- DVW(100) * failedRemoves / getLongMetric("remove.sum.count.count", ms),
- " (%'3.2f %%)");
- LongValue notFoundRemoves = getLongMetric("remove.sum.not_found.count", ms);
- table[2][3] = getValueString(notFoundRemoves) + getValueString(
- DVW(100) * notFoundRemoves / getLongMetric("remove.sum.count.count", ms),
- " (%'3.2f %%)");
- table[2][4] = getValueString(
- getDoubleMetric("remove.sum.latency.min", ms), "%'3.2f ms");
- table[2][5] = getValueString(
- getDoubleMetric("remove.sum.latency.average", ms), "%'3.2f ms");
- table[2][6] = getValueString(
- getDoubleMetric("remove.sum.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Get";
- table[3][0] = getValueString(
- DVW(1.0) * getLongMetric("get.sum.count.count", ms) / LVW(timePeriod),
- "%'3.2f");
- table[3][1] = getValueString(getLongMetric("get.sum.count.count", ms));
- LongValue failedGets = getLongMetric("get.sum.count.count", ms)
- - getLongMetric("get.sum.latency.count", ms);
- table[3][2] = getValueString(failedGets) + getValueString(
- DVW(100) * failedGets / getLongMetric("get.sum.count.count", ms),
- " (%'3.2f %%)");
- LongValue notFoundGets = getLongMetric("get.sum.not_found.count", ms);
- table[3][3] = getValueString(notFoundGets) + getValueString(
- DVW(100) * notFoundGets / getLongMetric("get.sum.count.count", ms),
- " (%'3.2f %%)");
- table[3][4] = getValueString(
- getDoubleMetric("get.sum.latency.min", ms), "%'3.2f ms");
- table[3][5] = getValueString(
- getDoubleMetric("get.sum.latency.average", ms), "%'3.2f ms");
- table[3][6] = getValueString(
- getDoubleMetric("get.sum.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Visit";
- std::string visPrefix = "../../../visitor.allthreads.";
- LongValue completedVis = getLongMetric(visPrefix + "completed.sum.count", ms);
- failed = getLongMetric(visPrefix + "failed.sum.count", ms);
- LongValue totalVis = failed + completedVis;
- // Not adding aborted to this count for now
- // + getLongMetric(visPrefix + "aborted.count", ms)
- table[4][0] = getValueString(DVW(1.0) * completedVis / timePeriod, "%'3.2f");
- table[4][1] = getValueString(completedVis);
- table[4][2] = getValueString(failed)
- + getValueString(DVW(100) * failed / totalVis, " (%'3.2f %%)");
- table[4][4] = getValueString(
- getDoubleMetric(visPrefix + "averagevisitorlifetime.sum.min", ms),
- "%'3.2f ms");
- table[4][5] = getValueString(
- getDoubleMetric(visPrefix + "averagevisitorlifetime.sum.average", ms),
- "%'3.2f ms");
- table[4][6] = getValueString(
- getDoubleMetric(visPrefix + "averagevisitorlifetime.sum.max", ms),
- "%'3.2f ms");
-
- /*
- table.rowNames += "Stat";
- table[3][0] = getValueString(
- getQuotient(getLongMetric("stats.count", ms),
- LVW(timePeriod)), "%'3.2f");
- table[3][1] = getValueString(getLongMetric("stats.count", ms));
- LongValue failedStats = getDiff(
- getLongMetric("stats.count", ms),
- getLongMetric("statlatencytotal.count", ms));
- table[3][2] = getValueString(failedStats) + getValueString(
- getProduct(LVW(100), getQuotient(failedStats,
- getLongMetric("stats.count", ms))),
- " (%'3.2f %%)");
- LongValue notFoundStats = getLongMetric("statsnotfound.count", ms);
- table[3][3] = getValueString(notFoundStats) + getValueString(
- getProduct(LVW(100), getQuotient(notFoundStat,
- getLongMetric("stats.count", ms))),
- " (%'3.2f %%)");
- table[3][4] = getValueString(
- getDoubleMetric("statlatencytotal.average", ms), "%'3.2f ms");
- */
-
- table.rowNames += "Revert";
- table[5][0] = getValueString(
- DVW(1.0) * getLongMetric("revert.sum.count.count", ms) / LVW(timePeriod),
- "%'3.2f");
- table[5][1] = getValueString(getLongMetric("revert.sum.count.count", ms));
- LongValue failedReverts = getLongMetric("revert.sum.count.count", ms)
- - getLongMetric("revert.sum.latency.count", ms);
- table[5][2] = getValueString(failedReverts) + getValueString(
- DVW(100) * failedReverts / getLongMetric("revert.sum.count.count", ms),
- " (%'3.2f %%)");
- LongValue notFoundReverts = getLongMetric("revert.sum.not_found.count", ms);
- table[5][3] = getValueString(notFoundReverts) + getValueString(
- DVW(100) * notFoundReverts / getLongMetric("revert.sum.count.count", ms),
- " (%'3.2f %%)");
- table[5][4] = getValueString(
- getDoubleMetric("revert.sum.latency.min", ms), "%'3.2f ms");
- table[5][5] = getValueString(
- getDoubleMetric("revert.sum.latency.average", ms), "%'3.2f ms");
- table[5][6] = getValueString(
- getDoubleMetric("revert.sum.latency.max", ms), "%'3.2f ms");
-
- table.print(out);
-}
-
-void
-StatusMetricConsumer::printMaintOpHtmlReport(
- std::ostream& out,
- std::map<metrics::Metric::String, metrics::Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const
-{
- using namespace boost::assign;
- using namespace metrics::printutils;
-
- MetricSource ms(snapshot, "vds.filestor.alldisks.allthreads", &usedMetrics);
- HttpTable table("Maintenance load", "Operation");
- table.colNames += "Ops/s", "Ops", "Failed", "Not found",
- "Min latency", "Avg latency", "Max latency", "Notes";
- LongValue failed;
-
- LVW timePeriod(snapshot.getLength());
-
- table.rowNames += "Merge bucket";
- table[0][0] = getValueString(
- DVW(1.0) * getLongMetric("mergebuckets.count.count", ms)
- / timePeriod, "%'3.2f");
- table[0][1] = getValueString(getLongMetric("mergebuckets.count.count", ms));
- failed = getLongMetric("mergebuckets.count.count", ms);
- table[0][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("mergebuckets.count.count", ms),
- " (%'3.2f %%)");
- table[0][4] = getValueString(
- getDoubleMetric("mergelatencytotal.min", ms), "%'3.2f ms");
- table[0][5] = getValueString(
- getDoubleMetric("mergelatencytotal.average", ms), "%'3.2f ms");
- table[0][6] = getValueString(
- getDoubleMetric("mergelatencytotal.max", ms), "%'3.2f ms");
-
- table.rowNames += "Split bucket";
- table[1][0] = getValueString(
- DVW(1.0) * getLongMetric("splitbuckets.count.count", ms)
- / timePeriod, "%'3.2f");
- table[1][1] = getValueString(getLongMetric("splitbuckets.count.count", ms));
- failed = getLongMetric("splitbuckets.failed.count", ms);
- table[1][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("splitbuckets.count.count", ms),
- " (%'3.2f %%)");
- table[1][4] = getValueString(
- getDoubleMetric("splitbuckets.latency.min", ms), "%'3.2f ms");
- table[1][5] = getValueString(
- getDoubleMetric("splitbuckets.latency.average", ms), "%'3.2f ms");
- table[1][6] = getValueString(
- getDoubleMetric("splitbuckets.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Delete bucket";
- table[2][0] = getValueString(
- DVW(1.0) * getLongMetric("deletebuckets.count.count", ms)
- / timePeriod, "%'3.2f");
- table[2][1] = getValueString(getLongMetric("deletebuckets.count.count", ms));
- failed = getLongMetric("deletebuckets.failed.count", ms);
- table[2][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("deletebuckets.count.count", ms),
- " (%'3.2f %%)");
- table[2][4] = getValueString(
- getDoubleMetric("deletebuckets.latency.min", ms), "%'3.2f ms");
- table[2][5] = getValueString(
- getDoubleMetric("deletebuckets.latency.average", ms), "%'3.2f ms");
- table[2][6] = getValueString(
- getDoubleMetric("deletebuckets.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Buckets verified";
- table[3][0] = getValueString(
- DVW(1.0) * getLongMetric("bucketverified.count.count", ms)
- / timePeriod, "%'3.2f");
- table[3][1] = getValueString(getLongMetric("bucketverified.count.count", ms));
- failed = getLongMetric("bucketverified.failed.count", ms);
- table[3][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("bucketverified.count.count", ms),
- " (%'3.2f %%)");
- table[3][4] = getValueString(
- getDoubleMetric("bucketverified.latency.min", ms), "%'3.2f ms");
- table[3][5] = getValueString(
- getDoubleMetric("bucketverified.latency.average", ms), "%'3.2f ms");
- table[3][6] = getValueString(
- getDoubleMetric("bucketverified.latency.max", ms), "%'3.2f ms");
- table[3][7] = "Buckets repaired: "
- + getValueString(getLongMetric("bucketfixed.count", ms))
- + getValueString(DVW(100)
- * getLongMetric("bucketfixed.count", ms)
- / getLongMetric("bucketverified.count.count", ms),
- " (%'3.2f %%)");
-
- table.rowNames += "List buckets";
- table[4][0] = getValueString(
- DVW(1.0) * getLongMetric("readbucketlist.count.count", ms)
- / timePeriod, "%'3.2f");
- table[4][1] = getValueString(
- getLongMetric("readbucketlist.count.count", ms));
- failed = getLongMetric("readbucketlist.failed.count", ms);
- table[4][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("readbucketlist.count.count", ms),
- " (%'3.2f %%)");
- table[4][4] = getValueString(
- getDoubleMetric("readbucketlist.latency.min", ms),
- "%'3.2f ms");
- table[4][5] = getValueString(
- getDoubleMetric("readbucketlist.latency.average", ms),
- "%'3.2f ms");
- table[4][6] = getValueString(
- getDoubleMetric("readbucketlist.latency.max", ms),
- "%'3.2f ms");
-
- table.rowNames += "Read bucket info";
- table[5][0] = getValueString(
- DVW(1.0) * getLongMetric("readbucketinfo.count.count", ms)
- / timePeriod, "%'3.2f");
- table[5][1] = getValueString(getLongMetric("readbucketinfo.count.count", ms));
- failed = getLongMetric("readbucketinfo.failed.count", ms);
- table[5][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("readbucketinfo.count.count", ms),
- " (%'3.2f %%)");
- table[5][4] = getValueString(
- getDoubleMetric("readbucketinfo.latency.min", ms),
- "%'3.2f ms");
- table[5][5] = getValueString(
- getDoubleMetric("readbucketinfo.latency.average", ms),
- "%'3.2f ms");
- table[5][6] = getValueString(
- getDoubleMetric("readbucketinfo.latency.max", ms),
- "%'3.2f ms");
-
- table.rowNames += "Bucket move";
- table[6][0] = getValueString(
- DVW(1.0) * getLongMetric("movedbuckets.count.count", ms)
- / timePeriod, "%'3.2f");
- table[6][1] = getValueString(getLongMetric("movedbuckets.count.count", ms));
- failed = getLongMetric("movedbuckets.failed.count", ms);
- table[6][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("movedbuckets.count.count", ms),
- " (%'3.2f %%)");
- table[6][4] = getValueString(
- getDoubleMetric("movedbuckets.latency.min", ms), "%'3.2f ms");
- table[6][5] = getValueString(
- getDoubleMetric("movedbuckets.latency.average", ms), "%'3.2f ms");
- table[6][6] = getValueString(
- getDoubleMetric("movedbuckets.latency.max", ms), "%'3.2f ms");
-
- table.rowNames += "Internal join";
- table[7][0] = getValueString(
- DVW(1.0) * getLongMetric("internaljoin.count.count", ms)
- / timePeriod, "%'3.2f");
- table[7][1] = getValueString(getLongMetric("internaljoin.count.count", ms));
- failed = getLongMetric("internaljoin.failed.count", ms);
- table[7][2] = getValueString(failed) + getValueString(
- DVW(100) * failed / getLongMetric("internaljoin.count.count", ms),
- " (%'3.2f %%)");
- table[7][4] = getValueString(
- getDoubleMetric("internaljoin.latency.min", ms),
- "%'3.2f ms");
- table[7][5] = getValueString(
- getDoubleMetric("internaljoin.latency.average", ms),
- "%'3.2f ms");
- table[7][6] = getValueString(
- getDoubleMetric("internaljoin.latency.max", ms),
- "%'3.2f ms");
-
- table.print(out);
-
-}
-
-void
-StatusMetricConsumer::printMergeHtmlReport(
- std::ostream& out,
- std::map<metrics::Metric::String, metrics::Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const
-{
- using namespace boost::assign;
- using namespace metrics::printutils;
- LVW timePeriod(snapshot.getLength());
-
- MetricSource ms(snapshot, "vds.filestor.alldisks.allthreads", &usedMetrics);
- HttpTable table("Merge frequency and partial latencies", "Type");
- table.colNames += "Ops/s", "Ops", "Failed",
- "Min latency", "Avg latency", "Max latency";
- LongValue failed;
-
- table.rowNames += "Complete merge";
- table[0][0] = getValueString(
- DVW(1.0) * getLongMetric("mergebuckets.count.count", ms)
- / timePeriod, "%'3.2f");
- table[0][1] = getValueString(getLongMetric("mergebuckets.count.count", ms));
- failed = getLongMetric("mergebuckets.count.count", ms)
- - getLongMetric("mergelatencytotal.count", ms);
- table[0][2] = getValueString(failed) + getValueString(
- DVW(100.0) * failed / getLongMetric("mergebuckets.count.count", ms),
- " (%'3.2f %%)");
- table[0][3] = getValueString(
- getDoubleMetric("mergelatencytotal.min", ms), "%'3.2f ms");
- table[0][4] = getValueString(
- getDoubleMetric("mergelatencytotal.average", ms), "%'3.2f ms");
- table[0][5] = getValueString(
- getDoubleMetric("mergelatencytotal.max", ms), "%'3.2f ms");
-
- table.rowNames += "Metadata read";
- LongValue metadataCount = getLongMetric("getbucketdiff.count.count", ms)
- + getLongMetric("mergebuckets.count.count", ms);
- table[1][0] = getValueString(DVW(1.0) * metadataCount
- / timePeriod, "%'3.2f");
- table[1][1] = getValueString(metadataCount);
- failed = metadataCount
- - getLongMetric("mergemetadatareadlatency.count", ms);
- table[1][2] = getValueString(failed) + getValueString(
- DVW(100.0) * failed / metadataCount, " (%'3.2f %%)");
- table[1][3] = getValueString(
- getDoubleMetric("mergemetadatareadlatency.min", ms),
- "%'3.2f ms");
- table[1][4] = getValueString(
- getDoubleMetric("mergemetadatareadlatency.average", ms),
- "%'3.2f ms");
- table[1][5] = getValueString(
- getDoubleMetric("mergemetadatareadlatency.max", ms),
- "%'3.2f ms");
-
- table.rowNames += "Successful data reads";
- table[2][0] = getValueString(
- DVW(1.0) * getLongMetric("mergedatareadlatency.count", ms)
- / timePeriod, "%'3.2f");
- table[2][1] = getValueString(
- getLongMetric("mergedatareadlatency.count", ms));
- table[2][3] = getValueString(
- getDoubleMetric("mergedatareadlatency.min", ms),
- "%'3.2f ms");
- table[2][4] = getValueString(
- getDoubleMetric("mergedatareadlatency.average", ms),
- "%'3.2f ms");
- table[2][5] = getValueString(
- getDoubleMetric("mergedatareadlatency.max", ms),
- "%'3.2f ms");
-
- table.rowNames += "Successful data writes";
- table[3][0] = getValueString(
- DVW(1.0) * getLongMetric("mergedatawritelatency.count", ms)
- / timePeriod, "%'3.2f");
- table[3][1] = getValueString(
- getLongMetric("mergedatawritelatency.count", ms));
- table[3][3] = getValueString(
- getDoubleMetric("mergedatawritelatency.min", ms),
- "%'3.2f ms");
- table[3][4] = getValueString(
- getDoubleMetric("mergedatawritelatency.average", ms),
- "%'3.2f ms");
- table[3][5] = getValueString(
- getDoubleMetric("mergedatawritelatency.max", ms),
- "%'3.2f ms");
-
- HttpTable table2("Other merge properties", "Property");
- table2.colNames += "Per merge value", "Total value";
-
- table2.rowNames += "Bytes merged";
- table2[0][0] = getByteValueString(
- DVW(1.0) * getLongMetric("bytesmerged.count", ms)
- / getLongMetric("mergebuckets.count.count", ms));
- table2[0][1] = getByteValueString(getLongMetric("bytesmerged.count", ms));
-
- table2.rowNames += "Network efficiency";
- table2[1][1] = getValueString(
- DVW(100)
- * getDoubleMetric("mergeavgdatareceivedneeded.average", ms),
- "%'3.2f %%");
-
- table2.rowNames += "Average merges pending";
- table2[2][1] = getValueString(
- getDoubleMetric("../pendingmerge.average", ms), "%'3.2f");
-
- table2.rowNames += "Data transfers";
- table2[3][0] = getValueString(
- DVW(1.0) * getLongMetric("applybucketdiff.count.count", ms)
- / getLongMetric("mergebuckets.count.count", ms), "%'3.2f");
- table2[3][1] = getValueString(
- getLongMetric("applybucketdiff.count.count", ms));
-
- table2.rowNames += "Merge master percentage";
- table2[4][1] = getValueString(
- DVW(100) * getLongMetric("mergebuckets.count.count", ms)
- / (getLongMetric("getbucketdiff.count.count", ms)
- + getLongMetric("mergebuckets.count.count", ms)), "%'3.2f %%");
-
- out << "<table cellpadding=\"0\" cellspacing=\"0\">\n"
- << "<td valign=\"top\" width=\"60%\">\n";
- table.print(out);
- out << "<p><font size=\"-1\"><div align=\"left\">\n"
- << "Complete merge lists amount of merges this node has been master of. Metadata read shows how many merges this node has taken part of in total. By looking at the data reads and writes one can see how many of these are done per merge if one compares it to the amount of metadata reads.\n"
- << "</div></font></p>\n";
- out << "</td><td width=\"1%\">&nbsp;&nbsp;</td>\n"
- << "<td valign=\"top\" width=\"39%\">\n";
- table2.print(out);
- out << "<p><font size=\"-1\"><div align=\"left\">\n"
- << "Bytes merged sets how many bytes have been merged into this node. The network efficiency states how big percent the byte merged was of the total data received during the merge. (A low efficiency indicates that data being merged between two nodes are routed through this node, which doesn't need it). Pending merges are the number of merges this node is master for that is currently being processed. Lastly, a percentage is shown, giving how many of total merges gone through this node the node has actually been master of.\n"
- << "</div></font></p>\n";
- out << "</td></table>\n";
-}
-
-void
-StatusMetricConsumer::printVisitHtmlReport(
- std::ostream& out,
- std::map<metrics::Metric::String, metrics::Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const
-{
- using namespace boost::assign;
- using namespace metrics::printutils;
-
- LVW timePeriod(snapshot.getLength());
-
- MetricSource ms(snapshot, "vds.visitor.allthreads", &usedMetrics);
- HttpTable table("Visiting", "Type");
- table.colNames += "Value", "Percentage";
- std::string persPrefix = "../../filestor.alldisks.allthreads.";
- std::string diskPrefix = "../../filestor.alldisks.";
- LongValue completedVisitors = getLongMetric("completed.sum.count", ms);
- LongValue failedVisitors = getLongMetric("failed.sum.count", ms);
- LongValue abortedVisitors = getLongMetric("aborted.sum.count", ms);
- LongValue totalVisitors = completedVisitors + failedVisitors
- + abortedVisitors;
- DoubleValue bucketsPerVisitor(
- DVW(1) * getLongMetric(persPrefix + "visit.sum.count.count", ms)
- / completedVisitors);
- LongValue totalTime = getLongMetric("averagevisitorlifetime.sum.average", ms);
-
- table.rowNames += "Pending visitors";
- table[0][0] = getValueString(
- getLongMetric("created.sum.count", ms) - completedVisitors);
-
- table.rowNames += "Completed visitors";
- table[1][0] = getValueString(completedVisitors);
- table[1][1] = getValueString(
- DVW(100.0) * completedVisitors / totalVisitors, "%'3.2f %%");
-
- table.rowNames += "Failed visitors";
- table[2][0] = getValueString(failedVisitors);
- table[2][1] = getValueString(
- DVW(100.0) * failedVisitors / totalVisitors, "%'3.2f %%");
-
- table.rowNames += "Aborted visitors";
- table[3][0] = getValueString(abortedVisitors);
- table[3][1] = getValueString(
- DVW(100.0) * abortedVisitors / totalVisitors, "%'3.2f %%");
-
- table.rowNames += "Buckets visited per visitor";
- table[4][0] = getValueString(bucketsPerVisitor, "%'3.2f");
-
- table.rowNames += "Average size of visitor manager queue (min/average/max)";
- table[5][0] = getValueString(getLongMetric("queuesize.min", ms),
- "%'llu")
- + getValueString(getLongMetric("queuesize.average", ms),
- " / %'llu")
- + getValueString(getLongMetric("queuesize.max", ms),
- " / %'llu");
-
- table.rowNames += "Total latency of completed visitors (min/average/max)";
- table[6][0] = getValueString(getLongMetric(
- + "averagevisitorlifetime.sum.min", ms), "%'llu ms")
- + getValueString(getLongMetric(
- "averagevisitorlifetime.sum.average", ms), " / %'llu ms")
- + getValueString(getLongMetric(
- "averagevisitorlifetime.sum.max", ms), " / %'llu ms");
- table[6][1] = getValueString(DVW(100), "%'3.2f %%");
-
-
- table.rowNames += "Time spent in visitor manager queue (min/average/max)";
- LongValue queueWait = getLongMetric("averagequeuewait.sum.average", ms);
- table[7][0] = getValueString(getLongMetric("averagequeuewait.sum.min", ms))
- + getValueString(queueWait, " ms / %'llu ms / ")
- + getValueString(
- getLongMetric("averagequeuewait.sum.max", ms), "%'llu ms");
- table[7][1] = getValueString(DVW(100) * queueWait / totalTime, "%'3.2f %%");
-
- table.rowNames += "Time spent processing in visitor thread";
- LongValue cpuTime = getLongMetric("averageprocessingtime.sum.average", ms);
- table[8][0] = getValueString(cpuTime, "%" PRId64 " ms");
- table[8][1] = getValueString(DVW(100) * cpuTime / totalTime, "%'3.2f %%");
-
- table.print(out);
-
- out << "<p><font size=\"-1\"><div align=\"left\">\n"
- << "Note that the buckets and blocks per visitor values assume that there are no aborted visitors. If there is a considerable amount of aborted visitors that has done persistence requests, these calculated numbers will be too large. Average time spent per visitor waiting in peristence layer, reading metadata or data, and the time used processing in visitor threads are also calculated values. If visiting consistently happens while cluster does not have average load, these values may also be a bit off.\n"
- << "</div></font></p>\n";
+ return true;
}
} // storage
diff --git a/storage/src/vespa/storage/common/statusmetricconsumer.h b/storage/src/vespa/storage/common/statusmetricconsumer.h
index ed8fee4fad6..8d38c72d162 100644
--- a/storage/src/vespa/storage/common/statusmetricconsumer.h
+++ b/storage/src/vespa/storage/common/statusmetricconsumer.h
@@ -13,12 +13,11 @@
#include <vespa/storageframework/generic/status/statusreporter.h>
#include <vespa/storageframework/generic/metric/metricupdatehook.h>
#include <vespa/vespalib/util/document_runnable.h>
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricmanager.h>
#include <map>
-namespace vespalib {
- class StringTokenizer;
-}
+namespace vespalib { class StringTokenizer; }
+namespace metrics { class MetricManager; }
namespace storage {
@@ -39,40 +38,12 @@ public:
bool reportStatus(std::ostream& out, const framework::HttpUrlPath&) const override;
void updateMetrics(const MetricLockGuard & guard) override;
private:
- typedef metrics::Metric Metric;
- typedef metrics::Metric::String String;
-
metrics::MetricManager& _manager;
StorageComponent _component;
std::string _name;
mutable std::mutex _lock;
framework::SecondTime _startTime;
framework::SecondTime _processedTime;
-
- void writeXmlTags(std::ostream& out,
- const vespalib::StringTokenizer& name,
- std::vector<std::string>& xmlTags) const;
-
- void printHtmlMetricsReport(std::ostream& out,
- const metrics::MetricSnapshot& data,
- bool includeNotUsed) const;
-
- void printStorageHtmlReport(std::ostream& out,
- std::map<String, Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot&) const;
- void printOperationHtmlReport(std::ostream& out,
- std::map<String, Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot&) const;
- void printMaintOpHtmlReport(std::ostream& out,
- std::map<String, Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot&) const;
- void printMergeHtmlReport(std::ostream& out,
- std::map<String, Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot& snapshot) const;
- void printVisitHtmlReport(std::ostream& out,
- std::map<String, Metric::SP>& usedMetrics,
- const metrics::MetricSnapshot&) const;
-
};
} // storage
diff --git a/storage/src/vespa/storage/common/storagecomponent.cpp b/storage/src/vespa/storage/common/storagecomponent.cpp
index c5194f909c0..b0ccacf487b 100644
--- a/storage/src/vespa/storage/common/storagecomponent.cpp
+++ b/storage/src/vespa/storage/common/storagecomponent.cpp
@@ -1,11 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "storagecomponent.h"
-#include <vespa/storage/storageserver/prioritymapper.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vdslib/distribution/distribution.h>
#include <vespa/document/fieldset/fieldsetrepo.h>
+#include <cassert>
namespace storage {
@@ -25,7 +25,8 @@ StorageComponent::setNodeInfo(vespalib::stringref clusterName,
uint16_t index)
{
// Assumed to not be set dynamically.
- _clusterName = clusterName;
+ assert(_cluster_ctx.my_cluster_name.empty());
+ _cluster_ctx.my_cluster_name = clusterName;
_nodeType = &nodeType;
_index = index;
}
@@ -40,22 +41,6 @@ StorageComponent::setDocumentTypeRepo(std::shared_ptr<const document::DocumentTy
}
void
-StorageComponent::setLoadTypes(LoadTypeSetSP loadTypes)
-{
- std::lock_guard guard(_lock);
- _loadTypes = loadTypes;
- _generation++;
-}
-
-
-void
-StorageComponent::setPriorityConfig(const PriorityConfig& c)
-{
- // Priority mapper is already thread safe.
- _priorityMapper->setConfig(c);
-}
-
-void
StorageComponent::setBucketIdFactory(const document::BucketIdFactory& factory)
{
// Assumed to not be set dynamically.
@@ -84,12 +69,10 @@ StorageComponent::setNodeStateUpdater(NodeStateUpdater& updater)
StorageComponent::StorageComponent(StorageComponentRegister& compReg,
vespalib::stringref name)
: Component(compReg, name),
- _clusterName(),
+ _cluster_ctx(),
_nodeType(nullptr),
_index(0),
_repos(),
- _loadTypes(),
- _priorityMapper(new PriorityMapper),
_bucketIdFactory(),
_distribution(),
_nodeStateUpdater(nullptr),
@@ -115,17 +98,11 @@ vespalib::string
StorageComponent::getIdentity() const
{
vespalib::asciistream name;
- name << "storage/cluster." << _clusterName << "/"
+ name << "storage/cluster." << _cluster_ctx.cluster_name() << "/"
<< _nodeType->serialize() << "/" << _index;
return name.str();
}
-uint8_t
-StorageComponent::getPriority(const documentapi::LoadType& lt) const
-{
- return _priorityMapper->getPriority(lt);
-}
-
std::shared_ptr<StorageComponent::Repos>
StorageComponent::getTypeRepo() const
{
@@ -133,13 +110,6 @@ StorageComponent::getTypeRepo() const
return _repos;
}
-StorageComponent::LoadTypeSetSP
-StorageComponent::getLoadTypes() const
-{
- std::lock_guard guard(_lock);
- return _loadTypes;
-}
-
StorageComponent::DistributionSP
StorageComponent::getDistribution() const
{
diff --git a/storage/src/vespa/storage/common/storagecomponent.h b/storage/src/vespa/storage/common/storagecomponent.h
index b33501e9dd1..4fda62929e7 100644
--- a/storage/src/vespa/storage/common/storagecomponent.h
+++ b/storage/src/vespa/storage/common/storagecomponent.h
@@ -31,33 +31,28 @@
#pragma once
+#include "cluster_context.h"
#include <vespa/storageframework/generic/component/component.h>
#include <vespa/storageframework/generic/component/componentregister.h>
#include <vespa/document/bucket/bucketidfactory.h>
#include <vespa/vdslib/state/node.h>
#include <mutex>
-namespace vespa::config::content::core::internal {
- class InternalStorPrioritymappingType;
-}
namespace document {
class DocumentTypeRepo;
class FieldSetRepo;
}
-namespace documentapi {
- class LoadType;
- class LoadTypeSet;
-}
namespace storage {
+
namespace lib {
class Distribution;
}
struct NodeStateUpdater;
-class PriorityMapper;
struct StorageComponentRegister;
-class StorageComponent : public framework::Component {
+class StorageComponent : public framework::Component
+{
public:
struct Repos {
explicit Repos(std::shared_ptr<const document::DocumentTypeRepo> repo);
@@ -66,8 +61,6 @@ public:
const std::shared_ptr<const document::FieldSetRepo> fieldSetRepo;
};
using UP = std::unique_ptr<StorageComponent>;
- using PriorityConfig = vespa::config::content::core::internal::InternalStorPrioritymappingType;
- using LoadTypeSetSP = std::shared_ptr<documentapi::LoadTypeSet>;
using DistributionSP = std::shared_ptr<lib::Distribution>;
/**
@@ -83,15 +76,13 @@ public:
*/
void setNodeStateUpdater(NodeStateUpdater& updater);
void setDocumentTypeRepo(std::shared_ptr<const document::DocumentTypeRepo>);
- void setLoadTypes(LoadTypeSetSP);
- void setPriorityConfig(const PriorityConfig&);
void setBucketIdFactory(const document::BucketIdFactory&);
void setDistribution(DistributionSP);
StorageComponent(StorageComponentRegister&, vespalib::stringref name);
~StorageComponent() override;
- const vespalib::string & getClusterName() const { return _clusterName; }
+ const ClusterContext & cluster_context() const noexcept { return _cluster_ctx; }
const lib::NodeType& getNodeType() const { return *_nodeType; }
uint16_t getIndex() const { return _index; }
lib::Node getNode() const { return lib::Node(*_nodeType, _index); }
@@ -99,20 +90,16 @@ public:
vespalib::string getIdentity() const;
std::shared_ptr<Repos> getTypeRepo() const;
- LoadTypeSetSP getLoadTypes() const;
const document::BucketIdFactory& getBucketIdFactory() const { return _bucketIdFactory; }
- uint8_t getPriority(const documentapi::LoadType&) const;
DistributionSP getDistribution() const;
NodeStateUpdater& getStateUpdater() const;
uint64_t getGeneration() const { return _generation.load(std::memory_order_relaxed); }
private:
- vespalib::string _clusterName;
+ SimpleClusterContext _cluster_ctx;
const lib::NodeType* _nodeType;
uint16_t _index;
std::shared_ptr<Repos> _repos;
- // TODO: move loadTypes and _distribution in to _repos so lock will only taken once and only copying one shared_ptr.
- LoadTypeSetSP _loadTypes;
- std::unique_ptr<PriorityMapper> _priorityMapper;
+ // TODO: move _distribution in to _repos so lock will only taken once and only copying one shared_ptr.
document::BucketIdFactory _bucketIdFactory;
DistributionSP _distribution;
NodeStateUpdater* _nodeStateUpdater;
diff --git a/storage/src/vespa/storage/config/distributorconfiguration.cpp b/storage/src/vespa/storage/config/distributorconfiguration.cpp
index cc04f1d554c..a87977bec11 100644
--- a/storage/src/vespa/storage/config/distributorconfiguration.cpp
+++ b/storage/src/vespa/storage/config/distributorconfiguration.cpp
@@ -46,6 +46,7 @@ DistributorConfiguration::DistributorConfiguration(StorageComponent& component)
_use_weak_internal_read_consistency_for_client_gets(false),
_enable_metadata_only_fetch_phase_for_inconsistent_updates(false),
_prioritize_global_bucket_merges(true),
+ _enable_revert(true),
_minimumReplicaCountingMode(ReplicaCountingMode::TRUSTED)
{
}
@@ -164,6 +165,7 @@ DistributorConfiguration::configure(const vespa::config::content::core::StorDist
_use_weak_internal_read_consistency_for_client_gets = config.useWeakInternalReadConsistencyForClientGets;
_enable_metadata_only_fetch_phase_for_inconsistent_updates = config.enableMetadataOnlyFetchPhaseForInconsistentUpdates;
_prioritize_global_bucket_merges = config.prioritizeGlobalBucketMerges;
+ _enable_revert = config.enableRevert;
_minimumReplicaCountingMode = config.minimumReplicaCountingMode;
diff --git a/storage/src/vespa/storage/config/distributorconfiguration.h b/storage/src/vespa/storage/config/distributorconfiguration.h
index 41a30165f49..5ff1a8b3503 100644
--- a/storage/src/vespa/storage/config/distributorconfiguration.h
+++ b/storage/src/vespa/storage/config/distributorconfiguration.h
@@ -253,6 +253,9 @@ public:
bool prioritize_global_bucket_merges() const noexcept {
return _prioritize_global_bucket_merges;
}
+ bool enable_revert() const noexcept {
+ return _enable_revert;
+ }
bool containsTimeStatement(const std::string& documentSelection) const;
@@ -303,9 +306,10 @@ private:
bool _use_weak_internal_read_consistency_for_client_gets;
bool _enable_metadata_only_fetch_phase_for_inconsistent_updates;
bool _prioritize_global_bucket_merges;
+ bool _enable_revert;
DistrConfig::MinimumReplicaCountingMode _minimumReplicaCountingMode;
-
+
friend struct distributor::DistributorTest;
void configureMaintenancePriorities(
const vespa::config::content::core::StorDistributormanagerConfig&);
diff --git a/storage/src/vespa/storage/config/stor-communicationmanager.def b/storage/src/vespa/storage/config/stor-communicationmanager.def
index e075f57514b..d674ee96aa3 100644
--- a/storage/src/vespa/storage/config/stor-communicationmanager.def
+++ b/storage/src/vespa/storage/config/stor-communicationmanager.def
@@ -18,39 +18,39 @@ mbus_distributor_node_max_pending_size int default=0
mbus_content_node_max_pending_size int default=0
# Minimum size of packets to compress (0 means no compression)
-mbus.compress.limit int default=1024
+mbus.compress.limit int default=1024 restart
## Compression level for packets
-mbus.compress.level int default=3
+mbus.compress.level int default=3 restart
## Compression type for packets.
-mbus.compress.type enum {NONE, LZ4, ZSTD} default=LZ4
+mbus.compress.type enum {NONE, LZ4, ZSTD} default=LZ4 restart
## TTL for rpc target cache
-mbus.rpctargetcache.ttl double default = 600
+mbus.rpctargetcache.ttl double default = 600 restart
## Number of threads for mbus threadpool
## Any value below 1 will be 1.
-mbus.num_threads int default=4
+mbus.num_threads int default=4 restart
mbus.optimize_for enum {LATENCY, THROUGHPUT, ADAPTIVE} default = LATENCY
## Enable to use above thread pool for encoding replies
## False will use network(fnet) thread
-mbus.dispatch_on_encode bool default=true
+mbus.dispatch_on_encode bool default=true restart
## Enable to use above thread pool for decoding replies
## False will use network(fnet) thread
## Todo: Change default once verified in large scale deployment.
-mbus.dispatch_on_decode bool default=false
+mbus.dispatch_on_decode bool default=false restart
## Skip messenger thread on reply
## Experimental
-mbus.skip_reply_thread bool default=false
+mbus.skip_reply_thread bool default=false restart
## Skip messenger thread on reply
## Experimental
-mbus.skip_request_thread bool default=false
+mbus.skip_request_thread bool default=false restart
## Skip communication manager thread on mbus requests
## Experimental
@@ -61,7 +61,10 @@ skip_thread bool default=false
use_direct_storageapi_rpc bool default=false
## The number of network (FNET) threads used by the shared rpc resource.
-rpc.num_network_threads int default=2
+rpc.num_network_threads int default=2 restart
+
+## The number of events in the queue of a network (FNET) thread before it is woken up.
+rpc.events_before_wakeup int default=1 restart
## The number of (FNET) RPC targets to use per node in the cluster.
##
@@ -70,13 +73,13 @@ rpc.num_network_threads int default=2
## and the RPC target itself handles sequencing of these messages.
## NB !! It is vital that this number is kept in sync with stor-filestor:num_network_threads.
## Only skilled vespa core developers should touch this.
-rpc.num_targets_per_node int default=1
+rpc.num_targets_per_node int default=1 restart
# Minimum size of packets to compress (0 means no compression)
-rpc.compress.limit int default=1024
+rpc.compress.limit int default=1024 restart
## Compression level for packets
-rpc.compress.level int default=3
+rpc.compress.level int default=3 restart
## Compression type for packets.
-rpc.compress.type enum {NONE, LZ4, ZSTD} default=LZ4
+rpc.compress.type enum {NONE, LZ4, ZSTD} default=LZ4 restart
diff --git a/storage/src/vespa/storage/config/stor-server.def b/storage/src/vespa/storage/config/stor-server.def
index 54160bc53fe..a00f7b4feb5 100644
--- a/storage/src/vespa/storage/config/stor-server.def
+++ b/storage/src/vespa/storage/config/stor-server.def
@@ -95,5 +95,5 @@ use_content_node_btree_bucket_db bool default=true restart
## WARNING:
## Setting this to a non-zero value requires the minimum split bit level in the cluster
## to be enforced, so only set this value if you know exactly what you're doing!
-content_node_bucket_db_stripe_bits int default=0
+content_node_bucket_db_stripe_bits int default=0 restart
diff --git a/storage/src/vespa/storage/distributor/CMakeLists.txt b/storage/src/vespa/storage/distributor/CMakeLists.txt
index 7fc13046b3f..f3ba6af6e0c 100644
--- a/storage/src/vespa/storage/distributor/CMakeLists.txt
+++ b/storage/src/vespa/storage/distributor/CMakeLists.txt
@@ -9,6 +9,7 @@ vespa_add_library(storage_distributor
bucketlistmerger.cpp
bucket_space_distribution_context.cpp
clusterinformation.cpp
+ crypto_uuid_generator.cpp
distributor_bucket_space.cpp
distributor_bucket_space_repo.cpp
distributor.cpp
@@ -19,6 +20,7 @@ vespa_add_library(storage_distributor
externaloperationhandler.cpp
idealstatemanager.cpp
idealstatemetricsset.cpp
+ ideal_service_layer_nodes_bundle.cpp
messagetracker.cpp
nodeinfo.cpp
operation_routing_snapshot.cpp
diff --git a/storage/src/vespa/storage/distributor/blockingoperationstarter.cpp b/storage/src/vespa/storage/distributor/blockingoperationstarter.cpp
index 0e4bc511b26..25c38888098 100644
--- a/storage/src/vespa/storage/distributor/blockingoperationstarter.cpp
+++ b/storage/src/vespa/storage/distributor/blockingoperationstarter.cpp
@@ -7,7 +7,7 @@ namespace storage::distributor {
bool
BlockingOperationStarter::start(const std::shared_ptr<Operation>& operation, Priority priority)
{
- if (operation->isBlocked(_messageTracker)) {
+ if (operation->isBlocked(_messageTracker, _operation_sequencer)) {
return true;
}
return _starterImpl.start(operation, priority);
diff --git a/storage/src/vespa/storage/distributor/blockingoperationstarter.h b/storage/src/vespa/storage/distributor/blockingoperationstarter.h
index a64a8f5b6bb..e79ae6b4a79 100644
--- a/storage/src/vespa/storage/distributor/blockingoperationstarter.h
+++ b/storage/src/vespa/storage/distributor/blockingoperationstarter.h
@@ -7,13 +7,16 @@
namespace storage::distributor {
class PendingMessageTracker;
+class OperationSequencer;
class BlockingOperationStarter : public OperationStarter
{
public:
BlockingOperationStarter(PendingMessageTracker& messageTracker,
+ OperationSequencer& operation_sequencer,
OperationStarter& starterImpl)
: _messageTracker(messageTracker),
+ _operation_sequencer(operation_sequencer),
_starterImpl(starterImpl)
{}
BlockingOperationStarter(const BlockingOperationStarter&) = delete;
@@ -22,7 +25,8 @@ public:
bool start(const std::shared_ptr<Operation>& operation, Priority priority) override;
private:
PendingMessageTracker& _messageTracker;
- OperationStarter& _starterImpl;
+ OperationSequencer& _operation_sequencer;
+ OperationStarter& _starterImpl;
};
}
diff --git a/storage/src/vespa/storage/distributor/bucket_ownership_flags.h b/storage/src/vespa/storage/distributor/bucket_ownership_flags.h
new file mode 100644
index 00000000000..c9003552f12
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/bucket_ownership_flags.h
@@ -0,0 +1,29 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+namespace storage::distributor {
+
+/*
+ * Compact bucket ownership representation. Default value is not owned
+ * by current state or pending state. Bucket is always considered
+ * owned in pending state if there is no pending state.
+ */
+class BucketOwnershipFlags {
+ uint8_t _flags;
+
+ static constexpr uint8_t owned_in_current_state_flag = 0x1;
+ static constexpr uint8_t owned_in_pending_state_flag = 0x2;
+
+public:
+ BucketOwnershipFlags() noexcept
+ : _flags(0)
+ {
+ }
+
+ bool owned_in_current_state() const noexcept { return ((_flags & owned_in_current_state_flag) != 0); }
+ bool owned_in_pending_state() const noexcept { return ((_flags & owned_in_pending_state_flag) != 0); }
+ void set_owned_in_current_state() noexcept { _flags |= owned_in_current_state_flag; }
+ void set_owned_in_pending_state() noexcept { _flags |= owned_in_pending_state_flag; }
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/bucket_space_distribution_context.cpp b/storage/src/vespa/storage/distributor/bucket_space_distribution_context.cpp
index 53040bc42b1..c6def05ef25 100644
--- a/storage/src/vespa/storage/distributor/bucket_space_distribution_context.cpp
+++ b/storage/src/vespa/storage/distributor/bucket_space_distribution_context.cpp
@@ -10,7 +10,7 @@ BucketSpaceDistributionContext::BucketSpaceDistributionContext(
std::shared_ptr<const lib::ClusterState> default_active_cluster_state,
std::shared_ptr<const lib::ClusterState> pending_cluster_state,
std::shared_ptr<const lib::Distribution> distribution,
- uint16_t this_node_index)
+ uint16_t this_node_index) noexcept
: _active_cluster_state(std::move(active_cluster_state)),
_default_active_cluster_state(std::move(default_active_cluster_state)),
_pending_cluster_state(std::move(pending_cluster_state)),
diff --git a/storage/src/vespa/storage/distributor/bucket_space_distribution_context.h b/storage/src/vespa/storage/distributor/bucket_space_distribution_context.h
index 7a9c0fcae60..662a1b1daac 100644
--- a/storage/src/vespa/storage/distributor/bucket_space_distribution_context.h
+++ b/storage/src/vespa/storage/distributor/bucket_space_distribution_context.h
@@ -29,7 +29,7 @@ public:
std::shared_ptr<const lib::ClusterState> default_active_cluster_state,
std::shared_ptr<const lib::ClusterState> pending_cluster_state,
std::shared_ptr<const lib::Distribution> distribution,
- uint16_t this_node_index);
+ uint16_t this_node_index) noexcept;
~BucketSpaceDistributionContext();
static std::shared_ptr<BucketSpaceDistributionContext> make_state_transition(
diff --git a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp
index c5fd7027fa6..a8c4e7c3544 100644
--- a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp
+++ b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp
@@ -8,7 +8,6 @@
#include "distributormetricsset.h"
#include "simpleclusterinformation.h"
#include <vespa/document/bucket/fixed_bucket_spaces.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageapi/message/removelocation.h>
#include <vespa/vespalib/util/xmlstream.h>
@@ -103,18 +102,6 @@ BucketDBUpdater::hasPendingClusterState() const
return static_cast<bool>(_pendingClusterState);
}
-BucketOwnership
-BucketDBUpdater::checkOwnershipInPendingState(const document::Bucket& b) const
-{
- if (hasPendingClusterState()) {
- const auto& state(*_pendingClusterState->getNewClusterStateBundle().getDerivedClusterState(b.getBucketSpace()));
- if (!_distributorComponent.ownsBucketInState(state, b)) {
- return BucketOwnership::createNotOwnedInState(state);
- }
- }
- return BucketOwnership::createOwned();
-}
-
const lib::ClusterState*
BucketDBUpdater::pendingClusterStateOrNull(const document::BucketSpace& space) const {
return (hasPendingClusterState()
@@ -317,6 +304,7 @@ BucketDBUpdater::storageDistributionChanged()
_distributorComponent.getBucketSpaceRepo(),
_distributorComponent.getUniqueTimestamp());
_outdatedNodesMap = _pendingClusterState->getOutdatedNodesMap();
+ _distributorComponent.getBucketSpaceRepo().set_pending_cluster_state_bundle(_pendingClusterState->getNewClusterStateBundle());
}
void
@@ -435,6 +423,7 @@ BucketDBUpdater::onSetSystemState(
_distributorComponent.getDistributor().getMetrics().set_cluster_state_processing_time.addValue(
process_timer.getElapsedTimeAsDouble());
+ _distributorComponent.getBucketSpaceRepo().set_pending_cluster_state_bundle(_pendingClusterState->getNewClusterStateBundle());
if (isPendingClusterStateCompleted()) {
processCompletedPendingClusterState();
}
@@ -782,6 +771,7 @@ BucketDBUpdater::activatePendingClusterState()
update_read_snapshot_after_activation(_pendingClusterState->getNewClusterStateBundle());
_pendingClusterState.reset();
_outdatedNodesMap.clear();
+ _distributorComponent.getBucketSpaceRepo().clear_pending_cluster_state_bundle();
sendAllQueuedBucketRechecks();
completeTransitionTimer();
clearReadOnlyBucketRepoDatabases();
diff --git a/storage/src/vespa/storage/distributor/bucketdbupdater.h b/storage/src/vespa/storage/distributor/bucketdbupdater.h
index 7f2a9b30a33..86bca224229 100644
--- a/storage/src/vespa/storage/distributor/bucketdbupdater.h
+++ b/storage/src/vespa/storage/distributor/bucketdbupdater.h
@@ -43,9 +43,6 @@ public:
~BucketDBUpdater() override;
void flush();
- // If there is a pending state, returns ownership state of bucket in it.
- // Otherwise always returns "is owned", i.e. it must also be checked in the current state.
- BucketOwnership checkOwnershipInPendingState(const document::Bucket&) const;
const lib::ClusterState* pendingClusterStateOrNull(const document::BucketSpace&) const;
void recheckBucketInfo(uint32_t nodeIdx, const document::Bucket& bucket);
diff --git a/storage/src/vespa/storage/distributor/bucketownership.h b/storage/src/vespa/storage/distributor/bucketownership.h
index bfe63c9799d..c22f690a830 100644
--- a/storage/src/vespa/storage/distributor/bucketownership.h
+++ b/storage/src/vespa/storage/distributor/bucketownership.h
@@ -16,9 +16,9 @@ class BucketOwnership
_owned(false)
{ }
+public:
BucketOwnership() : _checkedState(nullptr), _owned(true) {}
-public:
bool isOwned() const { return _owned; }
/**
* Cluster state in which the ownership check failed. Lifetime of returned
diff --git a/storage/src/vespa/storage/distributor/crypto_uuid_generator.cpp b/storage/src/vespa/storage/distributor/crypto_uuid_generator.cpp
new file mode 100644
index 00000000000..3f9ab0b529d
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/crypto_uuid_generator.cpp
@@ -0,0 +1,20 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "crypto_uuid_generator.h"
+#include <vespa/vespalib/crypto/random.h>
+
+namespace storage::distributor {
+
+vespalib::string CryptoUuidGenerator::generate_uuid() const {
+ unsigned char rand_buf[16];
+ vespalib::crypto::random_buffer(rand_buf, sizeof(rand_buf));
+ const char hex[16+1] = "0123456789abcdef";
+ vespalib::string ret(sizeof(rand_buf) * 2, '\0');
+ for (size_t i = 0; i < sizeof(rand_buf); ++i) {
+ ret[i*2 + 0] = hex[rand_buf[i] >> 4];
+ ret[i*2 + 1] = hex[rand_buf[i] & 0x0f];
+ }
+ return ret;
+}
+
+}
diff --git a/storage/src/vespa/storage/distributor/crypto_uuid_generator.h b/storage/src/vespa/storage/distributor/crypto_uuid_generator.h
new file mode 100644
index 00000000000..40d2bd732b7
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/crypto_uuid_generator.h
@@ -0,0 +1,18 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include "uuid_generator.h"
+
+namespace storage::distributor {
+
+/**
+ * Generates a 128-bit unique identifier (represented as a hex string) from
+ * a cryptographically strong source of pseudo-randomness.
+ */
+class CryptoUuidGenerator : public UuidGenerator {
+public:
+ ~CryptoUuidGenerator() override = default;
+ vespalib::string generate_uuid() const override;
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/distributor.cpp b/storage/src/vespa/storage/distributor/distributor.cpp
index e4563ec56ce..e93bb00b564 100644
--- a/storage/src/vespa/storage/distributor/distributor.cpp
+++ b/storage/src/vespa/storage/distributor/distributor.cpp
@@ -1,18 +1,20 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
//
-#include "distributor.h"
#include "blockingoperationstarter.h"
-#include "throttlingoperationstarter.h"
-#include "idealstatemetricsset.h"
-#include "ownership_transfer_safe_time_point_calculator.h"
+#include "distributor.h"
#include "distributor_bucket_space.h"
#include "distributormetricsset.h"
-#include <vespa/storage/distributor/maintenance/simplebucketprioritydatabase.h>
-#include <vespa/storage/common/nodestateupdater.h>
-#include <vespa/storage/common/hostreporter/hostinfo.h>
+#include "idealstatemetricsset.h"
+#include "operation_sequencer.h"
+#include "ownership_transfer_safe_time_point_calculator.h"
+#include "throttlingoperationstarter.h"
+#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/storage/common/global_bucket_space_distribution_converter.h>
+#include <vespa/storage/common/hostreporter/hostinfo.h>
+#include <vespa/storage/common/node_identity.h>
+#include <vespa/storage/common/nodestateupdater.h>
+#include <vespa/storage/distributor/maintenance/simplebucketprioritydatabase.h>
#include <vespa/storageframework/generic/status/xmlstatusreporter.h>
-#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/vespalib/util/memoryusage.h>
#include <vespa/log/log.h>
@@ -62,6 +64,7 @@ public:
};
Distributor::Distributor(DistributorComponentRegister& compReg,
+ const NodeIdentity& node_identity,
framework::TickingThreadPool& threadPool,
DoneInitializeHandler& doneInitHandler,
bool manageActiveBucketCopies,
@@ -71,34 +74,36 @@ Distributor::Distributor(DistributorComponentRegister& compReg,
DistributorInterface(),
framework::StatusReporter("distributor", "Distributor"),
_clusterStateBundle(lib::ClusterState()),
- _compReg(compReg),
- _component(compReg, "distributor"),
- _bucketSpaceRepo(std::make_unique<DistributorBucketSpaceRepo>()),
- _readOnlyBucketSpaceRepo(std::make_unique<DistributorBucketSpaceRepo>()),
- _metrics(new DistributorMetricSet(_component.getLoadTypes()->getMetricLoadTypes())),
+ _bucketSpaceRepo(std::make_unique<DistributorBucketSpaceRepo>(node_identity.node_index())),
+ _readOnlyBucketSpaceRepo(std::make_unique<DistributorBucketSpaceRepo>(node_identity.node_index())),
+ _component(*this, *_bucketSpaceRepo, *_readOnlyBucketSpaceRepo, compReg, "distributor"),
+ _metrics(std::make_shared<DistributorMetricSet>()),
_operationOwner(*this, _component.getClock()),
_maintenanceOperationOwner(*this, _component.getClock()),
+ _operation_sequencer(std::make_unique<OperationSequencer>()),
_pendingMessageTracker(compReg),
_bucketDBUpdater(*this, *_bucketSpaceRepo, *_readOnlyBucketSpaceRepo, *this, compReg),
_distributorStatusDelegate(compReg, *this, *this),
_bucketDBStatusDelegate(compReg, *this, _bucketDBUpdater),
_idealStateManager(*this, *_bucketSpaceRepo, *_readOnlyBucketSpaceRepo, compReg, manageActiveBucketCopies),
- _externalOperationHandler(*this, *_bucketSpaceRepo, *_readOnlyBucketSpaceRepo, _idealStateManager, compReg),
+ _messageSender(messageSender),
+ _externalOperationHandler(_component, _component, getMetrics(), getMessageSender(),
+ *_operation_sequencer, *this, _component,
+ _idealStateManager, _operationOwner),
_threadPool(threadPool),
_initializingIsUp(true),
_doneInitializeHandler(doneInitHandler),
_doneInitializing(false),
- _messageSender(messageSender),
- _bucketPriorityDb(new SimpleBucketPriorityDatabase()),
- _scanner(new SimpleMaintenanceScanner(*_bucketPriorityDb, _idealStateManager, *_bucketSpaceRepo)),
- _throttlingStarter(new ThrottlingOperationStarter(_maintenanceOperationOwner)),
- _blockingStarter(new BlockingOperationStarter(_pendingMessageTracker, *_throttlingStarter)),
- _scheduler(new MaintenanceScheduler(_idealStateManager, *_bucketPriorityDb, *_blockingStarter)),
+ _bucketPriorityDb(std::make_unique<SimpleBucketPriorityDatabase>()),
+ _scanner(std::make_unique<SimpleMaintenanceScanner>(*_bucketPriorityDb, _idealStateManager, *_bucketSpaceRepo)),
+ _throttlingStarter(std::make_unique<ThrottlingOperationStarter>(_maintenanceOperationOwner)),
+ _blockingStarter(std::make_unique<BlockingOperationStarter>(_pendingMessageTracker, *_operation_sequencer,
+ *_throttlingStarter)),
+ _scheduler(std::make_unique<MaintenanceScheduler>(_idealStateManager, *_bucketPriorityDb, *_blockingStarter)),
_schedulingMode(MaintenanceScheduler::NORMAL_SCHEDULING_MODE),
_recoveryTimeStarted(_component.getClock()),
_tickResult(framework::ThreadWaitInfo::NO_MORE_CRITICAL_WORK_KNOWN),
- _clusterName(_component.getClusterName()),
- _bucketIdHasher(new BucketGcTimeCalculator::BucketIdIdentityHasher()),
+ _bucketIdHasher(std::make_unique<BucketGcTimeCalculator::BucketIdIdentityHasher>()),
_metricUpdateHook(*this),
_metricLock(),
_maintenanceStats(),
@@ -132,24 +137,12 @@ Distributor::getDistributorIndex() const
return _component.getIndex();
}
-const std::string&
-Distributor::getClusterName() const
-{
- return _clusterName;
-}
-
const PendingMessageTracker&
Distributor::getPendingMessageTracker() const
{
return _pendingMessageTracker;
}
-BucketOwnership
-Distributor::checkOwnershipInPendingState(const document::Bucket &b) const
-{
- return _bucketDBUpdater.checkOwnershipInPendingState(b);
-}
-
const lib::ClusterState*
Distributor::pendingClusterStateOrNull(const document::BucketSpace& space) const {
return _bucketDBUpdater.pendingClusterStateOrNull(space);
@@ -217,6 +210,7 @@ void Distributor::onClose() {
}
LOG(debug, "Distributor::onClose invoked");
+ _pendingMessageTracker.abort_deferred_tasks();
_bucketDBUpdater.flush();
_externalOperationHandler.close_pending();
_operationOwner.onClose();
diff --git a/storage/src/vespa/storage/distributor/distributor.h b/storage/src/vespa/storage/distributor/distributor.h
index d7dd1fda2e9..05340d7dcd2 100644
--- a/storage/src/vespa/storage/distributor/distributor.h
+++ b/storage/src/vespa/storage/distributor/distributor.h
@@ -12,10 +12,10 @@
#include "pendingmessagetracker.h"
#include "statusreporterdelegate.h"
#include <vespa/config/config.h>
-#include <vespa/storage/common/distributorcomponent.h>
#include <vespa/storage/common/doneinitializehandler.h>
#include <vespa/storage/common/messagesender.h>
#include <vespa/storage/distributor/bucketdb/bucketdbmetricupdater.h>
+#include <vespa/storage/distributor/distributorcomponent.h>
#include <vespa/storage/distributor/maintenance/maintenancescheduler.h>
#include <vespa/storageapi/message/state.h>
#include <vespa/storageframework/generic/metric/metricupdatehook.h>
@@ -26,16 +26,18 @@
namespace storage {
struct DoneInitializeHandler;
class HostInfo;
+ class NodeIdentity;
}
namespace storage::distributor {
-class DistributorBucketSpaceRepo;
-class SimpleMaintenanceScanner;
class BlockingOperationStarter;
-class ThrottlingOperationStarter;
class BucketPriorityDatabase;
+class DistributorBucketSpaceRepo;
+class OperationSequencer;
class OwnershipTransferSafeTimePointCalculator;
+class SimpleMaintenanceScanner;
+class ThrottlingOperationStarter;
class Distributor : public StorageLink,
public DistributorInterface,
@@ -43,10 +45,12 @@ class Distributor : public StorageLink,
public framework::StatusReporter,
public framework::TickingThread,
public MinReplicaProvider,
- public BucketSpacesStatsProvider
+ public BucketSpacesStatsProvider,
+ public NonTrackingMessageSender
{
public:
Distributor(DistributorComponentRegister&,
+ const NodeIdentity& node_identity,
framework::TickingThreadPool&,
DoneInitializeHandler&,
bool manageActiveBucketCopies,
@@ -55,25 +59,30 @@ public:
~Distributor() override;
+ const ClusterContext& cluster_context() const override {
+ return _component.cluster_context();
+ }
void onOpen() override;
void onClose() override;
bool onDown(const std::shared_ptr<api::StorageMessage>&) override;
void sendUp(const std::shared_ptr<api::StorageMessage>&) override;
void sendDown(const std::shared_ptr<api::StorageMessage>&) override;
// Bypasses message tracker component. Thread safe.
- void send_up_without_tracking(const std::shared_ptr<api::StorageMessage>&);
+ void send_up_without_tracking(const std::shared_ptr<api::StorageMessage>&) override;
ChainedMessageSender& getMessageSender() override {
return (_messageSender == 0 ? *this : *_messageSender);
}
DistributorMetricSet& getMetrics() override { return *_metrics; }
-
+
PendingMessageTracker& getPendingMessageTracker() override {
return _pendingMessageTracker;
}
- BucketOwnership checkOwnershipInPendingState(const document::Bucket &bucket) const override;
+ const OperationSequencer& operation_sequencer() const noexcept override {
+ return *_operation_sequencer;
+ }
const lib::ClusterState* pendingClusterStateOrNull(const document::BucketSpace&) const override;
@@ -150,7 +159,6 @@ public:
}
int getDistributorIndex() const override;
- const std::string& getClusterName() const override;
const PendingMessageTracker& getPendingMessageTracker() const override;
void sendCommand(const std::shared_ptr<api::StorageCommand>&) override;
void sendReply(const std::shared_ptr<api::StorageReply>&) override;
@@ -262,23 +270,24 @@ private:
lib::ClusterStateBundle _clusterStateBundle;
- DistributorComponentRegister& _compReg;
- storage::DistributorComponent _component;
std::unique_ptr<DistributorBucketSpaceRepo> _bucketSpaceRepo;
// Read-only bucket space repo with DBs that only contain buckets transiently
// during cluster state transitions. Bucket set does not overlap that of _bucketSpaceRepo
// and the DBs are empty during non-transition phases.
std::unique_ptr<DistributorBucketSpaceRepo> _readOnlyBucketSpaceRepo;
+ storage::distributor::DistributorComponent _component;
std::shared_ptr<DistributorMetricSet> _metrics;
OperationOwner _operationOwner;
OperationOwner _maintenanceOperationOwner;
+ std::unique_ptr<OperationSequencer> _operation_sequencer;
PendingMessageTracker _pendingMessageTracker;
BucketDBUpdater _bucketDBUpdater;
StatusReporterDelegate _distributorStatusDelegate;
StatusReporterDelegate _bucketDBStatusDelegate;
IdealStateManager _idealStateManager;
+ ChainedMessageSender* _messageSender;
ExternalOperationHandler _externalOperationHandler;
std::shared_ptr<lib::Distribution> _distribution;
@@ -309,8 +318,6 @@ private:
DoneInitializeHandler& _doneInitializeHandler;
bool _doneInitializing;
- ChainedMessageSender* _messageSender;
-
std::unique_ptr<BucketPriorityDatabase> _bucketPriorityDb;
std::unique_ptr<SimpleMaintenanceScanner> _scanner;
std::unique_ptr<ThrottlingOperationStarter> _throttlingStarter;
@@ -319,7 +326,6 @@ private:
MaintenanceScheduler::SchedulingMode _schedulingMode;
framework::MilliSecTimer _recoveryTimeStarted;
framework::ThreadWaitInfo _tickResult;
- const std::string _clusterName;
BucketDBMetricUpdater _bucketDBMetricUpdater;
std::unique_ptr<BucketGcTimeCalculator::BucketIdHasher> _bucketIdHasher;
MetricUpdateHook _metricUpdateHook;
diff --git a/storage/src/vespa/storage/distributor/distributor_bucket_space.cpp b/storage/src/vespa/storage/distributor/distributor_bucket_space.cpp
index 7b7970228e7..784ae5ab8af 100644
--- a/storage/src/vespa/storage/distributor/distributor_bucket_space.cpp
+++ b/storage/src/vespa/storage/distributor/distributor_bucket_space.cpp
@@ -1,31 +1,198 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "distributor_bucket_space.h"
+#include "bucketownership.h"
#include <vespa/storage/bucketdb/btree_bucket_database.h>
#include <vespa/vdslib/state/clusterstate.h>
#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
namespace storage::distributor {
+namespace {
+
+const char *up_states = "uri";
+const char *nonretired_up_states = "ui";
+const char *nonretired_or_maintenance_up_states = "uim";
+
+}
+
DistributorBucketSpace::DistributorBucketSpace()
+ : DistributorBucketSpace(0u)
+{
+}
+
+DistributorBucketSpace::DistributorBucketSpace(uint16_t node_index)
: _bucketDatabase(std::make_unique<BTreeBucketDatabase>()),
_clusterState(),
- _distribution()
+ _distribution(),
+ _node_index(node_index),
+ _distribution_bits(1u),
+ _pending_cluster_state(),
+ _available_nodes(),
+ _ownerships(),
+ _ideal_nodes()
{
}
DistributorBucketSpace::~DistributorBucketSpace() = default;
void
+DistributorBucketSpace::clear()
+{
+ _ownerships.clear();
+ _ideal_nodes.clear();
+}
+
+void
+DistributorBucketSpace::enumerate_available_nodes()
+{
+ _distribution_bits = _clusterState->getDistributionBitCount();
+ auto node_count = _clusterState->getNodeCount(lib::NodeType::STORAGE);
+ if (_pending_cluster_state) {
+ _distribution_bits = std::min(_distribution_bits, _pending_cluster_state->getDistributionBitCount());
+ node_count = std::min(node_count, _pending_cluster_state->getNodeCount(lib::NodeType::STORAGE));
+ }
+ std::vector<bool> nodes(node_count);
+ for (uint32_t i = 0; i < node_count; ++i) {
+ lib::Node node_key(lib::NodeType::STORAGE, i);
+ const lib::NodeState& ns(_clusterState->getNodeState(node_key));
+ if (ns.getState().oneOf(up_states)) {
+ if (!_pending_cluster_state || _pending_cluster_state->getNodeState(node_key).getState().oneOf(up_states)) {
+ nodes[i] = true;
+ }
+ }
+ }
+ _available_nodes = std::move(nodes);
+}
+
+void
DistributorBucketSpace::setClusterState(std::shared_ptr<const lib::ClusterState> clusterState)
{
_clusterState = std::move(clusterState);
+ clear();
+ enumerate_available_nodes();
}
void
DistributorBucketSpace::setDistribution(std::shared_ptr<const lib::Distribution> distribution) {
_distribution = std::move(distribution);
+ clear();
+}
+
+void
+DistributorBucketSpace::set_pending_cluster_state(std::shared_ptr<const lib::ClusterState> pending_cluster_state)
+{
+ _pending_cluster_state = std::move(pending_cluster_state);
+ clear();
+ enumerate_available_nodes();
+}
+
+bool
+DistributorBucketSpace::owns_bucket_in_state(
+ const lib::Distribution& distribution,
+ const lib::ClusterState& cluster_state,
+ document::BucketId bucket) const
+{
+ try {
+ uint16_t distributor = distribution.getIdealDistributorNode(cluster_state, bucket);
+
+ return (_node_index == distributor);
+ } catch (lib::TooFewBucketBitsInUseException& e) {
+ return false;
+ } catch (lib::NoDistributorsAvailableException& e) {
+ return false;
+ }
+}
+
+bool
+DistributorBucketSpace::owns_bucket_in_state(
+ const lib::ClusterState& clusterState,
+ document::BucketId bucket) const
+{
+ return owns_bucket_in_state(*_distribution, clusterState, bucket);
+}
+
+namespace {
+
+void
+setup_ideal_nodes_bundle(IdealServiceLayerNodesBundle& ideal_nodes_bundle,
+ const lib::Distribution& distribution,
+ const lib::ClusterState& cluster_state,
+ document::BucketId bucket)
+{
+ ideal_nodes_bundle.set_available_nodes(distribution.getIdealStorageNodes(cluster_state, bucket, up_states));
+ ideal_nodes_bundle.set_available_nonretired_nodes(distribution.getIdealStorageNodes(cluster_state, bucket, nonretired_up_states));
+ ideal_nodes_bundle.set_available_nonretired_or_maintenance_nodes(distribution.getIdealStorageNodes(cluster_state, bucket, nonretired_or_maintenance_up_states));
+}
+
+// Ideal service layer nodes bundle used when bucket id used bits > 33.
+thread_local IdealServiceLayerNodesBundle fallback_ideal_nodes_bundle;
+
+}
+
+const IdealServiceLayerNodesBundle&
+DistributorBucketSpace::get_ideal_service_layer_nodes_bundle(document::BucketId bucket) const
+{
+ assert(bucket.getUsedBits() >= _distribution_bits);
+ if (bucket.getUsedBits() > 33) {
+ IdealServiceLayerNodesBundle &ideal_nodes_bundle = fallback_ideal_nodes_bundle;
+ setup_ideal_nodes_bundle(ideal_nodes_bundle, *_distribution, *_clusterState, bucket);
+ return ideal_nodes_bundle;
+ }
+ document::BucketId lookup_bucket((bucket.getUsedBits() > 33) ? bucket.getUsedBits() : _distribution_bits, bucket.getId());
+ auto itr = _ideal_nodes.find(lookup_bucket);
+ if (itr != _ideal_nodes.end()) {
+ return itr->second;
+ }
+ IdealServiceLayerNodesBundle ideal_nodes_bundle;
+ setup_ideal_nodes_bundle(ideal_nodes_bundle, *_distribution, *_clusterState, lookup_bucket);
+ auto insres = _ideal_nodes.insert(std::make_pair(lookup_bucket, std::move(ideal_nodes_bundle)));
+ assert(insres.second);
+ return insres.first->second;
+}
+
+BucketOwnershipFlags
+DistributorBucketSpace::get_bucket_ownership_flags(document::BucketId bucket) const
+{
+ if (bucket.getUsedBits() < _distribution_bits) {
+ BucketOwnershipFlags flags;
+ if (!_pending_cluster_state) {
+ flags.set_owned_in_pending_state();
+ }
+ return flags;
+ }
+ document::BucketId super_bucket(_distribution_bits, bucket.getId());
+ auto itr = _ownerships.find(super_bucket);
+ if (itr != _ownerships.end()) {
+ return itr->second;
+ }
+ BucketOwnershipFlags flags;
+ if (!_pending_cluster_state || owns_bucket_in_state(*_distribution, *_pending_cluster_state, super_bucket)) {
+ flags.set_owned_in_pending_state();
+ }
+ if (owns_bucket_in_state(*_distribution, *_clusterState, super_bucket)) {
+ flags.set_owned_in_current_state();
+ }
+ auto insres = _ownerships.insert(std::make_pair(super_bucket, flags));
+ assert(insres.second);
+ return insres.first->second;
+}
+
+BucketOwnership
+DistributorBucketSpace::check_ownership_in_pending_and_current_state(document::BucketId bucket) const
+{
+ auto flags = get_bucket_ownership_flags(bucket);
+ if (!flags.owned_in_pending_state()) {
+ assert(_pending_cluster_state);
+ return BucketOwnership::createNotOwnedInState(*_pending_cluster_state);
+ }
+ if (flags.owned_in_current_state()) {
+ return BucketOwnership::createOwned();
+ } else {
+ return BucketOwnership::createNotOwnedInState(*_clusterState);
+ }
}
}
diff --git a/storage/src/vespa/storage/distributor/distributor_bucket_space.h b/storage/src/vespa/storage/distributor/distributor_bucket_space.h
index c137414ecfb..f4d5bd6f5aa 100644
--- a/storage/src/vespa/storage/distributor/distributor_bucket_space.h
+++ b/storage/src/vespa/storage/distributor/distributor_bucket_space.h
@@ -1,7 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
+#include "bucketownership.h"
+#include "bucket_ownership_flags.h"
+#include "ideal_service_layer_nodes_bundle.h"
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/vespalib/stllike/hash_map.h>
#include <memory>
+#include <vector>
namespace storage {
class BucketDatabase;
@@ -29,8 +35,19 @@ class DistributorBucketSpace {
std::unique_ptr<BucketDatabase> _bucketDatabase;
std::shared_ptr<const lib::ClusterState> _clusterState;
std::shared_ptr<const lib::Distribution> _distribution;
+ uint16_t _node_index;
+ uint16_t _distribution_bits;
+ std::shared_ptr<const lib::ClusterState> _pending_cluster_state;
+ std::vector<bool> _available_nodes;
+ mutable vespalib::hash_map<document::BucketId, BucketOwnershipFlags, document::BucketId::hash> _ownerships;
+ mutable vespalib::hash_map<document::BucketId, IdealServiceLayerNodesBundle, document::BucketId::hash> _ideal_nodes;
+
+ void clear();
+ void enumerate_available_nodes();
+ bool owns_bucket_in_state(const lib::Distribution& distribution, const lib::ClusterState& cluster_state, document::BucketId bucket) const;
public:
explicit DistributorBucketSpace();
+ explicit DistributorBucketSpace(uint16_t node_index);
~DistributorBucketSpace();
DistributorBucketSpace(const DistributorBucketSpace&) = delete;
@@ -62,6 +79,35 @@ public:
return _distribution;
}
+ void set_pending_cluster_state(std::shared_ptr<const lib::ClusterState> pending_cluster_state);
+ const lib::ClusterState& get_pending_cluster_state() const noexcept { return *_pending_cluster_state; }
+
+ /**
+ * Returns true if this distributor owns the given bucket in the
+ * given cluster and current distribution config.
+ * Only used by unit tests.
+ */
+ bool owns_bucket_in_state(const lib::ClusterState& clusterState, document::BucketId bucket) const;
+
+ const std::vector<bool>& get_available_nodes() const { return _available_nodes; }
+
+ /**
+ * Returns the ideal nodes bundle for the given bucket.
+ */
+ const IdealServiceLayerNodesBundle &get_ideal_service_layer_nodes_bundle(document::BucketId bucket) const;
+
+ /*
+ * Return bucket ownership flags for the given bucket. Bucket is always
+ * considered owned in pending state if there is no pending state.
+ */
+ BucketOwnershipFlags get_bucket_ownership_flags(document::BucketId bucket) const;
+
+ /**
+ * Returns the ownership status of a bucket as decided with the current
+ * distribution and cluster state -and- that of the pending cluster
+ * state and distribution (if any pending exists).
+ */
+ BucketOwnership check_ownership_in_pending_and_current_state(document::BucketId bucket) const;
};
}
diff --git a/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.cpp b/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.cpp
index 744c54676ae..4f64dab9a68 100644
--- a/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.cpp
+++ b/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.cpp
@@ -2,7 +2,7 @@
#include "distributor_bucket_space_repo.h"
#include "distributor_bucket_space.h"
-#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vdslib/state/cluster_state_bundle.h>
#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <cassert>
@@ -13,11 +13,11 @@ using document::BucketSpace;
namespace storage::distributor {
-DistributorBucketSpaceRepo::DistributorBucketSpaceRepo()
+DistributorBucketSpaceRepo::DistributorBucketSpaceRepo(uint16_t node_index)
: _map()
{
- add(document::FixedBucketSpaces::default_space(), std::make_unique<DistributorBucketSpace>());
- add(document::FixedBucketSpaces::global_space(), std::make_unique<DistributorBucketSpace>());
+ add(document::FixedBucketSpaces::default_space(), std::make_unique<DistributorBucketSpace>(node_index));
+ add(document::FixedBucketSpaces::global_space(), std::make_unique<DistributorBucketSpace>(node_index));
}
DistributorBucketSpaceRepo::~DistributorBucketSpaceRepo() = default;
@@ -44,4 +44,20 @@ DistributorBucketSpaceRepo::get(BucketSpace bucketSpace) const
return *itr->second;
}
+void
+DistributorBucketSpaceRepo::set_pending_cluster_state_bundle(const lib::ClusterStateBundle& cluster_state_bundle)
+{
+ for (auto& entry : _map) {
+ entry.second->set_pending_cluster_state(cluster_state_bundle.getDerivedClusterState(entry.first));
+ }
+}
+
+void
+DistributorBucketSpaceRepo::clear_pending_cluster_state_bundle()
+{
+ for (auto& entry : _map) {
+ entry.second->set_pending_cluster_state({});
+ }
+}
+
}
diff --git a/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.h b/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.h
index ee36842969a..f012b25e351 100644
--- a/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.h
+++ b/storage/src/vespa/storage/distributor/distributor_bucket_space_repo.h
@@ -5,7 +5,7 @@
#include <memory>
#include <unordered_map>
-namespace storage::lib { class Distribution; }
+namespace storage::lib { class ClusterStateBundle; }
namespace storage::distributor {
@@ -19,7 +19,7 @@ private:
BucketSpaceMap _map;
public:
- DistributorBucketSpaceRepo();
+ explicit DistributorBucketSpaceRepo(uint16_t node_index);
~DistributorBucketSpaceRepo();
DistributorBucketSpaceRepo(const DistributorBucketSpaceRepo&&) = delete;
@@ -33,6 +33,8 @@ public:
BucketSpaceMap::const_iterator begin() const { return _map.begin(); }
BucketSpaceMap::const_iterator end() const { return _map.end(); }
void add(document::BucketSpace bucketSpace, std::unique_ptr<DistributorBucketSpace> distributorBucketSpace);
+ void set_pending_cluster_state_bundle(const lib::ClusterStateBundle& cluster_state_bundle);
+ void clear_pending_cluster_state_bundle();
};
}
diff --git a/storage/src/vespa/storage/distributor/distributor_node_context.h b/storage/src/vespa/storage/distributor/distributor_node_context.h
new file mode 100644
index 00000000000..3cb0f509ea7
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/distributor_node_context.h
@@ -0,0 +1,26 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/storage/common/cluster_context.h>
+#include <cstdint>
+
+namespace document { class BucketIdFactory; }
+
+namespace storage::framework { struct Clock; }
+
+namespace storage::distributor {
+
+/**
+ * Interface that provides information and state about a distributor node.
+ */
+class DistributorNodeContext : public ClusterContext {
+public:
+ virtual ~DistributorNodeContext() {}
+ virtual const framework::Clock& clock() const noexcept = 0;
+ virtual const document::BucketIdFactory& bucket_id_factory() const noexcept = 0;
+ virtual uint16_t node_index() const noexcept = 0;
+};
+
+}
+
diff --git a/storage/src/vespa/storage/distributor/distributor_operation_context.h b/storage/src/vespa/storage/distributor/distributor_operation_context.h
new file mode 100644
index 00000000000..083ffcdacf4
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/distributor_operation_context.h
@@ -0,0 +1,57 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "bucketownership.h"
+#include "operation_routing_snapshot.h"
+#include <vespa/document/bucket/bucketspace.h>
+#include <vespa/storage/bucketdb/bucketdatabase.h>
+#include <vespa/storage/common/distributorcomponent.h>
+#include <vespa/storageapi/defs.h>
+
+namespace document { class Bucket; }
+
+namespace storage { class DistributorConfiguration; }
+
+namespace storage::distributor {
+
+class DistributorBucketSpaceRepo;
+class PendingMessageTracker;
+
+/**
+ * Interface with functionality that is used when handling distributor operations.
+ */
+class DistributorOperationContext {
+public:
+ virtual ~DistributorOperationContext() {}
+ virtual api::Timestamp generate_unique_timestamp() = 0;
+ virtual void update_bucket_database(const document::Bucket& bucket,
+ const BucketCopy& changed_node,
+ uint32_t update_flags = 0) = 0;
+ virtual void update_bucket_database(const document::Bucket& bucket,
+ const std::vector<BucketCopy>& changed_nodes,
+ uint32_t update_flags = 0) = 0;
+ virtual void remove_node_from_bucket_database(const document::Bucket& bucket, uint16_t node_index) = 0;
+ virtual const DistributorBucketSpaceRepo& bucket_space_repo() const noexcept= 0;
+ virtual DistributorBucketSpaceRepo& bucket_space_repo() noexcept = 0;
+ virtual const DistributorBucketSpaceRepo& read_only_bucket_space_repo() const noexcept = 0;
+ virtual DistributorBucketSpaceRepo& read_only_bucket_space_repo() noexcept = 0;
+ virtual document::BucketId make_split_bit_constrained_bucket_id(const document::DocumentId& docId) const = 0;
+
+ virtual const DistributorConfiguration& distributor_config() const noexcept = 0;
+ virtual void send_inline_split_if_bucket_too_large(document::BucketSpace bucket_space,
+ const BucketDatabase::Entry& entry,
+ uint8_t pri) = 0;
+ virtual OperationRoutingSnapshot read_snapshot_for_bucket(const document::Bucket& bucket) const = 0;
+ virtual PendingMessageTracker& pending_message_tracker() noexcept = 0;
+ virtual bool has_pending_message(uint16_t node_index,
+ const document::Bucket& bucket,
+ uint32_t message_type) const = 0;
+ virtual const lib::ClusterState* pending_cluster_state_or_null(const document::BucketSpace& bucket_space) const = 0;
+
+ // TODO: Move to being a free function instead.
+ virtual const char* storage_node_up_states() const = 0;
+
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/distributorcomponent.cpp b/storage/src/vespa/storage/distributor/distributorcomponent.cpp
index 1c84376dea6..fa5dfa73efc 100644
--- a/storage/src/vespa/storage/distributor/distributorcomponent.cpp
+++ b/storage/src/vespa/storage/distributor/distributorcomponent.cpp
@@ -2,7 +2,8 @@
#include "distributorcomponent.h"
#include "distributor_bucket_space_repo.h"
#include "distributor_bucket_space.h"
-#include <vespa/storage/common/bucketoperationlogger.h>
+#include "pendingmessagetracker.h"
+#include <vespa/document/select/parser.h>
#include <vespa/vdslib/state/cluster_state_bundle.h>
@@ -46,116 +47,25 @@ DistributorComponent::getClusterStateBundle() const
return _distributor.getClusterStateBundle();
};
-std::vector<uint16_t>
-DistributorComponent::getIdealNodes(const document::Bucket &bucket) const
-{
- auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
- return bucketSpace.getDistribution().getIdealStorageNodes(
- bucketSpace.getClusterState(),
- bucket.getBucketId(),
- _distributor.getStorageNodeUpStates());
-}
-
-BucketOwnership
-DistributorComponent::checkOwnershipInPendingAndGivenState(
- const lib::Distribution& distribution,
- const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const
-{
- try {
- BucketOwnership pendingRes(
- _distributor.checkOwnershipInPendingState(bucket));
- if (!pendingRes.isOwned()) {
- return pendingRes;
- }
- uint16_t distributor = distribution.getIdealDistributorNode(
- clusterState, bucket.getBucketId());
-
- if (getIndex() == distributor) {
- return BucketOwnership::createOwned();
- } else {
- return BucketOwnership::createNotOwnedInState(clusterState);
- }
- } catch (lib::TooFewBucketBitsInUseException& e) {
- return BucketOwnership::createNotOwnedInState(clusterState);
- } catch (lib::NoDistributorsAvailableException& e) {
- return BucketOwnership::createNotOwnedInState(clusterState);
- }
-}
-
-BucketOwnership
-DistributorComponent::checkOwnershipInPendingAndCurrentState(
- const document::Bucket &bucket) const
-{
- auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
- return checkOwnershipInPendingAndGivenState(
- bucketSpace.getDistribution(), bucketSpace.getClusterState(), bucket);
-}
-
-bool
-DistributorComponent::ownsBucketInState(
- const lib::Distribution& distribution,
- const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const
-{
- LOG(spam, "checking bucket %s in state %s with distr %s",
- bucket.toString().c_str(), clusterState.toString().c_str(),
- distribution.getNodeGraph().getDistributionConfigHash().c_str());
- try {
- uint16_t distributor = distribution.getIdealDistributorNode(
- clusterState, bucket.getBucketId());
-
- return (getIndex() == distributor);
- } catch (lib::TooFewBucketBitsInUseException& e) {
- return false;
- } catch (lib::NoDistributorsAvailableException& e) {
- return false;
- }
-}
-
-bool
-DistributorComponent::ownsBucketInState(
- const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const
-{
- auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
- return ownsBucketInState(bucketSpace.getDistribution(), clusterState, bucket);
-}
-
-bool
-DistributorComponent::ownsBucketInCurrentState(const document::Bucket &bucket) const
-{
- auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
- return ownsBucketInState(bucketSpace.getDistribution(), bucketSpace.getClusterState(), bucket);
-}
-
api::StorageMessageAddress
DistributorComponent::nodeAddress(uint16_t nodeIndex) const
{
- return api::StorageMessageAddress(
- getClusterName(),
- lib::NodeType::STORAGE,
- nodeIndex);
+ return api::StorageMessageAddress::create(cluster_name_ptr(), lib::NodeType::STORAGE, nodeIndex);
}
bool
-DistributorComponent::checkDistribution(
- api::StorageCommand &cmd,
- const document::Bucket &bucket)
+DistributorComponent::checkDistribution(api::StorageCommand &cmd, const document::Bucket &bucket)
{
- BucketOwnership bo(checkOwnershipInPendingAndCurrentState(bucket));
+ auto &bucket_space(_bucketSpaceRepo.get(bucket.getBucketSpace()));
+ BucketOwnership bo(bucket_space.check_ownership_in_pending_and_current_state(bucket.getBucketId()));
if (!bo.isOwned()) {
std::string systemStateStr = bo.getNonOwnedState().toString();
LOG(debug,
- "Got message with wrong distribution, "
- "bucket %s sending back state '%s'",
- bucket.toString().c_str(),
- systemStateStr.c_str());
+ "Got message with wrong distribution, bucket %s sending back state '%s'",
+ bucket.toString().c_str(), systemStateStr.c_str());
api::StorageReply::UP reply(cmd.makeReply());
- api::ReturnCode ret(
- api::ReturnCode::WRONG_DISTRIBUTION,
- systemStateStr);
+ api::ReturnCode ret(api::ReturnCode::WRONG_DISTRIBUTION, systemStateStr);
reply->setResult(ret);
sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
return false;
@@ -164,8 +74,7 @@ DistributorComponent::checkDistribution(
}
void
-DistributorComponent::removeNodesFromDB(const document::Bucket &bucket,
- const std::vector<uint16_t>& nodes)
+DistributorComponent::removeNodesFromDB(const document::Bucket &bucket, const std::vector<uint16_t>& nodes)
{
auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
BucketDatabase::Entry dbentry = bucketSpace.getBucketDatabase().get(bucket.getBucketId());
@@ -218,6 +127,62 @@ DistributorComponent::enumerateUnavailableNodes(
}
}
+namespace {
+
+/**
+ * Helper class to update entry in bucket database when bucket copies from nodes have changed.
+ */
+class UpdateBucketDatabaseProcessor : public BucketDatabase::EntryUpdateProcessor {
+ const framework::Clock& _clock;
+ const std::vector<BucketCopy>& _changed_nodes;
+ std::vector<uint16_t> _ideal_nodes;
+ bool _reset_trusted;
+public:
+ UpdateBucketDatabaseProcessor(const framework::Clock& clock, const std::vector<BucketCopy>& changed_nodes, std::vector<uint16_t> ideal_nodes, bool reset_trusted);
+ virtual ~UpdateBucketDatabaseProcessor();
+ virtual BucketDatabase::Entry create_entry(const document::BucketId& bucket) const override;
+ virtual bool process_entry(BucketDatabase::Entry &entry) const override;
+};
+
+UpdateBucketDatabaseProcessor::UpdateBucketDatabaseProcessor(const framework::Clock& clock, const std::vector<BucketCopy>& changed_nodes, std::vector<uint16_t> ideal_nodes, bool reset_trusted)
+ : BucketDatabase::EntryUpdateProcessor(),
+ _clock(clock),
+ _changed_nodes(changed_nodes),
+ _ideal_nodes(std::move(ideal_nodes)),
+ _reset_trusted(reset_trusted)
+{
+}
+
+UpdateBucketDatabaseProcessor::~UpdateBucketDatabaseProcessor() = default;
+
+BucketDatabase::Entry
+UpdateBucketDatabaseProcessor::create_entry(const document::BucketId &bucket) const
+{
+ return BucketDatabase::Entry(bucket, BucketInfo());
+}
+
+bool
+UpdateBucketDatabaseProcessor::process_entry(BucketDatabase::Entry &entry) const
+{
+ // 0 implies bucket was just added. Since we don't know if any other
+ // distributor has run GC on it, we just have to assume this and set the
+ // timestamp to the current time to avoid duplicate work.
+ if (entry->getLastGarbageCollectionTime() == 0) {
+ entry->setLastGarbageCollectionTime(_clock.getTimeInSeconds().getTime());
+ }
+ entry->addNodes(_changed_nodes, _ideal_nodes);
+ if (_reset_trusted) {
+ entry->resetTrusted();
+ }
+ if (entry->getNodeCount() == 0) {
+ LOG(warning, "all nodes in changedNodes set (size %zu) are down, removing dbentry", _changed_nodes.size());
+ return false; // remove entry
+ }
+ return true; // keep entry
+}
+
+}
+
void
DistributorComponent::updateBucketDatabase(
const document::Bucket &bucket,
@@ -226,9 +191,8 @@ DistributorComponent::updateBucketDatabase(
{
auto &bucketSpace(_bucketSpaceRepo.get(bucket.getBucketSpace()));
assert(!(bucket.getBucketId() == document::BucketId()));
- BucketDatabase::Entry dbentry = bucketSpace.getBucketDatabase().get(bucket.getBucketId());
- BucketOwnership ownership(checkOwnershipInPendingAndCurrentState(bucket));
+ BucketOwnership ownership(bucketSpace.check_ownership_in_pending_and_current_state(bucket.getBucketId()));
if (!ownership.isOwned()) {
LOG(debug,
"Trying to add %s to database that we do not own according to "
@@ -238,54 +202,32 @@ DistributorComponent::updateBucketDatabase(
return;
}
- if (!dbentry.valid()) {
- if (updateFlags & DatabaseUpdate::CREATE_IF_NONEXISTING) {
- dbentry = BucketDatabase::Entry(bucket.getBucketId(), BucketInfo());
- } else {
- return;
- }
- }
-
- // 0 implies bucket was just added. Since we don't know if any other
- // distributor has run GC on it, we just have to assume this and set the
- // timestamp to the current time to avoid duplicate work.
- if (dbentry->getLastGarbageCollectionTime() == 0) {
- dbentry->setLastGarbageCollectionTime(
- getClock().getTimeInSeconds().getTime());
- }
-
// Ensure that we're not trying to bring any zombie copies into the
// bucket database (i.e. copies on nodes that are actually unavailable).
- std::vector<uint16_t> unavailableNodes;
- enumerateUnavailableNodes(unavailableNodes, bucketSpace.getClusterState(), bucket, changedNodes);
- if (auto* pending_state = _distributor.pendingClusterStateOrNull(bucket.getBucketSpace())) {
- enumerateUnavailableNodes(unavailableNodes, *pending_state, bucket, changedNodes);
+ const auto& available_nodes = bucketSpace.get_available_nodes();
+ bool found_down_node = false;
+ for (const auto& copy : changedNodes) {
+ if (copy.getNode() >= available_nodes.size() || !available_nodes[copy.getNode()]) {
+ found_down_node = true;
+ break;
+ }
}
// Optimize for common case where we don't have to create a new
// bucket copy vector
- if (unavailableNodes.empty()) {
- dbentry->addNodes(changedNodes, getIdealNodes(bucket));
- } else {
- std::vector<BucketCopy> upNodes;
+ std::vector<BucketCopy> up_nodes;
+ if (found_down_node) {
+ up_nodes.reserve(changedNodes.size());
for (uint32_t i = 0; i < changedNodes.size(); ++i) {
const BucketCopy& copy(changedNodes[i]);
- if (std::find(unavailableNodes.begin(), unavailableNodes.end(), copy.getNode())
- == unavailableNodes.end())
- {
- upNodes.emplace_back(copy);
+ if (copy.getNode() < available_nodes.size() && available_nodes[copy.getNode()]) {
+ up_nodes.emplace_back(copy);
}
}
- dbentry->addNodes(upNodes, getIdealNodes(bucket));
- }
- if (updateFlags & DatabaseUpdate::RESET_TRUSTED) {
- dbentry->resetTrusted();
- }
- if (dbentry->getNodeCount() == 0) {
- LOG(warning, "all nodes in changedNodes set (size %zu) are down, removing dbentry", changedNodes.size());
- bucketSpace.getBucketDatabase().remove(bucket.getBucketId());
- return;
}
- bucketSpace.getBucketDatabase().update(dbentry);
+
+ UpdateBucketDatabaseProcessor processor(getClock(), found_down_node ? up_nodes : changedNodes, bucketSpace.get_ideal_service_layer_nodes_bundle(bucket.getBucketId()).get_available_nodes(), (updateFlags & DatabaseUpdate::RESET_TRUSTED) != 0);
+
+ bucketSpace.getBucketDatabase().process_update(bucket.getBucketId(), processor, (updateFlags & DatabaseUpdate::CREATE_IF_NONEXISTING) != 0);
}
void
@@ -353,4 +295,20 @@ DistributorComponent::initializing() const {
return _distributor.initializing();
}
+bool
+DistributorComponent::has_pending_message(uint16_t node_index,
+ const document::Bucket& bucket,
+ uint32_t message_type) const
+{
+ const auto& sender = static_cast<const DistributorMessageSender&>(getDistributor());
+ return sender.getPendingMessageTracker().hasPendingMessage(node_index, bucket, message_type);
+}
+
+std::unique_ptr<document::select::Node>
+DistributorComponent::parse_selection(const vespalib::string& selection) const
+{
+ document::select::Parser parser(*getTypeRepo()->documentTypeRepo, getBucketIdFactory());
+ return parser.parse(selection);
+}
+
}
diff --git a/storage/src/vespa/storage/distributor/distributorcomponent.h b/storage/src/vespa/storage/distributor/distributorcomponent.h
index 283d0c20390..13c0a72d44e 100644
--- a/storage/src/vespa/storage/distributor/distributorcomponent.h
+++ b/storage/src/vespa/storage/distributor/distributorcomponent.h
@@ -1,7 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
+#include "distributor_node_context.h"
+#include "distributor_operation_context.h"
#include "distributorinterface.h"
+#include "document_selection_parser.h"
#include "operationowner.h"
#include "statechecker.h"
#include <vespa/storage/common/distributorcomponent.h>
@@ -25,7 +28,10 @@ struct DatabaseUpdate {
* Takes care of subscribing to document manager config and
* making those values available to other subcomponents.
*/
-class DistributorComponent : public storage::DistributorComponent
+class DistributorComponent : public storage::DistributorComponent,
+ public DistributorNodeContext,
+ public DistributorOperationContext,
+ public DocumentSelectionParser
{
public:
DistributorComponent(DistributorInterface& distributor,
@@ -37,47 +43,12 @@ public:
~DistributorComponent() override;
/**
- * Returns the ownership status of a bucket as decided with the given
- * distribution and cluster state -and- that of the pending cluster
- * state and distribution (if any pending exists).
- */
- BucketOwnership checkOwnershipInPendingAndGivenState(
- const lib::Distribution& distribution,
- const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const;
-
- BucketOwnership checkOwnershipInPendingAndCurrentState(
- const document::Bucket &bucket) const;
-
- bool ownsBucketInState(const lib::Distribution& distribution,
- const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const;
-
- /**
- * Returns true if this distributor owns the given bucket in the
- * given cluster and current distribution config.
- */
- bool ownsBucketInState(const lib::ClusterState& clusterState,
- const document::Bucket &bucket) const;
-
- /**
- * Returns true if this distributor owns the given bucket with the current
- * cluster state and distribution config.
- */
- bool ownsBucketInCurrentState(const document::Bucket &bucket) const;
-
- /**
* Returns a reference to the current cluster state bundle. Valid until the
* next time the distributor main thread processes its message queue.
*/
const lib::ClusterStateBundle& getClusterStateBundle() const;
/**
- * Returns the ideal nodes for the given bucket.
- */
- std::vector<uint16_t> getIdealNodes(const document::Bucket &bucket) const;
-
- /**
* Returns the slobrok address of the given storage node.
*/
api::StorageMessageAddress nodeAddress(uint16_t nodeIndex) const;
@@ -174,6 +145,70 @@ public:
*/
bool initializing() const;
+ // Implements DistributorNodeContext
+ const framework::Clock& clock() const noexcept override { return getClock(); }
+ const vespalib::string * cluster_name_ptr() const noexcept override { return cluster_context().cluster_name_ptr(); }
+ const document::BucketIdFactory& bucket_id_factory() const noexcept override { return getBucketIdFactory(); }
+ uint16_t node_index() const noexcept override { return getIndex(); }
+
+ // Implements DistributorOperationContext
+ api::Timestamp generate_unique_timestamp() override { return getUniqueTimestamp(); }
+ void update_bucket_database(const document::Bucket& bucket,
+ const BucketCopy& changed_node,
+ uint32_t update_flags = 0) override {
+ updateBucketDatabase(bucket, changed_node, update_flags);
+ }
+ virtual void update_bucket_database(const document::Bucket& bucket,
+ const std::vector<BucketCopy>& changed_nodes,
+ uint32_t update_flags = 0) override {
+ updateBucketDatabase(bucket, changed_nodes, update_flags);
+ }
+ void remove_node_from_bucket_database(const document::Bucket& bucket, uint16_t node_index) override {
+ removeNodeFromDB(bucket, node_index);
+ }
+ const DistributorBucketSpaceRepo& bucket_space_repo() const noexcept override {
+ return getBucketSpaceRepo();
+ }
+ DistributorBucketSpaceRepo& bucket_space_repo() noexcept override {
+ return getBucketSpaceRepo();
+ }
+ const DistributorBucketSpaceRepo& read_only_bucket_space_repo() const noexcept override {
+ return getReadOnlyBucketSpaceRepo();
+ }
+ DistributorBucketSpaceRepo& read_only_bucket_space_repo() noexcept override {
+ return getReadOnlyBucketSpaceRepo();
+ }
+ document::BucketId make_split_bit_constrained_bucket_id(const document::DocumentId& docId) const override {
+ return getBucketId(docId);
+ }
+ const DistributorConfiguration& distributor_config() const noexcept override {
+ return getDistributor().getConfig();
+ }
+ void send_inline_split_if_bucket_too_large(document::BucketSpace bucket_space,
+ const BucketDatabase::Entry& entry,
+ uint8_t pri) override {
+ getDistributor().checkBucketForSplit(bucket_space, entry, pri);
+ }
+ OperationRoutingSnapshot read_snapshot_for_bucket(const document::Bucket& bucket) const override {
+ return getDistributor().read_snapshot_for_bucket(bucket);
+ }
+ PendingMessageTracker& pending_message_tracker() noexcept override {
+ return getDistributor().getPendingMessageTracker();
+ }
+ bool has_pending_message(uint16_t node_index,
+ const document::Bucket& bucket,
+ uint32_t message_type) const override;
+ const lib::ClusterState* pending_cluster_state_or_null(const document::BucketSpace& bucket_space) const override {
+ return getDistributor().pendingClusterStateOrNull(bucket_space);
+ }
+ const char* storage_node_up_states() const override {
+ return getDistributor().getStorageNodeUpStates();
+ }
+
+ // Implements DocumentSelectionParser
+ std::unique_ptr<document::select::Node> parse_selection(const vespalib::string& selection) const override;
+
+
private:
void enumerateUnavailableNodes(
std::vector<uint16_t>& unavailableNodes,
diff --git a/storage/src/vespa/storage/distributor/distributorinterface.h b/storage/src/vespa/storage/distributor/distributorinterface.h
index b17bcd56d19..bf4ff9c4c99 100644
--- a/storage/src/vespa/storage/distributor/distributorinterface.h
+++ b/storage/src/vespa/storage/distributor/distributorinterface.h
@@ -24,7 +24,6 @@ public:
virtual PendingMessageTracker& getPendingMessageTracker() = 0;
virtual DistributorMetricSet& getMetrics() = 0;
virtual void enableClusterStateBundle(const lib::ClusterStateBundle& state) = 0;
- virtual BucketOwnership checkOwnershipInPendingState(const document::Bucket &bucket) const = 0;
virtual const lib::ClusterState* pendingClusterStateOrNull(const document::BucketSpace&) const = 0;
virtual void notifyDistributionChangeEnabled() = 0;
diff --git a/storage/src/vespa/storage/distributor/distributormessagesender.cpp b/storage/src/vespa/storage/distributor/distributormessagesender.cpp
index d40bd4bd9c2..3afd2ea8139 100644
--- a/storage/src/vespa/storage/distributor/distributormessagesender.cpp
+++ b/storage/src/vespa/storage/distributor/distributormessagesender.cpp
@@ -10,10 +10,10 @@ DistributorMessageSender::sendToNode(const lib::NodeType& nodeType, uint16_t nod
const std::shared_ptr<api::StorageCommand> & cmd, bool useDocumentAPI)
{
cmd->setSourceIndex(getDistributorIndex());
- cmd->setAddress(api::StorageMessageAddress(getClusterName(), nodeType, node,
- (useDocumentAPI
- ? api::StorageMessageAddress::DOCUMENT
- : api::StorageMessageAddress::STORAGE)));
+ const auto *cluster_np = cluster_context().cluster_name_ptr();
+ cmd->setAddress(useDocumentAPI
+ ? api::StorageMessageAddress::createDocApi(cluster_np, nodeType, node)
+ : api::StorageMessageAddress::create(cluster_np, nodeType, node));
uint64_t msgId = cmd->getMsgId();
sendCommand(cmd);
return msgId;
diff --git a/storage/src/vespa/storage/distributor/distributormessagesender.h b/storage/src/vespa/storage/distributor/distributormessagesender.h
index 078762dd05c..54be92dc99a 100644
--- a/storage/src/vespa/storage/distributor/distributormessagesender.h
+++ b/storage/src/vespa/storage/distributor/distributormessagesender.h
@@ -1,12 +1,15 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
+#include <vespa/storage/common/cluster_context.h>
#include <vespa/storage/common/messagesender.h>
+#include <vespa/vespalib/stllike/string.h>
namespace storage::lib { class NodeType; }
namespace storage::distributor {
class PendingMessageTracker;
+class OperationSequencer;
class DistributorMessageSender : public MessageSender {
public:
@@ -18,8 +21,9 @@ public:
const std::shared_ptr<api::StorageCommand>& cmd, bool useDocumentAPI = false);
virtual int getDistributorIndex() const = 0;
- virtual const std::string& getClusterName() const = 0;
+ virtual const ClusterContext & cluster_context() const = 0;
virtual const PendingMessageTracker& getPendingMessageTracker() const = 0;
+ virtual const OperationSequencer& operation_sequencer() const noexcept = 0;
};
}
diff --git a/storage/src/vespa/storage/distributor/distributormetricsset.cpp b/storage/src/vespa/storage/distributor/distributormetricsset.cpp
index ab4b124d71c..c95f74fd421 100644
--- a/storage/src/vespa/storage/distributor/distributormetricsset.cpp
+++ b/storage/src/vespa/storage/distributor/distributormetricsset.cpp
@@ -1,7 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "distributormetricsset.h"
-#include <vespa/metrics/loadmetric.hpp>
-#include <vespa/metrics/summetric.hpp>
#include <vespa/vespalib/util/memoryusage.h>
namespace storage::distributor {
@@ -15,19 +13,20 @@ BucketDbMetrics::BucketDbMetrics(const vespalib::string& db_type, metrics::Metri
BucketDbMetrics::~BucketDbMetrics() = default;
-DistributorMetricSet::DistributorMetricSet(const metrics::LoadTypeSet& lt)
+//TODO Vespa 8 all metrics with .sum in the name should have that removed.
+DistributorMetricSet::DistributorMetricSet()
: MetricSet("distributor", {{"distributor"}}, ""),
- puts(lt, PersistenceOperationMetricSet("puts"), this),
- updates(lt, UpdateMetricSet(), this),
- update_puts(lt, PersistenceOperationMetricSet("update_puts"), this),
- update_gets(lt, PersistenceOperationMetricSet("update_gets"), this),
- update_metadata_gets(lt, PersistenceOperationMetricSet("update_metadata_gets"), this),
- removes(lt, PersistenceOperationMetricSet("removes"), this),
- removelocations(lt, PersistenceOperationMetricSet("removelocations"), this),
- gets(lt, PersistenceOperationMetricSet("gets"), this),
- stats(lt, PersistenceOperationMetricSet("stats"), this),
- getbucketlists(lt, PersistenceOperationMetricSet("getbucketlists"), this),
- visits(lt, VisitorMetricSet(), this),
+ puts("puts.sum", this),
+ updates(this),
+ update_puts("update_puts", this),
+ update_gets("update_gets", this),
+ update_metadata_gets("update_metadata_gets", this),
+ removes("removes.sum", this),
+ removelocations("removelocations.sum", this),
+ gets("gets.sum", this),
+ stats("stats", this),
+ getbucketlists("getbucketlists", this),
+ visits(this),
stateTransitionTime("state_transition_time", {},
"Time it takes to complete a cluster state transition. If a "
"state transition is preempted before completing, its elapsed "
@@ -57,6 +56,3 @@ DistributorMetricSet::DistributorMetricSet(const metrics::LoadTypeSet& lt)
DistributorMetricSet::~DistributorMetricSet() = default;
} // storage
-
-template class metrics::LoadMetric<storage::PersistenceOperationMetricSet>;
-template class metrics::SumMetric<storage::PersistenceOperationMetricSet>;
diff --git a/storage/src/vespa/storage/distributor/distributormetricsset.h b/storage/src/vespa/storage/distributor/distributormetricsset.h
index ce4025d8311..89d34fd6474 100644
--- a/storage/src/vespa/storage/distributor/distributormetricsset.h
+++ b/storage/src/vespa/storage/distributor/distributormetricsset.h
@@ -4,9 +4,7 @@
#include "persistence_operation_metric_set.h"
#include "update_metric_set.h"
#include "visitormetricsset.h"
-#include <vespa/metrics/metrics.h>
#include <vespa/metrics/common/memory_usage_metrics.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
namespace vespalib { class MemoryUsage; }
@@ -21,17 +19,17 @@ struct BucketDbMetrics : metrics::MetricSet {
class DistributorMetricSet : public metrics::MetricSet {
public:
- metrics::LoadMetric<PersistenceOperationMetricSet> puts;
- metrics::LoadMetric<UpdateMetricSet> updates;
- metrics::LoadMetric<PersistenceOperationMetricSet> update_puts;
- metrics::LoadMetric<PersistenceOperationMetricSet> update_gets;
- metrics::LoadMetric<PersistenceOperationMetricSet> update_metadata_gets;
- metrics::LoadMetric<PersistenceOperationMetricSet> removes;
- metrics::LoadMetric<PersistenceOperationMetricSet> removelocations;
- metrics::LoadMetric<PersistenceOperationMetricSet> gets;
- metrics::LoadMetric<PersistenceOperationMetricSet> stats;
- metrics::LoadMetric<PersistenceOperationMetricSet> getbucketlists;
- metrics::LoadMetric<VisitorMetricSet> visits;
+ PersistenceOperationMetricSet puts;
+ UpdateMetricSet updates;
+ PersistenceOperationMetricSet update_puts;
+ PersistenceOperationMetricSet update_gets;
+ PersistenceOperationMetricSet update_metadata_gets;
+ PersistenceOperationMetricSet removes;
+ PersistenceOperationMetricSet removelocations;
+ PersistenceOperationMetricSet gets;
+ PersistenceOperationMetricSet stats;
+ PersistenceOperationMetricSet getbucketlists;
+ VisitorMetricSet visits;
metrics::DoubleAverageMetric stateTransitionTime;
metrics::DoubleAverageMetric set_cluster_state_processing_time;
metrics::DoubleAverageMetric activate_cluster_state_processing_time;
@@ -41,7 +39,7 @@ public:
BucketDbMetrics mutable_dbs;
BucketDbMetrics read_only_dbs;
- explicit DistributorMetricSet(const metrics::LoadTypeSet& lt);
+ explicit DistributorMetricSet();
~DistributorMetricSet() override;
};
diff --git a/storage/src/vespa/storage/distributor/document_selection_parser.h b/storage/src/vespa/storage/distributor/document_selection_parser.h
new file mode 100644
index 00000000000..bc4021c0ccd
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/document_selection_parser.h
@@ -0,0 +1,21 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/stllike/string.h>
+#include <memory>
+
+namespace document::select { class Node; }
+
+namespace storage::distributor {
+
+/**
+ * Interface to parse a document selection string.
+ */
+class DocumentSelectionParser {
+public:
+ virtual ~DocumentSelectionParser() {}
+ virtual std::unique_ptr<document::select::Node> parse_selection(const vespalib::string& str) const = 0;
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/externaloperationhandler.cpp b/storage/src/vespa/storage/distributor/externaloperationhandler.cpp
index 7e8eaaff15e..f9ec1fffacb 100644
--- a/storage/src/vespa/storage/distributor/externaloperationhandler.cpp
+++ b/storage/src/vespa/storage/distributor/externaloperationhandler.cpp
@@ -1,8 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "bucket_space_distribution_context.h"
+#include "crypto_uuid_generator.h"
#include "externaloperationhandler.h"
#include "distributor.h"
+#include "operation_sequencer.h"
#include <vespa/document/base/documentid.h>
#include <vespa/storage/distributor/operations/external/putoperation.h>
#include <vespa/storage/distributor/operations/external/twophaseupdateoperation.h>
@@ -11,8 +13,10 @@
#include <vespa/storage/distributor/operations/external/getoperation.h>
#include <vespa/storage/distributor/operations/external/statbucketoperation.h>
#include <vespa/storage/distributor/operations/external/statbucketlistoperation.h>
+#include <vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h>
#include <vespa/storage/distributor/operations/external/removelocationoperation.h>
#include <vespa/storage/distributor/operations/external/visitoroperation.h>
+#include <vespa/storage/common/reindexing_constants.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/storageapi/message/removelocation.h>
#include <vespa/storageapi/message/stat.h>
@@ -27,41 +31,58 @@ LOG_SETUP(".distributor.manager");
namespace storage::distributor {
class DirectDispatchSender : public DistributorMessageSender {
- Distributor& _distributor;
+ DistributorNodeContext& _node_ctx;
+ NonTrackingMessageSender& _msg_sender;
public:
- explicit DirectDispatchSender(Distributor& distributor)
- : _distributor(distributor)
+ DirectDispatchSender(DistributorNodeContext& node_ctx,
+ NonTrackingMessageSender& msg_sender)
+ : _node_ctx(node_ctx),
+ _msg_sender(msg_sender)
{}
~DirectDispatchSender() override = default;
void sendCommand(const std::shared_ptr<api::StorageCommand>& cmd) override {
- _distributor.send_up_without_tracking(cmd);
+ _msg_sender.send_up_without_tracking(cmd);
}
void sendReply(const std::shared_ptr<api::StorageReply>& reply) override {
- _distributor.send_up_without_tracking(reply);
+ _msg_sender.send_up_without_tracking(reply);
}
int getDistributorIndex() const override {
- return _distributor.getDistributorIndex(); // Thread safe
+ return _node_ctx.node_index();
}
- const std::string& getClusterName() const override {
- return _distributor.getClusterName(); // Thread safe
+ const ClusterContext & cluster_context() const override {
+ return _node_ctx;
}
const PendingMessageTracker& getPendingMessageTracker() const override {
abort(); // Never called by the messages using this component.
}
+ const OperationSequencer& operation_sequencer() const noexcept override {
+ abort(); // Never called by the messages using this component.
+ }
};
-ExternalOperationHandler::ExternalOperationHandler(Distributor& owner,
- DistributorBucketSpaceRepo& bucketSpaceRepo,
- DistributorBucketSpaceRepo& readOnlyBucketSpaceRepo,
+ExternalOperationHandler::ExternalOperationHandler(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorMetricSet& metrics,
+ ChainedMessageSender& msg_sender,
+ OperationSequencer& operation_sequencer,
+ NonTrackingMessageSender& non_tracking_sender,
+ DocumentSelectionParser& parser,
const MaintenanceOperationGenerator& gen,
- DistributorComponentRegister& compReg)
- : DistributorComponent(owner, bucketSpaceRepo, readOnlyBucketSpaceRepo, compReg, "External operation handler"),
- _direct_dispatch_sender(std::make_unique<DirectDispatchSender>(owner)),
+ OperationOwner& operation_owner)
+ : _node_ctx(node_ctx),
+ _op_ctx(op_ctx),
+ _metrics(metrics),
+ _msg_sender(msg_sender),
+ _operation_sequencer(operation_sequencer),
+ _parser(parser),
+ _direct_dispatch_sender(std::make_unique<DirectDispatchSender>(node_ctx, non_tracking_sender)),
_operationGenerator(gen),
_rejectFeedBeforeTimeReached(), // At epoch
+ _distributor_operation_owner(operation_owner),
_non_main_thread_ops_mutex(),
- _non_main_thread_ops_owner(*_direct_dispatch_sender, getClock()),
+ _non_main_thread_ops_owner(*_direct_dispatch_sender, _node_ctx.clock()),
+ _uuid_generator(std::make_unique<CryptoUuidGenerator>()),
_concurrent_gets_enabled(false),
_use_weak_internal_read_consistency_for_gets(false)
{
@@ -99,11 +120,11 @@ ExternalOperationHandler::makeSafeTimeRejectionResult(TimePoint unsafeTime)
bool
ExternalOperationHandler::checkSafeTimeReached(api::StorageCommand& cmd)
{
- const auto now = TimePoint(std::chrono::seconds(getClock().getTimeInSeconds().getTime()));
+ const auto now = TimePoint(std::chrono::seconds(_node_ctx.clock().getTimeInSeconds().getTime()));
if (now < _rejectFeedBeforeTimeReached) {
api::StorageReply::UP reply(cmd.makeReply());
reply->setResult(makeSafeTimeRejectionResult(now));
- sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
+ _msg_sender.sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
return false;
}
return true;
@@ -112,7 +133,7 @@ ExternalOperationHandler::checkSafeTimeReached(api::StorageCommand& cmd)
void ExternalOperationHandler::bounce_with_result(api::StorageCommand& cmd, const api::ReturnCode& result) {
api::StorageReply::UP reply(cmd.makeReply());
reply->setResult(result);
- sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
+ _msg_sender.sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
}
void ExternalOperationHandler::bounce_with_wrong_distribution(api::StorageCommand& cmd,
@@ -137,7 +158,7 @@ void ExternalOperationHandler::bounce_with_wrong_distribution(api::StorageComman
}
void ExternalOperationHandler::bounce_with_wrong_distribution(api::StorageCommand& cmd) {
- const auto& cluster_state = _bucketSpaceRepo.get(document::FixedBucketSpaces::default_space()).getClusterState();
+ const auto& cluster_state = _op_ctx.bucket_space_repo().get(document::FixedBucketSpaces::default_space()).getClusterState();
bounce_with_wrong_distribution(cmd, cluster_state);
}
@@ -153,7 +174,7 @@ void ExternalOperationHandler::bounce_with_busy_during_state_transition(
api::StorageReply::UP reply(cmd.makeReply());
api::ReturnCode ret(api::ReturnCode::BUSY, status_str);
reply->setResult(ret);
- sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
+ _msg_sender.sendUp(std::shared_ptr<api::StorageMessage>(reply.release()));
}
bool
@@ -161,8 +182,10 @@ ExternalOperationHandler::checkTimestampMutationPreconditions(api::StorageComman
const document::BucketId &bucketId,
PersistenceOperationMetricSet& persistenceMetrics)
{
- document::Bucket bucket(cmd.getBucket().getBucketSpace(), bucketId);
- if (!ownsBucketInCurrentState(bucket)) {
+ auto &bucket_space(_op_ctx.bucket_space_repo().get(cmd.getBucket().getBucketSpace()));
+ auto bucket_ownership_flags = bucket_space.get_bucket_ownership_flags(bucketId);
+ if (!bucket_ownership_flags.owned_in_current_state()) {
+ document::Bucket bucket(cmd.getBucket().getBucketSpace(), bucketId);
LOG(debug, "Distributor manager received %s, bucket %s with wrong distribution",
cmd.toString().c_str(), bucket.toString().c_str());
bounce_with_wrong_distribution(cmd);
@@ -170,12 +193,11 @@ ExternalOperationHandler::checkTimestampMutationPreconditions(api::StorageComman
return false;
}
- auto pending = getDistributor().checkOwnershipInPendingState(bucket);
- if (!pending.isOwned()) {
+ if (!bucket_ownership_flags.owned_in_pending_state()) {
// We return BUSY here instead of WrongDistributionReply to avoid clients potentially
// ping-ponging between cluster state versions during a state transition.
- auto& current_state = _bucketSpaceRepo.get(document::FixedBucketSpaces::default_space()).getClusterState();
- auto& pending_state = pending.getNonOwnedState();
+ auto& current_state = bucket_space.getClusterState();
+ auto& pending_state = bucket_space.get_pending_cluster_state();
bounce_with_busy_during_state_transition(cmd, current_state, pending_state);
return false;
}
@@ -202,7 +224,7 @@ ExternalOperationHandler::makeConcurrentMutationRejectionReply(api::StorageComma
}
bool ExternalOperationHandler::allowMutation(const SequencingHandle& handle) const {
- const auto& config(getDistributor().getConfig());
+ const auto& config(_op_ctx.distributor_config());
if (!config.getSequenceMutatingOperations()) {
// Sequencing explicitly disabled, so always allow.
return true;
@@ -217,7 +239,9 @@ void ExternalOperationHandler::bounce_or_invoke_read_only_op(
PersistenceOperationMetricSet& metrics,
Func func)
{
- if (!ownsBucketInCurrentState(bucket)) {
+ auto &bucket_space(_op_ctx.bucket_space_repo().get(bucket.getBucketSpace()));
+ auto bucket_ownership_flags = bucket_space.get_bucket_ownership_flags(bucket.getBucketId());
+ if (!bucket_ownership_flags.owned_in_current_state()) {
LOG(debug, "Distributor manager received %s, bucket %s with wrong distribution",
cmd.toString().c_str(), bucket.toString().c_str());
bounce_with_wrong_distribution(cmd);
@@ -225,108 +249,140 @@ void ExternalOperationHandler::bounce_or_invoke_read_only_op(
return;
}
- auto pending = getDistributor().checkOwnershipInPendingState(bucket);
- if (pending.isOwned()) {
- func(_bucketSpaceRepo);
+ if (bucket_ownership_flags.owned_in_pending_state()) {
+ func(_op_ctx.bucket_space_repo());
} else {
- if (getDistributor().getConfig().allowStaleReadsDuringClusterStateTransitions()) {
- func(_readOnlyBucketSpaceRepo);
+ if (_op_ctx.distributor_config().allowStaleReadsDuringClusterStateTransitions()) {
+ func(_op_ctx.read_only_bucket_space_repo());
} else {
- auto& current_state = _bucketSpaceRepo.get(document::FixedBucketSpaces::default_space()).getClusterState();
- auto& pending_state = pending.getNonOwnedState();
+ auto& current_state = bucket_space.getClusterState();
+ auto& pending_state = bucket_space.get_pending_cluster_state();
bounce_with_busy_during_state_transition(cmd, current_state, pending_state);
}
}
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, Put)
-{
- const documentapi::LoadType & loadType = cmd->getLoadType();
- auto& metrics = getMetrics().puts[loadType];
- if (!checkTimestampMutationPreconditions(*cmd, getBucketId(cmd->getDocumentId()), metrics)) {
+namespace {
+
+bool put_is_from_reindexing_visitor(const api::PutCommand& cmd) {
+ const auto& tas_cond = cmd.getCondition();
+ return (tas_cond.isPresent() && (tas_cond.getSelection().starts_with(reindexing_bucket_lock_bypass_prefix())));
+}
+
+// Precondition: put_is_from_reindexing_visitor(cmd) == true
+std::string extract_reindexing_token(const api::PutCommand& cmd) {
+ const std::string& tas_str = cmd.getCondition().getSelection();
+ auto eq_idx = tas_str.find_first_of('=');
+ if (eq_idx != std::string::npos) {
+ return tas_str.substr(eq_idx + 1);
+ }
+ return "";
+}
+
+}
+
+bool ExternalOperationHandler::onPut(const std::shared_ptr<api::PutCommand>& cmd) {
+ auto& metrics = getMetrics().puts;
+ if (!checkTimestampMutationPreconditions(*cmd, _op_ctx.make_split_bit_constrained_bucket_id(cmd->getDocumentId()), metrics)) {
return true;
}
if (cmd->getTimestamp() == 0) {
- cmd->setTimestamp(getUniqueTimestamp());
+ cmd->setTimestamp(_op_ctx.generate_unique_timestamp());
}
- auto handle = _mutationSequencer.try_acquire(cmd->getDocumentId());
- if (allowMutation(handle)) {
- document::BucketSpace bucketSpace = cmd->getBucket().getBucketSpace();
- _op = std::make_shared<PutOperation>(*this,
- _bucketSpaceRepo.get(bucketSpace),
- std::move(cmd), getMetrics().puts[loadType], std::move(handle));
+ const auto bucket_space = cmd->getBucket().getBucketSpace();
+ auto handle = _operation_sequencer.try_acquire(bucket_space, cmd->getDocumentId());
+ bool allow = allowMutation(handle);
+ if (put_is_from_reindexing_visitor(*cmd)) {
+ auto expect_token = extract_reindexing_token(*cmd);
+ if (!allow && handle.is_blocked_by_bucket()) {
+ if (handle.is_bucket_blocked_with_token(expect_token)) {
+ cmd->setCondition(documentapi::TestAndSetCondition()); // Must clear TaS or the backend will reject the op
+ allow = true;
+ } else {
+ bounce_with_result(*cmd, api::ReturnCode(api::ReturnCode::TEST_AND_SET_CONDITION_FAILED,
+ "Expected bucket lock token did not match actual lock token"));
+ return true;
+ }
+ } else {
+ bounce_with_result(*cmd, api::ReturnCode(api::ReturnCode::TEST_AND_SET_CONDITION_FAILED,
+ "Operation expects a read-for-write bucket lock to be present, "
+ "but none currently exists"));
+ return true;
+ }
+ }
+ if (allow) {
+ _op = std::make_shared<PutOperation>(_node_ctx, _op_ctx,
+ _op_ctx.bucket_space_repo().get(bucket_space),
+ std::move(cmd), getMetrics().puts, std::move(handle));
} else {
- sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
+ _msg_sender.sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
}
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, Update)
-{
- const documentapi::LoadType & loadType = cmd->getLoadType();
- auto& metrics = getMetrics().updates[loadType];
- if (!checkTimestampMutationPreconditions(*cmd, getBucketId(cmd->getDocumentId()), metrics)) {
+bool ExternalOperationHandler::onUpdate(const std::shared_ptr<api::UpdateCommand>& cmd) {
+ auto& metrics = getMetrics().updates;
+ if (!checkTimestampMutationPreconditions(*cmd, _op_ctx.make_split_bit_constrained_bucket_id(cmd->getDocumentId()), metrics)) {
return true;
}
if (cmd->getTimestamp() == 0) {
- cmd->setTimestamp(getUniqueTimestamp());
+ cmd->setTimestamp(_op_ctx.generate_unique_timestamp());
}
- auto handle = _mutationSequencer.try_acquire(cmd->getDocumentId());
+ const auto bucket_space = cmd->getBucket().getBucketSpace();
+ auto handle = _operation_sequencer.try_acquire(bucket_space, cmd->getDocumentId());
if (allowMutation(handle)) {
- document::BucketSpace bucketSpace = cmd->getBucket().getBucketSpace();
- _op = std::make_shared<TwoPhaseUpdateOperation>(*this,
- _bucketSpaceRepo.get(bucketSpace),
+ _op = std::make_shared<TwoPhaseUpdateOperation>(_node_ctx, _op_ctx, _parser,
+ _op_ctx.bucket_space_repo().get(bucket_space),
std::move(cmd), getMetrics(), std::move(handle));
} else {
- sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
+ _msg_sender.sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
}
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, Remove)
-{
- const documentapi::LoadType & loadType = cmd->getLoadType();
- auto& metrics = getMetrics().removes[loadType];
- if (!checkTimestampMutationPreconditions(*cmd, getBucketId(cmd->getDocumentId()), metrics)) {
+bool ExternalOperationHandler::onRemove(const std::shared_ptr<api::RemoveCommand>& cmd) {
+ auto& metrics = getMetrics().removes;
+ if (!checkTimestampMutationPreconditions(*cmd, _op_ctx.make_split_bit_constrained_bucket_id(cmd->getDocumentId()), metrics)) {
return true;
}
if (cmd->getTimestamp() == 0) {
- cmd->setTimestamp(getUniqueTimestamp());
+ cmd->setTimestamp(_op_ctx.generate_unique_timestamp());
}
- auto handle = _mutationSequencer.try_acquire(cmd->getDocumentId());
+ const auto bucket_space = cmd->getBucket().getBucketSpace();
+ auto handle = _operation_sequencer.try_acquire(bucket_space, cmd->getDocumentId());
if (allowMutation(handle)) {
- auto &distributorBucketSpace(_bucketSpaceRepo.get(cmd->getBucket().getBucketSpace()));
+ auto &distributorBucketSpace(_op_ctx.bucket_space_repo().get(bucket_space));
- _op = std::make_shared<RemoveOperation>(*this, distributorBucketSpace, std::move(cmd),
- getMetrics().removes[loadType], std::move(handle));
+ _op = std::make_shared<RemoveOperation>(_node_ctx, _op_ctx, distributorBucketSpace, std::move(cmd),
+ getMetrics().removes, std::move(handle));
} else {
- sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
+ _msg_sender.sendUp(makeConcurrentMutationRejectionReply(*cmd, cmd->getDocumentId(), metrics));
}
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, RemoveLocation)
-{
+bool ExternalOperationHandler::onRemoveLocation(const std::shared_ptr<api::RemoveLocationCommand>& cmd) {
document::BucketId bid;
- RemoveLocationOperation::getBucketId(*this, *cmd, bid);
+ RemoveLocationOperation::getBucketId(_node_ctx, _parser, *cmd, bid);
document::Bucket bucket(cmd->getBucket().getBucketSpace(), bid);
- auto& metrics = getMetrics().removelocations[cmd->getLoadType()];
+ auto& metrics = getMetrics().removelocations;
if (!checkTimestampMutationPreconditions(*cmd, bucket.getBucketId(), metrics)) {
return true;
}
- _op = std::make_shared<RemoveLocationOperation>(*this, _bucketSpaceRepo.get(cmd->getBucket().getBucketSpace()),
- std::move(cmd), getMetrics().removelocations[cmd->getLoadType()]);
+ _op = std::make_shared<RemoveLocationOperation>(_node_ctx, _op_ctx, _parser,
+ _op_ctx.bucket_space_repo().get(cmd->getBucket().getBucketSpace()),
+ std::move(cmd), getMetrics().removelocations);
return true;
}
@@ -337,9 +393,9 @@ api::InternalReadConsistency ExternalOperationHandler::desired_get_read_consiste
}
std::shared_ptr<Operation> ExternalOperationHandler::try_generate_get_operation(const std::shared_ptr<api::GetCommand>& cmd) {
- document::Bucket bucket(cmd->getBucket().getBucketSpace(), getBucketId(cmd->getDocumentId()));
- auto& metrics = getMetrics().gets[cmd->getLoadType()];
- auto snapshot = getDistributor().read_snapshot_for_bucket(bucket);
+ document::Bucket bucket(cmd->getBucket().getBucketSpace(), _op_ctx.make_split_bit_constrained_bucket_id(cmd->getDocumentId()));
+ auto& metrics = getMetrics().gets;
+ auto snapshot = _op_ctx.read_snapshot_for_bucket(bucket);
if (!snapshot.is_routable()) {
const auto& ctx = snapshot.context();
if (ctx.has_pending_state_transition()) {
@@ -354,45 +410,49 @@ std::shared_ptr<Operation> ExternalOperationHandler::try_generate_get_operation(
// The snapshot is aware of whether stale reads are enabled, so we don't have to check that here.
const auto* space_repo = snapshot.bucket_space_repo();
assert(space_repo != nullptr);
- return std::make_shared<GetOperation>(*this, space_repo->get(bucket.getBucketSpace()),
+ return std::make_shared<GetOperation>(_node_ctx, space_repo->get(bucket.getBucketSpace()),
snapshot.steal_read_guard(), cmd, metrics,
desired_get_read_consistency());
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, Get)
-{
+bool ExternalOperationHandler::onGet(const std::shared_ptr<api::GetCommand>& cmd) {
_op = try_generate_get_operation(cmd);
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, StatBucket)
-{
- auto& metrics = getMetrics().stats[cmd->getLoadType()];
+bool ExternalOperationHandler::onStatBucket(const std::shared_ptr<api::StatBucketCommand>& cmd) {
+ auto& metrics = getMetrics().stats;
bounce_or_invoke_read_only_op(*cmd, cmd->getBucket(), metrics, [&](auto& bucket_space_repo) {
auto& bucket_space = bucket_space_repo.get(cmd->getBucket().getBucketSpace());
- _op = std::make_shared<StatBucketOperation>(*this, bucket_space, cmd);
+ _op = std::make_shared<StatBucketOperation>(bucket_space, cmd);
});
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, GetBucketList)
-{
- auto& metrics = getMetrics().getbucketlists[cmd->getLoadType()];
+bool ExternalOperationHandler::onGetBucketList(const std::shared_ptr<api::GetBucketListCommand>& cmd) {
+ auto& metrics = getMetrics().getbucketlists;
bounce_or_invoke_read_only_op(*cmd, cmd->getBucket(), metrics, [&](auto& bucket_space_repo) {
auto& bucket_space = bucket_space_repo.get(cmd->getBucket().getBucketSpace());
auto& bucket_database = bucket_space.getBucketDatabase();
- _op = std::make_shared<StatBucketListOperation>(bucket_database, _operationGenerator, getIndex(), cmd);
+ _op = std::make_shared<StatBucketListOperation>(bucket_database, _operationGenerator, _node_ctx.node_index(), cmd);
});
return true;
}
-IMPL_MSG_COMMAND_H(ExternalOperationHandler, CreateVisitor)
-{
+bool ExternalOperationHandler::onCreateVisitor(const std::shared_ptr<api::CreateVisitorCommand>& cmd) {
// TODO same handling as Gets (VisitorOperation needs to change)
- const DistributorConfiguration& config(getDistributor().getConfig());
+ const auto& config(_op_ctx.distributor_config());
VisitorOperation::Config visitorConfig(config.getMinBucketsPerVisitor(), config.getMaxVisitorsPerNodePerClientVisitor());
- auto &distributorBucketSpace(_bucketSpaceRepo.get(cmd->getBucket().getBucketSpace()));
- _op = Operation::SP(new VisitorOperation(*this, distributorBucketSpace, cmd, visitorConfig, getMetrics().visits[cmd->getLoadType()]));
+ auto &distributorBucketSpace(_op_ctx.bucket_space_repo().get(cmd->getBucket().getBucketSpace()));
+ auto visit_op = std::make_shared<VisitorOperation>(_node_ctx, _op_ctx, distributorBucketSpace, cmd, visitorConfig, getMetrics().visits);
+ if (visit_op->is_read_for_write()) {
+ _op = std::make_shared<ReadForWriteVisitorOperationStarter>(std::move(visit_op), _operation_sequencer,
+ _distributor_operation_owner,
+ _op_ctx.pending_message_tracker(),
+ *_uuid_generator);
+ } else {
+ _op = std::move(visit_op);
+ }
return true;
}
diff --git a/storage/src/vespa/storage/distributor/externaloperationhandler.h b/storage/src/vespa/storage/distributor/externaloperationhandler.h
index 60cad15a791..9127325702a 100644
--- a/storage/src/vespa/storage/distributor/externaloperationhandler.h
+++ b/storage/src/vespa/storage/distributor/externaloperationhandler.h
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include "operation_sequencer.h"
#include <vespa/document/bucket/bucketid.h>
#include <vespa/document/bucket/bucketidfactory.h>
#include <vespa/vdslib/state/clusterstate.h>
@@ -11,6 +10,8 @@
#include <chrono>
#include <mutex>
+namespace documentapi { class TestAndSetCondition; }
+
namespace storage {
class PersistenceOperationMetricSet;
@@ -21,28 +22,35 @@ class DistributorMetricSet;
class Distributor;
class MaintenanceOperationGenerator;
class DirectDispatchSender;
+class SequencingHandle;
+class OperationSequencer;
+class OperationOwner;
+class UuidGenerator;
-class ExternalOperationHandler : public DistributorComponent,
- public api::MessageHandler
+class ExternalOperationHandler : public api::MessageHandler
{
public:
using Clock = std::chrono::system_clock;
using TimePoint = std::chrono::time_point<Clock>;
- DEF_MSG_COMMAND_H(Get);
- DEF_MSG_COMMAND_H(Put);
- DEF_MSG_COMMAND_H(Update);
- DEF_MSG_COMMAND_H(Remove);
- DEF_MSG_COMMAND_H(RemoveLocation);
- DEF_MSG_COMMAND_H(StatBucket);
- DEF_MSG_COMMAND_H(CreateVisitor);
- DEF_MSG_COMMAND_H(GetBucketList);
-
- ExternalOperationHandler(Distributor& owner,
- DistributorBucketSpaceRepo& bucketSpaceRepo,
- DistributorBucketSpaceRepo& readOnlyBucketSpaceRepo,
- const MaintenanceOperationGenerator&,
- DistributorComponentRegister& compReg);
+ bool onGet(const std::shared_ptr<api::GetCommand>&) override;
+ bool onPut(const std::shared_ptr<api::PutCommand>&) override;
+ bool onUpdate(const std::shared_ptr<api::UpdateCommand>&) override;
+ bool onRemove(const std::shared_ptr<api::RemoveCommand>&) override;
+ bool onRemoveLocation(const std::shared_ptr<api::RemoveLocationCommand>&) override;
+ bool onStatBucket(const std::shared_ptr<api::StatBucketCommand>&) override;
+ bool onCreateVisitor(const std::shared_ptr<api::CreateVisitorCommand>&) override;
+ bool onGetBucketList(const std::shared_ptr<api::GetBucketListCommand>&) override;
+
+ ExternalOperationHandler(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorMetricSet& metrics,
+ ChainedMessageSender& msg_sender,
+ OperationSequencer& operation_sequencer,
+ NonTrackingMessageSender& non_tracking_sender,
+ DocumentSelectionParser& parser,
+ const MaintenanceOperationGenerator& gen,
+ OperationOwner& operation_owner);
~ExternalOperationHandler() override;
@@ -74,14 +82,26 @@ public:
return _use_weak_internal_read_consistency_for_gets.load(std::memory_order_relaxed);
}
+ // Exposed for testing
+ OperationSequencer& operation_sequencer() noexcept {
+ return _operation_sequencer;
+ }
+
private:
+ DistributorNodeContext& _node_ctx;
+ DistributorOperationContext& _op_ctx;
+ DistributorMetricSet& _metrics;
+ ChainedMessageSender& _msg_sender;
+ OperationSequencer& _operation_sequencer;
+ DocumentSelectionParser& _parser;
std::unique_ptr<DirectDispatchSender> _direct_dispatch_sender;
const MaintenanceOperationGenerator& _operationGenerator;
- OperationSequencer _mutationSequencer;
Operation::SP _op;
TimePoint _rejectFeedBeforeTimeReached;
+ OperationOwner& _distributor_operation_owner;
mutable std::mutex _non_main_thread_ops_mutex;
OperationOwner _non_main_thread_ops_owner;
+ std::unique_ptr<UuidGenerator> _uuid_generator;
std::atomic<bool> _concurrent_gets_enabled;
std::atomic<bool> _use_weak_internal_read_consistency_for_gets;
@@ -114,7 +134,7 @@ private:
api::InternalReadConsistency desired_get_read_consistency() const noexcept;
- DistributorMetricSet& getMetrics() { return getDistributor().getMetrics(); }
+ DistributorMetricSet& getMetrics() { return _metrics; }
};
}
diff --git a/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.cpp b/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.cpp
new file mode 100644
index 00000000000..069be02eb10
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.cpp
@@ -0,0 +1,17 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "ideal_service_layer_nodes_bundle.h"
+#include <vespa/vdslib/distribution/idealnodecalculator.h>
+
+namespace storage::distributor {
+
+IdealServiceLayerNodesBundle::IdealServiceLayerNodesBundle() noexcept
+ : _available_nodes(),
+ _available_nonretired_nodes(),
+ _available_nonretired_or_maintenance_nodes()
+{
+}
+
+IdealServiceLayerNodesBundle::~IdealServiceLayerNodesBundle() = default;
+
+}
diff --git a/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.h b/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.h
new file mode 100644
index 00000000000..2fd1bc8ad4b
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/ideal_service_layer_nodes_bundle.h
@@ -0,0 +1,28 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vector>
+#include <cstdint>
+
+namespace storage::distributor {
+
+/*
+ * Bundle of ideal service layer nodes for a bucket.
+ */
+class IdealServiceLayerNodesBundle {
+ std::vector<uint16_t> _available_nodes;
+ std::vector<uint16_t> _available_nonretired_nodes;
+ std::vector<uint16_t> _available_nonretired_or_maintenance_nodes;
+public:
+ IdealServiceLayerNodesBundle() noexcept;
+ ~IdealServiceLayerNodesBundle();
+
+ void set_available_nodes(std::vector<uint16_t> available_nodes) { _available_nodes = std::move(available_nodes); }
+ void set_available_nonretired_nodes(std::vector<uint16_t> available_nonretired_nodes) { _available_nonretired_nodes = std::move(available_nonretired_nodes); }
+ void set_available_nonretired_or_maintenance_nodes(std::vector<uint16_t> available_nonretired_or_maintenance_nodes) { _available_nonretired_or_maintenance_nodes = std::move(available_nonretired_or_maintenance_nodes); }
+ std::vector<uint16_t> get_available_nodes() const { return _available_nodes; }
+ std::vector<uint16_t> get_available_nonretired_nodes() const { return _available_nonretired_nodes; }
+ std::vector<uint16_t> get_available_nonretired_or_maintenance_nodes() const { return _available_nonretired_or_maintenance_nodes; }
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/idealstatemanager.h b/storage/src/vespa/storage/distributor/idealstatemanager.h
index 10f18a35952..b30d7b35a6d 100644
--- a/storage/src/vespa/storage/distributor/idealstatemanager.h
+++ b/storage/src/vespa/storage/distributor/idealstatemanager.h
@@ -78,10 +78,7 @@ public:
getBucketStatus(out);
}
- DistributorComponent& getDistributorComponent() {
- return _distributorComponent; }
- StorageComponent::LoadTypeSetSP getLoadTypes() {
- return _distributorComponent.getLoadTypes(); }
+ DistributorComponent& getDistributorComponent() { return _distributorComponent; }
DistributorBucketSpaceRepo &getBucketSpaceRepo() { return _bucketSpaceRepo; }
const DistributorBucketSpaceRepo &getBucketSpaceRepo() const { return _bucketSpaceRepo; }
diff --git a/storage/src/vespa/storage/distributor/idealstatemetricsset.h b/storage/src/vespa/storage/distributor/idealstatemetricsset.h
index 2679da17598..c1fb39bb50a 100644
--- a/storage/src/vespa/storage/distributor/idealstatemetricsset.h
+++ b/storage/src/vespa/storage/distributor/idealstatemetricsset.h
@@ -1,7 +1,9 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/countmetric.h>
#include <vespa/storage/distributor/operations/idealstate/idealstateoperation.h>
namespace storage {
diff --git a/storage/src/vespa/storage/distributor/messagetracker.cpp b/storage/src/vespa/storage/distributor/messagetracker.cpp
index c20b862597a..315af4f0c31 100644
--- a/storage/src/vespa/storage/distributor/messagetracker.cpp
+++ b/storage/src/vespa/storage/distributor/messagetracker.cpp
@@ -9,8 +9,8 @@ LOG_SETUP(".messagetracker");
namespace storage::distributor {
-MessageTracker::MessageTracker(const std::string& clusterName)
- : _clusterName(clusterName)
+MessageTracker::MessageTracker(const ClusterContext& cluster_context)
+ : _cluster_ctx(cluster_context)
{}
MessageTracker::~MessageTracker() = default;
@@ -19,8 +19,7 @@ void
MessageTracker::flushQueue(MessageSender& sender)
{
for (uint32_t i = 0; i < _commandQueue.size(); i++) {
- _commandQueue[i]._msg->setAddress(
- api::StorageMessageAddress(_clusterName, lib::NodeType::STORAGE, _commandQueue[i]._target));
+ _commandQueue[i]._msg->setAddress(api::StorageMessageAddress::create(_cluster_ctx.cluster_name_ptr(), lib::NodeType::STORAGE, _commandQueue[i]._target));
_sentMessages[_commandQueue[i]._msg->getMsgId()] = _commandQueue[i]._target;
sender.sendCommand(_commandQueue[i]._msg);
}
diff --git a/storage/src/vespa/storage/distributor/messagetracker.h b/storage/src/vespa/storage/distributor/messagetracker.h
index 11d8c36082e..ae33f6fc407 100644
--- a/storage/src/vespa/storage/distributor/messagetracker.h
+++ b/storage/src/vespa/storage/distributor/messagetracker.h
@@ -1,10 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
+#include <vespa/storage/common/cluster_context.h>
#include <vespa/storage/common/messagesender.h>
+#include <vespa/vespalib/stllike/string.h>
#include <vector>
#include <map>
-#include <string>
namespace storage::api {
class BucketCommand;
@@ -24,9 +25,11 @@ public:
uint16_t _target;
};
- MessageTracker(const std::string& clusterName);
+ MessageTracker(const ClusterContext &cluster_context);
MessageTracker(MessageTracker &&) = default;
MessageTracker & operator = (MessageTracker &&) = default;
+ MessageTracker(const MessageTracker &) = delete;
+ MessageTracker & operator = (const MessageTracker &) = delete;
~MessageTracker();
void queueCommand(std::shared_ptr<api::BucketCommand> msg, uint16_t target) {
@@ -50,7 +53,7 @@ protected:
// Keeps track of which node a message was sent to.
std::map<uint64_t, uint16_t> _sentMessages;
- std::string _clusterName;
+ const ClusterContext &_cluster_ctx;
};
}
diff --git a/storage/src/vespa/storage/distributor/operation_sequencer.cpp b/storage/src/vespa/storage/distributor/operation_sequencer.cpp
index d268028de78..234952c1e34 100644
--- a/storage/src/vespa/storage/distributor/operation_sequencer.cpp
+++ b/storage/src/vespa/storage/distributor/operation_sequencer.cpp
@@ -2,10 +2,10 @@
#include "operation_sequencer.h"
#include <vespa/document/base/documentid.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
#include <cassert>
-namespace storage {
-namespace distributor {
+namespace storage::distributor {
void SequencingHandle::release() {
if (valid()) {
@@ -14,27 +14,53 @@ void SequencingHandle::release() {
}
}
-OperationSequencer::OperationSequencer() {
-}
-
-OperationSequencer::~OperationSequencer() {
-}
+OperationSequencer::OperationSequencer() = default;
+OperationSequencer::~OperationSequencer() = default;
-SequencingHandle OperationSequencer::try_acquire(const document::DocumentId& id) {
+SequencingHandle OperationSequencer::try_acquire(document::BucketSpace bucket_space, const document::DocumentId& id) {
const document::GlobalId gid(id.getGlobalId());
+ if (!_active_buckets.empty()) {
+ auto doc_bucket_id = gid.convertToBucketId();
+ // TODO avoid O(n), but sub bucket resolving is tricky and we expect the number
+ // of locked buckets to be in the range of 0 to <very small number>.
+ for (const auto& entry : _active_buckets) {
+ if ((entry.first.getBucketSpace() == bucket_space)
+ && entry.first.getBucketId().contains(doc_bucket_id))
+ {
+ return SequencingHandle(SequencingHandle::BlockedByLockedBucket(entry.second));
+ }
+ }
+ }
const auto inserted = _active_gids.insert(gid);
if (inserted.second) {
return SequencingHandle(*this, gid);
} else {
- return SequencingHandle();
+ return SequencingHandle(SequencingHandle::BlockedByPendingOperation());
+ }
+}
+
+SequencingHandle OperationSequencer::try_acquire(const document::Bucket& bucket,
+ const vespalib::string& token) {
+ const auto inserted = _active_buckets.insert(std::make_pair(bucket, token));
+ if (inserted.second) {
+ return SequencingHandle(*this, bucket);
+ } else {
+ return SequencingHandle(SequencingHandle::BlockedByLockedBucket(inserted.first->second));
}
}
+bool OperationSequencer::is_blocked(const document::Bucket& bucket) const noexcept {
+ return (_active_buckets.find(bucket) != _active_buckets.end());
+}
+
void OperationSequencer::release(const SequencingHandle& handle) {
assert(handle.valid());
- _active_gids.erase(handle.gid());
+ if (handle.has_gid()) {
+ _active_gids.erase(handle.gid());
+ } else {
+ assert(handle.has_bucket());
+ _active_buckets.erase(handle.bucket());
+ }
}
-} // distributor
-} // storage
-
+} // storage::distributor
diff --git a/storage/src/vespa/storage/distributor/operation_sequencer.h b/storage/src/vespa/storage/distributor/operation_sequencer.h
index 7a523b61e53..72a6f547a0d 100644
--- a/storage/src/vespa/storage/distributor/operation_sequencer.h
+++ b/storage/src/vespa/storage/distributor/operation_sequencer.h
@@ -2,8 +2,11 @@
#pragma once
#include <vespa/document/base/globalid.h>
+#include <vespa/document/bucket/bucket.h>
#include <vespa/vespalib/stllike/hash_set.h>
+#include <vespa/vespalib/stllike/hash_map.h>
#include <utility>
+#include <variant>
namespace document {
class DocumentId;
@@ -15,19 +18,55 @@ class OperationSequencer;
/**
* Represents a move-only handle which effectively holds a guard for
- * allowing sequenced operations towards a particular document ID.
+ * allowing sequenced operations towards a particular document ID or
+ * bucket ID.
*
* Destroying a handle will implicitly release the guard, allowing
* new sequenced operations towards the ID.
*/
class SequencingHandle {
+public:
+ struct BlockedByPendingOperation {};
+ struct BlockedByLockedBucket {
+ vespalib::string lock_token;
+
+ BlockedByLockedBucket() = default;
+ explicit BlockedByLockedBucket(vespalib::stringref token) : lock_token(token) {}
+ };
+private:
OperationSequencer* _sequencer;
- document::GlobalId _gid;
+ using HandleVariant = std::variant<
+ document::Bucket,
+ document::GlobalId,
+ BlockedByPendingOperation,
+ BlockedByLockedBucket
+ >;
+ HandleVariant _handle;
public:
- SequencingHandle() noexcept : _sequencer(nullptr) {}
- SequencingHandle(OperationSequencer& sequencer, const document::GlobalId& gid)
- : _sequencer(&sequencer),
- _gid(gid)
+ SequencingHandle() noexcept
+ : _sequencer(nullptr),
+ _handle()
+ {}
+
+ explicit SequencingHandle(BlockedByPendingOperation blocked_by)
+ : _sequencer(nullptr),
+ _handle(blocked_by)
+ {}
+
+ explicit SequencingHandle(BlockedByLockedBucket blocked_by)
+ : _sequencer(nullptr),
+ _handle(std::move(blocked_by))
+ {}
+
+ SequencingHandle(OperationSequencer& sequencer, const document::GlobalId& gid) noexcept
+ : _sequencer(&sequencer),
+ _handle(gid)
+ {
+ }
+
+ SequencingHandle(OperationSequencer& sequencer, const document::Bucket& bucket)
+ : _sequencer(&sequencer),
+ _handle(bucket)
{
}
@@ -39,8 +78,8 @@ public:
SequencingHandle& operator=(const SequencingHandle&) = delete;
SequencingHandle(SequencingHandle&& rhs) noexcept
- : _sequencer(rhs._sequencer),
- _gid(rhs._gid)
+ : _sequencer(rhs._sequencer),
+ _handle(std::move(rhs._handle))
{
rhs._sequencer = nullptr;
}
@@ -48,13 +87,38 @@ public:
SequencingHandle& operator=(SequencingHandle&& rhs) noexcept {
if (&rhs != this) {
std::swap(_sequencer, rhs._sequencer);
- std::swap(_gid, rhs._gid);
+ std::swap(_handle, rhs._handle);
}
return *this;
}
- bool valid() const noexcept { return (_sequencer != nullptr); }
- const document::GlobalId& gid() const noexcept { return _gid; }
+ [[nodiscard]] bool valid() const noexcept { return (_sequencer != nullptr); }
+ [[nodiscard]] bool is_blocked() const noexcept {
+ return (std::holds_alternative<BlockedByPendingOperation>(_handle) ||
+ std::holds_alternative<BlockedByLockedBucket>(_handle));
+ }
+ [[nodiscard]] bool is_blocked_by_pending_operation() const noexcept {
+ return std::holds_alternative<BlockedByPendingOperation>(_handle);
+ }
+ [[nodiscard]] bool is_blocked_by_bucket() const noexcept {
+ return std::holds_alternative<BlockedByLockedBucket>(_handle);
+ }
+ [[nodiscard]] bool is_bucket_blocked_with_token(vespalib::stringref token) const noexcept {
+ return (std::holds_alternative<BlockedByLockedBucket>(_handle) &&
+ (std::get<BlockedByLockedBucket>(_handle).lock_token == token));
+ }
+ [[nodiscard]] bool has_bucket() const noexcept {
+ return std::holds_alternative<document::Bucket>(_handle);
+ }
+ const document::Bucket& bucket() const noexcept {
+ return std::get<document::Bucket>(_handle); // FIXME can actually throw
+ }
+ [[nodiscard]] bool has_gid() const noexcept {
+ return std::holds_alternative<document::GlobalId>(_handle);
+ }
+ const document::GlobalId& gid() const noexcept {
+ return std::get<document::GlobalId>(_handle); // FIXME can actually throw
+ }
void release();
};
@@ -67,8 +131,11 @@ public:
* can be acquired for that ID until the original handle has been destroyed.
*/
class OperationSequencer {
- using GidSet = vespalib::hash_set<document::GlobalId, document::GlobalId::hash>;
- GidSet _active_gids;
+ using GidSet = vespalib::hash_set<document::GlobalId, document::GlobalId::hash>;
+ using BucketLocks = vespalib::hash_map<document::Bucket, vespalib::string, document::Bucket::hash>;
+
+ GidSet _active_gids;
+ BucketLocks _active_buckets;
friend class SequencingHandle;
public:
@@ -76,8 +143,13 @@ public:
~OperationSequencer();
// Returns a handle with valid() == true iff no concurrent operations are
- // already active for `id`.
- SequencingHandle try_acquire(const document::DocumentId& id);
+ // already active for `id` _and_ the there are no active bucket locks for
+ // any bucket that may contain `id`.
+ SequencingHandle try_acquire(document::BucketSpace bucket_space, const document::DocumentId& id);
+
+ SequencingHandle try_acquire(const document::Bucket& bucket, const vespalib::string& token);
+
+ bool is_blocked(const document::Bucket&) const noexcept;
private:
void release(const SequencingHandle& handle);
};
diff --git a/storage/src/vespa/storage/distributor/operationowner.h b/storage/src/vespa/storage/distributor/operationowner.h
index bcd5a8419f5..5cd0fcb644d 100644
--- a/storage/src/vespa/storage/distributor/operationowner.h
+++ b/storage/src/vespa/storage/distributor/operationowner.h
@@ -40,14 +40,18 @@ public:
return _sender.getDistributorIndex();
}
- const std::string& getClusterName() const override {
- return _sender.getClusterName();
+ const ClusterContext & cluster_context() const override {
+ return _sender.cluster_context();
}
const PendingMessageTracker& getPendingMessageTracker() const override {
return _sender.getPendingMessageTracker();
}
+ const OperationSequencer& operation_sequencer() const noexcept override {
+ return _sender.operation_sequencer();
+ }
+
private:
OperationOwner& _owner;
DistributorMessageSender& _sender;
@@ -59,7 +63,7 @@ public:
: _sender(sender),
_clock(clock) {
}
- ~OperationOwner();
+ ~OperationOwner() override;
/**
Handles replies from storage, mapping from a message id to an operation.
@@ -82,6 +86,8 @@ public:
*/
void erase(api::StorageMessage::Id msgId);
+ [[nodiscard]] DistributorMessageSender& sender() noexcept { return _sender; }
+
void onClose();
uint32_t size() const { return _sentMessageMap.size(); }
std::string toString() const;
diff --git a/storage/src/vespa/storage/distributor/operations/external/CMakeLists.txt b/storage/src/vespa/storage/distributor/operations/external/CMakeLists.txt
index bb2992034f7..57a5a6cdde5 100644
--- a/storage/src/vespa/storage/distributor/operations/external/CMakeLists.txt
+++ b/storage/src/vespa/storage/distributor/operations/external/CMakeLists.txt
@@ -4,6 +4,7 @@ vespa_add_library(storage_distributoroperationexternal OBJECT
getoperation.cpp
newest_replica.cpp
putoperation.cpp
+ read_for_write_visitor_operation.cpp
removelocationoperation.cpp
removeoperation.cpp
statbucketlistoperation.cpp
diff --git a/storage/src/vespa/storage/distributor/operations/external/getoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/getoperation.cpp
index c72e5731a59..61bdcd4444d 100644
--- a/storage/src/vespa/storage/distributor/operations/external/getoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/getoperation.cpp
@@ -1,11 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "getoperation.h"
-#include <vespa/storage/distributor/distributorcomponent.h>
+#include <vespa/storage/distributor/distributor_node_context.h>
#include <vespa/storage/distributor/distributormetricsset.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/vdslib/state/nodestate.h>
#include <vespa/document/fieldvalue/document.h>
#include <vespa/storage/distributor/distributor_bucket_space.h>
+#include <cassert>
#include <vespa/log/log.h>
LOG_SETUP(".distributor.callback.doc.get");
@@ -44,21 +45,21 @@ GetOperation::GroupId::operator==(const GroupId& other) const
&& _node == other._node);
}
-GetOperation::GetOperation(DistributorComponent& manager,
+GetOperation::GetOperation(DistributorNodeContext& node_ctx,
const DistributorBucketSpace &bucketSpace,
std::shared_ptr<BucketDatabase::ReadGuard> read_guard,
std::shared_ptr<api::GetCommand> msg,
PersistenceOperationMetricSet& metric,
api::InternalReadConsistency desired_read_consistency)
: Operation(),
- _manager(manager),
+ _node_ctx(node_ctx),
_bucketSpace(bucketSpace),
_msg(std::move(msg)),
_returnCode(api::ReturnCode::OK),
_doc(),
_newest_replica(),
_metric(metric),
- _operationTimer(manager.getClock()),
+ _operationTimer(node_ctx.clock()),
_desired_read_consistency(desired_read_consistency),
_has_replica_inconsistency(false),
_any_replicas_failed(false)
@@ -76,7 +77,7 @@ GetOperation::onClose(DistributorMessageSender& sender)
bool
GetOperation::copyIsOnLocalNode(const BucketCopy& copy) const
{
- return (copy.getNode() == _manager.getIndex());
+ return (copy.getNode() == _node_ctx.node_index());
}
int
diff --git a/storage/src/vespa/storage/distributor/operations/external/getoperation.h b/storage/src/vespa/storage/distributor/operations/external/getoperation.h
index 546cf7a7543..cc6fd6680e0 100644
--- a/storage/src/vespa/storage/distributor/operations/external/getoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/getoperation.h
@@ -20,13 +20,13 @@ class PersistenceOperationMetricSet;
namespace distributor {
-class DistributorComponent;
+class DistributorNodeContext;
class DistributorBucketSpace;
class GetOperation : public Operation
{
public:
- GetOperation(DistributorComponent& manager,
+ GetOperation(DistributorNodeContext& node_ctx,
const DistributorBucketSpace &bucketSpace,
std::shared_ptr<BucketDatabase::ReadGuard> read_guard,
std::shared_ptr<api::GetCommand> msg,
@@ -79,7 +79,7 @@ private:
};
struct BucketChecksumGroup {
- explicit BucketChecksumGroup(const BucketCopy& c)
+ explicit BucketChecksumGroup(const BucketCopy& c) noexcept
: copy(c), sent(0), returnCode(api::ReturnCode::OK), to_node(UINT16_MAX), received(false)
{}
@@ -97,7 +97,7 @@ private:
// within that bucket.
std::map<GroupId, GroupVector> _responses;
- DistributorComponent& _manager;
+ DistributorNodeContext& _node_ctx;
const DistributorBucketSpace &_bucketSpace;
std::shared_ptr<api::GetCommand> _msg;
diff --git a/storage/src/vespa/storage/distributor/operations/external/putoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/putoperation.cpp
index e9348e8e8e1..7a247f6c524 100644
--- a/storage/src/vespa/storage/distributor/operations/external/putoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/putoperation.cpp
@@ -19,14 +19,16 @@ using namespace storage::distributor;
using namespace storage;
using document::BucketSpace;
-PutOperation::PutOperation(DistributorComponent& manager, DistributorBucketSpace &bucketSpace,
+PutOperation::PutOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::PutCommand> msg,
PersistenceOperationMetricSet& metric, SequencingHandle sequencingHandle)
: SequencedOperation(std::move(sequencingHandle)),
- _trackerInstance(metric, std::make_shared<api::PutReply>(*msg), manager, msg->getTimestamp()),
+ _trackerInstance(metric, std::make_shared<api::PutReply>(*msg), node_ctx, op_ctx, msg->getTimestamp()),
_tracker(_trackerInstance),
_msg(std::move(msg)),
- _manager(manager),
+ _op_ctx(op_ctx),
_bucketSpace(bucketSpace)
{
}
@@ -97,8 +99,8 @@ PutOperation::insertDatabaseEntryAndScheduleCreateBucket(const OperationTargetLi
// Copy is inserted with timestamp 0 such that any actual bucket info
// subsequently arriving from the storage node will always overwrite it.
BucketCopy copy(BucketCopy::recentlyCreatedCopy(0, copies[i].getNode().getIndex()));
- _manager.updateBucketDatabase(document::Bucket(originalCommand.getBucket().getBucketSpace(), lastBucket), copy,
- DatabaseUpdate::CREATE_IF_NONEXISTING);
+ _op_ctx.update_bucket_database(document::Bucket(originalCommand.getBucket().getBucketSpace(), lastBucket), copy,
+ DatabaseUpdate::CREATE_IF_NONEXISTING);
}
ActiveList active;
if (setOneActive) {
@@ -106,7 +108,7 @@ PutOperation::insertDatabaseEntryAndScheduleCreateBucket(const OperationTargetLi
(void) multipleBuckets;
BucketDatabase::Entry entry(_bucketSpace.getBucketDatabase().get(lastBucket));
std::vector<uint16_t> idealState(
- _bucketSpace.getDistribution().getIdealStorageNodes(_bucketSpace.getClusterState(), lastBucket, "ui"));
+ _bucketSpace.get_ideal_service_layer_nodes_bundle(lastBucket).get_available_nodes());
active = ActiveCopy::calculate(idealState, _bucketSpace.getDistribution(), entry);
LOG(debug, "Active copies for bucket %s: %s", entry.getBucketId().toString().c_str(), active.toString().c_str());
for (uint32_t i=0; i<active.size(); ++i) {
@@ -147,11 +149,11 @@ PutOperation::sendPutToBucketOnNode(document::BucketSpace bucketSpace, const doc
}
bool PutOperation::has_unavailable_targets_in_pending_state(const OperationTargetList& targets) const {
- auto* pending_state = _manager.getDistributor().pendingClusterStateOrNull(_msg->getBucket().getBucketSpace());
+ auto* pending_state = _op_ctx.pending_cluster_state_or_null(_msg->getBucket().getBucketSpace());
if (!pending_state) {
return false;
}
- const char* up_states = _manager.getDistributor().getStorageNodeUpStates();
+ const char* up_states = _op_ctx.storage_node_up_states();
return std::any_of(targets.begin(), targets.end(), [pending_state, up_states](const auto& target){
return !pending_state->getNodeState(target.getNode()).getState().oneOf(up_states);
});
@@ -171,7 +173,7 @@ PutOperation::onStart(DistributorMessageSender& sender)
bool up = false;
for (uint16_t i = 0; i < systemState.getNodeCount(lib::NodeType::STORAGE); i++) {
if (systemState.getNodeState(lib::Node(lib::NodeType::STORAGE, i))
- .getState().oneOf(_manager.getDistributor().getStorageNodeUpStates()))
+ .getState().oneOf(_op_ctx.storage_node_up_states()))
{
up = true;
}
@@ -180,19 +182,15 @@ PutOperation::onStart(DistributorMessageSender& sender)
if (up) {
std::vector<document::BucketId> bucketsToCheckForSplit;
- lib::IdealNodeCalculatorImpl idealNodeCalculator;
- idealNodeCalculator.setDistribution(_bucketSpace.getDistribution());
- idealNodeCalculator.setClusterState(_bucketSpace.getClusterState());
- OperationTargetResolverImpl targetResolver(_bucketSpace.getBucketDatabase(), idealNodeCalculator,
- _manager.getDistributor().getConfig().getMinimalBucketSplit(),
+ OperationTargetResolverImpl targetResolver(_bucketSpace, _bucketSpace.getBucketDatabase(),
+ _op_ctx.distributor_config().getMinimalBucketSplit(),
_bucketSpace.getDistribution().getRedundancy(),
_msg->getBucket().getBucketSpace());
OperationTargetList targets(targetResolver.getTargets(OperationTargetResolver::PUT, bid));
for (size_t i = 0; i < targets.size(); ++i) {
- if (_manager.getDistributor().getPendingMessageTracker().
- hasPendingMessage(targets[i].getNode().getIndex(), targets[i].getBucket(),
- api::MessageType::DELETEBUCKET_ID))
+ if (_op_ctx.has_pending_message(targets[i].getNode().getIndex(), targets[i].getBucket(),
+ api::MessageType::DELETEBUCKET_ID))
{
_tracker.fail(sender, api::ReturnCode(api::ReturnCode::BUCKET_DELETED,
"Bucket was being deleted while we got a PUT, failing operation to be safe"));
@@ -242,7 +240,7 @@ PutOperation::onStart(DistributorMessageSender& sender)
// Check whether buckets are large enough to be split.
// TODO(vekterli): only check entries for sendToExisting?
for (uint32_t i = 0; i < entries.size(); ++i) {
- _manager.getDistributor().checkBucketForSplit(_msg->getBucket().getBucketSpace(),
+ _op_ctx.send_inline_split_if_bucket_too_large(_msg->getBucket().getBucketSpace(),
entries[i], _msg->getPriority());
}
@@ -259,7 +257,7 @@ PutOperation::onStart(DistributorMessageSender& sender)
bool
PutOperation::shouldImplicitlyActivateReplica(const OperationTargetList& targets) const
{
- const auto& config(_manager.getDistributor().getConfig());
+ const auto& config(_op_ctx.distributor_config());
if (config.isBucketActivationDisabled()) {
return false;
}
diff --git a/storage/src/vespa/storage/distributor/operations/external/putoperation.h b/storage/src/vespa/storage/distributor/operations/external/putoperation.h
index 61149839ed1..6503a5ce438 100644
--- a/storage/src/vespa/storage/distributor/operations/external/putoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/putoperation.h
@@ -23,8 +23,11 @@ class OperationTargetList;
class PutOperation : public SequencedOperation
{
public:
- PutOperation(DistributorComponent& manager, DistributorBucketSpace &bucketSpace,
- std::shared_ptr<api::PutCommand> msg, PersistenceOperationMetricSet& metric,
+ PutOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorBucketSpace &bucketSpace,
+ std::shared_ptr<api::PutCommand> msg,
+ PersistenceOperationMetricSet& metric,
SequencingHandle sequencingHandle = SequencingHandle());
void onStart(DistributorMessageSender& sender) override;
@@ -51,7 +54,7 @@ private:
bool has_unavailable_targets_in_pending_state(const OperationTargetList& targets) const;
std::shared_ptr<api::PutCommand> _msg;
- DistributorComponent& _manager;
+ DistributorOperationContext& _op_ctx;
DistributorBucketSpace &_bucketSpace;
};
diff --git a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp
new file mode 100644
index 00000000000..04e64703c19
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp
@@ -0,0 +1,108 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "read_for_write_visitor_operation.h"
+#include "visitoroperation.h"
+#include <vespa/storage/distributor/distributormessagesender.h>
+#include <vespa/storage/distributor/pendingmessagetracker.h>
+#include <vespa/storage/distributor/operationowner.h>
+#include <vespa/storage/distributor/uuid_generator.h>
+#include <cassert>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".operations.external.read_for_write_visitor_operation");
+
+namespace storage::distributor {
+
+ReadForWriteVisitorOperationStarter::ReadForWriteVisitorOperationStarter(
+ std::shared_ptr<VisitorOperation> visitor_op,
+ OperationSequencer& operation_sequencer,
+ OperationOwner& stable_operation_owner,
+ PendingMessageTracker& message_tracker,
+ UuidGenerator& uuid_generator)
+ : _visitor_op(std::move(visitor_op)),
+ _operation_sequencer(operation_sequencer),
+ _stable_operation_owner(stable_operation_owner),
+ _message_tracker(message_tracker),
+ _uuid_generator(uuid_generator)
+{
+}
+
+ReadForWriteVisitorOperationStarter::~ReadForWriteVisitorOperationStarter() = default;
+
+void ReadForWriteVisitorOperationStarter::onClose(DistributorMessageSender& sender) {
+ _visitor_op->onClose(sender);
+}
+
+void ReadForWriteVisitorOperationStarter::onStart(DistributorMessageSender& sender) {
+ if (_visitor_op->verify_command_and_expand_buckets(sender)) {
+ assert(!_visitor_op->has_sent_reply());
+ auto maybe_bucket = _visitor_op->first_bucket_to_visit();
+ if (!maybe_bucket) {
+ LOG(debug, "No buckets found to visit, tagging visitor complete");
+ // No buckets to be found, start op to trigger immediate reply.
+ _visitor_op->start(sender, _startTime);
+ assert(_visitor_op->has_sent_reply());
+ return;
+ }
+ if (bucket_has_pending_merge(*maybe_bucket, sender.getPendingMessageTracker())) {
+ LOG(debug, "A merge is pending for bucket %s, failing visitor", maybe_bucket->toString().c_str());
+ _visitor_op->fail_with_merge_pending(sender);
+ return;
+ }
+ auto token = _uuid_generator.generate_uuid();
+ auto bucket_handle = _operation_sequencer.try_acquire(*maybe_bucket, token);
+ if (!bucket_handle.valid()) {
+ LOG(debug, "An operation is already pending for bucket %s, failing visitor",
+ maybe_bucket->toString().c_str());
+ _visitor_op->fail_with_bucket_already_locked(sender);
+ return;
+ }
+ _visitor_op->assign_put_lock_access_token(token);
+ LOG(debug, "Possibly deferring start of visitor for bucket %s, using lock token %s",
+ maybe_bucket->toString().c_str(), token.c_str());
+ _message_tracker.run_once_no_pending_for_bucket(
+ *maybe_bucket,
+ make_deferred_task([self = shared_from_this(), handle = std::move(bucket_handle)](TaskRunState state) mutable {
+ LOG(debug, "Starting deferred visitor");
+ self->_visitor_op->assign_bucket_lock_handle(std::move(handle));
+ if (state == TaskRunState::OK) {
+ // Once started, ownership of _visitor_op will pass to the Distributor's OperationOwner
+ self->_stable_operation_owner.start(self->_visitor_op, 120/*TODO*/);
+ } else {
+ self->_visitor_op->onClose(self->_stable_operation_owner.sender());
+ }
+ }));
+ } else {
+ LOG(debug, "Failed verification of visitor, responding immediately");
+ assert(_visitor_op->has_sent_reply());
+ }
+}
+
+void ReadForWriteVisitorOperationStarter::onReceive(DistributorMessageSender& sender,
+ const std::shared_ptr<api::StorageReply> & msg) {
+ _visitor_op->onReceive(sender, msg);
+}
+
+namespace {
+
+struct MergePendingChecker : PendingMessageTracker::Checker {
+ bool has_pending_merge = false;
+ bool check(uint32_t message_type, [[maybe_unused]] uint16_t node, [[maybe_unused]] uint8_t priority) override {
+ if (message_type == api::MessageType::MERGEBUCKET_ID) {
+ has_pending_merge = true;
+ }
+ return true;
+ }
+};
+
+}
+
+bool ReadForWriteVisitorOperationStarter::bucket_has_pending_merge(const document::Bucket& bucket,
+ const PendingMessageTracker& tracker) const {
+ MergePendingChecker merge_checker;
+ tracker.checkPendingMessages(bucket, merge_checker);
+ return merge_checker.has_pending_merge;
+}
+
+
+}
diff --git a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h
new file mode 100644
index 00000000000..e9391f9f133
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h
@@ -0,0 +1,53 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/storage/distributor/operations/operation.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
+#include <memory>
+
+namespace storage::distributor {
+
+class PendingMessageTracker;
+class VisitorOperation;
+class OperationOwner;
+class UuidGenerator;
+
+/**
+ * Operation starting indirection for a visitor operation that has the semantics
+ * of an exclusive bucket lock. Such operations can only resolve to a single
+ * super-bucket/sub-bucket pair and care should be taken to avoid starving client
+ * operations through long-running locks.
+ *
+ * Operation starting may be deferred to the PendingMessageTracker if there are
+ * pending operations to the sub-bucket when onStart is called. If so, the deferred
+ * operation start takes place automatically and immediately when all pending
+ * bucket operations have completed. These will be started in the context of the
+ * OperationOwner provided to the operation.
+ */
+class ReadForWriteVisitorOperationStarter
+ : public Operation,
+ public std::enable_shared_from_this<ReadForWriteVisitorOperationStarter>
+{
+ std::shared_ptr<VisitorOperation> _visitor_op;
+ OperationSequencer& _operation_sequencer;
+ OperationOwner& _stable_operation_owner;
+ PendingMessageTracker& _message_tracker;
+ UuidGenerator& _uuid_generator;
+public:
+ ReadForWriteVisitorOperationStarter(std::shared_ptr<VisitorOperation> visitor_op,
+ OperationSequencer& operation_sequencer,
+ OperationOwner& stable_operation_owner,
+ PendingMessageTracker& message_tracker,
+ UuidGenerator& uuid_generator);
+ ~ReadForWriteVisitorOperationStarter() override;
+
+ const char* getName() const override { return "ReadForWriteVisitorOperationStarter"; }
+ void onClose(DistributorMessageSender& sender) override;
+ void onStart(DistributorMessageSender& sender) override;
+ void onReceive(DistributorMessageSender& sender,
+ const std::shared_ptr<api::StorageReply> & msg) override;
+private:
+ bool bucket_has_pending_merge(const document::Bucket&, const PendingMessageTracker& tracker) const;
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.cpp
index 4c762cf4c23..c0d06171320 100644
--- a/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.cpp
@@ -16,18 +16,22 @@ using namespace storage;
using document::BucketSpace;
RemoveLocationOperation::RemoveLocationOperation(
- DistributorComponent& manager,
+ DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DocumentSelectionParser& parser,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::RemoveLocationCommand> msg,
PersistenceOperationMetricSet& metric)
: Operation(),
_trackerInstance(metric,
std::make_shared<api::RemoveLocationReply>(*msg),
- manager,
+ node_ctx,
+ op_ctx,
0),
_tracker(_trackerInstance),
_msg(std::move(msg)),
- _manager(manager),
+ _node_ctx(node_ctx),
+ _parser(parser),
_bucketSpace(bucketSpace)
{}
@@ -35,14 +39,13 @@ RemoveLocationOperation::~RemoveLocationOperation() = default;
int
RemoveLocationOperation::getBucketId(
- DistributorComponent& manager,
+ DistributorNodeContext& node_ctx,
+ DocumentSelectionParser& parser,
const api::RemoveLocationCommand& cmd, document::BucketId& bid)
{
- document::select::Parser parser(*manager.getTypeRepo()->documentTypeRepo, manager.getBucketIdFactory());
-
- document::BucketSelector bucketSel(manager.getBucketIdFactory());
+ document::BucketSelector bucketSel(node_ctx.bucket_id_factory());
std::unique_ptr<document::BucketSelector::BucketVector> exprResult
- = bucketSel.select(*parser.parse(cmd.getDocumentSelection()));
+ = bucketSel.select(*parser.parse_selection(cmd.getDocumentSelection()));
if (!exprResult.get()) {
return 0;
@@ -58,7 +61,7 @@ void
RemoveLocationOperation::onStart(DistributorMessageSender& sender)
{
document::BucketId bid;
- int count = getBucketId(_manager, *_msg, bid);
+ int count = getBucketId(_node_ctx, _parser, *_msg, bid);
if (count != 1) {
_tracker.fail(sender,
diff --git a/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.h b/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.h
index bad55497fa1..5cad43e02ca 100644
--- a/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/removelocationoperation.h
@@ -15,14 +15,17 @@ class DistributorBucketSpace;
class RemoveLocationOperation : public Operation
{
public:
- RemoveLocationOperation(DistributorComponent& manager,
+ RemoveLocationOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DocumentSelectionParser& parser,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::RemoveLocationCommand> msg,
PersistenceOperationMetricSet& metric);
~RemoveLocationOperation() override;
- static int getBucketId(DistributorComponent& manager,
+ static int getBucketId(DistributorNodeContext& node_ctx,
+ DocumentSelectionParser& parser,
const api::RemoveLocationCommand& cmd,
document::BucketId& id);
void onStart(DistributorMessageSender& sender) override;
@@ -36,7 +39,8 @@ private:
std::shared_ptr<api::RemoveLocationCommand> _msg;
- DistributorComponent& _manager;
+ DistributorNodeContext& _node_ctx;
+ DocumentSelectionParser& _parser;
DistributorBucketSpace &_bucketSpace;
};
diff --git a/storage/src/vespa/storage/distributor/operations/external/removeoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/removeoperation.cpp
index 9211e75ca80..6a7ea8b8f89 100644
--- a/storage/src/vespa/storage/distributor/operations/external/removeoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/removeoperation.cpp
@@ -11,7 +11,8 @@ using namespace storage::distributor;
using namespace storage;
using document::BucketSpace;
-RemoveOperation::RemoveOperation(DistributorComponent& manager,
+RemoveOperation::RemoveOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::RemoveCommand> msg,
PersistenceOperationMetricSet& metric,
@@ -19,10 +20,10 @@ RemoveOperation::RemoveOperation(DistributorComponent& manager,
: SequencedOperation(std::move(sequencingHandle)),
_trackerInstance(metric,
std::make_shared<api::RemoveReply>(*msg),
- manager, msg->getTimestamp()),
+ node_ctx, op_ctx, msg->getTimestamp()),
_tracker(_trackerInstance),
_msg(std::move(msg)),
- _manager(manager),
+ _node_ctx(node_ctx),
_bucketSpace(bucketSpace)
{
}
@@ -35,7 +36,7 @@ RemoveOperation::onStart(DistributorMessageSender& sender)
LOG(spam, "Started remove on document %s", _msg->getDocumentId().toString().c_str());
document::BucketId bucketId(
- _manager.getBucketIdFactory().getBucketId(
+ _node_ctx.bucket_id_factory().getBucketId(
_msg->getDocumentId()));
std::vector<BucketDatabase::Entry> entries;
diff --git a/storage/src/vespa/storage/distributor/operations/external/removeoperation.h b/storage/src/vespa/storage/distributor/operations/external/removeoperation.h
index 90e7ac94f0a..8dc88cb1d65 100644
--- a/storage/src/vespa/storage/distributor/operations/external/removeoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/removeoperation.h
@@ -15,7 +15,8 @@ class DistributorBucketSpace;
class RemoveOperation : public SequencedOperation
{
public:
- RemoveOperation(DistributorComponent& manager,
+ RemoveOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::RemoveCommand> msg,
PersistenceOperationMetricSet& metric,
@@ -35,7 +36,7 @@ private:
std::shared_ptr<api::RemoveCommand> _msg;
- DistributorComponent& _manager;
+ DistributorNodeContext& _node_ctx;
DistributorBucketSpace &_bucketSpace;
};
diff --git a/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.cpp
index 60c1137bd6d..ec8e4539ad1 100644
--- a/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.cpp
@@ -11,7 +11,6 @@ LOG_SETUP(".distributor.callback.statbucket");
namespace storage::distributor {
StatBucketOperation::StatBucketOperation(
- [[maybe_unused]] DistributorComponent& manager,
DistributorBucketSpace &bucketSpace,
const std::shared_ptr<api::StatBucketCommand> & cmd)
: Operation(),
diff --git a/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.h b/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.h
index 914e104943a..beb9e9c3445 100644
--- a/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/statbucketoperation.h
@@ -14,13 +14,12 @@ namespace storage::api { class StatBucketCommand; }
namespace storage::distributor {
-class DistributorComponent;
class DistributorBucketSpace;
class StatBucketOperation : public Operation
{
public:
- StatBucketOperation(DistributorComponent& manager, DistributorBucketSpace &bucketSpace,
+ StatBucketOperation(DistributorBucketSpace &bucketSpace,
const std::shared_ptr<api::StatBucketCommand> & cmd);
~StatBucketOperation();
diff --git a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
index d7dd0be7f4f..80e7942c68e 100644
--- a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp
@@ -5,6 +5,7 @@
#include "putoperation.h"
#include "updateoperation.h"
#include <vespa/storage/distributor/distributor_bucket_space.h>
+#include <vespa/storage/distributor/distributor_bucket_space_repo.h>
#include <vespa/storageapi/message/persistence.h>
#include <vespa/document/datatype/documenttype.h>
#include <vespa/document/fieldvalue/document.h>
@@ -20,20 +21,26 @@ using document::BucketSpace;
namespace storage::distributor {
+
+
TwoPhaseUpdateOperation::TwoPhaseUpdateOperation(
- DistributorComponent& manager,
+ DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DocumentSelectionParser& parser,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::UpdateCommand> msg,
DistributorMetricSet& metrics,
SequencingHandle sequencingHandle)
: SequencedOperation(std::move(sequencingHandle)),
- _updateMetric(metrics.updates[msg->getLoadType()]),
- _putMetric(metrics.update_puts[msg->getLoadType()]),
- _getMetric(metrics.update_gets[msg->getLoadType()]),
- _metadata_get_metrics(metrics.update_metadata_gets[msg->getLoadType()]),
+ _updateMetric(metrics.updates),
+ _putMetric(metrics.update_puts),
+ _getMetric(metrics.update_gets),
+ _metadata_get_metrics(metrics.update_metadata_gets),
_updateCmd(std::move(msg)),
_updateReply(),
- _manager(manager),
+ _node_ctx(node_ctx),
+ _op_ctx(op_ctx),
+ _parser(parser),
_bucketSpace(bucketSpace),
_sendState(SendState::NONE_SENT),
_mode(Mode::FAST_PATH),
@@ -41,7 +48,7 @@ TwoPhaseUpdateOperation::TwoPhaseUpdateOperation(
_single_get_latency_timer(),
_fast_path_repair_source_node(0xffff),
_use_initial_cheap_metadata_fetch_phase(
- _manager.getDistributor().getConfig().enable_metadata_only_fetch_phase_for_inconsistent_updates()),
+ _op_ctx.distributor_config().enable_metadata_only_fetch_phase_for_inconsistent_updates()),
_replySent(false)
{
document::BucketIdFactory idFactory;
@@ -74,13 +81,17 @@ struct IntermediateMessageSender : DistributorMessageSender {
return forward.getDistributorIndex();
}
- const std::string& getClusterName() const override {
- return forward.getClusterName();
+ const ClusterContext & cluster_context() const override {
+ return forward.cluster_context();
}
const PendingMessageTracker& getPendingMessageTracker() const override {
return forward.getPendingMessageTracker();
}
+
+ const OperationSequencer& operation_sequencer() const noexcept override {
+ return forward.operation_sequencer();
+ }
};
IntermediateMessageSender::IntermediateMessageSender(SentMessageMap& mm,
@@ -148,13 +159,18 @@ TwoPhaseUpdateOperation::sendReplyWithResult(
sendReply(sender, _updateReply);
}
-bool
-TwoPhaseUpdateOperation::isFastPathPossible() const
+std::vector<BucketDatabase::Entry>
+TwoPhaseUpdateOperation::get_bucket_database_entries() const
{
- // Fast path iff bucket exists AND is consistent (split and copies).
std::vector<BucketDatabase::Entry> entries;
_bucketSpace.getBucketDatabase().getParents(_updateDocBucketId, entries);
+ return entries;
+}
+bool
+TwoPhaseUpdateOperation::isFastPathPossible(const std::vector<BucketDatabase::Entry>& entries) const
+{
+ // Fast path iff bucket exists AND is consistent (split and copies).
if (entries.size() != 1) {
return false;
}
@@ -162,14 +178,15 @@ TwoPhaseUpdateOperation::isFastPathPossible() const
}
void
-TwoPhaseUpdateOperation::startFastPathUpdate(DistributorMessageSender& sender)
+TwoPhaseUpdateOperation::startFastPathUpdate(DistributorMessageSender& sender, std::vector<BucketDatabase::Entry> entries)
{
_mode = Mode::FAST_PATH;
LOG(debug, "Update(%s) fast path: sending Update commands", update_doc_id().c_str());
- auto updateOperation = std::make_shared<UpdateOperation>(_manager, _bucketSpace, _updateCmd, _updateMetric);
+ auto updateOperation = std::make_shared<UpdateOperation>
+ (_node_ctx, _op_ctx, _bucketSpace, _updateCmd, std::move(entries), _updateMetric);
UpdateOperation & op = *updateOperation;
IntermediateMessageSender intermediate(_sentMessageMap, std::move(updateOperation), sender);
- op.start(intermediate, _manager.getClock().getTimeInMillis());
+ op.start(intermediate, _node_ctx.clock().getTimeInMillis());
transitionTo(SendState::UPDATES_SENT);
if (intermediate._reply.get()) {
@@ -185,7 +202,7 @@ TwoPhaseUpdateOperation::startSafePathUpdate(DistributorMessageSender& sender)
GetOperation& op = *get_operation;
IntermediateMessageSender intermediate(_sentMessageMap, std::move(get_operation), sender);
_replicas_at_get_send_time = op.replicas_in_db(); // Populated at construction time, not at start()-time
- op.start(intermediate, _manager.getClock().getTimeInMillis());
+ op.start(intermediate, _node_ctx.clock().getTimeInMillis());
transitionTo(_use_initial_cheap_metadata_fetch_phase
? SendState::METADATA_GETS_SENT
@@ -221,14 +238,15 @@ TwoPhaseUpdateOperation::create_initial_safe_path_get_operation() {
update_doc_id().c_str(), field_set, api::to_string(read_consistency));
auto& get_metric = (_use_initial_cheap_metadata_fetch_phase ? _metadata_get_metrics : _getMetric);
return std::make_shared<GetOperation>(
- _manager, _bucketSpace, _bucketSpace.getBucketDatabase().acquire_read_guard(),
+ _node_ctx, _bucketSpace, _bucketSpace.getBucketDatabase().acquire_read_guard(),
get, get_metric, read_consistency);
}
void
TwoPhaseUpdateOperation::onStart(DistributorMessageSender& sender) {
- if (isFastPathPossible()) {
- startFastPathUpdate(sender);
+ auto entries = get_bucket_database_entries();
+ if (isFastPathPossible(entries)) {
+ startFastPathUpdate(sender, std::move(entries));
} else {
startSafePathUpdate(sender);
}
@@ -245,8 +263,8 @@ TwoPhaseUpdateOperation::onStart(DistributorMessageSender& sender) {
bool
TwoPhaseUpdateOperation::lostBucketOwnershipBetweenPhases() const
{
- document::Bucket updateDocBucket(_updateCmd->getBucket().getBucketSpace(), _updateDocBucketId);
- BucketOwnership bo(_manager.checkOwnershipInPendingAndCurrentState(updateDocBucket));
+ auto &bucket_space(_op_ctx.bucket_space_repo().get(_updateCmd->getBucket().getBucketSpace()));
+ BucketOwnership bo(bucket_space.check_ownership_in_pending_and_current_state(_updateDocBucketId));
return !bo.isOwned();
}
@@ -271,10 +289,10 @@ TwoPhaseUpdateOperation::schedulePutsWithUpdatedDocument(std::shared_ptr<documen
document::Bucket bucket(_updateCmd->getBucket().getBucketSpace(), document::BucketId(0));
auto put = std::make_shared<api::PutCommand>(bucket, doc, putTimestamp);
copyMessageSettings(*_updateCmd, *put);
- auto putOperation = std::make_shared<PutOperation>(_manager, _bucketSpace, std::move(put), _putMetric);
+ auto putOperation = std::make_shared<PutOperation>(_node_ctx, _op_ctx, _bucketSpace, std::move(put), _putMetric);
PutOperation & op = *putOperation;
IntermediateMessageSender intermediate(_sentMessageMap, std::move(putOperation), sender);
- op.start(intermediate, _manager.getClock().getTimeInMillis());
+ op.start(intermediate, _node_ctx.clock().getTimeInMillis());
transitionTo(SendState::PUTS_SENT);
LOG(debug, "Update(%s): sending Puts at timestamp %" PRIu64, update_doc_id().c_str(), putTimestamp);
@@ -317,7 +335,7 @@ TwoPhaseUpdateOperation::handleFastPathReceive(DistributorMessageSender& sender,
sendReplyWithResult(sender, api::ReturnCode(api::ReturnCode::INTERNAL_FAILURE, ""));
return;
}
- schedulePutsWithUpdatedDocument(getReply.getDocument(), _manager.getUniqueTimestamp(), sender);
+ schedulePutsWithUpdatedDocument(getReply.getDocument(), _op_ctx.generate_unique_timestamp(), sender);
return;
}
@@ -466,7 +484,7 @@ void TwoPhaseUpdateOperation::handle_safe_path_received_metadata_get(
// Note that this timestamp may be for a tombstone (remove) entry, in which case
// conditional create-if-missing behavior kicks in as usual.
// TODO avoid sending the Get at all if the newest replica is marked as a tombstone.
- _single_get_latency_timer.emplace(_manager.getClock());
+ _single_get_latency_timer.emplace(_node_ctx.clock());
document::Bucket bucket(_updateCmd->getBucket().getBucketSpace(), newest_replica->bucket_id);
LOG(debug, "Update(%s): sending single payload Get to %s on node %u (had timestamp %" PRIu64 ")",
update_doc_id().c_str(), bucket.toString().c_str(),
@@ -497,7 +515,7 @@ TwoPhaseUpdateOperation::handleSafePathReceivedGet(DistributorMessageSender& sen
}
document::Document::SP docToUpdate;
- api::Timestamp putTimestamp = _manager.getUniqueTimestamp();
+ api::Timestamp putTimestamp = _op_ctx.generate_unique_timestamp();
if (reply.getDocument().get()) {
api::Timestamp receivedTimestamp = reply.getLastModifiedTimestamp();
@@ -532,7 +550,7 @@ TwoPhaseUpdateOperation::handleSafePathReceivedGet(DistributorMessageSender& sen
}
bool TwoPhaseUpdateOperation::may_restart_with_fast_path(const api::GetReply& reply) {
- return (_manager.getDistributor().getConfig().update_fast_path_restart_enabled() &&
+ return (_op_ctx.distributor_config().update_fast_path_restart_enabled() &&
!_replicas_at_get_send_time.empty() && // To ensure we send CreateBucket+Put if no replicas exist.
reply.had_consistent_replicas() &&
replica_set_unchanged_after_get_operation());
@@ -564,7 +582,7 @@ void TwoPhaseUpdateOperation::restart_with_fast_path_due_to_consistent_get_times
// Must not be any other messages in flight, or we might mis-interpret them when we
// have switched back to fast-path mode.
assert(_sentMessageMap.empty());
- startFastPathUpdate(sender);
+ startFastPathUpdate(sender, {});
}
bool
@@ -575,10 +593,9 @@ TwoPhaseUpdateOperation::processAndMatchTasCondition(DistributorMessageSender& s
return true; // No condition; nothing to do here.
}
- document::select::Parser parser(*_manager.getTypeRepo()->documentTypeRepo, _manager.getBucketIdFactory());
std::unique_ptr<document::select::Node> selection;
try {
- selection = parser.parse(_updateCmd->getCondition().getSelection());
+ selection = _parser.parse_selection(_updateCmd->getCondition().getSelection());
} catch (const document::select::ParsingFailedException & e) {
sendReplyWithResult(sender, api::ReturnCode(
api::ReturnCode::ILLEGAL_PARAMETERS,
diff --git a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.h b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.h
index a98fbe98c38..af45932b530 100644
--- a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.h
@@ -55,7 +55,9 @@ class GetOperation;
class TwoPhaseUpdateOperation : public SequencedOperation
{
public:
- TwoPhaseUpdateOperation(DistributorComponent& manager,
+ TwoPhaseUpdateOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DocumentSelectionParser& parser,
DistributorBucketSpace &bucketSpace,
std::shared_ptr<api::UpdateCommand> msg,
DistributorMetricSet& metrics,
@@ -96,8 +98,9 @@ private:
void sendReplyWithResult(DistributorMessageSender&, const api::ReturnCode&);
void ensureUpdateReplyCreated();
- bool isFastPathPossible() const;
- void startFastPathUpdate(DistributorMessageSender&);
+ std::vector<BucketDatabase::Entry> get_bucket_database_entries() const;
+ bool isFastPathPossible(const std::vector<BucketDatabase::Entry>& entries) const;
+ void startFastPathUpdate(DistributorMessageSender& sender, std::vector<BucketDatabase::Entry> entries);
void startSafePathUpdate(DistributorMessageSender&);
bool lostBucketOwnershipBetweenPhases() const;
void sendLostOwnershipTransientErrorReply(DistributorMessageSender&);
@@ -141,7 +144,9 @@ private:
PersistenceOperationMetricSet& _metadata_get_metrics;
std::shared_ptr<api::UpdateCommand> _updateCmd;
std::shared_ptr<api::StorageReply> _updateReply;
- DistributorComponent& _manager;
+ DistributorNodeContext& _node_ctx;
+ DistributorOperationContext& _op_ctx;
+ DocumentSelectionParser& _parser;
DistributorBucketSpace &_bucketSpace;
SentMessageMap _sentMessageMap;
SendState _sendState;
diff --git a/storage/src/vespa/storage/distributor/operations/external/updateoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/updateoperation.cpp
index 3cf311936ea..f0cd53c15f5 100644
--- a/storage/src/vespa/storage/distributor/operations/external/updateoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/updateoperation.cpp
@@ -17,18 +17,21 @@ using document::BucketSpace;
namespace storage::distributor {
-UpdateOperation::UpdateOperation(DistributorComponent& manager,
- DistributorBucketSpace &bucketSpace,
- const std::shared_ptr<api::UpdateCommand> & msg,
+UpdateOperation::UpdateOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorBucketSpace& bucketSpace,
+ const std::shared_ptr<api::UpdateCommand>& msg,
+ std::vector<BucketDatabase::Entry> entries,
UpdateMetricSet& metric)
: Operation(),
_trackerInstance(metric, std::make_shared<api::UpdateReply>(*msg),
- manager, msg->getTimestamp()),
+ node_ctx, op_ctx, msg->getTimestamp()),
_tracker(_trackerInstance),
_msg(msg),
+ _entries(std::move(entries)),
_new_timestamp(_msg->getTimestamp()),
_is_auto_create_update(_msg->getUpdate()->getCreateIfNonExistent()),
- _manager(manager),
+ _node_ctx(node_ctx),
_bucketSpace(bucketSpace),
_newestTimestampLocation(),
_infoAtSendTime(),
@@ -60,7 +63,7 @@ UpdateOperation::onStart(DistributorMessageSender& sender)
{
LOG(debug, "Received UPDATE %s for bucket %" PRIx64,
_msg->getDocumentId().toString().c_str(),
- _manager.getBucketIdFactory().getBucketId(
+ _node_ctx.bucket_id_factory().getBucketId(
_msg->getDocumentId()).getRawId());
// Don't do anything if all nodes are down.
@@ -72,14 +75,12 @@ UpdateOperation::onStart(DistributorMessageSender& sender)
return;
}
- document::BucketId bucketId(
- _manager.getBucketIdFactory().getBucketId(
- _msg->getDocumentId()));
-
- std::vector<BucketDatabase::Entry> entries;
- _bucketSpace.getBucketDatabase().getParents(bucketId, entries);
+ if (_entries.empty()) {
+ document::BucketId bucketId(_node_ctx.bucket_id_factory().getBucketId(_msg->getDocumentId()));
+ _bucketSpace.getBucketDatabase().getParents(bucketId, _entries);
+ }
- if (entries.empty()) {
+ if (_entries.empty()) {
_tracker.fail(sender,
api::ReturnCode(api::ReturnCode::OK,
"No buckets found for given document update"));
@@ -88,14 +89,14 @@ UpdateOperation::onStart(DistributorMessageSender& sender)
// An UpdateOperation should only be started iff all replicas are consistent
// with each other, so sampling a single replica should be equal to sampling them all.
- assert(entries[0].getBucketInfo().getNodeCount() > 0); // Empty buckets are not allowed
- _infoAtSendTime = entries[0].getBucketInfo().getNodeRef(0).getBucketInfo();
+ assert(_entries[0].getBucketInfo().getNodeCount() > 0); // Empty buckets are not allowed
+ _infoAtSendTime = _entries[0].getBucketInfo().getNodeRef(0).getBucketInfo();
// FIXME(vekterli): this loop will happily update all replicas in the
// bucket sub-tree, but there is nothing here at all which will fail the
// update if we cannot satisfy a desired replication level (not even for
// n-of-m operations).
- for (const auto& entry : entries) {
+ for (const auto& entry : _entries) {
LOG(spam, "Found bucket %s", entry.toString().c_str());
const std::vector<uint16_t>& nodes = entry->getNodes();
diff --git a/storage/src/vespa/storage/distributor/operations/external/updateoperation.h b/storage/src/vespa/storage/distributor/operations/external/updateoperation.h
index 2e69a52a644..9f0796e71d2 100644
--- a/storage/src/vespa/storage/distributor/operations/external/updateoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/updateoperation.h
@@ -23,9 +23,11 @@ class DistributorBucketSpace;
class UpdateOperation : public Operation
{
public:
- UpdateOperation(DistributorComponent& manager,
- DistributorBucketSpace &bucketSpace,
- const std::shared_ptr<api::UpdateCommand> & msg,
+ UpdateOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
+ DistributorBucketSpace& bucketSpace,
+ const std::shared_ptr<api::UpdateCommand>& msg,
+ std::vector<BucketDatabase::Entry> entries,
UpdateMetricSet& metric);
void onStart(DistributorMessageSender& sender) override;
@@ -42,10 +44,11 @@ private:
PersistenceMessageTrackerImpl _trackerInstance;
PersistenceMessageTracker& _tracker;
std::shared_ptr<api::UpdateCommand> _msg;
+ std::vector<BucketDatabase::Entry> _entries;
const api::Timestamp _new_timestamp;
const bool _is_auto_create_update;
- DistributorComponent& _manager;
+ DistributorNodeContext& _node_ctx;
DistributorBucketSpace &_bucketSpace;
std::pair<document::BucketId, uint16_t> _newestTimestampLocation;
api::BucketInfo _infoAtSendTime; // Should be same across all replicas
diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
index 0868f18e88a..292a3a5fc0b 100644
--- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "visitoroperation.h"
+#include <vespa/storage/common/reindexing_constants.h>
#include <vespa/storage/storageserver/storagemetricsset.h>
#include <vespa/storage/distributor/distributor.h>
#include <vespa/storage/distributor/distributor_bucket_space.h>
@@ -43,21 +44,44 @@ VisitorOperation::BucketInfo::toString() const
VisitorOperation::SuperBucketInfo::~SuperBucketInfo() = default;
+namespace {
+
+[[nodiscard]] bool
+matches_visitor_library(vespalib::stringref input, vespalib::stringref expected)
+{
+ if (input.size() != expected.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < input.size(); ++i) {
+ if (static_cast<char>(std::tolower(static_cast<unsigned char>(input[i]))) != expected[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
VisitorOperation::VisitorOperation(
- DistributorComponent& owner,
+ DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
DistributorBucketSpace &bucketSpace,
const api::CreateVisitorCommand::SP& m,
const Config& config,
VisitorMetricSet& metrics)
: Operation(),
- _owner(owner),
+ _node_ctx(node_ctx),
+ _op_ctx(op_ctx),
_bucketSpace(bucketSpace),
_msg(m),
- _sentReply(false),
_config(config),
_metrics(metrics),
_trace(TRACE_SOFT_MEMORY_LIMIT),
- _operationTimer(owner.getClock())
+ _operationTimer(_node_ctx.clock()),
+ _bucket_lock(), // Initially no lock is held
+ _sentReply(false),
+ _verified_and_expanded(false),
+ _is_read_for_write(matches_visitor_library(_msg->getLibraryName(), "reindexingvisitor"))
{
const std::vector<document::BucketId>& buckets = m->getBuckets();
@@ -72,7 +96,7 @@ VisitorOperation::VisitorOperation(
_fromTime = m->getFromTime();
_toTime = m->getToTime();
if (_toTime == 0) {
- _toTime = owner.getUniqueTimestamp();
+ _toTime = _op_ctx.generate_unique_timestamp();
}
}
@@ -243,7 +267,7 @@ VisitorOperation::verifyVisitorDistributionBitCount(
const document::BucketId& bid)
{
const lib::ClusterState& clusterState = _bucketSpace.getClusterState();
- if (_msg->getDocumentSelection().length() == 0
+ if (_msg->getDocumentSelection().empty()
&& bid.getUsedBits() != clusterState.getDistributionBitCount())
{
LOG(debug,
@@ -264,7 +288,7 @@ VisitorOperation::verifyDistributorIsNotDown(const lib::ClusterState& state)
{
const lib::NodeState& ownState(
state.getNodeState(
- lib::Node(lib::NodeType::DISTRIBUTOR, _owner.getIndex())));
+ lib::Node(lib::NodeType::DISTRIBUTOR, _node_ctx.node_index())));
if (!ownState.getState().oneOf("ui")) {
throw VisitorVerificationException(
api::ReturnCode::ABORTED, "Distributor is shutting down");
@@ -274,8 +298,8 @@ VisitorOperation::verifyDistributorIsNotDown(const lib::ClusterState& state)
void
VisitorOperation::verifyDistributorOwnsBucket(const document::BucketId& bid)
{
- document::Bucket bucket(_msg->getBucketSpace(), bid);
- BucketOwnership bo(_owner.checkOwnershipInPendingAndCurrentState(bucket));
+ auto &bucket_space(_op_ctx.bucket_space_repo().get(_msg->getBucketSpace()));
+ BucketOwnership bo(bucket_space.check_ownership_in_pending_and_current_state(bid));
if (!bo.isOwned()) {
verifyDistributorIsNotDown(bo.getNonOwnedState());
std::string systemStateStr = bo.getNonOwnedState().toString();
@@ -283,7 +307,7 @@ VisitorOperation::verifyDistributorOwnsBucket(const document::BucketId& bid)
"Bucket %s is not owned by distributor %d, "
"sending back system state '%s'",
bid.toString().c_str(),
- _owner.getIndex(),
+ _node_ctx.node_index(),
bo.getNonOwnedState().toString().c_str());
throw VisitorVerificationException(
api::ReturnCode::WRONG_DISTRIBUTION,
@@ -330,6 +354,13 @@ VisitorOperation::verifyCreateVisitorCommand(DistributorMessageSender& sender)
verifyOperationContainsBuckets();
verifyOperationHasSuperbucketAndProgress();
verifyOperationSentToCorrectDistributor();
+ // TODO wrap and test
+ if (is_read_for_write() && (_msg->getMaxBucketsPerVisitor() != 1)) {
+ throw VisitorVerificationException(
+ api::ReturnCode::ILLEGAL_PARAMETERS,
+ vespalib::make_string("Read-for-write visitors can only have 1 max pending bucket, was %u",
+ _msg->getMaxBucketsPerVisitor()));
+ }
return true;
} catch (const VisitorVerificationException& e) {
LOG(debug,
@@ -380,14 +411,6 @@ VisitorOperation::pickBucketsToVisit(const std::vector<BucketDatabase::Entry>& b
}
bool
-VisitorOperation::expandBucketAll()
-{
- std::vector<BucketDatabase::Entry> entries;
- _bucketSpace.getBucketDatabase().getAll(_superBucket.bid, entries);
- return pickBucketsToVisit(entries);
-}
-
-bool
VisitorOperation::expandBucketContaining()
{
std::vector<BucketDatabase::Entry> entries;
@@ -566,13 +589,24 @@ VisitorOperation::pickTargetNode(
void
VisitorOperation::onStart(DistributorMessageSender& sender)
{
- if (!verifyCreateVisitorCommand(sender)) {
- return;
+ if (!_verified_and_expanded) {
+ if (!verify_command_and_expand_buckets(sender)) {
+ return;
+ }
}
+ startNewVisitors(sender);
+}
+bool
+VisitorOperation::verify_command_and_expand_buckets(DistributorMessageSender& sender)
+{
+ assert(!_verified_and_expanded);
+ _verified_and_expanded = true;
+ if (!verifyCreateVisitorCommand(sender)) {
+ return false;
+ }
expandBucket();
-
- startNewVisitors(sender);
+ return true;
}
bool
@@ -662,9 +696,7 @@ bool
VisitorOperation::bucketIsValidAndConsistent(const BucketDatabase::Entry& entry) const
{
if (!entry.valid()) {
- LOG(debug,
- "Bucket %s does not exist anymore",
- entry.toString().c_str());
+ LOG(debug, "Bucket %s does not exist anymore", entry.toString().c_str());
return false;
}
assert(entry->getNodeCount() != 0);
@@ -696,10 +728,8 @@ VisitorOperation::assignBucketsToNodes(NodeToBucketsMap& nodeToBucketsMap)
BucketInfo& bucketInfo(subIter->second);
if (shouldSkipBucket(bucketInfo)) {
- LOG(spam,
- "Skipping subbucket %s because it is done/active/failed: %s",
- subBucket.toString().c_str(),
- bucketInfo.toString().c_str());
+ LOG(spam, "Skipping subbucket %s because it is done/active/failed: %s",
+ subBucket.toString().c_str(), bucketInfo.toString().c_str());
continue;
}
@@ -721,25 +751,13 @@ VisitorOperation::assignBucketsToNodes(NodeToBucketsMap& nodeToBucketsMap)
}
int
-VisitorOperation::getNumVisitorsToSendForNode(uint16_t node,
- uint32_t totalBucketsOnNode) const
+VisitorOperation::getNumVisitorsToSendForNode(uint16_t node, uint32_t totalBucketsOnNode) const
{
- int visitorCountAvailable(
- std::max(1, static_cast<int>(_config.maxVisitorsPerNodePerVisitor -
- _activeNodes[node])));
-
- int visitorCountMinBucketsPerVisitor(
- std::max(1, static_cast<int>(totalBucketsOnNode / _config.minBucketsPerVisitor)));
-
- int visitorCount(
- std::min(visitorCountAvailable, visitorCountMinBucketsPerVisitor));
- LOG(spam,
- "Will send %d visitors to node %d (available=%d, "
- "buckets restricted=%d)",
- visitorCount,
- node,
- visitorCountAvailable,
- visitorCountMinBucketsPerVisitor);
+ int visitorCountAvailable(std::max(1, static_cast<int>(_config.maxVisitorsPerNodePerVisitor - _activeNodes[node])));
+ int visitorCountMinBucketsPerVisitor(std::max(1, static_cast<int>(totalBucketsOnNode / _config.minBucketsPerVisitor)));
+ int visitorCount(std::min(visitorCountAvailable, visitorCountMinBucketsPerVisitor));
+ LOG(spam, "Will send %d visitors to node %d (available=%d, buckets restricted=%d)",
+ visitorCount, node, visitorCountAvailable, visitorCountMinBucketsPerVisitor);
return visitorCount;
}
@@ -749,31 +767,24 @@ VisitorOperation::sendStorageVisitors(const NodeToBucketsMap& nodeToBucketsMap,
DistributorMessageSender& sender)
{
bool visitorsSent = false;
- for (NodeToBucketsMap::const_iterator iter = nodeToBucketsMap.begin();
- iter != nodeToBucketsMap.end();
- ++iter) {
- if (iter->second.size() > 0) {
- int visitorCount(getNumVisitorsToSendForNode(iter->first, iter->second.size()));
+ for (const auto & entry : nodeToBucketsMap ) {
+ if (entry.second.size() > 0) {
+ int visitorCount(getNumVisitorsToSendForNode(entry.first, entry.second.size()));
std::vector<std::vector<document::BucketId> > bucketsVector(visitorCount);
- for (unsigned int i = 0; i < iter->second.size(); i++) {
- bucketsVector[i % visitorCount].push_back(iter->second[i]);
+ for (unsigned int i = 0; i < entry.second.size(); i++) {
+ bucketsVector[i % visitorCount].push_back(entry.second[i]);
}
for (int i = 0; i < visitorCount; i++) {
- LOG(spam,
- "Send visitor to node %d with %u buckets",
- iter->first,
- (unsigned int)bucketsVector[i].size());
+ LOG(spam, "Send visitor to node %d with %u buckets",
+ entry.first, (unsigned int)bucketsVector[i].size());
- sendStorageVisitor(iter->first,
- bucketsVector[i],
- _msg->getMaximumPendingReplyCount(),
- sender);
+ sendStorageVisitor(entry.first, bucketsVector[i], _msg->getMaximumPendingReplyCount(), sender);
visitorsSent = true;
}
} else {
- LOG(spam, "Do not send visitor to node %d, no buckets", iter->first);
+ LOG(spam, "Do not send visitor to node %d, no buckets", entry.first);
}
}
return visitorsSent;
@@ -791,7 +802,8 @@ VisitorOperation::sendStorageVisitor(uint16_t node,
uint32_t pending,
DistributorMessageSender& sender)
{
- api::CreateVisitorCommand::SP cmd(new api::CreateVisitorCommand(*_msg));
+ // TODO rewrite to not use copy ctor and remove wonky StorageCommand copy ctor impl
+ auto cmd = std::make_shared<api::CreateVisitorCommand>(*_msg);
cmd->getBuckets() = buckets;
// TODO: Send this through distributor - do after moving visitor stuff from docapi to storageprotocol
@@ -800,12 +812,11 @@ VisitorOperation::sendStorageVisitor(uint16_t node,
vespalib::asciistream os;
os << _msg->getInstanceId() << '-'
- << _owner.getIndex() << '-' << cmd->getMsgId();
+ << _node_ctx.node_index() << '-' << cmd->getMsgId();
vespalib::string storageInstanceId(os.str());
cmd->setInstanceId(storageInstanceId);
- cmd->setAddress(api::StorageMessageAddress(_owner.getClusterName(),
- lib::NodeType::STORAGE, node));
+ cmd->setAddress(api::StorageMessageAddress::create(_node_ctx.cluster_name_ptr(), lib::NodeType::STORAGE, node));
cmd->setMaximumPendingReplyCount(pending);
cmd->setQueueTimeout(computeVisitorQueueTimeoutMs());
@@ -813,6 +824,10 @@ VisitorOperation::sendStorageVisitor(uint16_t node,
cmd->setTimeout(timeLeft());
+ if (!_put_lock_token.empty()) {
+ cmd->getParameters().set(reindexing_bucket_lock_visitor_parameter_key(), _put_lock_token);
+ }
+
LOG(spam, "Priority is %d", cmd->getPriority());
LOG(debug, "Sending CreateVisitor command %" PRIu64 " for storage visitor '%s' to %s",
cmd->getMsgId(),
@@ -867,8 +882,42 @@ VisitorOperation::updateReplyMetrics(const api::ReturnCode& result)
void
VisitorOperation::onClose(DistributorMessageSender& sender)
{
- sendReply(api::ReturnCode(api::ReturnCode::ABORTED, "Process is shutting down"),
- sender);
+ sendReply(api::ReturnCode(api::ReturnCode::ABORTED, "Process is shutting down"), sender);
+}
+
+void
+VisitorOperation::fail_with_bucket_already_locked(DistributorMessageSender& sender)
+{
+ assert(is_read_for_write());
+ sendReply(api::ReturnCode(api::ReturnCode::BUSY, "This bucket is already locked by another operation"), sender);
+}
+
+void
+VisitorOperation::fail_with_merge_pending(DistributorMessageSender& sender)
+{
+ assert(is_read_for_write());
+ sendReply(api::ReturnCode(api::ReturnCode::BUSY, "A merge operation is pending for this bucket"), sender);
+}
+
+std::optional<document::Bucket>
+VisitorOperation::first_bucket_to_visit() const
+{
+ if (_superBucket.subBuckets.empty()) {
+ return {};
+ }
+ return {document::Bucket(_msg->getBucketSpace(), _superBucket.subBuckets.begin()->first)};
+}
+
+void
+VisitorOperation::assign_bucket_lock_handle(SequencingHandle handle)
+{
+ _bucket_lock = std::move(handle);
+}
+
+void
+VisitorOperation::assign_put_lock_access_token(const vespalib::string& token)
+{
+ _put_lock_token = token;
}
}
diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
index 24c7157b481..179727a330c 100644
--- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
@@ -2,12 +2,14 @@
#pragma once
#include <vespa/storage/distributor/operations/operation.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
#include <vespa/storage/bucketdb/bucketdatabase.h>
#include <vespa/storage/visiting/memory_bounded_trace.h>
#include <vespa/storageapi/defs.h>
#include <vespa/storageapi/messageapi/storagemessage.h>
#include <vespa/storageapi/message/visitor.h>
#include <vespa/storageframework/generic/clock/timer.h>
+#include <optional>
namespace document { class Document; }
@@ -16,8 +18,9 @@ namespace storage::lib { class ClusterState; }
namespace storage::distributor {
-class DistributorComponent;
class DistributorBucketSpace;
+class DistributorNodeContext;
+class DistributorOperationContext;
class VisitorOperation : public Operation
{
@@ -32,9 +35,10 @@ public:
uint32_t maxVisitorsPerNodePerVisitor;
};
- VisitorOperation(DistributorComponent& manager,
+ VisitorOperation(DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
DistributorBucketSpace &bucketSpace,
- const std::shared_ptr<api::CreateVisitorCommand> & msg,
+ const std::shared_ptr<api::CreateVisitorCommand>& msg,
const Config& config,
VisitorMetricSet& metrics);
@@ -45,9 +49,21 @@ public:
void onReceive(DistributorMessageSender& sender,
const std::shared_ptr<api::StorageReply> & msg) override;
+ // Only valid to call if is_read_for_write() == true
+ void fail_with_bucket_already_locked(DistributorMessageSender& sender);
+ void fail_with_merge_pending(DistributorMessageSender& sender);
+
+ [[nodiscard]] bool verify_command_and_expand_buckets(DistributorMessageSender& sender);
+
const char* getName() const override { return "visit"; }
std::string getStatus() const override { return ""; }
+ [[nodiscard]] bool has_sent_reply() const noexcept { return _sentReply; }
+ [[nodiscard]] bool is_read_for_write() const noexcept { return _is_read_for_write; }
+ [[nodiscard]] std::optional<document::Bucket> first_bucket_to_visit() const;
+ void assign_bucket_lock_handle(SequencingHandle handle);
+ void assign_put_lock_access_token(const vespalib::string& token);
+
private:
struct BucketInfo {
bool done;
@@ -61,7 +77,7 @@ private:
vespalib::string toString() const;
};
- typedef std::map<document::BucketId, BucketInfo> VisitBucketMap;
+ using VisitBucketMap = std::map<document::BucketId, BucketInfo>;
struct SuperBucketInfo {
document::BucketId bid;
@@ -69,7 +85,7 @@ private:
VisitBucketMap subBuckets;
std::vector<document::BucketId> subBucketsVisitOrder;
- SuperBucketInfo(const document::BucketId& b = document::BucketId(0))
+ explicit SuperBucketInfo(const document::BucketId& b = document::BucketId(0))
: bid(b),
subBucketsCompletelyExpanded(false)
{
@@ -78,8 +94,8 @@ private:
};
- typedef std::map<uint16_t, std::vector<document::BucketId> > NodeToBucketsMap;
- typedef std::map<uint64_t, api::CreateVisitorCommand::SP> SentMessagesMap;
+ using NodeToBucketsMap = std::map<uint16_t, std::vector<document::BucketId>>;
+ using SentMessagesMap = std::map<uint64_t, api::CreateVisitorCommand::SP>;
void sendReply(const api::ReturnCode& code, DistributorMessageSender& sender);
void updateReplyMetrics(const api::ReturnCode& result);
@@ -92,15 +108,12 @@ private:
void verifyOperationSentToCorrectDistributor();
bool verifyCreateVisitorCommand(DistributorMessageSender& sender);
bool pickBucketsToVisit(const std::vector<BucketDatabase::Entry>& buckets);
- bool expandBucketAll();
bool expandBucketContaining();
bool expandBucketContained();
void expandBucket();
int pickTargetNode(
const BucketDatabase::Entry& entry,
const std::vector<uint16_t>& triedNodes);
- void attemptToParseOrderingSelector();
- bool documentSelectionMayHaveOrdering() const;
bool maySendNewStorageVisitors() const noexcept;
void startNewVisitors(DistributorMessageSender& sender);
void initializeActiveNodes();
@@ -139,13 +152,13 @@ private:
*/
vespalib::duration timeLeft() const noexcept;
- DistributorComponent& _owner;
+ DistributorNodeContext& _node_ctx;
+ DistributorOperationContext& _op_ctx;
DistributorBucketSpace &_bucketSpace;
SentMessagesMap _sentMessages;
api::CreateVisitorCommand::SP _msg;
api::ReturnCode _storageError;
- bool _sentReply;
SuperBucketInfo _superBucket;
document::BucketId _lastBucket;
@@ -154,7 +167,6 @@ private:
api::Timestamp _toTime;
std::vector<uint32_t> _activeNodes;
- uint32_t _bucketCount;
vdslib::VisitorStatistics _visitorStatistics;
@@ -164,11 +176,14 @@ private:
static constexpr size_t TRACE_SOFT_MEMORY_LIMIT = 65536;
- bool done();
- bool hasNoPendingMessages();
document::BucketId getLastBucketVisited();
mbus::TraceNode trace;
framework::MilliSecTimer _operationTimer;
+ SequencingHandle _bucket_lock;
+ vespalib::string _put_lock_token;
+ bool _sentReply;
+ bool _verified_and_expanded;
+ bool _is_read_for_write;
};
}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.cpp
index fc127c2e0eb..71f5693329a 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.cpp
@@ -12,9 +12,9 @@ LOG_SETUP(".distributor.operation.idealstate.remove");
namespace storage::distributor {
-GarbageCollectionOperation::GarbageCollectionOperation(const std::string& clusterName, const BucketAndNodes& nodes)
+GarbageCollectionOperation::GarbageCollectionOperation(const ClusterContext& cluster_ctx, const BucketAndNodes& nodes)
: IdealStateOperation(nodes),
- _tracker(clusterName),
+ _tracker(cluster_ctx),
_replica_info(),
_max_documents_removed(0)
{}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h
index 28de9592a63..545dd10b539 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h
@@ -13,8 +13,9 @@ class PendingMessageTracker;
class GarbageCollectionOperation : public IdealStateOperation
{
public:
- GarbageCollectionOperation(const std::string& clusterName, const BucketAndNodes& nodes);
- ~GarbageCollectionOperation();
+ GarbageCollectionOperation(const ClusterContext& cluster_ctx,
+ const BucketAndNodes& nodes);
+ ~GarbageCollectionOperation() override;
void onStart(DistributorMessageSender& sender) override;
void onReceive(DistributorMessageSender& sender, const std::shared_ptr<api::StorageReply> &) override;
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.cpp
index bc77f4cf88f..42d9e3d4a3d 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.cpp
@@ -4,7 +4,7 @@
#include <vespa/storage/distributor/pendingmessagetracker.h>
#include <vespa/storage/distributor/idealstatemetricsset.h>
#include <vespa/storage/distributor/distributor_bucket_space_repo.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
+#include <vespa/storage/distributor/operation_sequencer.h>
#include <vespa/log/log.h>
LOG_SETUP(".distributor.operation");
@@ -201,8 +201,12 @@ checkNullBucketRequestBucketInfoMessage(uint16_t node,
bool
IdealStateOperation::checkBlock(const document::Bucket &bucket,
- const PendingMessageTracker& tracker) const
+ const PendingMessageTracker& tracker,
+ const OperationSequencer& seq) const
{
+ if (seq.is_blocked(bucket)) {
+ return true;
+ }
IdealStateOpChecker ichk(*this);
const std::vector<uint16_t>& nodes(getNodes());
for (auto node : nodes) {
@@ -220,8 +224,12 @@ IdealStateOperation::checkBlock(const document::Bucket &bucket,
bool
IdealStateOperation::checkBlockForAllNodes(
const document::Bucket &bucket,
- const PendingMessageTracker& tracker) const
+ const PendingMessageTracker& tracker,
+ const OperationSequencer& seq) const
{
+ if (seq.is_blocked(bucket)) {
+ return true;
+ }
IdealStateOpChecker ichk(*this);
// Check messages sent to _any node_ for _this_ particular bucket.
tracker.checkPendingMessages(bucket, ichk);
@@ -239,9 +247,9 @@ IdealStateOperation::checkBlockForAllNodes(
bool
-IdealStateOperation::isBlocked(const PendingMessageTracker& tracker) const
+IdealStateOperation::isBlocked(const PendingMessageTracker& tracker, const OperationSequencer& op_seq) const
{
- return checkBlock(getBucket(), tracker);
+ return checkBlock(getBucket(), tracker, op_seq);
}
std::string
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.h
index 08b545057cf..dcdc2f32374 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/idealstateoperation.h
@@ -182,7 +182,7 @@ public:
* Returns true if we are blocked to start this operation given
* the pending messages.
*/
- bool isBlocked(const PendingMessageTracker& pendingMessages) const override;
+ bool isBlocked(const PendingMessageTracker& pendingMessages, const OperationSequencer&) const override;
/**
Returns the priority we should send messages with.
@@ -235,8 +235,12 @@ protected:
* operations to other nodes for this bucket, these will not be part of
* the set of messages checked.
*/
- bool checkBlock(const document::Bucket &bucket, const PendingMessageTracker& tracker) const;
- bool checkBlockForAllNodes(const document::Bucket &bucket, const PendingMessageTracker& tracker) const;
+ bool checkBlock(const document::Bucket& bucket,
+ const PendingMessageTracker& tracker,
+ const OperationSequencer&) const;
+ bool checkBlockForAllNodes(const document::Bucket& bucket,
+ const PendingMessageTracker& tracker,
+ const OperationSequencer&) const;
};
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.cpp
index 130e039a43e..44f7b5d3b49 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.cpp
@@ -3,12 +3,23 @@
#include "joinoperation.h"
#include <vespa/storageapi/message/bucketsplitting.h>
#include <vespa/storage/distributor/distributor_bucket_space.h>
+#include <vespa/storage/distributor/idealstatemanager.h>
#include <climits>
#include <vespa/log/bufferedlogger.h>
LOG_SETUP(".distributor.operation.idealstate.join");
using namespace storage::distributor;
+JoinOperation::JoinOperation(const ClusterContext &clusterName,
+ const BucketAndNodes& nodes,
+ const std::vector<document::BucketId>& bucketsToJoin)
+ : IdealStateOperation(nodes),
+ _tracker(clusterName),
+ _bucketsToJoin(bucketsToJoin)
+{}
+
+JoinOperation::~JoinOperation() = default;
+
void
JoinOperation::onStart(DistributorMessageSender& sender)
{
@@ -150,10 +161,10 @@ JoinOperation::getJoinBucket(size_t idx) const
}
bool
-JoinOperation::isBlocked(const PendingMessageTracker& tracker) const
+JoinOperation::isBlocked(const PendingMessageTracker& tracker, const OperationSequencer& op_seq) const
{
- return (checkBlock(getBucket(), tracker) ||
- checkBlock(getJoinBucket(0), tracker) ||
- (_bucketsToJoin.size() > 1 && checkBlock(getJoinBucket(1), tracker)));
+ return (checkBlock(getBucket(), tracker, op_seq) ||
+ checkBlock(getJoinBucket(0), tracker, op_seq) ||
+ (_bucketsToJoin.size() > 1 && checkBlock(getJoinBucket(1), tracker, op_seq)));
}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.h
index 55a7c05264a..ad133a937e4 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/joinoperation.h
@@ -1,12 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include <vespa/storage/distributor/idealstatemanager.h>
-#include <vespa/storage/distributor/operations/idealstate/idealstateoperation.h>
+#include "idealstateoperation.h"
#include <vespa/storage/distributor/messagetracker.h>
-namespace storage {
-namespace distributor {
+namespace storage::distributor {
class JoinOperation : public IdealStateOperation
{
@@ -18,15 +16,11 @@ public:
* @param bucketAndNodes The bucket to join into, along with the nodes this operation uses.
* @param bucketsToJoin The buckets to join together. The size of this array should always be either one or two.
*/
- JoinOperation(const std::string& clusterName,
+ JoinOperation(const ClusterContext& cluster_ctx,
const BucketAndNodes& nodes,
- const std::vector<document::BucketId>& bucketsToJoin)
- : IdealStateOperation(nodes),
- _tracker(clusterName),
- _bucketsToJoin(bucketsToJoin)
- {};
+ const std::vector<document::BucketId>& bucketsToJoin);
- ~JoinOperation() {}
+ ~JoinOperation() override;
void onStart(DistributorMessageSender& sender) override;
@@ -41,7 +35,8 @@ public:
return JOIN_BUCKET;
}
- bool isBlocked(const PendingMessageTracker& pendingMessages) const override;
+ bool isBlocked(const PendingMessageTracker& pendingMessages,
+ const OperationSequencer& op_seq) const override;
protected:
using NodeToBuckets = std::map<uint16_t, std::vector<document::BucketId>>;
@@ -61,6 +56,4 @@ protected:
std::vector<document::BucketId> _bucketsToJoin;
};
-} // distributor
-} // storage
-
+}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.cpp
index 445d0972937..7a1529606b0 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.cpp
@@ -227,16 +227,13 @@ MergeOperation::deleteSourceOnlyNodes(
getBucketId().toString().c_str());
if (!sourceOnlyNodes.empty()) {
- _removeOperation.reset(
- new RemoveBucketOperation(
- _manager->getDistributorComponent().getClusterName(),
- BucketAndNodes(getBucket(), sourceOnlyNodes)));
+ _removeOperation = std::make_unique<RemoveBucketOperation>(
+ _manager->getDistributorComponent().cluster_context(),
+ BucketAndNodes(getBucket(), sourceOnlyNodes));
// Must not send removes to source only copies if something has caused
// pending load to the copy after the merge was sent!
- if (_removeOperation->isBlocked(sender.getPendingMessageTracker())) {
- LOG(debug,
- "Source only removal for %s was blocked by a pending "
- "operation",
+ if (_removeOperation->isBlocked(sender.getPendingMessageTracker(), sender.operation_sequencer())) {
+ LOG(debug, "Source only removal for %s was blocked by a pending operation",
getBucketId().toString().c_str());
_ok = false;
done();
@@ -324,14 +321,15 @@ bool MergeOperation::shouldBlockThisOperation(uint32_t messageType, uint8_t pri)
return IdealStateOperation::shouldBlockThisOperation(messageType, pri);
}
-bool MergeOperation::isBlocked(const PendingMessageTracker& pending_tracker) const {
+bool MergeOperation::isBlocked(const PendingMessageTracker& pending_tracker,
+ const OperationSequencer& op_seq) const {
const auto& node_info = pending_tracker.getNodeInfo();
for (auto node : getNodes()) {
if (node_info.isBusy(node)) {
return true;
}
}
- return IdealStateOperation::isBlocked(pending_tracker);
+ return IdealStateOperation::isBlocked(pending_tracker, op_seq);
}
}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.h
index d09bc0ba5c4..a5f7d352eea 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/mergeoperation.h
@@ -47,7 +47,7 @@ public:
std::vector<MergeMetaData>&);
bool shouldBlockThisOperation(uint32_t messageType, uint8_t pri) const override;
- bool isBlocked(const PendingMessageTracker& pendingMessages) const override;
+ bool isBlocked(const PendingMessageTracker& pendingMessages, const OperationSequencer&) const override;
private:
static void addIdealNodes(
const std::vector<uint16_t>& idealNodes,
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/removebucketoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/removebucketoperation.h
index 95583685836..5b79a465f4e 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/removebucketoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/removebucketoperation.h
@@ -11,8 +11,8 @@ class PendingMessageTracker;
class RemoveBucketOperation : public IdealStateOperation
{
public:
- RemoveBucketOperation(const std::string& clusterName, const BucketAndNodes& nodes)
- : IdealStateOperation(nodes), _tracker(clusterName)
+ RemoveBucketOperation(const ClusterContext &cluster_context, const BucketAndNodes& nodes)
+ : IdealStateOperation(nodes), _tracker(cluster_context)
{}
/**
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.cpp
index 6a87688c295..f05feae6dab 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.cpp
@@ -10,28 +10,25 @@ LOG_SETUP(".distributor.operation.idealstate.setactive");
namespace storage::distributor {
-SetBucketStateOperation::SetBucketStateOperation(const std::string& clusterName,
+SetBucketStateOperation::SetBucketStateOperation(const ClusterContext &cluster_ctx,
const BucketAndNodes& nodes,
const std::vector<uint16_t>& wantedActiveNodes)
: IdealStateOperation(nodes),
- _tracker(clusterName),
+ _tracker(cluster_ctx),
_wantedActiveNodes(wantedActiveNodes)
{ }
-SetBucketStateOperation::~SetBucketStateOperation() {}
+SetBucketStateOperation::~SetBucketStateOperation() = default;
void
SetBucketStateOperation::enqueueSetBucketStateCommand(uint16_t node, bool active) {
- std::shared_ptr<api::SetBucketStateCommand> msg(
- new api::SetBucketStateCommand(
- getBucket(),
- active
- ? api::SetBucketStateCommand::ACTIVE
- : api::SetBucketStateCommand::INACTIVE));
+ auto msg = std::make_shared<api::SetBucketStateCommand>(getBucket(),
+ active
+ ? api::SetBucketStateCommand::ACTIVE
+ : api::SetBucketStateCommand::INACTIVE);
LOG(debug, "Enqueuing %s for %s to node %u",
active ? "Activate" : "Deactivate",
- getBucketId().toString().c_str(),
- node);
+ getBucketId().toString().c_str(), node);
setCommandMeta(*msg);
_tracker.queueCommand(msg, node);
}
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h
index 3fb0c81421e..1c818f9198d 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h
@@ -9,10 +9,10 @@ namespace storage::distributor {
class SetBucketStateOperation : public IdealStateOperation
{
public:
- SetBucketStateOperation(const std::string& clusterName,
+ SetBucketStateOperation(const ClusterContext& cluster_ctx,
const BucketAndNodes& nodes,
const std::vector<uint16_t>& wantedActiveNodes);
- ~SetBucketStateOperation();
+ ~SetBucketStateOperation() override;
void onStart(DistributorMessageSender&) override;
void onReceive(DistributorMessageSender&, const std::shared_ptr<api::StorageReply>&) override;
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp
index 508dcf13916..2b3c80f9401 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp
@@ -2,7 +2,6 @@
#include "splitoperation.h"
#include <vespa/storage/distributor/idealstatemanager.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storageapi/message/bucketsplitting.h>
#include <vespa/storage/distributor/distributor_bucket_space.h>
#include <climits>
@@ -12,10 +11,10 @@ LOG_SETUP(".distributor.operation.idealstate.split");
using namespace storage::distributor;
-SplitOperation::SplitOperation(const std::string& clusterName, const BucketAndNodes& nodes,
+SplitOperation::SplitOperation(const ClusterContext &cluster_ctx, const BucketAndNodes& nodes,
uint32_t maxBits, uint32_t splitCount, uint32_t splitSize)
: IdealStateOperation(nodes),
- _tracker(clusterName),
+ _tracker(cluster_ctx),
_maxBits(maxBits),
_splitCount(splitCount),
_splitSize(splitSize)
@@ -107,11 +106,6 @@ SplitOperation::onReceive(DistributorMessageSender&, const api::StorageReply::SP
(DatabaseUpdate::CREATE_IF_NONEXISTING
| DatabaseUpdate::RESET_TRUSTED));
- LOG_BUCKET_OPERATION_NO_LOCK(
- sinfo.first, vespalib::make_string(
- "Split from bucket %s: %s",
- getBucketId().toString().c_str(),
- copy.toString().c_str()));
}
} else if (
rep.getResult().getResult() == api::ReturnCode::BUCKET_NOT_FOUND
@@ -137,21 +131,6 @@ SplitOperation::onReceive(DistributorMessageSender&, const api::StorageReply::SP
getBucketId().toString().c_str(),
rep.getResult().toString().c_str());
}
-#ifdef ENABLE_BUCKET_OPERATION_LOGGING
- if (_ok) {
- LOG_BUCKET_OPERATION_NO_LOCK(
- getBucketId(), vespalib::make_string(
- "Split OK on node %d: %s. Finished: %s",
- node, ost.str().c_str(),
- _tracker.finished() ? "yes" : "no"));
- } else {
- LOG_BUCKET_OPERATION_NO_LOCK(
- getBucketId(), vespalib::make_string(
- "Split FAILED on node %d: %s. Finished: %s",
- node, rep.getResult().toString().c_str(),
- _tracker.finished() ? "yes" : "no"));
- }
-#endif
if (_tracker.finished()) {
LOG(debug, "Split done on node %d: %s completed operation",
@@ -164,9 +143,9 @@ SplitOperation::onReceive(DistributorMessageSender&, const api::StorageReply::SP
}
bool
-SplitOperation::isBlocked(const PendingMessageTracker& tracker) const
+SplitOperation::isBlocked(const PendingMessageTracker& tracker, const OperationSequencer& op_seq) const
{
- return checkBlockForAllNodes(getBucket(), tracker);
+ return checkBlockForAllNodes(getBucket(), tracker, op_seq);
}
bool
diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.h b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.h
index 6959929bf01..1bb82c2a39e 100644
--- a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.h
+++ b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.h
@@ -9,7 +9,8 @@ namespace storage::distributor {
class SplitOperation : public IdealStateOperation
{
public:
- SplitOperation(const std::string& clusterName, const BucketAndNodes& nodes,
+ SplitOperation(const ClusterContext& cluster_ctx,
+ const BucketAndNodes& nodes,
uint32_t maxBits, uint32_t splitCount, uint32_t splitSize);
SplitOperation(const SplitOperation &) = delete;
SplitOperation & operator = (const SplitOperation &) = delete;
@@ -19,8 +20,7 @@ public:
void onReceive(DistributorMessageSender& sender, const std::shared_ptr<api::StorageReply> &) override;
const char* getName() const override { return "split"; };
Type getType() const override { return SPLIT_BUCKET; }
- uint32_t getMaxSplitBits() const { return _maxBits; }
- bool isBlocked(const PendingMessageTracker&) const override;
+ bool isBlocked(const PendingMessageTracker&, const OperationSequencer&) const override;
bool shouldBlockThisOperation(uint32_t, uint8_t) const override;
protected:
MessageTracker _tracker;
@@ -28,7 +28,6 @@ protected:
uint32_t _maxBits;
uint32_t _splitCount;
uint32_t _splitSize;
- std::vector<document::BucketId> _inconsistentBuckets;
};
}
diff --git a/storage/src/vespa/storage/distributor/operations/operation.h b/storage/src/vespa/storage/distributor/operations/operation.h
index 538f15d2bf2..e9320817a8e 100644
--- a/storage/src/vespa/storage/distributor/operations/operation.h
+++ b/storage/src/vespa/storage/distributor/operations/operation.h
@@ -18,6 +18,7 @@ class StorageComponent;
namespace distributor {
class PendingMessageTracker;
+class OperationSequencer;
class Operation
{
@@ -61,7 +62,7 @@ public:
* Returns true if we are blocked to start this operation given
* the pending messages.
*/
- virtual bool isBlocked(const PendingMessageTracker&) const {
+ virtual bool isBlocked(const PendingMessageTracker&, const OperationSequencer&) const {
return false;
}
diff --git a/storage/src/vespa/storage/distributor/operationtargetresolverimpl.cpp b/storage/src/vespa/storage/distributor/operationtargetresolverimpl.cpp
index 23bb6b1db78..7e2da056b5a 100644
--- a/storage/src/vespa/storage/distributor/operationtargetresolverimpl.cpp
+++ b/storage/src/vespa/storage/distributor/operationtargetresolverimpl.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "operationtargetresolverimpl.h"
+#include "distributor_bucket_space.h"
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/printable.hpp>
#include <sstream>
@@ -8,6 +9,20 @@
namespace storage::distributor {
+namespace {
+
+lib::IdealNodeList
+make_node_list(const std::vector<uint16_t>& nodes)
+{
+ lib::IdealNodeList list;
+ for (auto node : nodes) {
+ list.push_back(lib::Node(lib::NodeType::STORAGE, node));
+ }
+ return list;
+}
+
+}
+
BucketInstance::BucketInstance(
const document::BucketId& id, const api::BucketInfo& info,
lib::Node node, uint16_t idealLocationPriority, bool trusted, bool exist)
@@ -54,15 +69,12 @@ BucketInstanceList::add(BucketDatabase::Entry& e,
}
void
-BucketInstanceList::populate(const document::BucketId& specificId, BucketDatabase& db,
- const lib::IdealNodeCalculator& idealNodeCalc)
+BucketInstanceList::populate(const document::BucketId& specificId, const DistributorBucketSpace& distributor_bucket_space, BucketDatabase& db)
{
std::vector<BucketDatabase::Entry> entries;
db.getParents(specificId, entries);
for (uint32_t i=0; i<entries.size(); ++i) {
- lib::IdealNodeList idealNodes(idealNodeCalc.getIdealStorageNodes(
- entries[i].getBucketId(),
- lib::IdealNodeCalculator::UpInitMaintenance));
+ lib::IdealNodeList idealNodes(make_node_list(distributor_bucket_space.get_ideal_service_layer_nodes_bundle(entries[i].getBucketId()).get_available_nonretired_or_maintenance_nodes()));
add(entries[i], idealNodes);
}
}
@@ -108,17 +120,16 @@ BucketInstanceList::leastSpecificLeafBucketInSubtree(
void
BucketInstanceList::extendToEnoughCopies(
+ const DistributorBucketSpace& distributor_bucket_space,
const BucketDatabase& db,
const document::BucketId& targetIfNonPreExisting,
- const document::BucketId& mostSpecificId,
- const lib::IdealNodeCalculator& idealNodeCalc)
+ const document::BucketId& mostSpecificId)
{
document::BucketId newTarget(_instances.empty() ? targetIfNonPreExisting
: _instances[0]._bucket);
newTarget = leastSpecificLeafBucketInSubtree(newTarget, mostSpecificId, db);
- lib::IdealNodeList idealNodes(idealNodeCalc.getIdealStorageNodes(
- newTarget, lib::IdealNodeCalculator::UpInit));
+ lib::IdealNodeList idealNodes(make_node_list(distributor_bucket_space.get_ideal_service_layer_nodes_bundle(newTarget).get_available_nonretired_nodes()));
for (uint32_t i=0; i<idealNodes.size(); ++i) {
if (!contains(idealNodes[i])) {
_instances.push_back(BucketInstance(
@@ -182,14 +193,14 @@ OperationTargetResolverImpl::getAllInstances(OperationType type,
{
BucketInstanceList instances;
if (type == PUT) {
- instances.populate(id, _bucketDatabase, _idealNodeCalculator);
+ instances.populate(id, _distributor_bucket_space, _bucketDatabase);
instances.sort(InstanceOrder());
instances.removeNodeDuplicates();
instances.extendToEnoughCopies(
+ _distributor_bucket_space,
_bucketDatabase,
_bucketDatabase.getAppropriateBucket(_minUsedBucketBits, id),
- id,
- _idealNodeCalculator);
+ id);
} else {
throw vespalib::IllegalArgumentException(
"Unsupported operation type given", VESPA_STRLOC);
diff --git a/storage/src/vespa/storage/distributor/operationtargetresolverimpl.h b/storage/src/vespa/storage/distributor/operationtargetresolverimpl.h
index 73a2c281b18..a23c8ba7f59 100644
--- a/storage/src/vespa/storage/distributor/operationtargetresolverimpl.h
+++ b/storage/src/vespa/storage/distributor/operationtargetresolverimpl.h
@@ -9,6 +9,8 @@
namespace storage::distributor {
+class DistributorBucketSpace;
+
struct BucketInstance : public vespalib::AsciiPrintable {
document::BucketId _bucket;
api::BucketInfo _info;
@@ -57,13 +59,12 @@ public:
* _instances.size() >= configured redundancy level, unless insufficient
* number of nodes are available
*/
- void extendToEnoughCopies(const BucketDatabase& db,
+ void extendToEnoughCopies(const DistributorBucketSpace& distributor_bucket_space,
+ const BucketDatabase& db,
const document::BucketId& targetIfNonPreExisting,
- const document::BucketId& mostSpecificId,
- const lib::IdealNodeCalculator& idealNodeCalc);
+ const document::BucketId& mostSpecificId);
- void populate(const document::BucketId&, BucketDatabase&,
- const lib::IdealNodeCalculator&);
+ void populate(const document::BucketId&, const DistributorBucketSpace&, BucketDatabase&);
void add(BucketDatabase::Entry& e, const lib::IdealNodeList& idealState);
template <typename Order>
@@ -77,20 +78,20 @@ public:
};
class OperationTargetResolverImpl : public OperationTargetResolver {
+ const DistributorBucketSpace& _distributor_bucket_space;
BucketDatabase& _bucketDatabase;
- const lib::IdealNodeCalculator& _idealNodeCalculator;
uint32_t _minUsedBucketBits;
uint16_t _redundancy;
document::BucketSpace _bucketSpace;
public:
- OperationTargetResolverImpl(BucketDatabase& bucketDatabase,
- const lib::IdealNodeCalculator& idealNodeCalc,
+ OperationTargetResolverImpl(const DistributorBucketSpace& distributor_bucket_space,
+ BucketDatabase& bucketDatabase,
uint32_t minUsedBucketBits,
uint16_t redundancy,
document::BucketSpace bucketSpace)
- : _bucketDatabase(bucketDatabase),
- _idealNodeCalculator(idealNodeCalc),
+ : _distributor_bucket_space(distributor_bucket_space),
+ _bucketDatabase(bucketDatabase),
_minUsedBucketBits(minUsedBucketBits),
_redundancy(redundancy),
_bucketSpace(bucketSpace)
diff --git a/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp b/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp
index 6983e3594af..7eb2e2bf236 100644
--- a/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp
+++ b/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp
@@ -4,7 +4,6 @@
#include "clusterinformation.h"
#include "pendingclusterstate.h"
#include "distributor_bucket_space.h"
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <algorithm>
#include <vespa/log/log.h>
diff --git a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp
index 3dda989ff74..d009375a641 100644
--- a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp
+++ b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp
@@ -6,7 +6,6 @@
#include "distributor_bucket_space_repo.h"
#include "distributor_bucket_space.h"
#include <vespa/storageframework/defaultimplementation/clock/realclock.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storage/common/global_bucket_space_distribution_converter.h>
#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/vespalib/util/xmlstream.hpp>
diff --git a/storage/src/vespa/storage/distributor/pendingmessagetracker.cpp b/storage/src/vespa/storage/distributor/pendingmessagetracker.cpp
index 715ac1722b4..f84eafe8d85 100644
--- a/storage/src/vespa/storage/distributor/pendingmessagetracker.cpp
+++ b/storage/src/vespa/storage/distributor/pendingmessagetracker.cpp
@@ -22,7 +22,7 @@ PendingMessageTracker::PendingMessageTracker(framework::ComponentRegister& cr)
PendingMessageTracker::~PendingMessageTracker() = default;
PendingMessageTracker::MessageEntry::MessageEntry(TimePoint timeStamp_, uint32_t msgType_, uint32_t priority_,
- uint64_t msgId_, document::Bucket bucket_, uint16_t nodeIdx_)
+ uint64_t msgId_, document::Bucket bucket_, uint16_t nodeIdx_) noexcept
: timeStamp(timeStamp_),
msgType(msgType_),
priority(priority_),
@@ -71,7 +71,7 @@ pairAsRange(Pair pair)
std::vector<uint64_t>
PendingMessageTracker::clearMessagesForNode(uint16_t node)
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
MessagesByNodeAndBucket& idx(boost::multi_index::get<1>(_messages));
auto range = pairAsRange(idx.equal_range(boost::make_tuple(node)));
@@ -88,7 +88,7 @@ PendingMessageTracker::clearMessagesForNode(uint16_t node)
void
PendingMessageTracker::insert(const std::shared_ptr<api::StorageMessage>& msg)
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
if (msg->getAddress()) {
_messages.emplace(currentTime(), msg->getType().getId(), msg->getPriority(), msg->getMsgId(),
msg->getBucket(), msg->getAddress()->getIndex());
@@ -103,7 +103,7 @@ PendingMessageTracker::insert(const std::shared_ptr<api::StorageMessage>& msg)
document::Bucket
PendingMessageTracker::reply(const api::StorageReply& r)
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::unique_lock guard(_lock);
document::Bucket bucket;
LOG(debug, "Got reply: %s", r.toString().c_str());
@@ -121,6 +121,16 @@ PendingMessageTracker::reply(const api::StorageReply& r)
}
LOG(debug, "Erased message with id %" PRIu64, msgId);
msgs.erase(msgId);
+ auto deferred_tasks = get_deferred_ops_if_bucket_writes_drained(bucket);
+ // Deferred tasks may try to send messages, which in turn will invoke the PendingMessageTracker.
+ // To avoid deadlocking, we run the tasks outside the lock.
+ // TODO remove locking entirely... Only exists for status pages!
+ guard.unlock();
+ // We expect this to be "effectively noexcept", i.e. any tasks throwing an
+ // exception will end up nuking the distributor process from the unwind.
+ for (auto& task : deferred_tasks) {
+ task->run(TaskRunState::OK);
+ }
}
return bucket;
@@ -129,6 +139,81 @@ PendingMessageTracker::reply(const api::StorageReply& r)
namespace {
template <typename Range>
+bool is_empty_range(const Range& range) noexcept {
+ return (range.first == range.second);
+}
+
+template <typename Range>
+bool range_is_empty_or_only_has_read_ops(const Range& range) noexcept {
+ if (is_empty_range(range)) {
+ return true;
+ }
+ // Number of ops to check is expected to be small in the common case
+ for (auto iter = range.first; iter != range.second; ++iter) {
+ switch (iter->msgType) {
+ case api::MessageType::GET_ID:
+ case api::MessageType::STAT_ID:
+ case api::MessageType::VISITOR_CREATE_ID:
+ case api::MessageType::VISITOR_DESTROY_ID:
+ continue;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
+bool
+PendingMessageTracker::bucket_has_no_pending_write_ops(const document::Bucket& bucket) const noexcept
+{
+ auto& bucket_idx = boost::multi_index::get<2>(_messages);
+ auto pending_tasks_for_bucket = bucket_idx.equal_range(bucket);
+ return range_is_empty_or_only_has_read_ops(pending_tasks_for_bucket);
+}
+
+std::vector<std::unique_ptr<DeferredTask>>
+PendingMessageTracker::get_deferred_ops_if_bucket_writes_drained(const document::Bucket& bucket)
+{
+ if (_deferred_read_tasks.empty()) {
+ return {};
+ }
+ std::vector<std::unique_ptr<DeferredTask>> tasks;
+ if (bucket_has_no_pending_write_ops(bucket)) {
+ auto waiting_tasks = _deferred_read_tasks.equal_range(bucket);
+ for (auto task_iter = waiting_tasks.first; task_iter != waiting_tasks.second; ++task_iter) {
+ tasks.emplace_back(std::move(task_iter->second));
+ }
+ _deferred_read_tasks.erase(waiting_tasks.first, waiting_tasks.second);
+ }
+ return tasks;
+}
+
+void
+PendingMessageTracker::run_once_no_pending_for_bucket(const document::Bucket& bucket, std::unique_ptr<DeferredTask> task)
+{
+ std::unique_lock guard(_lock);
+ if (bucket_has_no_pending_write_ops(bucket)) {
+ guard.unlock(); // Must not be held whilst running task, or else recursive sends will deadlock.
+ task->run(TaskRunState::OK); // Nothing pending, run immediately.
+ } else {
+ _deferred_read_tasks.emplace(bucket, std::move(task));
+ }
+}
+
+void
+PendingMessageTracker::abort_deferred_tasks()
+{
+ std::lock_guard guard(_lock);
+ for (auto& task : _deferred_read_tasks) {
+ task.second->run(TaskRunState::Aborted);
+ }
+}
+
+namespace {
+
+template <typename Range>
void
runCheckerOnRange(PendingMessageTracker::Checker& checker, const Range& range)
{
@@ -144,7 +229,7 @@ runCheckerOnRange(PendingMessageTracker::Checker& checker, const Range& range)
void
PendingMessageTracker::checkPendingMessages(uint16_t node, const document::Bucket &bucket, Checker& checker) const
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
const MessagesByNodeAndBucket& msgs(boost::multi_index::get<1>(_messages));
auto range = pairAsRange(msgs.equal_range(boost::make_tuple(node, bucket)));
@@ -154,7 +239,7 @@ PendingMessageTracker::checkPendingMessages(uint16_t node, const document::Bucke
void
PendingMessageTracker::checkPendingMessages(const document::Bucket &bucket, Checker& checker) const
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
const MessagesByBucketAndType& msgs(boost::multi_index::get<2>(_messages));
auto range = pairAsRange(msgs.equal_range(boost::make_tuple(bucket)));
@@ -164,7 +249,7 @@ PendingMessageTracker::checkPendingMessages(const document::Bucket &bucket, Chec
bool
PendingMessageTracker::hasPendingMessage(uint16_t node, const document::Bucket &bucket, uint32_t messageType) const
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
const MessagesByNodeAndBucket& msgs(boost::multi_index::get<1>(_messages));
auto range = msgs.equal_range(boost::make_tuple(node, bucket, messageType));
@@ -181,7 +266,7 @@ PendingMessageTracker::getStatusStartPage(std::ostream& out) const
void
PendingMessageTracker::getStatusPerBucket(std::ostream& out) const
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
const MessagesByNodeAndBucket& msgs = boost::multi_index::get<1>(_messages);
using BucketMap = std::map<document::Bucket, std::vector<vespalib::string>>;
BucketMap perBucketMsgs;
@@ -210,7 +295,7 @@ PendingMessageTracker::getStatusPerBucket(std::ostream& out) const
void
PendingMessageTracker::getStatusPerNode(std::ostream& out) const
{
- std::lock_guard<std::mutex> guard(_lock);
+ std::lock_guard guard(_lock);
const MessagesByNodeAndBucket& msgs = boost::multi_index::get<1>(_messages);
int lastNode = -1;
for (const auto & node : msgs) {
diff --git a/storage/src/vespa/storage/distributor/pendingmessagetracker.h b/storage/src/vespa/storage/distributor/pendingmessagetracker.h
index 2dba244dc9f..51971a276b4 100644
--- a/storage/src/vespa/storage/distributor/pendingmessagetracker.h
+++ b/storage/src/vespa/storage/distributor/pendingmessagetracker.h
@@ -15,7 +15,6 @@
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/composite_key.hpp>
-
#include <set>
#include <unordered_map>
#include <chrono>
@@ -23,14 +22,50 @@
namespace storage::distributor {
-class PendingMessageTracker : public framework::HtmlStatusReporter
-{
+/**
+ * Since the state a deferred task depends on may have changed between the
+ * time a task was scheduled and when it's actually executed, this enum provides
+ * a means of communicating if a task should be started as normal.
+ */
+enum class TaskRunState {
+ OK, // Task may be started as normal
+ Aborted, // Task should trigger an immediate abort behavior (distributor is shutting down)
+ BucketLost // Task should trigger an immediate abort behavior (bucket no longer present on node)
+};
+
+/**
+ * Represents an arbitrary task whose execution may be deferred until no
+ * further pending operations are present.
+ */
+struct DeferredTask {
+ virtual ~DeferredTask() = default;
+ virtual void run(TaskRunState state) = 0;
+};
+template <typename Func>
+class LambdaDeferredTask : public DeferredTask {
+ Func _func;
+public:
+ explicit LambdaDeferredTask(Func&& f) : _func(std::move(f)) {}
+ LambdaDeferredTask(const LambdaDeferredTask&) = delete;
+ LambdaDeferredTask(LambdaDeferredTask&&) = delete;
+ ~LambdaDeferredTask() override = default;
+
+ void run(TaskRunState state) override {
+ _func(state);
+ }
+};
+
+template <typename Func>
+std::unique_ptr<DeferredTask> make_deferred_task(Func&& f) {
+ return std::make_unique<LambdaDeferredTask<std::decay_t<Func>>>(std::forward<Func>(f));
+}
+
+class PendingMessageTracker : public framework::HtmlStatusReporter {
public:
class Checker {
public:
- virtual ~Checker() {}
-
+ virtual ~Checker() = default;
virtual bool check(uint32_t messageType, uint16_t node, uint8_t priority) = 0;
};
@@ -42,8 +77,8 @@ public:
*/
using TimePoint = std::chrono::milliseconds;
- PendingMessageTracker(framework::ComponentRegister&);
- ~PendingMessageTracker();
+ explicit PendingMessageTracker(framework::ComponentRegister&);
+ ~PendingMessageTracker() override;
void insert(const std::shared_ptr<api::StorageMessage>&);
document::Bucket reply(const api::StorageReply& reply);
@@ -89,6 +124,8 @@ public:
_nodeBusyDuration = secs;
}
+ void run_once_no_pending_for_bucket(const document::Bucket& bucket, std::unique_ptr<DeferredTask> task);
+ void abort_deferred_tasks();
private:
struct MessageEntry {
TimePoint timeStamp;
@@ -99,7 +136,7 @@ private:
uint16_t nodeIdx;
MessageEntry(TimePoint timeStamp, uint32_t msgType, uint32_t priority,
- uint64_t msgId, document::Bucket bucket, uint16_t nodeIdx);
+ uint64_t msgId, document::Bucket bucket, uint16_t nodeIdx) noexcept;
vespalib::string toHtml() const;
};
@@ -130,23 +167,29 @@ private:
{
};
- typedef boost::multi_index::multi_index_container <
+ using Messages = boost::multi_index::multi_index_container <
MessageEntry,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<MessageIdKey>,
boost::multi_index::ordered_non_unique<CompositeNodeBucketKey>,
boost::multi_index::ordered_non_unique<CompositeBucketMsgNodeKey>
>
- > Messages;
-
- typedef Messages::nth_index<0>::type MessagesByMsgId;
- typedef Messages::nth_index<1>::type MessagesByNodeAndBucket;
- typedef Messages::nth_index<2>::type MessagesByBucketAndType;
-
- Messages _messages;
- framework::Component _component;
- NodeInfo _nodeInfo;
- std::chrono::seconds _nodeBusyDuration;
+ >;
+
+ using MessagesByMsgId = Messages::nth_index<0>::type;
+ using MessagesByNodeAndBucket = Messages::nth_index<1>::type;
+ using MessagesByBucketAndType = Messages::nth_index<2>::type;
+ using DeferredBucketTaskMap = std::unordered_multimap<
+ document::Bucket,
+ std::unique_ptr<DeferredTask>,
+ document::Bucket::hash
+ >;
+
+ Messages _messages;
+ framework::Component _component;
+ NodeInfo _nodeInfo;
+ std::chrono::seconds _nodeBusyDuration;
+ DeferredBucketTaskMap _deferred_read_tasks;
// Since distributor is currently single-threaded, this will only
// contend when status page is being accessed. It is, however, required
@@ -169,6 +212,9 @@ private:
void getStatusPerNode(std::ostream& out) const;
void getStatusPerBucket(std::ostream& out) const;
TimePoint currentTime() const;
+
+ [[nodiscard]] bool bucket_has_no_pending_write_ops(const document::Bucket& bucket) const noexcept;
+ std::vector<std::unique_ptr<DeferredTask>> get_deferred_ops_if_bucket_writes_drained(const document::Bucket&);
};
}
diff --git a/storage/src/vespa/storage/distributor/persistence_operation_metric_set.cpp b/storage/src/vespa/storage/distributor/persistence_operation_metric_set.cpp
index 457d1e051b9..96d8ef66db3 100644
--- a/storage/src/vespa/storage/distributor/persistence_operation_metric_set.cpp
+++ b/storage/src/vespa/storage/distributor/persistence_operation_metric_set.cpp
@@ -2,7 +2,6 @@
#include "distributormetricsset.h"
#include <vespa/storageapi/messageapi/returncode.h>
-#include <vespa/metrics/loadmetric.hpp>
#include <vespa/metrics/summetric.hpp>
namespace storage {
diff --git a/storage/src/vespa/storage/distributor/persistence_operation_metric_set.h b/storage/src/vespa/storage/distributor/persistence_operation_metric_set.h
index 1299fdad2ad..d3e022c08b8 100644
--- a/storage/src/vespa/storage/distributor/persistence_operation_metric_set.h
+++ b/storage/src/vespa/storage/distributor/persistence_operation_metric_set.h
@@ -2,8 +2,10 @@
#pragma once
-#include <vespa/metrics/metrics.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/countmetric.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/summetric.h>
#include <mutex>
namespace storage {
diff --git a/storage/src/vespa/storage/distributor/persistencemessagetracker.cpp b/storage/src/vespa/storage/distributor/persistencemessagetracker.cpp
index 584cb379400..10e69bcfd14 100644
--- a/storage/src/vespa/storage/distributor/persistencemessagetracker.cpp
+++ b/storage/src/vespa/storage/distributor/persistencemessagetracker.cpp
@@ -15,15 +15,16 @@ namespace storage::distributor {
PersistenceMessageTrackerImpl::PersistenceMessageTrackerImpl(
PersistenceOperationMetricSet& metric,
std::shared_ptr<api::BucketInfoReply> reply,
- DistributorComponent& link,
+ DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
api::Timestamp revertTimestamp)
- : MessageTracker(link.getClusterName()),
+ : MessageTracker(node_ctx),
_metric(metric),
_reply(std::move(reply)),
- _manager(link),
+ _op_ctx(op_ctx),
_revertTimestamp(revertTimestamp),
_trace(_reply->getTrace().getLevel()),
- _requestTimer(link.getClock()),
+ _requestTimer(node_ctx.clock()),
_n_persistence_replies_total(0),
_n_successful_persistence_replies(0),
_priority(_reply->getPriority()),
@@ -37,11 +38,11 @@ void
PersistenceMessageTrackerImpl::updateDB()
{
for (const auto & entry : _bucketInfo) {
- _manager.updateBucketDatabase(entry.first, entry.second);
+ _op_ctx.update_bucket_database(entry.first, entry.second);
}
for (const auto & entry : _remapBucketInfo){
- _manager.updateBucketDatabase(entry.first, entry.second,DatabaseUpdate::CREATE_IF_NONEXISTING);
+ _op_ctx.update_bucket_database(entry.first, entry.second, DatabaseUpdate::CREATE_IF_NONEXISTING);
}
}
@@ -119,7 +120,7 @@ PersistenceMessageTrackerImpl::canSendReplyEarly() const
LOG(spam, "Can't return early because we have already replied or failed");
return false;
}
- auto &bucketSpaceRepo(_manager.getBucketSpaceRepo());
+ auto &bucketSpaceRepo(_op_ctx.bucket_space_repo());
auto &bucketSpace(bucketSpaceRepo.get(_reply->getBucket().getBucketSpace()));
const lib::Distribution& distribution = bucketSpace.getDistribution();
@@ -164,13 +165,13 @@ PersistenceMessageTrackerImpl::addBucketInfoFromReply(
bucket.toString().c_str(),
bucketInfo.toString().c_str(),
node);
- _remapBucketInfo[bucket].emplace_back(_manager.getUniqueTimestamp(), node, bucketInfo);
+ _remapBucketInfo[bucket].emplace_back(_op_ctx.generate_unique_timestamp(), node, bucketInfo);
} else {
LOG(debug, "Bucket %s: Received bucket info %s from node %d",
bucket.toString().c_str(),
bucketInfo.toString().c_str(),
node);
- _bucketInfo[bucket].emplace_back(_manager.getUniqueTimestamp(), node, bucketInfo);
+ _bucketInfo[bucket].emplace_back(_op_ctx.generate_unique_timestamp(), node, bucketInfo);
}
}
@@ -195,7 +196,7 @@ PersistenceMessageTrackerImpl::logSuccessfulReply(uint16_t node, const api::Buck
bool
PersistenceMessageTrackerImpl::shouldRevert() const
{
- return _manager.getDistributorConfig().enableRevert
+ return _op_ctx.distributor_config().enable_revert()
&& !_revertNodes.empty() && !_success && _reply;
}
@@ -222,8 +223,8 @@ PersistenceMessageTrackerImpl::sendReply(MessageSender& sender)
}
updateMetrics();
- _trace.setStrict(false);
if ( ! _trace.isEmpty()) {
+ _trace.setStrict(false);
_reply->getTrace().addChild(std::move(_trace));
}
@@ -258,7 +259,7 @@ PersistenceMessageTrackerImpl::handleCreateBucketReply(
&& reply.getResult().getResult() != api::ReturnCode::EXISTS)
{
LOG(spam, "Create bucket reply failed, so deleting it from bucket db");
- _manager.removeNodeFromDB(reply.getBucket(), node);
+ _op_ctx.remove_node_from_bucket_database(reply.getBucket(), node);
}
}
diff --git a/storage/src/vespa/storage/distributor/persistencemessagetracker.h b/storage/src/vespa/storage/distributor/persistencemessagetracker.h
index cf9f4017eda..1421b4c2038 100644
--- a/storage/src/vespa/storage/distributor/persistencemessagetracker.h
+++ b/storage/src/vespa/storage/distributor/persistencemessagetracker.h
@@ -36,7 +36,8 @@ private:
public:
PersistenceMessageTrackerImpl(PersistenceOperationMetricSet& metric,
std::shared_ptr<api::BucketInfoReply> reply,
- DistributorComponent&,
+ DistributorNodeContext& node_ctx,
+ DistributorOperationContext& op_ctx,
api::Timestamp revertTimestamp = 0);
~PersistenceMessageTrackerImpl() override;
@@ -70,7 +71,7 @@ private:
PersistenceOperationMetricSet& _metric;
std::shared_ptr<api::BucketInfoReply> _reply;
- DistributorComponent& _manager;
+ DistributorOperationContext& _op_ctx;
api::Timestamp _revertTimestamp;
std::vector<BucketNodePair> _revertNodes;
mbus::Trace _trace;
diff --git a/storage/src/vespa/storage/distributor/statecheckers.cpp b/storage/src/vespa/storage/distributor/statecheckers.cpp
index e861adda428..a2342545ae1 100644
--- a/storage/src/vespa/storage/distributor/statecheckers.cpp
+++ b/storage/src/vespa/storage/distributor/statecheckers.cpp
@@ -9,7 +9,6 @@
#include <vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h>
#include <vespa/storage/distributor/operations/idealstate/mergeoperation.h>
#include <vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/log/log.h>
@@ -83,15 +82,14 @@ StateChecker::Result
SplitBucketStateChecker::generateMinimumBucketSplitOperation(
StateChecker::Context& c)
{
- IdealStateOperation::UP so(new SplitOperation(
- c.component.getClusterName(),
+ auto so = std::make_unique<SplitOperation>(
+ c.component.cluster_context(),
BucketAndNodes(c.getBucket(), c.entry->getNodes()),
c.distributorConfig.getMinimalBucketSplit(),
0,
- 0));
+ 0);
- so->setPriority(c.distributorConfig.getMaintenancePriorities()
- .splitDistributionBits);
+ so->setPriority(c.distributorConfig.getMaintenancePriorities().splitDistributionBits);
so->setDetailedReason(
"[Splitting bucket because the current system size requires "
"a higher minimum split bit]");
@@ -102,15 +100,14 @@ StateChecker::Result
SplitBucketStateChecker::generateMaxSizeExceededSplitOperation(
StateChecker::Context& c)
{
- IdealStateOperation::UP so(new SplitOperation(
- c.component.getClusterName(),
+ auto so = std::make_unique<SplitOperation>(
+ c.component.cluster_context(),
BucketAndNodes(c.getBucket(), c.entry->getNodes()),
58,
c.distributorConfig.getSplitCount(),
- c.distributorConfig.getSplitSize()));
+ c.distributorConfig.getSplitSize());
- so->setPriority(c.distributorConfig.getMaintenancePriorities()
- .splitLargeBucket);
+ so->setPriority(c.distributorConfig.getMaintenancePriorities().splitLargeBucket);
const BucketInfo& info(c.entry.getBucketInfo());
vespalib::asciistream ost;
@@ -466,12 +463,11 @@ JoinBucketsStateChecker::check(StateChecker::Context& c)
sourceBuckets.push_back(c.getBucketId());
}
sourceBuckets.push_back(c.getBucketId());
- IdealStateOperation::UP op(new JoinOperation(
- c.component.getClusterName(),
+ auto op = std::make_unique<JoinOperation>(
+ c.component.cluster_context(),
BucketAndNodes(joinedBucket, c.entry->getNodes()),
- sourceBuckets));
- op->setPriority(c.distributorConfig.getMaintenancePriorities()
- .joinBuckets);
+ sourceBuckets);
+ op->setPriority(c.distributorConfig.getMaintenancePriorities().joinBuckets);
vespalib::asciistream ost;
ost << "[Joining buckets "
<< sourceBuckets[1].toString()
@@ -571,15 +567,14 @@ SplitInconsistentStateChecker::check(StateChecker::Context& c)
return Result::noMaintenanceNeeded();
}
- IdealStateOperation::UP op(new SplitOperation(
- c.component.getClusterName(),
+ auto op = std::make_unique<SplitOperation>(
+ c.component.cluster_context(),
BucketAndNodes(c.getBucket(), c.entry->getNodes()),
getHighestUsedBits(c.entries),
0,
- 0));
+ 0);
- op->setPriority(c.distributorConfig.getMaintenancePriorities()
- .splitInconsistentBucket);
+ op->setPriority(c.distributorConfig.getMaintenancePriorities().splitInconsistentBucket);
op->setDetailedReason(getReason(c.getBucketId(), c.entries));
return Result::createStoredResult(std::move(op), MaintenancePriority::HIGH);
}
@@ -971,8 +966,7 @@ DeleteExtraCopiesStateChecker::removeRedundantEmptyOrConsistentCopies(
&& enoughCopiesKept(keptIdealCopies, keptNonIdealCopies, c)
&& !cp.active())
{
- addToRemoveSet(cp, "redundant in-sync copy",
- removedCopies, reasons);
+ addToRemoveSet(cp, "redundant in-sync copy", removedCopies, reasons);
} else {
++keptNonIdealCopies;
}
@@ -1011,12 +1005,11 @@ DeleteExtraCopiesStateChecker::check(StateChecker::Context& c)
}
if (!removedCopies.empty()) {
- IdealStateOperation::UP ro(new RemoveBucketOperation(
- c.component.getClusterName(),
- BucketAndNodes(c.getBucket(), removedCopies)));
+ auto ro = std::make_unique<RemoveBucketOperation>(
+ c.component.cluster_context(),
+ BucketAndNodes(c.getBucket(), removedCopies));
- ro->setPriority(c.distributorConfig.getMaintenancePriorities()
- .deleteBucketCopy);
+ ro->setPriority(c.distributorConfig.getMaintenancePriorities().deleteBucketCopy);
ro->setDetailedReason(reasons.str());
return Result::createStoredResult(std::move(ro), MaintenancePriority::HIGH);
}
@@ -1113,7 +1106,7 @@ BucketStateStateChecker::check(StateChecker::Context& c)
activeNodeIndexes.push_back(activeNodes[i]._nodeIndex);
}
auto op = std::make_unique<SetBucketStateOperation>(
- c.component.getClusterName(),
+ c.component.cluster_context(),
BucketAndNodes(c.getBucket(), operationNodes),
activeNodeIndexes);
@@ -1149,10 +1142,9 @@ StateChecker::Result
GarbageCollectionStateChecker::check(Context& c)
{
if (needsGarbageCollection(c)) {
- IdealStateOperation::UP op(
- new GarbageCollectionOperation(
- c.component.getClusterName(),
- BucketAndNodes(c.getBucket(), c.entry->getNodes())));
+ auto op = std::make_unique<GarbageCollectionOperation>(
+ c.component.cluster_context(),
+ BucketAndNodes(c.getBucket(), c.entry->getNodes()));
vespalib::asciistream reason;
reason << "[Needs garbage collection: Last check at "
diff --git a/storage/src/vespa/storage/distributor/update_metric_set.cpp b/storage/src/vespa/storage/distributor/update_metric_set.cpp
index 1edde270517..fbb5d700aa9 100644
--- a/storage/src/vespa/storage/distributor/update_metric_set.cpp
+++ b/storage/src/vespa/storage/distributor/update_metric_set.cpp
@@ -1,15 +1,13 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "update_metric_set.h"
-#include <vespa/metrics/loadmetric.hpp>
-#include <vespa/metrics/summetric.hpp>
namespace storage {
using metrics::MetricSet;
UpdateMetricSet::UpdateMetricSet(MetricSet* owner)
- : PersistenceOperationMetricSet("updates", owner),
+ : PersistenceOperationMetricSet("updates.sum", owner),
diverging_timestamp_updates("diverging_timestamp_updates", {},
"Number of updates that report they were performed against "
"divergent version timestamps on different replicas", this),
@@ -32,6 +30,3 @@ UpdateMetricSet::clone(std::vector<Metric::UP>& ownerList, CopyType copyType,
}
}
-
-template class metrics::LoadMetric<storage::UpdateMetricSet>;
-template class metrics::SumMetric<storage::UpdateMetricSet>;
diff --git a/storage/src/vespa/storage/distributor/update_metric_set.h b/storage/src/vespa/storage/distributor/update_metric_set.h
index 8a88aa6b9a9..e31ec714adf 100644
--- a/storage/src/vespa/storage/distributor/update_metric_set.h
+++ b/storage/src/vespa/storage/distributor/update_metric_set.h
@@ -2,8 +2,6 @@
#pragma once
#include "persistence_operation_metric_set.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
-#include <vespa/metrics/metrics.h>
namespace storage {
diff --git a/storage/src/vespa/storage/distributor/uuid_generator.h b/storage/src/vespa/storage/distributor/uuid_generator.h
new file mode 100644
index 00000000000..ae133d83fd4
--- /dev/null
+++ b/storage/src/vespa/storage/distributor/uuid_generator.h
@@ -0,0 +1,19 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/stllike/string.h>
+
+namespace storage::distributor {
+
+/**
+ * Generator of universally unique identifiers (not actually conforming UUIDs, as these
+ * have MSB semantics) that are expected to be effectively collision free.
+ */
+class UuidGenerator {
+public:
+ virtual ~UuidGenerator() = default;
+ // Returns a string that is guaranteed ASCII-only
+ virtual vespalib::string generate_uuid() const = 0;
+};
+
+}
diff --git a/storage/src/vespa/storage/distributor/visitormetricsset.cpp b/storage/src/vespa/storage/distributor/visitormetricsset.cpp
index 84b1174962c..3ca92c7df79 100644
--- a/storage/src/vespa/storage/distributor/visitormetricsset.cpp
+++ b/storage/src/vespa/storage/distributor/visitormetricsset.cpp
@@ -1,15 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "visitormetricsset.h"
-#include <vespa/metrics/loadmetric.hpp>
-#include <vespa/metrics/summetric.hpp>
namespace storage {
using metrics::MetricSet;
VisitorMetricSet::VisitorMetricSet(MetricSet* owner)
- : PersistenceOperationMetricSet("visitor", owner),
+ : PersistenceOperationMetricSet("visitor.sum", owner),
buckets_per_visitor("buckets_per_visitor", {},
"The number of sub buckets visited as part of a "
"single client visitor command", this),
@@ -22,7 +20,7 @@ VisitorMetricSet::VisitorMetricSet(MetricSet* owner)
{
}
-VisitorMetricSet::~VisitorMetricSet() { }
+VisitorMetricSet::~VisitorMetricSet() = default;
MetricSet *
VisitorMetricSet::clone(std::vector<Metric::UP>& ownerList, CopyType copyType,
@@ -35,6 +33,3 @@ VisitorMetricSet::clone(std::vector<Metric::UP>& ownerList, CopyType copyType,
}
}
-
-template class metrics::LoadMetric<storage::VisitorMetricSet>;
-template class metrics::SumMetric<storage::VisitorMetricSet>;
diff --git a/storage/src/vespa/storage/distributor/visitormetricsset.h b/storage/src/vespa/storage/distributor/visitormetricsset.h
index 7ea78a887a8..93258c9a416 100644
--- a/storage/src/vespa/storage/distributor/visitormetricsset.h
+++ b/storage/src/vespa/storage/distributor/visitormetricsset.h
@@ -2,8 +2,6 @@
#pragma once
#include "persistence_operation_metric_set.h"
-#include <vespa/metrics/metrics.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
namespace storage {
diff --git a/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.cpp b/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.cpp
index 9c421eb7f8f..3ce02a73324 100644
--- a/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.cpp
+++ b/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.cpp
@@ -16,8 +16,6 @@ StorageComponentRegisterImpl::StorageComponentRegisterImpl()
_nodeType(nullptr),
_index(0xffff),
_docTypeRepo(),
- _loadTypes(new documentapi::LoadTypeSet),
- _priorityConfig(),
_bucketIdFactory(),
_distribution(),
_nodeStateUpdater(nullptr),
@@ -38,8 +36,6 @@ StorageComponentRegisterImpl::registerStorageComponent(StorageComponent& smc)
smc.setNodeStateUpdater(*_nodeStateUpdater);
}
smc.setDocumentTypeRepo(_docTypeRepo);
- smc.setLoadTypes(_loadTypes);
- smc.setPriorityConfig(_priorityConfig);
smc.setBucketIdFactory(_bucketIdFactory);
smc.setDistribution(_distribution);
}
@@ -85,26 +81,6 @@ StorageComponentRegisterImpl::setDocumentTypeRepo(std::shared_ptr<const document
}
void
-StorageComponentRegisterImpl::setLoadTypes(documentapi::LoadTypeSet::SP loadTypes)
-{
- std::lock_guard lock(_componentLock);
- _loadTypes = loadTypes;
- for (auto& component : _components) {
- component->setLoadTypes(loadTypes);
- }
-}
-
-void
-StorageComponentRegisterImpl::setPriorityConfig(const PriorityConfig& config)
-{
- std::lock_guard lock(_componentLock);
- _priorityConfig = config;
- for (auto& component : _components) {
- component->setPriorityConfig(config);
- }
-}
-
-void
StorageComponentRegisterImpl::setBucketIdFactory(const document::BucketIdFactory& factory)
{
std::lock_guard lock(_componentLock);
diff --git a/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h b/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h
index b22ea93223b..85edfe78c28 100644
--- a/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h
+++ b/storage/src/vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h
@@ -8,10 +8,8 @@
#pragma once
#include <vespa/document/bucket/bucketidfactory.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/storage/common/storagecomponent.h>
#include <vespa/config-bucketspaces.h>
-#include <vespa/storage/config/config-stor-prioritymapping.h>
#include <vespa/storageframework/defaultimplementation/component/componentregisterimpl.h>
#include <vespa/vdslib/distribution/distribution.h>
@@ -21,7 +19,6 @@ class StorageComponentRegisterImpl
: public virtual StorageComponentRegister,
public virtual framework::defaultimplementation::ComponentRegisterImpl
{
- using PriorityConfig = StorageComponent::PriorityConfig;
using BucketspacesConfig = vespa::config::content::core::internal::InternalBucketspacesType;
std::mutex _componentLock;
@@ -30,8 +27,6 @@ class StorageComponentRegisterImpl
const lib::NodeType* _nodeType;
uint16_t _index;
std::shared_ptr<const document::DocumentTypeRepo> _docTypeRepo;
- documentapi::LoadTypeSet::SP _loadTypes;
- PriorityConfig _priorityConfig;
document::BucketIdFactory _bucketIdFactory;
lib::Distribution::SP _distribution;
NodeStateUpdater* _nodeStateUpdater;
@@ -43,11 +38,9 @@ public:
StorageComponentRegisterImpl();
~StorageComponentRegisterImpl() override;
- const vespalib::string& getClusterName() const { return _clusterName; }
const lib::NodeType& getNodeType() const { return *_nodeType; }
uint16_t getIndex() const { return _index; }
std::shared_ptr<const document::DocumentTypeRepo> getTypeRepo() { return _docTypeRepo; }
- documentapi::LoadTypeSet::SP getLoadTypes() { return _loadTypes; }
const document::BucketIdFactory& getBucketIdFactory() { return _bucketIdFactory; }
lib::Distribution::SP getDistribution() { return _distribution; }
NodeStateUpdater& getNodeStateUpdater() { return *_nodeStateUpdater; }
@@ -57,8 +50,6 @@ public:
void setNodeInfo(vespalib::stringref clusterName, const lib::NodeType& nodeType, uint16_t index);
virtual void setNodeStateUpdater(NodeStateUpdater& updater);
virtual void setDocumentTypeRepo(std::shared_ptr<const document::DocumentTypeRepo>);
- virtual void setLoadTypes(documentapi::LoadTypeSet::SP);
- virtual void setPriorityConfig(const PriorityConfig&);
virtual void setBucketIdFactory(const document::BucketIdFactory&);
virtual void setDistribution(lib::Distribution::SP);
virtual void setBucketSpacesConfig(const BucketspacesConfig&);
diff --git a/storage/src/vespa/storage/persistence/asynchandler.cpp b/storage/src/vespa/storage/persistence/asynchandler.cpp
index 5344553dd45..5ec1623c599 100644
--- a/storage/src/vespa/storage/persistence/asynchandler.cpp
+++ b/storage/src/vespa/storage/persistence/asynchandler.cpp
@@ -98,7 +98,7 @@ MessageTracker::UP
AsyncHandler::handlePut(api::PutCommand& cmd, MessageTracker::UP trackerUP) const
{
MessageTracker & tracker = *trackerUP;
- auto& metrics = _env._metrics.put[cmd.getLoadType()];
+ auto& metrics = _env._metrics.put;
tracker.setMetric(metrics);
metrics.request_size.addValue(cmd.getApproxByteSize());
@@ -124,7 +124,7 @@ MessageTracker::UP
AsyncHandler::handleUpdate(api::UpdateCommand& cmd, MessageTracker::UP trackerUP) const
{
MessageTracker & tracker = *trackerUP;
- auto& metrics = _env._metrics.update[cmd.getLoadType()];
+ auto& metrics = _env._metrics.update;
tracker.setMetric(metrics);
metrics.request_size.addValue(cmd.getApproxByteSize());
@@ -154,7 +154,7 @@ MessageTracker::UP
AsyncHandler::handleRemove(api::RemoveCommand& cmd, MessageTracker::UP trackerUP) const
{
MessageTracker & tracker = *trackerUP;
- auto& metrics = _env._metrics.remove[cmd.getLoadType()];
+ auto& metrics = _env._metrics.remove;
tracker.setMetric(metrics);
metrics.request_size.addValue(cmd.getApproxByteSize());
diff --git a/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp b/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp
index 76547dc83a8..4178b2bb947 100644
--- a/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp
+++ b/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp
@@ -2,7 +2,6 @@
#include "bucketownershipnotifier.h"
#include <vespa/storage/common/nodestateupdater.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storage/common/content_bucket_space_repo.h>
#include <vespa/vdslib/state/cluster_state_bundle.h>
#include <vespa/storageapi/message/bucket.h>
@@ -60,10 +59,8 @@ BucketOwnershipNotifier::sendNotifyBucketToDistributor(
}
auto notifyCmd = std::make_shared<api::NotifyBucketChangeCommand>(bucket, infoToSend);
- notifyCmd->setAddress(api::StorageMessageAddress(
- _component.getClusterName(),
- lib::NodeType::DISTRIBUTOR,
- distributorIndex));
+ const auto *cluster_np = _component.cluster_context().cluster_name_ptr();
+ notifyCmd->setAddress(api::StorageMessageAddress::create(cluster_np, lib::NodeType::DISTRIBUTOR, distributorIndex));
notifyCmd->setSourceIndex(_component.getIndex());
LOG(debug,
"Sending notify to distributor %u: %s",
@@ -86,12 +83,6 @@ BucketOwnershipNotifier::logNotification(const document::Bucket &bucket,
currentOwnerIndex,
sourceIndex,
newInfo.toString().c_str());
- LOG_BUCKET_OPERATION_NO_LOCK(
- bucket,
- vespalib::make_string(
- "Sending notify to distributor %u "
- "(ownership changed away from %u)",
- currentOwnerIndex, sourceIndex));
}
void
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestorhandler.h b/storage/src/vespa/storage/persistence/filestorage/filestorhandler.h
index 8b031af4b69..7723d0ee765 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestorhandler.h
+++ b/storage/src/vespa/storage/persistence/filestorage/filestorhandler.h
@@ -86,7 +86,6 @@ public:
enum DiskState {
AVAILABLE,
- DISABLED,
CLOSED
};
@@ -108,11 +107,6 @@ public:
/** Check whether it is enabled or not. */
bool enabled() { return (getDiskState() == AVAILABLE); }
bool closed() { return (getDiskState() == CLOSED); }
- /**
- * Disable the disk. Operations towards threads using this disk will
- * start to fail. Typically called when disk errors are detected.
- */
- void disable() { setDiskState(DISABLED); }
/** Closes all disk threads. */
virtual void close() = 0;
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
index 5a7a598fb4c..ec8521d3ab1 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
@@ -9,7 +9,6 @@
#include <vespa/storage/bucketdb/storbucketdb.h>
#include <vespa/storage/common/bucketmessages.h>
#include <vespa/storage/common/statusmessages.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storage/common/messagebucket.h>
#include <vespa/storage/persistence/asynchandler.h>
#include <vespa/storage/persistence/messages.h>
@@ -196,20 +195,6 @@ FileStorHandlerImpl::flush(bool killPendingMerges)
}
void
-FileStorHandlerImpl::reply(api::StorageMessage& msg, DiskState state) const
-{
- if (!msg.getType().isReply()) {
- std::shared_ptr<api::StorageReply> rep = static_cast<api::StorageCommand&>(msg).makeReply();
- if (state == FileStorHandler::DISABLED) {
- rep->setResult(api::ReturnCode(api::ReturnCode::DISK_FAILURE, "Disk disabled"));
- } else {
- rep->setResult(api::ReturnCode(api::ReturnCode::ABORTED, "Shutting down storage node."));
- }
- _messageSender.sendReply(rep);
- }
-}
-
-void
FileStorHandlerImpl::setDiskState(DiskState state)
{
// Mark disk closed
@@ -494,16 +479,6 @@ FileStorHandlerImpl::remapMessage(api::StorageMessage& msg, const document::Buck
if (idx > -1) {
cmd.remapBucketId(targets[idx]->bucket.getBucketId());
targets[idx]->foundInQueue = true;
-#if defined(ENABLE_BUCKET_OPERATION_LOGGING)
- {
- vespalib::string desc = vespalib::make_string(
- "Remapping %s from %s to %s, targetDisk = %u",
- cmd.toString().c_str(), source.toString().c_str(),
- targets[idx]->bid.toString().c_str(), targetDisk);
- LOG_BUCKET_OPERATION_NO_LOCK(source, desc);
- LOG_BUCKET_OPERATION_NO_LOCK(targets[idx]->bid, desc);
- }
-#endif
newBucket = targets[idx]->bucket;
} else {
document::DocumentId did(getDocId(msg));
@@ -536,16 +511,6 @@ FileStorHandlerImpl::remapMessage(api::StorageMessage& msg, const document::Buck
cmd.toString().c_str(), targets[0]->bucket.getBucketId().toString().c_str());
cmd.remapBucketId(targets[0]->bucket.getBucketId());
newBucket = targets[0]->bucket;
-#ifdef ENABLE_BUCKET_OPERATION_LOGGING
- {
- vespalib::string desc = vespalib::make_string(
- "Remapping %s from %s to %s, targetDisk = %u",
- cmd.toString().c_str(), source.toString().c_str(),
- targets[0]->bid.toString().c_str(), targetDisk);
- LOG_BUCKET_OPERATION_NO_LOCK(source, desc);
- LOG_BUCKET_OPERATION_NO_LOCK(targets[0]->bid, desc);
- }
-#endif
}
} else {
LOG(debug, "Did not remap %s with bucket %s from bucket %s",
@@ -658,7 +623,6 @@ FileStorHandlerImpl::remapMessage(api::StorageMessage& msg, const document::Buck
source.getBucketId().toString().c_str(), op);
break;
}
- case InternalBucketJoinCommand::ID:
default:
// Fail and log error
{
@@ -852,7 +816,7 @@ FileStorHandlerImpl::MessageEntry::MessageEntry(const std::shared_ptr<api::Stora
{ }
-FileStorHandlerImpl::MessageEntry::MessageEntry(const MessageEntry& entry)
+FileStorHandlerImpl::MessageEntry::MessageEntry(const MessageEntry& entry) noexcept
: _command(entry._command),
_timer(entry._timer),
_bucket(entry._bucket),
@@ -1260,7 +1224,6 @@ FileStorHandlerImpl::getStatus(std::ostream& out, const framework::HttpUrlPath&
out << "Disk state: ";
switch (getState()) {
case FileStorHandler::AVAILABLE: out << "AVAILABLE"; break;
- case FileStorHandler::DISABLED: out << "DISABLED"; break;
case FileStorHandler::CLOSED: out << "CLOSED"; break;
}
out << "<h4>Active operations</h4>\n";
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.h b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.h
index b3d4ff0c730..688a4b96def 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.h
+++ b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.h
@@ -17,7 +17,7 @@
#include "filestorhandler.h"
#include <vespa/document/bucket/bucketid.h>
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metrictimer.h>
#include <vespa/storage/common/servicelayercomponent.h>
#include <vespa/storageframework/generic/metric/metricupdatehook.h>
#include <vespa/storageapi/messageapi/storagereply.h>
@@ -54,7 +54,7 @@ public:
MessageEntry(const std::shared_ptr<api::StorageMessage>& cmd, const document::Bucket &bId);
MessageEntry(MessageEntry &&) noexcept ;
- MessageEntry(const MessageEntry &);
+ MessageEntry(const MessageEntry &) noexcept;
MessageEntry & operator = (const MessageEntry &) = delete;
~MessageEntry();
@@ -249,8 +249,6 @@ private:
mutable std::condition_variable _pauseCond;
std::atomic<bool> _paused;
- void reply(api::StorageMessage&, DiskState state) const;
-
// Returns the index in the targets array we are sending to, or -1 if none of them match.
int calculateTargetBasedOnDocId(const api::StorageMessage& msg, std::vector<RemapInfo*>& targets);
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
index c1c412fefeb..0626f3d687e 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
@@ -55,7 +55,7 @@ FileStorManager(const config::ConfigUri & configUri, spi::PersistenceProvider& p
_threadLockCheckInterval(60),
_failDiskOnError(false),
_use_async_message_handling_on_schedule(false),
- _metrics(std::make_unique<FileStorMetrics>(_component.getLoadTypes()->getMetricLoadTypes())),
+ _metrics(std::make_unique<FileStorMetrics>()),
_closed(false),
_lock()
{
@@ -91,9 +91,8 @@ FileStorManager::~FileStorManager()
}
void
-FileStorManager::print(std::ostream& out, bool verbose, const std::string& indent) const
+FileStorManager::print(std::ostream& out, bool , const std::string& ) const
{
- (void) verbose; (void) indent;
out << "FileStorManager";
}
@@ -124,6 +123,14 @@ selectSequencer(vespa::config::content::StorFilestorConfig::ResponseSequencerTyp
thread_local PersistenceHandler * _G_threadLocalHandler TLS_LINKAGE = nullptr;
+size_t
+computeAllPossibleHandlerThreads(const vespa::config::content::StorFilestorConfig & cfg) {
+ return cfg.numThreads +
+ computeNumResponseThreads(cfg.numResponseThreads) +
+ cfg.numNetworkThreads +
+ cfg.numVisitorThreads;
+}
+
}
PersistenceHandler &
@@ -164,8 +171,7 @@ FileStorManager::configure(std::unique_ptr<vespa::config::content::StorFilestorC
_config = std::move(config);
size_t numThreads = _config->numThreads;
size_t numStripes = std::max(size_t(1u), numThreads / 2);
- _metrics->initDiskMetrics(_component.getLoadTypes()->getMetricLoadTypes(), numStripes,
- numThreads + _config->numResponseThreads + _config->numNetworkThreads);
+ _metrics->initDiskMetrics(numStripes, computeAllPossibleHandlerThreads(*_config));
_filestorHandler = std::make_unique<FileStorHandlerImpl>(numThreads, numStripes, *this, *_metrics, _compReg);
uint32_t numResponseThreads = computeNumResponseThreads(_config->numResponseThreads);
@@ -283,9 +289,6 @@ FileStorManager::handlePersistenceMessage(const shared_ptr<api::StorageMessage>&
}
}
switch (_filestorHandler->getDiskState()) {
- case FileStorHandler::DISABLED:
- errorCode = api::ReturnCode(api::ReturnCode::DISK_FAILURE, "Disk disabled");
- break;
case FileStorHandler::CLOSED:
errorCode = api::ReturnCode(api::ReturnCode::ABORTED, "Shutting down storage node.");
break;
@@ -694,15 +697,6 @@ FileStorManager::onInternal(const shared_ptr<api::InternalCommand>& msg)
}
return true;
}
- case InternalBucketJoinCommand::ID:
- {
- shared_ptr<InternalBucketJoinCommand> cmd(std::static_pointer_cast<InternalBucketJoinCommand>(msg));
- StorBucketDatabase::WrappedEntry entry(mapOperationToDisk(*cmd, cmd->getBucket()));
- if (entry.exist()) {
- handlePersistenceMessage(cmd);
- }
- return true;
- }
case RecheckBucketInfoCommand::ID:
{
shared_ptr<RecheckBucketInfoCommand> cmd(std::static_pointer_cast<RecheckBucketInfoCommand>(msg));
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormanager.h b/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
index 7abb41f4741..af290b7b085 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
@@ -9,7 +9,6 @@
#pragma once
#include "filestorhandler.h"
-#include "filestormetrics.h"
#include <vespa/vespalib/util/document_runnable.h>
#include <vespa/vespalib/util/isequencedtaskexecutor.h>
#include <vespa/document/bucket/bucketid.h>
@@ -43,6 +42,7 @@ class BucketOwnershipNotifier;
class AbortBucketOperationsCommand;
struct DoneInitializeHandler;
class PersistenceHandler;
+struct FileStorMetrics;
class FileStorManager : public StorageLinkQueued,
public framework::HtmlStatusReporter,
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormetrics.cpp b/storage/src/vespa/storage/persistence/filestorage/filestormetrics.cpp
index 996e3bfe515..2c7b74cebbd 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormetrics.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormetrics.cpp
@@ -1,14 +1,13 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "filestormetrics.h"
-#include <vespa/metrics/loadmetric.hpp>
#include <vespa/metrics/summetric.hpp>
#include <sstream>
namespace storage {
using metrics::MetricSet;
-using metrics::LoadTypeSet;
+// TODO Vespa 8 all metrics with .sum in the name should have that removed.
FileStorThreadMetrics::Op::Op(const std::string& id, const std::string& name, MetricSet* owner)
: MetricSet(id, {}, name + " load in filestor thread", owner),
_name(name),
@@ -109,7 +108,7 @@ FileStorThreadMetrics::OpWithNotFound::clone(std::vector<Metric::UP>& ownerList,
}
FileStorThreadMetrics::Update::Update(MetricSet* owner)
- : OpWithTestAndSetFailed("update", "Update", owner),
+ : OpWithTestAndSetFailed("update.sum", "Update", owner),
latencyRead("latency_read", {}, "Latency of the source read in the request.", this)
{ }
@@ -128,7 +127,7 @@ FileStorThreadMetrics::Update::clone(std::vector<Metric::UP>& ownerList,
}
FileStorThreadMetrics::Visitor::Visitor(MetricSet* owner)
- : Op("visit", "Visit", owner),
+ : Op("visit.sum", "Visit", owner),
documentsPerIterate("docs", {}, "Number of entries read per iterate call", this)
{ }
@@ -146,20 +145,20 @@ FileStorThreadMetrics::Visitor::clone(std::vector<Metric::UP>& ownerList,
return (Visitor*) (new Visitor(owner))->assignValues(*this);
}
-FileStorThreadMetrics::FileStorThreadMetrics(const std::string& name, const std::string& desc, const LoadTypeSet& lt)
+FileStorThreadMetrics::FileStorThreadMetrics(const std::string& name, const std::string& desc)
: MetricSet(name, {{"filestor"},{"partofsum"}}, desc),
operations("operations", {}, "Number of operations processed.", this),
failedOperations("failedoperations", {}, "Number of operations throwing exceptions.", this),
- put(lt, PutMetricType("put", "Put"), this),
- get(lt, GetMetricType("get", "Get"), this),
- remove(lt, RemoveMetricType("remove", "Remove"), this),
- removeLocation(lt, Op("remove_location", "Remove location"), this),
- statBucket(lt, Op("stat_bucket", "Stat bucket"), this),
- update(lt, Update(), this),
- revert(lt, OpWithNotFound("revert", "Revert"), this),
+ put("put.sum", "Put", this),
+ get("get.sum", "Get", this),
+ remove("remove.sum", "Remove", this),
+ removeLocation("remove_location.sum", "Remove location", this),
+ statBucket("stat_bucket", "Stat bucket", this),
+ update(this),
+ revert("revert", "Revert", this),
createIterator("createiterator", {}, this),
- visit(lt, Visitor(), this),
- multiOp(lt, Op("multioperations", "The number of multioperations that have been created"), this),
+ visit(this),
+ multiOp("multioperations", "The number of multioperations that have been created", this),
createBuckets("createbuckets", "Number of buckets that has been created.", this),
deleteBuckets("deletebuckets", "Number of buckets that has been deleted.", this),
repairs("bucketverified", "Number of times buckets have been checked.", this),
@@ -201,7 +200,7 @@ FileStorDiskMetrics::FileStorDiskMetrics(const std::string& name, const std::str
: MetricSet(name, {{"partofsum"}}, description, owner),
sumThreads("allthreads", {{"sum"}}, "", this),
sumStripes("allstripes", {{"sum"}}, "", this),
- averageQueueWaitingTime("averagequeuewait", {}, "Average time an operation spends in input queue.", this),
+ averageQueueWaitingTime("averagequeuewait.sum", {}, "Average time an operation spends in input queue.", this),
queueSize("queuesize", {}, "Size of input message queue.", this),
pendingMerges("pendingmerge", {}, "Number of buckets currently being merged.", this),
waitingForLockHitRate("waitingforlockrate", {},
@@ -216,7 +215,7 @@ FileStorDiskMetrics::FileStorDiskMetrics(const std::string& name, const std::str
FileStorDiskMetrics::~FileStorDiskMetrics() = default;
void
-FileStorDiskMetrics::initDiskMetrics(const LoadTypeSet& loadTypes, uint32_t numStripes, uint32_t threadsPerDisk)
+FileStorDiskMetrics::initDiskMetrics(uint32_t numStripes, uint32_t threadsPerDisk)
{
threads.clear();
threads.resize(threadsPerDisk);
@@ -225,7 +224,7 @@ FileStorDiskMetrics::initDiskMetrics(const LoadTypeSet& loadTypes, uint32_t numS
std::ostringstream name;
name << "thread" << i;
desc << "Thread " << i << '/' << threadsPerDisk;
- threads[i] = std::make_shared<FileStorThreadMetrics>(name.str(), desc.str(), loadTypes);
+ threads[i] = std::make_shared<FileStorThreadMetrics>(name.str(), desc.str());
registerMetric(*threads[i]);
sumThreads.addMetricToSum(*threads[i]);
}
@@ -242,7 +241,7 @@ FileStorDiskMetrics::initDiskMetrics(const LoadTypeSet& loadTypes, uint32_t numS
}
}
-FileStorMetrics::FileStorMetrics(const LoadTypeSet&)
+FileStorMetrics::FileStorMetrics()
: MetricSet("filestor", {{"filestor"}}, ""),
sum("alldisks", {{"sum"}}, "", this),
directoryEvents("directoryevents", {}, "Number of directory events received.", this),
@@ -254,26 +253,14 @@ FileStorMetrics::FileStorMetrics(const LoadTypeSet&)
FileStorMetrics::~FileStorMetrics() = default;
-void FileStorMetrics::initDiskMetrics(const LoadTypeSet& loadTypes, uint32_t numStripes, uint32_t threadsPerDisk)
+void FileStorMetrics::initDiskMetrics(uint32_t numStripes, uint32_t threadsPerDisk)
{
assert( ! disk);
// Currently FileStorHandlerImpl expects metrics to exist for
// disks that are not in use too.
disk = std::make_shared<FileStorDiskMetrics>( "disk_0", "Disk 0", this);
sum.addMetricToSum(*disk);
- disk->initDiskMetrics(loadTypes, numStripes, threadsPerDisk);
+ disk->initDiskMetrics(numStripes, threadsPerDisk);
}
}
-
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::Op>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::OpWithNotFound>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::Update>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::Visitor>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::PutMetricType>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::GetMetricType>;
-template class metrics::LoadMetric<storage::FileStorThreadMetrics::RemoveMetricType>;
-template class metrics::SumMetric<storage::FileStorThreadMetrics::Op>;
-template class metrics::SumMetric<storage::FileStorThreadMetrics::OpWithNotFound>;
-template class metrics::SumMetric<storage::FileStorThreadMetrics::Update>;
-template class metrics::SumMetric<storage::FileStorThreadMetrics::Visitor>;
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormetrics.h b/storage/src/vespa/storage/persistence/filestorage/filestormetrics.h
index aecbfc1ae2b..f3b9d07c322 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormetrics.h
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormetrics.h
@@ -11,8 +11,8 @@
#pragma once
#include "merge_handler_metrics.h"
-#include <vespa/metrics/metrics.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/summetric.h>
namespace storage {
@@ -91,16 +91,16 @@ struct FileStorThreadMetrics : public metrics::MetricSet
metrics::LongCountMetric operations;
metrics::LongCountMetric failedOperations;
- metrics::LoadMetric<PutMetricType> put;
- metrics::LoadMetric<GetMetricType> get;
- metrics::LoadMetric<RemoveMetricType> remove;
- metrics::LoadMetric<Op> removeLocation;
- metrics::LoadMetric<Op> statBucket;
- metrics::LoadMetric<Update> update;
- metrics::LoadMetric<OpWithNotFound> revert;
+ PutMetricType put;
+ GetMetricType get;
+ RemoveMetricType remove;
+ Op removeLocation;
+ Op statBucket;
+ Update update;
+ OpWithNotFound revert;
Op createIterator;
- metrics::LoadMetric<Visitor> visit;
- metrics::LoadMetric<Op> multiOp;
+ Visitor visit;
+ Op multiOp;
Op createBuckets;
Op deleteBuckets;
Op repairs;
@@ -121,7 +121,7 @@ struct FileStorThreadMetrics : public metrics::MetricSet
MergeHandlerMetrics merge_handler_metrics;
metrics::LongAverageMetric batchingSize;
- FileStorThreadMetrics(const std::string& name, const std::string& desc, const metrics::LoadTypeSet& lt);
+ FileStorThreadMetrics(const std::string& name, const std::string& desc);
~FileStorThreadMetrics() override;
};
@@ -152,7 +152,7 @@ public:
FileStorDiskMetrics(const std::string& name, const std::string& description, MetricSet* owner);
~FileStorDiskMetrics() override;
- void initDiskMetrics(const metrics::LoadTypeSet& loadTypes, uint32_t numStripes, uint32_t threadsPerDisk);
+ void initDiskMetrics(uint32_t numStripes, uint32_t threadsPerDisk);
};
struct FileStorMetrics : public metrics::MetricSet
@@ -164,10 +164,10 @@ struct FileStorMetrics : public metrics::MetricSet
metrics::LongCountMetric diskEvents;
metrics::LongAverageMetric bucket_db_init_latency;
- explicit FileStorMetrics(const metrics::LoadTypeSet&);
+ FileStorMetrics();
~FileStorMetrics() override;
- void initDiskMetrics(const metrics::LoadTypeSet& loadTypes, uint32_t numStripes, uint32_t threadsPerDisk);
+ void initDiskMetrics(uint32_t numStripes, uint32_t threadsPerDisk);
};
}
diff --git a/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.cpp b/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.cpp
index d4e82b8a64f..ee2a2d933c3 100644
--- a/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.cpp
@@ -1,5 +1,6 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "merge_handler_metrics.h"
+#include <vespa/metrics/metricset.h>
namespace storage {
diff --git a/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.h b/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.h
index ffa3cf204a3..bd1a6251ff6 100644
--- a/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.h
+++ b/storage/src/vespa/storage/persistence/filestorage/merge_handler_metrics.h
@@ -1,8 +1,10 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/countmetric.h>
+namespace metrics { class MetricSet; }
namespace storage {
// Provides a convenient wrapper for all MergeHandler-related metrics.
diff --git a/storage/src/vespa/storage/persistence/mergehandler.cpp b/storage/src/vespa/storage/persistence/mergehandler.cpp
index 2e65302ee3b..d4d4dd5e62b 100644
--- a/storage/src/vespa/storage/persistence/mergehandler.cpp
+++ b/storage/src/vespa/storage/persistence/mergehandler.cpp
@@ -19,11 +19,11 @@ LOG_SETUP(".persistence.mergehandler");
namespace storage {
MergeHandler::MergeHandler(PersistenceUtil& env, spi::PersistenceProvider& spi,
- const vespalib::string & clusterName, const framework::Clock & clock,
+ const ClusterContext& cluster_context, const framework::Clock & clock,
uint32_t maxChunkSize,
uint32_t commonMergeChainOptimalizationMinimumSize)
: _clock(clock),
- _clusterName(clusterName),
+ _cluster_context(cluster_context),
_env(env),
_spi(spi),
_maxChunkSize(maxChunkSize),
@@ -294,8 +294,8 @@ namespace {
return value;
}
- api::StorageMessageAddress createAddress(const std::string& clusterName, uint16_t node) {
- return api::StorageMessageAddress(clusterName, lib::NodeType::STORAGE, node);
+ api::StorageMessageAddress createAddress(const vespalib::string * clusterName, uint16_t node) {
+ return api::StorageMessageAddress::create(clusterName, lib::NodeType::STORAGE, node);
}
void assertContainedInBucket(const document::DocumentId& docId,
@@ -706,7 +706,7 @@ MergeHandler::processBucketMerge(const spi::Bucket& bucket, MergeStatus& status,
assert(nodes.size() > 1);
cmd = std::make_shared<api::ApplyBucketDiffCommand>(bucket.getBucket(), nodes);
- cmd->setAddress(createAddress(_clusterName, nodes[1].index));
+ cmd->setAddress(createAddress(_cluster_context.cluster_name_ptr(), nodes[1].index));
findCandidates(status,
active_nodes_mask,
true,
@@ -782,7 +782,7 @@ MergeHandler::processBucketMerge(const spi::Bucket& bucket, MergeStatus& status,
}
assert(nodes.size() > 1);
cmd = std::make_shared<api::ApplyBucketDiffCommand>(bucket.getBucket(), nodes);
- cmd->setAddress(createAddress(_clusterName, nodes[1].index));
+ cmd->setAddress(createAddress(_cluster_context.cluster_name_ptr(), nodes[1].index));
// Add all the metadata, and thus use big limit. Max
// data to fetch parameter will control amount added.
findCandidates(status, active_nodes_mask, true, e.first, newMask, *cmd);
@@ -795,7 +795,7 @@ MergeHandler::processBucketMerge(const spi::Bucket& bucket, MergeStatus& status,
// merge to merge the remaining data.
if ( ! cmd ) {
cmd = std::make_shared<api::ApplyBucketDiffCommand>(bucket.getBucket(), status.nodeList);
- cmd->setAddress(createAddress(_clusterName, status.nodeList[1].index));
+ cmd->setAddress(createAddress(_cluster_context.cluster_name_ptr(), status.nodeList[1].index));
findCandidates(status, active_nodes_mask, false, 0, 0, *cmd);
}
cmd->setPriority(status.context.getPriority());
@@ -901,7 +901,7 @@ MergeHandler::handleMergeBucket(api::MergeBucketCommand& cmd, MessageTracker::UP
bucket.toString().c_str(),
s->nodeList[1].index,
uint32_t(cmd2->getDiff().size()));
- cmd2->setAddress(createAddress(_clusterName, s->nodeList[1].index));
+ cmd2->setAddress(createAddress(_cluster_context.cluster_name_ptr(), s->nodeList[1].index));
cmd2->setPriority(s->context.getPriority());
cmd2->setTimeout(s->timeout);
cmd2->setSourceIndex(cmd.getSourceIndex());
@@ -1111,7 +1111,7 @@ MergeHandler::handleGetBucketDiff(api::GetBucketDiffCommand& cmd, MessageTracker
bucket.toString().c_str(), cmd.getNodes()[index + 1].index,
local.size() - remote.size());
auto cmd2 = std::make_shared<api::GetBucketDiffCommand>(bucket.getBucket(), cmd.getNodes(), cmd.getMaxTimestamp());
- cmd2->setAddress(createAddress(_clusterName, cmd.getNodes()[index + 1].index));
+ cmd2->setAddress(createAddress(_cluster_context.cluster_name_ptr(), cmd.getNodes()[index + 1].index));
cmd2->getDiff().swap(local);
cmd2->setPriority(cmd.getPriority());
cmd2->setTimeout(cmd.getTimeout());
@@ -1293,7 +1293,7 @@ MergeHandler::handleApplyBucketDiff(api::ApplyBucketDiffCommand& cmd, MessageTra
LOG(spam, "Sending ApplyBucketDiff for %s on to node %d",
bucket.toString().c_str(), cmd.getNodes()[index + 1].index);
auto cmd2 = std::make_shared<api::ApplyBucketDiffCommand>(bucket.getBucket(), cmd.getNodes());
- cmd2->setAddress(createAddress(_clusterName, cmd.getNodes()[index + 1].index));
+ cmd2->setAddress(createAddress(_cluster_context.cluster_name_ptr(), cmd.getNodes()[index + 1].index));
cmd2->getDiff().swap(cmd.getDiff());
cmd2->setPriority(cmd.getPriority());
cmd2->setTimeout(cmd.getTimeout());
diff --git a/storage/src/vespa/storage/persistence/mergehandler.h b/storage/src/vespa/storage/persistence/mergehandler.h
index 25b7f281ef0..17a961a3982 100644
--- a/storage/src/vespa/storage/persistence/mergehandler.h
+++ b/storage/src/vespa/storage/persistence/mergehandler.h
@@ -17,6 +17,7 @@
#include <vespa/persistence/spi/bucket.h>
#include <vespa/persistence/spi/docentry.h>
#include <vespa/storageapi/message/bucket.h>
+#include <vespa/storage/common/cluster_context.h>
#include <vespa/storage/common/messagesender.h>
namespace storage {
@@ -39,7 +40,7 @@ public:
};
MergeHandler(PersistenceUtil& env, spi::PersistenceProvider& spi,
- const vespalib::string & clusterName, const framework::Clock & clock,
+ const ClusterContext& cluster_context, const framework::Clock & clock,
uint32_t maxChunkSize = 4190208,
uint32_t commonMergeChainOptimalizationMinimumSize = 64);
@@ -67,7 +68,7 @@ public:
private:
const framework::Clock &_clock;
- const vespalib::string &_clusterName;
+ const ClusterContext &_cluster_context;
PersistenceUtil &_env;
spi::PersistenceProvider &_spi;
const uint32_t _maxChunkSize;
diff --git a/storage/src/vespa/storage/persistence/persistencehandler.cpp b/storage/src/vespa/storage/persistence/persistencehandler.cpp
index c3751abb7d9..cbe5454f4e7 100644
--- a/storage/src/vespa/storage/persistence/persistencehandler.cpp
+++ b/storage/src/vespa/storage/persistence/persistencehandler.cpp
@@ -17,7 +17,7 @@ PersistenceHandler::PersistenceHandler(vespalib::ISequencedTaskExecutor & sequen
: _clock(component.getClock()),
_env(component, filestorHandler, metrics, provider),
_processAllHandler(_env, provider),
- _mergeHandler(_env, provider, component.getClusterName(), _clock,
+ _mergeHandler(_env, provider, component.cluster_context(), _clock,
cfg.bucketMergeChunkSize,
cfg.commonMergeChainOptimalizationMinimumSize),
_asyncHandler(_env, provider, sequencedExecutor, component.getBucketIdFactory()),
@@ -73,8 +73,6 @@ PersistenceHandler::handleCommandSplitByType(api::StorageCommand& msg, MessageTr
return _simpleHandler.handleReadBucketList(static_cast<ReadBucketList&>(msg), std::move(tracker));
case ReadBucketInfo::ID:
return _simpleHandler.handleReadBucketInfo(static_cast<ReadBucketInfo&>(msg), std::move(tracker));
- case InternalBucketJoinCommand::ID:
- return _splitJoinHandler.handleInternalBucketJoin(static_cast<InternalBucketJoinCommand&>(msg), std::move(tracker));
case RecheckBucketInfoCommand::ID:
return _splitJoinHandler.handleRecheckBucketInfo(static_cast<RecheckBucketInfoCommand&>(msg), std::move(tracker));
default:
diff --git a/storage/src/vespa/storage/persistence/processallhandler.cpp b/storage/src/vespa/storage/persistence/processallhandler.cpp
index a9c1aafd4d9..9cf570ef7a4 100644
--- a/storage/src/vespa/storage/persistence/processallhandler.cpp
+++ b/storage/src/vespa/storage/persistence/processallhandler.cpp
@@ -76,7 +76,7 @@ public:
MessageTracker::UP
ProcessAllHandler::handleRemoveLocation(api::RemoveLocationCommand& cmd, MessageTracker::UP tracker) const
{
- tracker->setMetric(_env._metrics.removeLocation[cmd.getLoadType()]);
+ tracker->setMetric(_env._metrics.removeLocation);
LOG(debug, "RemoveLocation(%s): using selection '%s'",
cmd.getBucketId().toString().c_str(),
@@ -95,7 +95,7 @@ ProcessAllHandler::handleRemoveLocation(api::RemoveLocationCommand& cmd, Message
MessageTracker::UP
ProcessAllHandler::handleStatBucket(api::StatBucketCommand& cmd, MessageTracker::UP tracker) const
{
- tracker->setMetric(_env._metrics.statBucket[cmd.getLoadType()]);
+ tracker->setMetric(_env._metrics.statBucket);
std::ostringstream ost;
ost << "Persistence bucket " << cmd.getBucketId() << "\n";
diff --git a/storage/src/vespa/storage/persistence/simplemessagehandler.cpp b/storage/src/vespa/storage/persistence/simplemessagehandler.cpp
index 6ed928245db..9c31a1c81bc 100644
--- a/storage/src/vespa/storage/persistence/simplemessagehandler.cpp
+++ b/storage/src/vespa/storage/persistence/simplemessagehandler.cpp
@@ -3,7 +3,6 @@
#include "simplemessagehandler.h"
#include "persistenceutil.h"
#include <vespa/persistence/spi/persistenceprovider.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storageapi/message/bucket.h>
#include <vespa/document/base/exceptions.h>
#include <vespa/document/fieldset/fieldsetrepo.h>
@@ -64,7 +63,7 @@ SimpleMessageHandler::SimpleMessageHandler(const PersistenceUtil& env, spi::Pers
MessageTracker::UP
SimpleMessageHandler::handleGet(api::GetCommand& cmd, MessageTracker::UP tracker) const
{
- auto& metrics = _env._metrics.get[cmd.getLoadType()];
+ auto& metrics = _env._metrics.get;
tracker->setMetric(metrics);
metrics.request_size.addValue(cmd.getApproxByteSize());
@@ -89,7 +88,7 @@ SimpleMessageHandler::handleGet(api::GetCommand& cmd, MessageTracker::UP tracker
MessageTracker::UP
SimpleMessageHandler::handleRevert(api::RevertCommand& cmd, MessageTracker::UP tracker) const
{
- tracker->setMetric(_env._metrics.revert[cmd.getLoadType()]);
+ tracker->setMetric(_env._metrics.revert);
spi::Bucket b = spi::Bucket(cmd.getBucket());
const std::vector<api::Timestamp> & tokens = cmd.getRevertTokens();
for (const api::Timestamp & token : tokens) {
@@ -105,7 +104,6 @@ SimpleMessageHandler::handleCreateBucket(api::CreateBucketCommand& cmd, MessageT
LOG(debug, "CreateBucket(%s)", cmd.getBucketId().toString().c_str());
if (_env._fileStorHandler.isMerging(cmd.getBucket())) {
LOG(warning, "Bucket %s was merging at create time. Unexpected.", cmd.getBucketId().toString().c_str());
- DUMP_LOGGED_BUCKET_OPERATIONS(cmd.getBucketId());
}
spi::Bucket spiBucket(cmd.getBucket());
_spi.createBucket(spiBucket, tracker->context());
@@ -147,7 +145,6 @@ SimpleMessageHandler::handleDeleteBucket(api::DeleteBucketCommand& cmd, MessageT
{
tracker->setMetric(_env._metrics.deleteBuckets);
LOG(debug, "DeletingBucket(%s)", cmd.getBucketId().toString().c_str());
- LOG_BUCKET_OPERATION(cmd.getBucketId(), "deleteBucket()");
if (_env._fileStorHandler.isMerging(cmd.getBucket())) {
_env._fileStorHandler.clearMergeStatus(cmd.getBucket(),
api::ReturnCode(api::ReturnCode::ABORTED, "Bucket was deleted during the merge"));
@@ -183,13 +180,12 @@ SimpleMessageHandler::handleDeleteBucket(api::DeleteBucketCommand& cmd, MessageT
MessageTracker::UP
SimpleMessageHandler::handleGetIter(GetIterCommand& cmd, MessageTracker::UP tracker) const
{
- tracker->setMetric(_env._metrics.visit[cmd.getLoadType()]);
+ tracker->setMetric(_env._metrics.visit);
spi::IterateResult result(_spi.iterate(cmd.getIteratorId(), cmd.getMaxByteSize(), tracker->context()));
if (tracker->checkForError(result)) {
auto reply = std::make_shared<GetIterReply>(cmd);
reply->getEntries() = result.steal_entries();
- _env._metrics.visit[cmd.getLoadType()].
- documentsPerIterate.addValue(reply->getEntries().size());
+ _env._metrics.visit.documentsPerIterate.addValue(reply->getEntries().size());
if (result.isCompleted()) {
reply->setCompleted();
}
diff --git a/storage/src/vespa/storage/persistence/splitjoinhandler.cpp b/storage/src/vespa/storage/persistence/splitjoinhandler.cpp
index c64a892d6fb..756f9edc3dd 100644
--- a/storage/src/vespa/storage/persistence/splitjoinhandler.cpp
+++ b/storage/src/vespa/storage/persistence/splitjoinhandler.cpp
@@ -268,32 +268,6 @@ SplitJoinHandler::handleJoinBuckets(api::JoinBucketsCommand& cmd, MessageTracker
return tracker;
}
-MessageTracker::UP
-SplitJoinHandler::handleInternalBucketJoin(InternalBucketJoinCommand& cmd, MessageTracker::UP tracker) const
-{
- tracker->setMetric(_env._metrics.internalJoin);
- document::Bucket destBucket = cmd.getBucket();
- {
- // Create empty bucket for target.
- StorBucketDatabase::WrappedEntry entry =
- _env.getBucketDatabase(destBucket.getBucketSpace()).get(
- destBucket.getBucketId(), "join", StorBucketDatabase::CREATE_IF_NONEXISTING);
-
- entry.write();
- }
- assert(cmd.getDiskOfInstanceToJoin() == 0u);
- assert(cmd.getDiskOfInstanceToKeep() == 0u);
- spi::Result result =
- _spi.join(spi::Bucket(destBucket),
- spi::Bucket(destBucket),
- spi::Bucket(destBucket),
- tracker->context());
- if (tracker->checkForError(result)) {
- tracker->setReply(std::make_shared<InternalBucketJoinReply>(cmd, _env.getBucketInfo(cmd.getBucket())));
- }
- return tracker;
-}
-
bool
SplitJoinHandler::validateJoinCommand(const api::JoinBucketsCommand& cmd, MessageTracker& tracker)
{
diff --git a/storage/src/vespa/storage/persistence/splitjoinhandler.h b/storage/src/vespa/storage/persistence/splitjoinhandler.h
index 2279b0b6ef9..408838e3715 100644
--- a/storage/src/vespa/storage/persistence/splitjoinhandler.h
+++ b/storage/src/vespa/storage/persistence/splitjoinhandler.h
@@ -11,7 +11,6 @@ namespace spi { struct PersistenceProvider; }
class PersistenceUtil;
class BucketOwnershipNotifier;
class RecheckBucketInfoCommand;
-class InternalBucketJoinCommand;
/**
* Handle operations that might changes bucket ownership.
@@ -25,7 +24,6 @@ public:
MessageTrackerUP handleSetBucketState(api::SetBucketStateCommand& cmd, MessageTrackerUP tracker) const;
MessageTrackerUP handleRecheckBucketInfo(RecheckBucketInfoCommand& cmd, MessageTrackerUP tracker) const;
MessageTrackerUP handleJoinBuckets(api::JoinBucketsCommand& cmd, MessageTrackerUP tracker) const;
- MessageTrackerUP handleInternalBucketJoin(InternalBucketJoinCommand& cmd, MessageTrackerUP tracker) const;
private:
/**
* Sanity-checking of join command parameters. Invokes tracker.fail() with
diff --git a/storage/src/vespa/storage/storageserver/bouncer_metrics.h b/storage/src/vespa/storage/storageserver/bouncer_metrics.h
index 9842bed1c6f..a2831092926 100644
--- a/storage/src/vespa/storage/storageserver/bouncer_metrics.h
+++ b/storage/src/vespa/storage/storageserver/bouncer_metrics.h
@@ -2,7 +2,8 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/countmetric.h>
namespace storage {
diff --git a/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.cpp b/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.cpp
index aec0adf790c..a736ea58406 100644
--- a/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.cpp
+++ b/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.cpp
@@ -9,6 +9,8 @@
#include <vespa/storage/common/nodestateupdater.h>
#include <vespa/storage/common/content_bucket_space_repo.h>
#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/metrics/metrictimer.h>
+
#include <vespa/log/bufferedlogger.h>
LOG_SETUP(".bucketownershiphandler");
@@ -35,9 +37,7 @@ ChangedBucketOwnershipHandler::ChangedBucketOwnershipHandler(
_component.registerMetric(_metrics);
}
-ChangedBucketOwnershipHandler::~ChangedBucketOwnershipHandler()
-{
-}
+ChangedBucketOwnershipHandler::~ChangedBucketOwnershipHandler() = default;
void
ChangedBucketOwnershipHandler::configure(
diff --git a/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.h b/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.h
index 0fc456b515c..b2661ce0d8d 100644
--- a/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.h
+++ b/storage/src/vespa/storage/storageserver/changedbucketownershiphandler.h
@@ -4,11 +4,13 @@
#include <vespa/document/bucket/bucketid.h>
#include <vespa/storage/common/storagelink.h>
#include <vespa/vdslib/distribution/distribution.h>
-#include <vespa/metrics/metrics.h>
#include <vespa/config/config.h>
#include <vespa/config-persistence.h>
#include <vespa/storage/common/servicelayercomponent.h>
#include <vespa/storage/persistence/messages.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/countmetric.h>
+#include <vespa/metrics/metricset.h>
#include <atomic>
#include <vector>
#include <unordered_map>
diff --git a/storage/src/vespa/storage/storageserver/communicationmanager.cpp b/storage/src/vespa/storage/storageserver/communicationmanager.cpp
index c296f215c8c..6021673d472 100644
--- a/storage/src/vespa/storage/storageserver/communicationmanager.cpp
+++ b/storage/src/vespa/storage/storageserver/communicationmanager.cpp
@@ -56,7 +56,7 @@ CommunicationManager::receiveStorageReply(const std::shared_ptr<api::StorageRepl
namespace {
vespalib::string getNodeId(StorageComponent& sc) {
vespalib::asciistream ost;
- ost << sc.getClusterName() << "/" << sc.getNodeType() << "/" << sc.getIndex();
+ ost << sc.cluster_context().cluster_name() << "/" << sc.getNodeType() << "/" << sc.getIndex();
return ost.str();
}
@@ -375,6 +375,7 @@ void CommunicationManager::configure(std::unique_ptr<CommunicationManagerConfig>
{
// Only allow dynamic (live) reconfiguration of message bus limits.
_skip_thread = config->skipThread;
+ _use_direct_storageapi_rpc = config->useDirectStorageapiRpc;
if (_mbus) {
configureMessageBusLimits(*config);
if (_mbus->getRPCNetwork().getPort() != config->mbusport) {
@@ -417,21 +418,19 @@ void CommunicationManager::configure(std::unique_ptr<CommunicationManagerConfig>
// Configure messagebus here as we for legacy reasons have
// config here.
auto documentTypeRepo = _component.getTypeRepo()->documentTypeRepo;
- auto loadTypes = _component.getLoadTypes();
_mbus = std::make_unique<mbus::RPCMessageBus>(
mbus::ProtocolSet()
- .add(std::make_shared<documentapi::DocumentProtocol>(*loadTypes, documentTypeRepo))
- .add(std::make_shared<mbusprot::StorageProtocol>(documentTypeRepo, *loadTypes)),
+ .add(std::make_shared<documentapi::DocumentProtocol>(documentTypeRepo))
+ .add(std::make_shared<mbusprot::StorageProtocol>(documentTypeRepo)),
params,
_configUri);
configureMessageBusLimits(*config);
}
- _use_direct_storageapi_rpc = config->useDirectStorageapiRpc;
- _message_codec_provider = std::make_unique<rpc::MessageCodecProvider>(_component.getTypeRepo()->documentTypeRepo,
- _component.getLoadTypes());
- _shared_rpc_resources = std::make_unique<rpc::SharedRpcResources>(_configUri, config->rpcport, config->rpc.numNetworkThreads);
+ _message_codec_provider = std::make_unique<rpc::MessageCodecProvider>(_component.getTypeRepo()->documentTypeRepo);
+ _shared_rpc_resources = std::make_unique<rpc::SharedRpcResources>(_configUri, config->rpcport,
+ config->rpc.numNetworkThreads, config->rpc.eventsBeforeWakeup);
_cc_rpc_service = std::make_unique<rpc::ClusterControllerApiRpcService>(*this, *_shared_rpc_resources);
rpc::StorageApiRpcService::Params rpc_params;
rpc_params.compression_config = convert_to_rpc_compression_config(*config);
@@ -478,7 +477,7 @@ void
CommunicationManager::enqueue_or_process(std::shared_ptr<api::StorageMessage> msg)
{
assert(msg);
- if (_skip_thread) {
+ if (_skip_thread.load(std::memory_order_relaxed)) {
LOG(spam, "Process storage message %s, priority %d", msg->toString().c_str(), msg->getPriority());
process(msg);
} else {
@@ -562,8 +561,8 @@ CommunicationManager::sendCommand(
api::StorageMessageAddress address(*msg->getAddress());
switch (msg->getType().getId()) {
case api::MessageType::STATBUCKET_ID: {
- if (address.getProtocol() == api::StorageMessageAddress::STORAGE) {
- address.setProtocol(api::StorageMessageAddress::DOCUMENT);
+ if (address.getProtocol() == api::StorageMessageAddress::Protocol::STORAGE) {
+ address.setProtocol(api::StorageMessageAddress::Protocol::DOCUMENT);
}
}
default:
@@ -572,10 +571,12 @@ CommunicationManager::sendCommand(
framework::MilliSecTimer startTime(_component.getClock());
switch (address.getProtocol()) {
- case api::StorageMessageAddress::STORAGE:
+ case api::StorageMessageAddress::Protocol::STORAGE:
{
LOG(debug, "Send to %s: %s", address.toString().c_str(), msg->toString().c_str());
- if (_use_direct_storageapi_rpc && _storage_api_rpc_service->target_supports_direct_rpc(address)) {
+ if (_use_direct_storageapi_rpc.load(std::memory_order_relaxed) &&
+ _storage_api_rpc_service->target_supports_direct_rpc(address))
+ {
_storage_api_rpc_service->send_rpc_v1_request(msg);
} else {
auto cmd = std::make_unique<mbusprot::StorageCommand>(msg);
@@ -588,7 +589,7 @@ CommunicationManager::sendCommand(
}
break;
}
- case api::StorageMessageAddress::DOCUMENT:
+ case api::StorageMessageAddress::Protocol::DOCUMENT:
{
MBUS_TRACE(msg->getTrace(), 7, "Communication manager: Converting storageapi message to documentapi");
@@ -788,18 +789,17 @@ CommunicationManager::print(std::ostream& out, bool verbose, const std::string&
out << "CommunicationManager";
}
-void CommunicationManager::updateMessagebusProtocol(
- const std::shared_ptr<const document::DocumentTypeRepo>& repo) {
+void CommunicationManager::updateMessagebusProtocol(const std::shared_ptr<const document::DocumentTypeRepo>& repo) {
if (_mbus) {
framework::SecondTime now(_component.getClock().getTimeInSeconds());
- auto newDocumentProtocol = std::make_shared<documentapi::DocumentProtocol>(*_component.getLoadTypes(), repo);
+ auto newDocumentProtocol = std::make_shared<documentapi::DocumentProtocol>(repo);
std::lock_guard<std::mutex> guard(_earlierGenerationsLock);
_earlierGenerations.push_back(std::make_pair(now, _mbus->getMessageBus().putProtocol(newDocumentProtocol)));
- auto newStorageProtocol = std::make_shared<mbusprot::StorageProtocol>(repo, *_component.getLoadTypes());
+ auto newStorageProtocol = std::make_shared<mbusprot::StorageProtocol>(repo);
_earlierGenerations.push_back(std::make_pair(now, _mbus->getMessageBus().putProtocol(newStorageProtocol)));
}
if (_message_codec_provider) {
- _message_codec_provider->update_atomically(repo, _component.getLoadTypes());
+ _message_codec_provider->update_atomically(repo);
}
}
diff --git a/storage/src/vespa/storage/storageserver/communicationmanager.h b/storage/src/vespa/storage/storageserver/communicationmanager.h
index 7227f1d7e5b..db88f95af6d 100644
--- a/storage/src/vespa/storage/storageserver/communicationmanager.h
+++ b/storage/src/vespa/storage/storageserver/communicationmanager.h
@@ -118,8 +118,8 @@ private:
std::atomic<bool> _closed;
DocumentApiConverter _docApiConverter;
framework::Thread::UP _thread;
- bool _skip_thread;
- bool _use_direct_storageapi_rpc;
+ std::atomic<bool> _skip_thread;
+ std::atomic<bool> _use_direct_storageapi_rpc;
void updateMetrics(const MetricLockGuard &) override;
void enqueue_or_process(std::shared_ptr<api::StorageMessage> msg);
diff --git a/storage/src/vespa/storage/storageserver/communicationmanagermetrics.h b/storage/src/vespa/storage/storageserver/communicationmanagermetrics.h
index cc62b93e6d4..2e439bc9266 100644
--- a/storage/src/vespa/storage/storageserver/communicationmanagermetrics.h
+++ b/storage/src/vespa/storage/storageserver/communicationmanagermetrics.h
@@ -8,7 +8,9 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/countmetric.h>
namespace storage {
diff --git a/storage/src/vespa/storage/storageserver/distributornode.cpp b/storage/src/vespa/storage/storageserver/distributornode.cpp
index e6bee3248d4..37174903697 100644
--- a/storage/src/vespa/storage/storageserver/distributornode.cpp
+++ b/storage/src/vespa/storage/storageserver/distributornode.cpp
@@ -108,7 +108,7 @@ DistributorNode::createChain(IStorageChainBuilder &builder)
// manager, which is safe since the lifetime of said state manager
// extends to the end of the process.
builder.add(std::make_unique<storage::distributor::Distributor>
- (dcr, *_threadPool, getDoneInitializeHandler(),
+ (dcr, *_node_identity, *_threadPool, getDoneInitializeHandler(),
_manageActiveBucketCopies,
stateManager->getHostInfo()));
diff --git a/storage/src/vespa/storage/storageserver/distributornodecontext.h b/storage/src/vespa/storage/storageserver/distributornodecontext.h
index 152218707e0..3e3541498c0 100644
--- a/storage/src/vespa/storage/storageserver/distributornodecontext.h
+++ b/storage/src/vespa/storage/storageserver/distributornodecontext.h
@@ -8,10 +8,6 @@
* This utility class sets up the default component register implementation.
* It also sets up the clock and the threadpool, such that the most basic
* features are available to the provider, before the service layer is set up.
- *
- * The service layer still provides the memory manager functionality though,
- * so you cannot retrieve the memory manager before the service layer has
- * started up. (Before getPartitionStates() have been called on provider)
*/
#pragma once
diff --git a/storage/src/vespa/storage/storageserver/documentapiconverter.cpp b/storage/src/vespa/storage/storageserver/documentapiconverter.cpp
index b1c8c1e43a4..70f47d8108b 100644
--- a/storage/src/vespa/storage/storageserver/documentapiconverter.cpp
+++ b/storage/src/vespa/storage/storageserver/documentapiconverter.cpp
@@ -185,7 +185,7 @@ DocumentApiConverter::toStorageAPI(documentapi::DocumentReply& fromReply,
break;
}
- if (toMsg.get()) {
+ if (toMsg) {
if (fromReply.hasErrors()) {
toMsg->setResult(api::ReturnCode((api::ReturnCode::Result) fromReply.getError(0).getCode(),
fromReply.getError(0).getMessage()));
diff --git a/storage/src/vespa/storage/storageserver/fnet_metrics_wrapper.h b/storage/src/vespa/storage/storageserver/fnet_metrics_wrapper.h
index dacb9e9f52c..15bbf31e9e6 100644
--- a/storage/src/vespa/storage/storageserver/fnet_metrics_wrapper.h
+++ b/storage/src/vespa/storage/storageserver/fnet_metrics_wrapper.h
@@ -2,7 +2,9 @@
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/valuemetric.h>
+
#include <vespa/fnet/connection.h>
namespace storage {
diff --git a/storage/src/vespa/storage/storageserver/framework.cpp b/storage/src/vespa/storage/storageserver/framework.cpp
deleted file mode 100644
index 1cbed2ea39d..00000000000
--- a/storage/src/vespa/storage/storageserver/framework.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "framework.h"
-
-#include <vespa/storageframework/defaultimplementation/memory/prioritymemorylogic.h>
-
-using storage::framework::defaultimplementation::AllocationLogic;
-
-namespace storage {
-
-Framework::Framework(framework::Clock::UP clock)
- : _componentRegister(),
- _clock(clock),
- _threadPool(*_clock),
- _memoryLogic(new framework::defaultimplementation::PriorityMemoryLogic(
- *_clock, 1024 * 1024 * 1024)),
- _memoryManager(AllocationLogic::UP(_memoryLogic))
-{
- framework::defaultimplementation::ComponentRegisterImpl& cri(
- _componentRegister.getComponentRegisterImpl());
- cri.setClock(*_clock);
- cri.setThreadPool(_threadPool);
- cri.setMemoryManager(_memoryManager);
-}
-
-void
-Framework::setMaximumMemoryUsage(uint64_t max)
-{
- using storage::framework::defaultimplementation::PriorityMemoryLogic;
- static_cast<PriorityMemoryLogic*>(_memoryLogic)->setMaximumMemoryUsage(max);
-}
-
-} // storage
diff --git a/storage/src/vespa/storage/storageserver/framework.h b/storage/src/vespa/storage/storageserver/framework.h
deleted file mode 100644
index f0ea1d71aa6..00000000000
--- a/storage/src/vespa/storage/storageserver/framework.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @class storage::Framework
- * @ingroup storageserver
- *
- * @brief Data available to both provider implementations and storage server
- *
- * This utility class sets up the default component register implementation.
- * It also sets up the clock and the threadpool, such that the most basic
- * features are available to the provider, before the service layer is set up.
- *
- * The service layer still provides the memory manager functionality though,
- * so you cannot retrieve the memory manager before the service layer has
- * started up. (Before getPartitionStates() have been called on provider)
- */
-
-#pragma once
-
-#include <vespa/storage/frameworkimpl/component/storagecomponentregisterimpl.h>
-#include <vespa/storageframework/defaultimplementation/clock/realclock.h>
-#include <vespa/storageframework/defaultimplementation/thread/threadpoolimpl.h>
-
-namespace storage {
-
-struct Framework {
- // Typedefs to simplify the remainder of the interface
- typedef StorageComponentRegisterImpl CompReg;
- typedef framework::defaultimplementation::RealClock RealClock;
-
- /**
- * You can provide your own clock implementation. Useful in testing where
- * you want to fake the clock.
- */
- Framework(framework::Clock::UP clock = framework::Clock::UP(new RealClock));
-
- /**
- * Get the actual component register. Available as the actual type as the
- * storage server need to set implementations, and the components need the
- * actual component register interface.
- */
- CompReg& getComponentRegister() { return _componentRegister; }
-
- /**
- * There currently exist threads that doesn't use the component model.
- * Let the backend threadpool be accessible for now.
- */
- FastOS_ThreadPool& getThreadPool() { return _threadPool.getThreadPool(); }
-
-private:
- CompReg _componentRegister;
- framework::Clock::UP _clock;
- framework::defaultimplementation::ThreadPoolImpl _threadPool;
-
-};
-
-} // storage
-
diff --git a/storage/src/vespa/storage/storageserver/mergethrottler.cpp b/storage/src/vespa/storage/storageserver/mergethrottler.cpp
index 2e3c65ef70c..2984ba27344 100644
--- a/storage/src/vespa/storage/storageserver/mergethrottler.cpp
+++ b/storage/src/vespa/storage/storageserver/mergethrottler.cpp
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "mergethrottler.h"
-#include <vespa/vdslib/state/cluster_state_bundle.h>
#include <vespa/storage/common/nodestateupdater.h>
#include <vespa/storage/persistence/messages.h>
#include <vespa/messagebus/message.h>
@@ -66,7 +65,7 @@ MergeThrottler::ChainedMergeState::ChainedMergeState(const api::StorageMessage::
_cycleBroken(false),
_aborted(false)
{ }
-MergeThrottler::ChainedMergeState::~ChainedMergeState() {}
+MergeThrottler::ChainedMergeState::~ChainedMergeState() = default;
MergeThrottler::Metrics::Metrics(metrics::MetricSet* owner)
: metrics::MetricSet("mergethrottler", {}, "", owner),
@@ -75,7 +74,7 @@ MergeThrottler::Metrics::Metrics(metrics::MetricSet* owner)
chaining("mergechains", this),
local("locallyexecutedmerges", this)
{ }
-MergeThrottler::Metrics::~Metrics() {}
+MergeThrottler::Metrics::~Metrics() = default;
MergeThrottler::MergeFailureMetrics::MergeFailureMetrics(metrics::MetricSet* owner)
: metrics::MetricSet("failures", {}, "Detailed failure statistics", owner),
@@ -100,7 +99,7 @@ MergeThrottler::MergeFailureMetrics::MergeFailureMetrics(metrics::MetricSet* own
sum.addMetricToSum(rejected);
sum.addMetricToSum(other);
}
-MergeThrottler::MergeFailureMetrics::~MergeFailureMetrics() { }
+MergeThrottler::MergeFailureMetrics::~MergeFailureMetrics() = default;
MergeThrottler::MergeOperationMetrics::MergeOperationMetrics(const std::string& name, metrics::MetricSet* owner)
@@ -109,7 +108,7 @@ MergeThrottler::MergeOperationMetrics::MergeOperationMetrics(const std::string&
failures(this)
{
}
-MergeThrottler::MergeOperationMetrics::~MergeOperationMetrics() { }
+MergeThrottler::MergeOperationMetrics::~MergeOperationMetrics() = default;
MergeThrottler::MergeNodeSequence::MergeNodeSequence(
const api::MergeBucketCommand& cmd,
@@ -374,11 +373,8 @@ MergeThrottler::forwardCommandToNode(
mergeCmd.getMaxTimestamp(),
mergeCmd.getClusterStateVersion(),
newChain));
- fwdMerge->setAddress(
- api::StorageMessageAddress(
- _component.getClusterName(),
- lib::NodeType::STORAGE,
- nodeIndex));
+ const auto *cluster_np = _component.cluster_context().cluster_name_ptr();
+ fwdMerge->setAddress(api::StorageMessageAddress::create(cluster_np, lib::NodeType::STORAGE, nodeIndex));
fwdMerge->setSourceIndex(mergeCmd.getSourceIndex());
fwdMerge->setPriority(mergeCmd.getPriority());
fwdMerge->setTimeout(mergeCmd.getTimeout());
diff --git a/storage/src/vespa/storage/storageserver/mergethrottler.h b/storage/src/vespa/storage/storageserver/mergethrottler.h
index 9e0e9c08b3c..e8815eee680 100644
--- a/storage/src/vespa/storage/storageserver/mergethrottler.h
+++ b/storage/src/vespa/storage/storageserver/mergethrottler.h
@@ -16,7 +16,11 @@
#include <vespa/document/bucket/bucket.h>
#include <vespa/vespalib/util/document_runnable.h>
#include <vespa/messagebus/staticthrottlepolicy.h>
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/summetric.h>
+#include <vespa/metrics/countmetric.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/metrictimer.h>
#include <vespa/config/config.h>
#include <chrono>
@@ -44,7 +48,7 @@ public:
metrics::LongCountMetric other;
MergeFailureMetrics(metrics::MetricSet* owner);
- ~MergeFailureMetrics();
+ ~MergeFailureMetrics() override;
};
class MergeOperationMetrics : public metrics::MetricSet {
diff --git a/storage/src/vespa/storage/storageserver/priorityconverter.cpp b/storage/src/vespa/storage/storageserver/priorityconverter.cpp
index 41bea1b44df..d4dbe943664 100644
--- a/storage/src/vespa/storage/storageserver/priorityconverter.cpp
+++ b/storage/src/vespa/storage/storageserver/priorityconverter.cpp
@@ -13,9 +13,7 @@ PriorityConverter::PriorityConverter(const config::ConfigUri & configUri)
_configFetcher.start();
}
-PriorityConverter::~PriorityConverter()
-{
-}
+PriorityConverter::~PriorityConverter() = default;
uint8_t
PriorityConverter::toStoragePriority(documentapi::Priority::Value documentApiPriority) const
diff --git a/storage/src/vespa/storage/storageserver/prioritymapper.h b/storage/src/vespa/storage/storageserver/prioritymapper.h
deleted file mode 100644
index f5aebcfb786..00000000000
--- a/storage/src/vespa/storage/storageserver/prioritymapper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/documentapi/loadtypes/loadtype.h>
-#include <vespa/storage/config/config-stor-prioritymapping.h>
-
-namespace storage {
-
-class PriorityMapper
-{
- std::vector<uint8_t> _priorities;
-
-public:
- typedef vespa::config::content::core::internal::InternalStorPrioritymappingType Config;
-
- PriorityMapper() : _priorities(16, 120) {}
-
- void setConfig(const Config c) {
- _priorities[documentapi::Priority::PRI_HIGHEST] = c.highest;
- _priorities[documentapi::Priority::PRI_VERY_HIGH] = c.veryHigh;
- _priorities[documentapi::Priority::PRI_HIGH_1] = c.high1;
- _priorities[documentapi::Priority::PRI_HIGH_2] = c.high2;
- _priorities[documentapi::Priority::PRI_HIGH_3] = c.high3;
- _priorities[documentapi::Priority::PRI_NORMAL_1] = c.normal1;
- _priorities[documentapi::Priority::PRI_NORMAL_2] = c.normal2;
- _priorities[documentapi::Priority::PRI_NORMAL_3] = c.normal3;
- _priorities[documentapi::Priority::PRI_NORMAL_4] = c.normal4;
- _priorities[documentapi::Priority::PRI_NORMAL_5] = c.normal5;
- _priorities[documentapi::Priority::PRI_NORMAL_6] = c.normal6;
- _priorities[documentapi::Priority::PRI_LOW_1] = c.low1;
- _priorities[documentapi::Priority::PRI_LOW_2] = c.low2;
- _priorities[documentapi::Priority::PRI_LOW_3] = c.low3;
- _priorities[documentapi::Priority::PRI_VERY_LOW] = c.veryLow;
- _priorities[documentapi::Priority::PRI_LOWEST] = c.lowest;
- }
-
- uint8_t getPriority(const documentapi::LoadType& lt) const {
- return _priorities[lt.getPriority()];
- }
-};
-
-} // storage
diff --git a/storage/src/vespa/storage/storageserver/rpc/caching_rpc_target_resolver.cpp b/storage/src/vespa/storage/storageserver/rpc/caching_rpc_target_resolver.cpp
index c497421f8f7..39959c24968 100644
--- a/storage/src/vespa/storage/storageserver/rpc/caching_rpc_target_resolver.cpp
+++ b/storage/src/vespa/storage/storageserver/rpc/caching_rpc_target_resolver.cpp
@@ -29,7 +29,7 @@ vespalib::string
CachingRpcTargetResolver::address_to_slobrok_id(const api::StorageMessageAddress& address) {
vespalib::asciistream as;
as << "storage/cluster." << address.getCluster()
- << '/' << ((address.getNodeType() == lib::NodeType::STORAGE) ? "storage" : "distributor")
+ << '/' << ((address.getNodeType() == lib::NodeType::Type::STORAGE) ? "storage" : "distributor")
<< '/' << address.getIndex();
return as.str();
}
diff --git a/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.cpp b/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.cpp
index 90ea4291a30..59c456daff4 100644
--- a/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.cpp
+++ b/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.cpp
@@ -4,20 +4,17 @@
namespace storage::rpc {
-WrappedCodec::WrappedCodec(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set)
+WrappedCodec::WrappedCodec(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo)
: _doc_type_repo(std::move(doc_type_repo)),
- _load_type_set(std::move(load_type_set)),
- _codec(std::make_unique<mbusprot::ProtocolSerialization7>(_doc_type_repo, *_load_type_set))
+ _codec(std::make_unique<mbusprot::ProtocolSerialization7>(_doc_type_repo))
{
}
WrappedCodec::~WrappedCodec() = default;
-MessageCodecProvider::MessageCodecProvider(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set)
+MessageCodecProvider::MessageCodecProvider(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo)
: _rw_mutex(),
- _active_codec(std::make_shared<WrappedCodec>(std::move(doc_type_repo), std::move(load_type_set)))
+ _active_codec(std::make_shared<WrappedCodec>(std::move(doc_type_repo)))
{
}
@@ -28,11 +25,10 @@ std::shared_ptr<const WrappedCodec> MessageCodecProvider::wrapped_codec() const
return _active_codec;
}
-void MessageCodecProvider::update_atomically(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set)
+void MessageCodecProvider::update_atomically(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo)
{
std::unique_lock w_lock(_rw_mutex);
- _active_codec = std::make_shared<WrappedCodec>(std::move(doc_type_repo), std::move(load_type_set));
+ _active_codec = std::make_shared<WrappedCodec>(std::move(doc_type_repo));
}
}
diff --git a/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.h b/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.h
index fdadfd6f910..f8585abe3f5 100644
--- a/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.h
+++ b/storage/src/vespa/storage/storageserver/rpc/message_codec_provider.h
@@ -5,18 +5,15 @@
#include <shared_mutex>
namespace document { class DocumentTypeRepo; }
-namespace documentapi { class LoadTypeSet; }
namespace storage::mbusprot { class ProtocolSerialization7; }
namespace storage::rpc {
class WrappedCodec {
const std::shared_ptr<const document::DocumentTypeRepo> _doc_type_repo;
- const std::shared_ptr<const documentapi::LoadTypeSet> _load_type_set;
std::unique_ptr<mbusprot::ProtocolSerialization7> _codec;
public:
- WrappedCodec(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set);
+ explicit WrappedCodec(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo);
~WrappedCodec();
[[nodiscard]] const mbusprot::ProtocolSerialization7& codec() const noexcept { return *_codec; }
@@ -34,14 +31,12 @@ class MessageCodecProvider {
mutable std::shared_mutex _rw_mutex;
std::shared_ptr<WrappedCodec> _active_codec;
public:
- MessageCodecProvider(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set);
+ explicit MessageCodecProvider(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo);
~MessageCodecProvider();
[[nodiscard]] std::shared_ptr<const WrappedCodec> wrapped_codec() const noexcept;
- void update_atomically(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo,
- std::shared_ptr<const documentapi::LoadTypeSet> load_type_set);
+ void update_atomically(std::shared_ptr<const document::DocumentTypeRepo> doc_type_repo);
};
}
diff --git a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp
index f8ee5afd1fd..4c075f44d35 100644
--- a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp
+++ b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp
@@ -62,9 +62,11 @@ public:
SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
int rpc_server_port,
- size_t rpc_thread_pool_size)
+ size_t rpc_thread_pool_size,
+ size_t rpc_events_before_wakeup)
: _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)),
- _transport(std::make_unique<FNET_Transport>(rpc_thread_pool_size)),
+ _transport(std::make_unique<FNET_Transport>(TransportConfig(rpc_thread_pool_size).
+ events_before_wakeup(rpc_events_before_wakeup))),
_orb(std::make_unique<FRT_Supervisor>(_transport.get())),
_slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
_slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
@@ -72,8 +74,7 @@ SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
_hostname(vespalib::HostName::get()),
_rpc_server_port(rpc_server_port),
_shutdown(false)
-{
-}
+{ }
// TODO make sure init/shutdown is safe for aborted init in comm. mgr.
diff --git a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h
index 740277218c3..1fdd0f2648b 100644
--- a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h
+++ b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h
@@ -30,7 +30,8 @@ class SharedRpcResources {
int _rpc_server_port;
bool _shutdown;
public:
- SharedRpcResources(const config::ConfigUri& config_uri, int rpc_server_port, size_t rpc_thread_pool_size);
+ SharedRpcResources(const config::ConfigUri& config_uri, int rpc_server_port,
+ size_t rpc_thread_pool_size, size_t rpc_events_before_wakeup);
~SharedRpcResources();
FRT_Supervisor& supervisor() noexcept { return *_orb; }
diff --git a/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.cpp b/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.cpp
index c465315a5a6..4a5bbfec8c4 100644
--- a/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.cpp
+++ b/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.cpp
@@ -1,22 +1,23 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "storage_api_rpc_service.h"
#include "caching_rpc_target_resolver.h"
#include "message_codec_provider.h"
-#include "shared_rpc_resources.h"
#include "rpc_envelope_proto.h"
+#include "shared_rpc_resources.h"
+#include "storage_api_rpc_service.h"
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/slobrok/sbmirror.h>
+#include <vespa/storage/common/bucket_utils.h>
#include <vespa/storage/storageserver/communicationmanager.h>
#include <vespa/storage/storageserver/message_dispatcher.h>
#include <vespa/storage/storageserver/rpcrequestwrapper.h>
#include <vespa/storageapi/mbusprot/protocolserialization7.h>
#include <vespa/storageapi/messageapi/storagecommand.h>
#include <vespa/vespalib/data/databuffer.h>
+#include <vespa/vespalib/trace/tracelevel.h>
#include <vespa/vespalib/util/compressor.h>
#include <vespa/vespalib/util/stringfmt.h>
-#include <vespa/vespalib/trace/tracelevel.h>
#include <cassert>
#include <vespa/log/log.h>
@@ -220,7 +221,8 @@ void StorageApiRpcService::send_rpc_v1_request(std::shared_ptr<api::StorageComma
cmd->getType().getName().c_str(), cmd->getAddress()->toString().c_str());
assert(cmd->getAddress() != nullptr);
- auto target = _target_resolver->resolve_rpc_target(*cmd->getAddress(), cmd->getBucketId().getId());
+ auto target = _target_resolver->resolve_rpc_target(*cmd->getAddress(),
+ get_super_bucket_key(cmd->getBucketId()));
if (!target) {
auto reply = cmd->makeReply();
reply->setResult(make_no_address_for_service_error(*cmd->getAddress()));
diff --git a/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.h b/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.h
index 3ccd235fc43..7fc382fda07 100644
--- a/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.h
+++ b/storage/src/vespa/storage/storageserver/rpc/storage_api_rpc_service.h
@@ -14,7 +14,6 @@ class FRT_RPCRequest;
class FRT_Target;
namespace document { class DocumentTypeRepo; }
-namespace documentapi { class LoadTypeSet; }
namespace storage {
diff --git a/storage/src/vespa/storage/storageserver/servicelayernode.cpp b/storage/src/vespa/storage/storageserver/servicelayernode.cpp
index 68b53738b20..e4bc1757493 100644
--- a/storage/src/vespa/storage/storageserver/servicelayernode.cpp
+++ b/storage/src/vespa/storage/storageserver/servicelayernode.cpp
@@ -35,8 +35,7 @@ ServiceLayerNode::ServiceLayerNode(const config::ConfigUri & configUri, ServiceL
_persistenceProvider(persistenceProvider),
_externalVisitors(externalVisitors),
_fileStorManager(nullptr),
- _init_has_been_called(false),
- _noUsablePartitionMode(false)
+ _init_has_been_called(false)
{
}
@@ -162,14 +161,6 @@ ServiceLayerNode::createChain(IStorageChainBuilder &builder)
_communicationManager = communication_manager.get();
builder.add(std::move(communication_manager));
builder.add(std::make_unique<Bouncer>(compReg, _configUri));
- if (_noUsablePartitionMode) {
- /*
- * No usable partitions. Use minimal chain. Still needs to be
- * able to report state back to cluster controller.
- */
- builder.add(releaseStateManager());
- return;
- }
builder.add(std::make_unique<OpsLogger>(compReg, _configUri));
auto merge_throttler_up = std::make_unique<MergeThrottler>(_configUri, compReg);
auto merge_throttler = merge_throttler_up.get();
diff --git a/storage/src/vespa/storage/storageserver/servicelayernode.h b/storage/src/vespa/storage/storageserver/servicelayernode.h
index 9513888fd8d..9153e085033 100644
--- a/storage/src/vespa/storage/storageserver/servicelayernode.h
+++ b/storage/src/vespa/storage/storageserver/servicelayernode.h
@@ -35,7 +35,6 @@ class ServiceLayerNode
std::unique_ptr<config::ConfigFetcher> _configFetcher;
FileStorManager* _fileStorManager;
bool _init_has_been_called;
- bool _noUsablePartitionMode;
public:
typedef std::unique_ptr<ServiceLayerNode> UP;
diff --git a/storage/src/vespa/storage/storageserver/servicelayernodecontext.h b/storage/src/vespa/storage/storageserver/servicelayernodecontext.h
index 0516c9e3bda..0f2ca2a9048 100644
--- a/storage/src/vespa/storage/storageserver/servicelayernodecontext.h
+++ b/storage/src/vespa/storage/storageserver/servicelayernodecontext.h
@@ -8,10 +8,6 @@
* This utility class sets up the default component register implementation.
* It also sets up the clock and the threadpool, such that the most basic
* features are available to the provider, before the service layer is set up.
- *
- * The service layer still provides the memory manager functionality though,
- * so you cannot retrieve the memory manager before the service layer has
- * started up. (Before getPartitionStates() have been called on provider)
*/
#pragma once
diff --git a/storage/src/vespa/storage/storageserver/statemanager.cpp b/storage/src/vespa/storage/storageserver/statemanager.cpp
index 653822626ed..395e33a0393 100644
--- a/storage/src/vespa/storage/storageserver/statemanager.cpp
+++ b/storage/src/vespa/storage/storageserver/statemanager.cpp
@@ -6,7 +6,6 @@
#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/metricmanager.h>
-#include <vespa/storage/common/bucketoperationlogger.h>
#include <vespa/storageapi/messageapi/storagemessage.h>
#include <vespa/vdslib/state/cluster_state_bundle.h>
#include <vespa/vespalib/io/fileutil.h>
diff --git a/storage/src/vespa/storage/storageserver/statereporter.h b/storage/src/vespa/storage/storageserver/statereporter.h
index b06e08c3ef5..72c2b856612 100644
--- a/storage/src/vespa/storage/storageserver/statereporter.h
+++ b/storage/src/vespa/storage/storageserver/statereporter.h
@@ -13,7 +13,6 @@
#include "applicationgenerationfetcher.h"
#include <vespa/storage/common/storagecomponent.h>
#include <vespa/storageframework/generic/status/statusreporter.h>
-#include <vespa/metrics/metrics.h>
#include <vespa/metrics/state_api_adapter.h>
#include <vespa/vespalib/net/metrics_producer.h>
#include <vespa/vespalib/net/state_api.h>
diff --git a/storage/src/vespa/storage/storageserver/storagemetricsset.h b/storage/src/vespa/storage/storageserver/storagemetricsset.h
index a315e974c01..7e8284fc734 100644
--- a/storage/src/vespa/storage/storageserver/storagemetricsset.h
+++ b/storage/src/vespa/storage/storageserver/storagemetricsset.h
@@ -4,7 +4,6 @@
#include "tls_statistics_metrics_wrapper.h"
#include "fnet_metrics_wrapper.h"
-#include <vespa/metrics/metrics.h>
namespace storage {
diff --git a/storage/src/vespa/storage/storageserver/storagenode.cpp b/storage/src/vespa/storage/storageserver/storagenode.cpp
index c6d50e6dca6..74052932853 100644
--- a/storage/src/vespa/storage/storageserver/storagenode.cpp
+++ b/storage/src/vespa/storage/storageserver/storagenode.cpp
@@ -1,22 +1,22 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "config_logging.h"
-#include "storagenode.h"
#include "communicationmanager.h"
+#include "config_logging.h"
#include "statemanager.h"
#include "statereporter.h"
#include "storagemetricsset.h"
+#include "storagenode.h"
#include "storagenodecontext.h"
-#include "tls_statistics_metrics_wrapper.h"
-#include <vespa/storage/frameworkimpl/status/statuswebserver.h>
-#include <vespa/storage/frameworkimpl/thread/deadlockdetector.h>
+#include <vespa/metrics/metricmanager.h>
+#include <vespa/storage/common/node_identity.h>
#include <vespa/storage/common/statusmetricconsumer.h>
#include <vespa/storage/common/storage_chain_builder.h>
+#include <vespa/storage/frameworkimpl/status/statuswebserver.h>
+#include <vespa/storage/frameworkimpl/thread/deadlockdetector.h>
#include <vespa/vespalib/io/fileutil.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/time.h>
-#include <vespa/metrics/metricmanager.h>
#include <fcntl.h>
#include <vespa/log/log.h>
@@ -89,16 +89,15 @@ StorageNode::StorageNode(
_serverConfig(),
_clusterConfig(),
_distributionConfig(),
- _priorityConfig(),
_doctypesConfig(),
_bucketSpacesConfig(),
_newServerConfig(),
_newClusterConfig(),
_newDistributionConfig(),
- _newPriorityConfig(),
_newDoctypesConfig(),
_newBucketSpacesConfig(),
_component(),
+ _node_identity(),
_configUri(configUri),
_communicationManager(nullptr),
_chain_builder(std::make_unique<StorageChainBuilder>())
@@ -112,7 +111,6 @@ StorageNode::subscribeToConfigs()
_configFetcher->subscribe<StorDistributionConfig>(_configUri.getConfigId(), this);
_configFetcher->subscribe<UpgradingConfig>(_configUri.getConfigId(), this);
_configFetcher->subscribe<StorServerConfig>(_configUri.getConfigId(), this);
- _configFetcher->subscribe<StorPrioritymappingConfig>(_configUri.getConfigId(), this);
_configFetcher->subscribe<BucketspacesConfig>(_configUri.getConfigId(), this);
_configFetcher->start();
@@ -121,7 +119,6 @@ StorageNode::subscribeToConfigs()
_serverConfig = std::move(_newServerConfig);
_clusterConfig = std::move(_newClusterConfig);
_distributionConfig = std::move(_newDistributionConfig);
- _priorityConfig = std::move(_newPriorityConfig);
_bucketSpacesConfig = std::move(_newBucketSpacesConfig);
}
@@ -145,11 +142,10 @@ StorageNode::initialize()
_rootFolder = _serverConfig->rootFolder;
_context.getComponentRegister().setNodeInfo(_serverConfig->clusterName, getNodeType(), _serverConfig->nodeIndex);
- _context.getComponentRegister().setLoadTypes(make_shared<documentapi::LoadTypeSet>(_configUri));
_context.getComponentRegister().setBucketIdFactory(document::BucketIdFactory());
_context.getComponentRegister().setDistribution(make_shared<lib::Distribution>(*_distributionConfig));
- _context.getComponentRegister().setPriorityConfig(*_priorityConfig);
_context.getComponentRegister().setBucketSpacesConfig(*_bucketSpacesConfig);
+ _node_identity = std::make_unique<NodeIdentity>(_serverConfig->clusterName, getNodeType(), _serverConfig->nodeIndex);
_metrics = std::make_shared<StorageMetricSet>();
_component = std::make_unique<StorageComponent>(_context.getComponentRegister(), "storagenode");
@@ -164,11 +160,11 @@ StorageNode::initialize()
// update node state according min used bits etc.
// Needs node type to be set right away. Needs thread pool, index and
// dead lock detector too, but not before open()
- _stateManager.reset(new StateManager(
+ _stateManager = std::make_unique<StateManager>(
_context.getComponentRegister(),
_context.getComponentRegister().getMetricManager(),
std::move(_hostInfo),
- _singleThreadedDebugMode));
+ _singleThreadedDebugMode);
_context.getComponentRegister().setNodeStateUpdater(*_stateManager);
// Create VDS root folder, in case it doesn't already exist.
@@ -178,11 +174,11 @@ StorageNode::initialize()
initializeNodeSpecific();
- _statusMetrics.reset(new StatusMetricConsumer(
- _context.getComponentRegister(), _context.getComponentRegister().getMetricManager()));
- _stateReporter.reset(new StateReporter(
+ _statusMetrics = std::make_unique<StatusMetricConsumer>(
+ _context.getComponentRegister(), _context.getComponentRegister().getMetricManager());
+ _stateReporter = std::make_unique<StateReporter>(
_context.getComponentRegister(), _context.getComponentRegister().getMetricManager(),
- _generationFetcher));
+ _generationFetcher);
// Start deadlock detector
_deadLockDetector.reset(new DeadLockDetector(_context.getComponentRegister()));
@@ -335,10 +331,7 @@ StorageNode::handleLiveConfigUpdate(const InitialGuard & initGuard)
}
_newClusterConfig.reset();
}
- if (_newPriorityConfig) {
- _priorityConfig = std::move(_newPriorityConfig);
- _context.getComponentRegister().setPriorityConfig(*_priorityConfig);
- }
+
if (_newBucketSpacesConfig) {
_bucketSpacesConfig = std::move(_newBucketSpacesConfig);
_context.getComponentRegister().setBucketSpacesConfig(*_bucketSpacesConfig);
@@ -490,19 +483,6 @@ void StorageNode::configure(std::unique_ptr<StorDistributionConfig> config) {
handleLiveConfigUpdate(concurrent_config_guard);
}
}
-
-void StorageNode::configure(std::unique_ptr<StorPrioritymappingConfig> config) {
- log_config_received(*config);
- {
- std::lock_guard configLockGuard(_configLock);
- _newPriorityConfig = std::move(config);
- }
- if (_priorityConfig) {
- InitialGuard concurrent_config_guard(_initial_config_mutex);
- handleLiveConfigUpdate(concurrent_config_guard);
- }
-}
-
void
StorageNode::configure(std::unique_ptr<document::DocumenttypesConfig> config,
bool hasChanged, int64_t generation)
diff --git a/storage/src/vespa/storage/storageserver/storagenode.h b/storage/src/vespa/storage/storageserver/storagenode.h
index 9450cdce5ff..44b87f4b61c 100644
--- a/storage/src/vespa/storage/storageserver/storagenode.h
+++ b/storage/src/vespa/storage/storageserver/storagenode.h
@@ -20,7 +20,6 @@
#include <vespa/document/config/config-documenttypes.h>
#include <vespa/storage/common/doneinitializehandler.h>
#include <vespa/config-bucketspaces.h>
-#include <vespa/storage/config/config-stor-prioritymapping.h>
#include <vespa/storage/config/config-stor-server.h>
#include <vespa/storage/storageutil/resumeguard.h>
#include <vespa/storageframework/defaultimplementation/component/componentregisterimpl.h>
@@ -31,21 +30,22 @@ namespace document { class DocumentTypeRepo; }
namespace storage {
-class StatusMetricConsumer;
-class StateReporter;
+class ApplicationGenerationFetcher;
class CommunicationManager;
class FileStorManager;
class HostInfo;
-class StateManager;
+class IStorageChainBuilder;
class MemoryStatusViewer;
+class NodeIdentity;
+class StateManager;
+class StateReporter;
+class StatusMetricConsumer;
class StatusWebServer;
+class StorageComponent;
class StorageLink;
struct DeadLockDetector;
struct StorageMetricSet;
struct StorageNodeContext;
-class ApplicationGenerationFetcher;
-class IStorageChainBuilder;
-class StorageComponent;
namespace lib { class NodeType; }
@@ -53,7 +53,6 @@ namespace lib { class NodeType; }
class StorageNode : private config::IFetcherCallback<vespa::config::content::core::StorServerConfig>,
private config::IFetcherCallback<vespa::config::content::StorDistributionConfig>,
private config::IFetcherCallback<vespa::config::content::UpgradingConfig>,
- private config::IFetcherCallback<vespa::config::content::core::StorPrioritymappingConfig>,
private config::IFetcherCallback<vespa::config::content::core::BucketspacesConfig>,
private framework::MetricUpdateHook,
private DoneInitializeHandler,
@@ -100,7 +99,6 @@ protected:
using StorServerConfig = vespa::config::content::core::StorServerConfig;
using UpgradingConfig = vespa::config::content::UpgradingConfig;
using StorDistributionConfig = vespa::config::content::StorDistributionConfig;
- using StorPrioritymappingConfig = vespa::config::content::core::StorPrioritymappingConfig;
using BucketspacesConfig = vespa::config::content::core::BucketspacesConfig;
private:
bool _singleThreadedDebugMode;
@@ -135,7 +133,6 @@ private:
void configure(std::unique_ptr<StorServerConfig> config) override;
void configure(std::unique_ptr<UpgradingConfig> config) override;
void configure(std::unique_ptr<StorDistributionConfig> config) override;
- void configure(std::unique_ptr<StorPrioritymappingConfig>) override;
virtual void configure(std::unique_ptr<document::DocumenttypesConfig> config,
bool hasChanged, int64_t generation);
void configure(std::unique_ptr<BucketspacesConfig>) override;
@@ -151,17 +148,16 @@ protected:
std::unique_ptr<StorServerConfig> _serverConfig;
std::unique_ptr<UpgradingConfig> _clusterConfig;
std::unique_ptr<StorDistributionConfig> _distributionConfig;
- std::unique_ptr<StorPrioritymappingConfig> _priorityConfig;
std::unique_ptr<document::DocumenttypesConfig> _doctypesConfig;
std::unique_ptr<BucketspacesConfig> _bucketSpacesConfig;
// New configs gotten that has yet to have been handled
std::unique_ptr<StorServerConfig> _newServerConfig;
std::unique_ptr<UpgradingConfig> _newClusterConfig;
std::unique_ptr<StorDistributionConfig> _newDistributionConfig;
- std::unique_ptr<StorPrioritymappingConfig> _newPriorityConfig;
std::unique_ptr<document::DocumenttypesConfig> _newDoctypesConfig;
std::unique_ptr<BucketspacesConfig> _newBucketSpacesConfig;
std::unique_ptr<StorageComponent> _component;
+ std::unique_ptr<NodeIdentity> _node_identity;
config::ConfigUri _configUri;
CommunicationManager* _communicationManager;
private:
diff --git a/storage/src/vespa/storage/storageserver/storagenodecontext.h b/storage/src/vespa/storage/storageserver/storagenodecontext.h
index 163c02ef5af..34afac43ab3 100644
--- a/storage/src/vespa/storage/storageserver/storagenodecontext.h
+++ b/storage/src/vespa/storage/storageserver/storagenodecontext.h
@@ -8,10 +8,6 @@
* This utility class sets up the default component register implementation.
* It also sets up the clock and the threadpool, such that the most basic
* features are available to the provider, before the service layer is set up.
- *
- * The service layer still provides the memory manager functionality though,
- * so you cannot retrieve the memory manager before the service layer has
- * started up. (Before getPartitionStates() have been called on provider)
*/
#pragma once
diff --git a/storage/src/vespa/storage/storageserver/tls_statistics_metrics_wrapper.h b/storage/src/vespa/storage/storageserver/tls_statistics_metrics_wrapper.h
index e1852efa5e6..85a8584a591 100644
--- a/storage/src/vespa/storage/storageserver/tls_statistics_metrics_wrapper.h
+++ b/storage/src/vespa/storage/storageserver/tls_statistics_metrics_wrapper.h
@@ -1,7 +1,8 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/metricset.h>
+#include <vespa/metrics/countmetric.h>
#include <vespa/vespalib/net/tls/statistics.h>
#include <chrono>
diff --git a/storage/src/vespa/storage/tools/storage-cmd.cpp b/storage/src/vespa/storage/tools/storage-cmd.cpp
index 8c0fcc83330..00ee2c9c4cf 100644
--- a/storage/src/vespa/storage/tools/storage-cmd.cpp
+++ b/storage/src/vespa/storage/tools/storage-cmd.cpp
@@ -1,5 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/fnet/frt/frt.h>
+#include <vespa/fnet/frt/rpcrequest.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/fastos/app.h>
#include <vespa/vespalib/locale/c.h>
diff --git a/storage/src/vespa/storage/visiting/CMakeLists.txt b/storage/src/vespa/storage/visiting/CMakeLists.txt
index 05097163479..27c8b8853b8 100644
--- a/storage/src/vespa/storage/visiting/CMakeLists.txt
+++ b/storage/src/vespa/storage/visiting/CMakeLists.txt
@@ -6,10 +6,12 @@ vespa_add_library(storage_visitor OBJECT
dumpvisitorsingle.cpp
memory_bounded_trace.cpp
recoveryvisitor.cpp
+ reindexing_visitor.cpp
testvisitor.cpp
visitor.cpp
visitormanager.cpp
visitormetrics.cpp
+ visitorthreadmetrics.cpp
visitorthread.cpp
DEPENDS
)
diff --git a/storage/src/vespa/storage/visiting/dumpvisitorsingle.h b/storage/src/vespa/storage/visiting/dumpvisitorsingle.h
index 4cc538d6fd7..ccfc8a5a3cf 100644
--- a/storage/src/vespa/storage/visiting/dumpvisitorsingle.h
+++ b/storage/src/vespa/storage/visiting/dumpvisitorsingle.h
@@ -26,11 +26,10 @@ struct DumpVisitorSingleFactory : public VisitorFactory {
VisitorEnvironment::UP
makeVisitorEnvironment(StorageComponent&) override {
- return VisitorEnvironment::UP(new VisitorEnvironment);
+ return std::make_unique<VisitorEnvironment>();
};
Visitor*
-
makeVisitor(StorageComponent& c, VisitorEnvironment&, const vdslib::Parameters& params) override {
return new DumpVisitorSingle(c, params);
}
diff --git a/storage/src/vespa/storage/visiting/reindexing_visitor.cpp b/storage/src/vespa/storage/visiting/reindexing_visitor.cpp
new file mode 100644
index 00000000000..5577bcd00ae
--- /dev/null
+++ b/storage/src/vespa/storage/visiting/reindexing_visitor.cpp
@@ -0,0 +1,58 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "reindexing_visitor.h"
+#include <vespa/document/fieldvalue/document.h>
+#include <vespa/documentapi/messagebus/messages/putdocumentmessage.h>
+#include <vespa/storage/common/reindexing_constants.h>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".visitor.instance.reindexing_visitor");
+
+namespace storage {
+
+ReindexingVisitor::ReindexingVisitor(StorageComponent& component)
+ : Visitor(component)
+{
+}
+
+void ReindexingVisitor::handleDocuments(const document::BucketId& /*bucketId*/,
+ std::vector<spi::DocEntry::UP>& entries,
+ HitCounter& hitCounter)
+{
+ auto lock_token = make_lock_access_token();
+ LOG(debug, "ReindexingVisitor %s handling block of %zu documents. Using access token '%s'",
+ _id.c_str(), entries.size(), lock_token.c_str());
+ for (auto& entry : entries) {
+ if (entry->isRemove()) {
+ // We don't reindex removed documents, as that would be very silly.
+ continue;
+ }
+ const uint32_t doc_size = entry->getDocumentSize();
+ hitCounter.addHit(*entry->getDocumentId(), doc_size);
+ auto msg = std::make_unique<documentapi::PutDocumentMessage>(entry->releaseDocument());
+ msg->setApproxSize(doc_size);
+ msg->setCondition(documentapi::TestAndSetCondition(lock_token));
+ sendMessage(std::move(msg));
+ }
+}
+
+bool ReindexingVisitor::remap_docapi_message_error_code(api::ReturnCode& in_out_code) {
+ if (in_out_code.getResult() == api::ReturnCode::TEST_AND_SET_CONDITION_FAILED) {
+ in_out_code = api::ReturnCode(api::ReturnCode::ABORTED, "Got TaS failure from upstream, indicating visitor is "
+ "outdated. Aborting session to allow client to retry");
+ return true;
+ }
+ return Visitor::remap_docapi_message_error_code(in_out_code);
+}
+
+vespalib::string ReindexingVisitor::make_lock_access_token() const {
+ vespalib::string prefix = reindexing_bucket_lock_bypass_prefix();
+ vespalib::stringref passed_token = visitor_parameters().get(
+ reindexing_bucket_lock_visitor_parameter_key(),
+ vespalib::stringref(""));
+ if (passed_token.empty()) {
+ return prefix;
+ }
+ return (prefix + "=" + passed_token);
+}
+
+}
diff --git a/storage/src/vespa/storage/visiting/reindexing_visitor.h b/storage/src/vespa/storage/visiting/reindexing_visitor.h
new file mode 100644
index 00000000000..0fdba607134
--- /dev/null
+++ b/storage/src/vespa/storage/visiting/reindexing_visitor.h
@@ -0,0 +1,38 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include "visitor.h"
+
+namespace storage {
+
+/**
+ * A visitor instance that is intended to be used for background reindexing.
+ * Only meant to be run alongside distributor-level bucket locking support
+ * that prevents concurrent writes to documents in the visited bucket.
+ *
+ * The bucket lock is explicitly bypassed by the Puts sent by the visitor
+ * by having all these be augmented with a special TaS string that is
+ * recognized by the distributor.
+ */
+class ReindexingVisitor : public Visitor {
+public:
+ explicit ReindexingVisitor(StorageComponent& component);
+ ~ReindexingVisitor() override = default;
+
+private:
+ void handleDocuments(const document::BucketId&, std::vector<spi::DocEntry::UP>&, HitCounter&) override;
+ bool remap_docapi_message_error_code(api::ReturnCode& in_out_code) override;
+ vespalib::string make_lock_access_token() const;
+};
+
+struct ReindexingVisitorFactory : public VisitorFactory {
+ VisitorEnvironment::UP makeVisitorEnvironment(StorageComponent&) override {
+ return std::make_unique<VisitorEnvironment>();
+ };
+
+ Visitor* makeVisitor(StorageComponent& c, VisitorEnvironment&, const vdslib::Parameters&) override {
+ return new ReindexingVisitor(c);
+ }
+};
+
+}
diff --git a/storage/src/vespa/storage/visiting/stor-visitor.def b/storage/src/vespa/storage/visiting/stor-visitor.def
index 72b3699fe2d..ef3c0cd6113 100644
--- a/storage/src/vespa/storage/visiting/stor-visitor.def
+++ b/storage/src/vespa/storage/visiting/stor-visitor.def
@@ -2,6 +2,7 @@
namespace=vespa.config.content.core
## Number of separate threads that runs visitors.
+## Keep in sync with #stor-filestor:num_visitor_threads
visitorthreads int default=16 restart
## Default timeout of visitors that loses contact with client (in seconds)
diff --git a/storage/src/vespa/storage/visiting/visitor.cpp b/storage/src/vespa/storage/visiting/visitor.cpp
index 16a9b26a754..e69721e8177 100644
--- a/storage/src/vespa/storage/visiting/visitor.cpp
+++ b/storage/src/vespa/storage/visiting/visitor.cpp
@@ -6,7 +6,6 @@
#include <vespa/storageapi/message/datagram.h>
#include <vespa/storage/persistence/messages.h>
#include <vespa/documentapi/messagebus/messages/visitor.h>
-#include <vespa/documentapi/loadtypes/loadtype.h>
#include <vespa/document/select/node.h>
#include <vespa/document/fieldset/fieldsets.h>
#include <vespa/vespalib/stllike/hash_map.hpp>
@@ -553,7 +552,7 @@ Visitor::start(api::VisitorId id, api::StorageMessage::Id cmdId,
}
void
-Visitor::attach(std::shared_ptr<api::StorageCommand> initiatingCmd,
+Visitor::attach(std::shared_ptr<api::CreateVisitorCommand> initiatingCmd,
const mbus::Route& controlAddress,
const mbus::Route& dataAddress,
framework::MilliSecTime timeout)
@@ -602,6 +601,17 @@ Visitor::addBoundedTrace(uint32_t level, const vespalib::string &message) {
return _trace.add(std::move(tempTrace));
}
+const vdslib::Parameters&
+Visitor::visitor_parameters() const noexcept {
+ assert(_initiatingCmd);
+ return _initiatingCmd->getParameters();
+}
+
+bool
+Visitor::remap_docapi_message_error_code(api::ReturnCode& in_out_code) {
+ return in_out_code.isCriticalForVisitor();
+}
+
void
Visitor::handleDocumentApiReply(mbus::Reply::UP reply, VisitorThreadMetrics& metrics)
{
@@ -623,7 +633,7 @@ Visitor::handleDocumentApiReply(mbus::Reply::UP reply, VisitorThreadMetrics& met
auto meta = _visitorTarget.releaseMetaForMessageId(messageId);
if (!reply->hasErrors()) {
- metrics.averageMessageSendTime[getLoadType()].addValue(
+ metrics.averageMessageSendTime.addValue(
(message->getTimeRemaining() - message->getTimeRemainingNow()).count() / 1000.0);
LOG(debug, "Visitor '%s' reply %s for message ID %" PRIu64 " was OK", _id.c_str(),
reply->toString().c_str(), messageId);
@@ -632,11 +642,10 @@ Visitor::handleDocumentApiReply(mbus::Reply::UP reply, VisitorThreadMetrics& met
return;
}
- metrics.visitorDestinationFailureReplies[getLoadType()].inc();
+ metrics.visitorDestinationFailureReplies.inc();
if (message->getType() == documentapi::DocumentProtocol::MESSAGE_VISITORINFO) {
- LOG(debug, "Aborting visitor as we failed to talk to "
- "controller: %s",
+ LOG(debug, "Aborting visitor as we failed to talk to controller: %s",
reply->getError(0).toString().c_str());
api::ReturnCode returnCode(
static_cast<api::ReturnCode::Result>(
@@ -650,7 +659,8 @@ Visitor::handleDocumentApiReply(mbus::Reply::UP reply, VisitorThreadMetrics& met
api::ReturnCode returnCode(
static_cast<api::ReturnCode::Result>(reply->getError(0).getCode()),
reply->getError(0).getMessage());
- if (returnCode.isCriticalForVisitor()) {
+ const bool should_fail = remap_docapi_message_error_code(returnCode);
+ if (should_fail) {
// Abort - something is wrong with target.
fail(returnCode, true);
close();
@@ -791,18 +801,14 @@ Visitor::onGetIterReply(const std::shared_ptr<GetIterReply>& reply,
if (isRunning()) {
MBUS_TRACE(reply->getTrace(), 5,
vespalib::make_string("Visitor %s handling block of %zu documents.",
- _id.c_str(),
- reply->getEntries().size()));
+ _id.c_str(), reply->getEntries().size()));
LOG(debug, "Visitor %s handling block of %zu documents.",
_id.c_str(),
reply->getEntries().size());
try {
framework::MilliSecTimer processingTimer(_component.getClock());
- handleDocuments(reply->getBucketId(),
- reply->getEntries(),
- *_hitCounter);
- metrics.averageProcessingTime[reply->getLoadType()]
- .addValue(processingTimer.getElapsedTimeAsDouble());
+ handleDocuments(reply->getBucketId(), reply->getEntries(), *_hitCounter);
+ metrics.averageProcessingTime.addValue(processingTimer.getElapsedTimeAsDouble());
MBUS_TRACE(reply->getTrace(), 5, "Done processing data block in visitor plugin");
@@ -1173,13 +1179,10 @@ Visitor::getIterators()
selection.setToTimestamp(
spi::Timestamp(_visitorOptions._toTime.getTime()));
- std::shared_ptr<CreateIteratorCommand> cmd(
- new CreateIteratorCommand(bucket,
- selection,
- _visitorOptions._fieldSet,
- _visitorOptions._visitRemoves ?
- spi::NEWEST_DOCUMENT_OR_REMOVE :
- spi::NEWEST_DOCUMENT_ONLY));
+ auto cmd = std::make_shared<CreateIteratorCommand>(bucket, selection,_visitorOptions._fieldSet,
+ _visitorOptions._visitRemoves
+ ? spi::NEWEST_DOCUMENT_OR_REMOVE
+ : spi::NEWEST_DOCUMENT_ONLY);
cmd->getTrace().setLevel(_traceLevel);
cmd->setPriority(_initiatingCmd->getPriority());
diff --git a/storage/src/vespa/storage/visiting/visitor.h b/storage/src/vespa/storage/visiting/visitor.h
index 8eb02e6ccfc..d6b4c4b9381 100644
--- a/storage/src/vespa/storage/visiting/visitor.h
+++ b/storage/src/vespa/storage/visiting/visitor.h
@@ -307,7 +307,7 @@ private:
// Used by visitor client to identify what visitor messages belong to
api::StorageMessage::Id _visitorCmdId;
api::VisitorId _visitorId;
- std::shared_ptr<api::StorageCommand> _initiatingCmd;
+ std::shared_ptr<api::CreateVisitorCommand> _initiatingCmd;
api::StorageMessage::Priority _priority;
api::ReturnCode _result;
@@ -348,6 +348,14 @@ protected:
* Returns true iff message was added to internal trace tree.
*/
bool addBoundedTrace(uint32_t level, const vespalib::string& message);
+
+ const vdslib::Parameters& visitor_parameters() const noexcept;
+
+ // Possibly modifies the ReturnCode parameter in-place if its return code should
+ // be changed based on visitor subclass-specific behavior.
+ // Returns true if the visitor itself should be failed (aborted) with the
+ // error code, false if the DocumentAPI message should be retried later.
+ [[nodiscard]] virtual bool remap_docapi_message_error_code(api::ReturnCode& in_out_code);
public:
Visitor(StorageComponent& component);
virtual ~Visitor();
@@ -382,10 +390,6 @@ public:
void setOwnNodeIndex(uint16_t nodeIndex) { _ownNodeIndex = nodeIndex; }
void setBucketSpace(document::BucketSpace bucketSpace) { _bucketSpace = bucketSpace; }
- const documentapi::LoadType& getLoadType() const {
- return _initiatingCmd->getLoadType();
- }
-
/** Override this to know which buckets are currently being visited. */
virtual void startingVisitor(const std::vector<document::BucketId>&) {}
@@ -472,7 +476,7 @@ public:
VisitorMessageSession::UP,
documentapi::Priority::Value);
- void attach(std::shared_ptr<api::StorageCommand> initiatingCmd,
+ void attach(std::shared_ptr<api::CreateVisitorCommand> initiatingCmd,
const mbus::Route& controlAddress,
const mbus::Route& dataAddress,
framework::MilliSecTime timeout);
diff --git a/storage/src/vespa/storage/visiting/visitormanager.cpp b/storage/src/vespa/storage/visiting/visitormanager.cpp
index abe496ac770..bc77fd268d5 100644
--- a/storage/src/vespa/storage/visiting/visitormanager.cpp
+++ b/storage/src/vespa/storage/visiting/visitormanager.cpp
@@ -6,9 +6,9 @@
#include "countvisitor.h"
#include "testvisitor.h"
#include "recoveryvisitor.h"
+#include "reindexing_visitor.h"
#include <vespa/storage/common/statusmessages.h>
#include <vespa/config/common/exceptions.h>
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>
@@ -56,6 +56,7 @@ VisitorManager::VisitorManager(const config::ConfigUri & configUri,
_visitorFactories["testvisitor"] = std::make_shared<TestVisitorFactory>();
_visitorFactories["countvisitor"] = std::make_shared<CountVisitorFactory>();
_visitorFactories["recoveryvisitor"] = std::make_shared<RecoveryVisitorFactory>();
+ _visitorFactories["reindexingvisitor"] = std::make_shared<ReindexingVisitorFactory>();
_component.registerStatusPage(*this);
}
@@ -171,15 +172,11 @@ VisitorManager::configure(std::unique_ptr<vespa::config::content::core::StorVisi
"No visitor threads configured. If you don't want visitors "
"to run, don't use visitormanager.", VESPA_STRLOC);
}
- _metrics->initThreads(config->visitorthreads, _component.getLoadTypes()->getMetricLoadTypes());
+ _metrics->initThreads(config->visitorthreads);
for (int32_t i=0; i<config->visitorthreads; ++i) {
- _visitorThread.push_back(std::make_pair(
- std::shared_ptr<VisitorThread>(
- new VisitorThread(i, _componentRegister,
- _messageSessionFactory,
- _visitorFactories,
- *_metrics->threads[i], *this)),
- std::map<api::VisitorId, std::string>()));
+ _visitorThread.emplace_back(
+ new VisitorThread(i, _componentRegister, _messageSessionFactory, _visitorFactories, *_metrics->threads[i], *this),
+ std::map<api::VisitorId, std::string>());
}
}
_maxFixedConcurrentVisitors = maxConcurrentVisitorsFixed;
diff --git a/storage/src/vespa/storage/visiting/visitormessagesessionfactory.h b/storage/src/vespa/storage/visiting/visitormessagesessionfactory.h
index 5515595a1c5..308bf1959a8 100644
--- a/storage/src/vespa/storage/visiting/visitormessagesessionfactory.h
+++ b/storage/src/vespa/storage/visiting/visitormessagesessionfactory.h
@@ -3,6 +3,7 @@
#pragma once
#include "visitormessagesession.h"
+#include <vespa/documentapi/messagebus/priority.h>
namespace storage {
@@ -12,13 +13,11 @@ class VisitorThread;
struct VisitorMessageSessionFactory {
typedef std::unique_ptr<VisitorMessageSessionFactory> UP;
- virtual ~VisitorMessageSessionFactory() {}
+ virtual ~VisitorMessageSessionFactory() = default;
- virtual VisitorMessageSession::UP createSession(Visitor&,
- VisitorThread&) = 0;
+ virtual VisitorMessageSession::UP createSession(Visitor&, VisitorThread&) = 0;
- virtual documentapi::Priority::Value toDocumentPriority(
- uint8_t storagePriority) const = 0;
+ virtual documentapi::Priority::Value toDocumentPriority(uint8_t storagePriority) const = 0;
};
} // storage
diff --git a/storage/src/vespa/storage/visiting/visitormetrics.cpp b/storage/src/vespa/storage/visiting/visitormetrics.cpp
index 191f9fabc60..c35e0ab77ef 100644
--- a/storage/src/vespa/storage/visiting/visitormetrics.cpp
+++ b/storage/src/vespa/storage/visiting/visitormetrics.cpp
@@ -31,10 +31,10 @@ VisitorMetrics::VisitorMetrics()
queueSize.unsetOnZeroValue();
}
-VisitorMetrics::~VisitorMetrics() { }
+VisitorMetrics::~VisitorMetrics() = default;
void
-VisitorMetrics::initThreads(uint16_t threadCount, const metrics::LoadTypeSet& loadTypes) {
+VisitorMetrics::initThreads(uint16_t threadCount) {
if (!threads.empty()) {
throw vespalib::IllegalStateException("Cannot initialize visitor metrics twice", VESPA_STRLOC);
}
@@ -43,7 +43,7 @@ VisitorMetrics::initThreads(uint16_t threadCount, const metrics::LoadTypeSet& lo
for (uint32_t i=0; i<threads.size(); ++i) {
vespalib::asciistream ost;
ost << "visitor_thread_" << i;
- threads[i].reset(new VisitorThreadMetrics( ost.str(), ost.str(), loadTypes));
+ threads[i] = std::make_shared<VisitorThreadMetrics>( ost.str(), ost.str());
registerMetric(*threads[i]);
sum.addMetricToSum(*threads[i]);
}
diff --git a/storage/src/vespa/storage/visiting/visitormetrics.h b/storage/src/vespa/storage/visiting/visitormetrics.h
index f44cc6a7f61..52b29a3a234 100644
--- a/storage/src/vespa/storage/visiting/visitormetrics.h
+++ b/storage/src/vespa/storage/visiting/visitormetrics.h
@@ -1,16 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @class storage::VisitorMetrics
- * @ingroup visiting
- *
- * @brief Metrics for visiting.
- *
- * @version $Id$
- */
+
#pragma once
-#include <vespa/metrics/metrics.h>
#include "visitorthreadmetrics.h"
+#include <vespa/metrics/summetric.h>
+#include <vespa/metrics/countmetric.h>
namespace storage {
@@ -26,9 +20,9 @@ struct VisitorMetrics : public metrics::MetricSet
metrics::SumMetric<MetricSet> sum;
VisitorMetrics();
- ~VisitorMetrics();
+ ~VisitorMetrics() override;
- void initThreads(uint16_t threadCount, const metrics::LoadTypeSet& loadTypes);
+ void initThreads(uint16_t threadCount);
};
} // storage
diff --git a/storage/src/vespa/storage/visiting/visitorthread.cpp b/storage/src/vespa/storage/visiting/visitorthread.cpp
index 2839d3566aa..918a0ce2ee3 100644
--- a/storage/src/vespa/storage/visiting/visitorthread.cpp
+++ b/storage/src/vespa/storage/visiting/visitorthread.cpp
@@ -2,7 +2,6 @@
#include "visitorthread.h"
#include "messages.h"
-#include <vespa/documentapi/loadtypes/loadtype.h>
#include <vespa/document/select/bodyfielddetector.h>
#include <vespa/document/select/parser.h>
#include <vespa/messagebus/rpcmessagebus.h>
@@ -23,7 +22,7 @@ using storage::api::ReturnCode;
namespace storage {
-VisitorThread::Event::Event(Event&& other)
+VisitorThread::Event::Event(Event&& other) noexcept
: _visitorId(other._visitorId),
_message(other._message),
_mbusReply(std::move(other._mbusReply)),
@@ -35,7 +34,7 @@ VisitorThread::Event::Event(Event&& other)
VisitorThread::Event::~Event() = default;
VisitorThread::Event&
-VisitorThread::Event::operator= (Event&& other)
+VisitorThread::Event::operator= (Event&& other) noexcept
{
_visitorId = other._visitorId;
_message = other._message;
@@ -207,7 +206,7 @@ VisitorThread::run(framework::ThreadHandle& thread)
(entry._message->getType() != api::MessageType::INTERNAL
|| static_cast<api::InternalCommand&>(*entry._message).getType() != PropagateVisitorConfig::ID))
{
- entry._timer.stop(_metrics.averageQueueWaitingTime[entry._message->getLoadType()]);
+ entry._timer.stop(_metrics.averageQueueWaitingTime);
}
}
@@ -231,8 +230,7 @@ VisitorThread::run(framework::ThreadHandle& thread)
if (_currentlyRunningVisitor == _visitors.end()) {
handleNonExistingVisitorCall(entry, result);
} else {
- _currentlyRunningVisitor->second->handleDocumentApiReply(
- std::move(entry._mbusReply), _metrics);
+ _currentlyRunningVisitor->second->handleDocumentApiReply(std::move(entry._mbusReply), _metrics);
if (_currentlyRunningVisitor->second->isCompleted()) {
close();
}
@@ -250,7 +248,7 @@ VisitorThread::run(framework::ThreadHandle& thread)
result = ReturnCode(ReturnCode::INTERNAL_FAILURE, ost.str());
if (entry._message.get() && entry._message->getType() == api::MessageType::VISITOR_CREATE) {
_messageSender.closed(entry._visitorId);
- _metrics.failedVisitors[entry._message->getLoadType()].inc(1);
+ _metrics.failedVisitors.inc(1);
}
}
_currentlyRunningVisitor = _visitors.end();
@@ -291,16 +289,13 @@ VisitorThread::close()
Visitor& v = *_currentlyRunningVisitor->second;
- documentapi::LoadType loadType(v.getLoadType());
-
- _metrics.averageVisitorLifeTime[loadType].addValue(
- (closeTime - v.getStartTime()).getMillis().getTime());
+ _metrics.averageVisitorLifeTime.addValue((closeTime - v.getStartTime()).getMillis().getTime());
v.finalize();
_messageSender.closed(_currentlyRunningVisitor->first);
if (v.failed()) {
- _metrics.abortedVisitors[loadType].inc(1);
+ _metrics.abortedVisitors.inc(1);
} else {
- _metrics.completedVisitors[loadType].inc(1);
+ _metrics.completedVisitors.inc(1);
}
framework::SecondTime currentTime(_component.getClock().getTimeInSeconds());
trimRecentlyCompletedList(currentTime);
@@ -322,8 +317,7 @@ VisitorThread::trimRecentlyCompletedList(framework::SecondTime currentTime)
}
void
-VisitorThread::handleNonExistingVisitorCall(const Event& entry,
- ReturnCode& code)
+VisitorThread::handleNonExistingVisitorCall(const Event& entry, ReturnCode& code)
{
// Get current time. Set the time that is the oldest still recent.
framework::SecondTime currentTime(_component.getClock().getTimeInSeconds());
@@ -368,8 +362,7 @@ VisitorThread::createVisitor(vespalib::stringref libName,
}
try{
- std::shared_ptr<Visitor> visitor(it->second->makeVisitor(
- _component, *libIter->second, params));
+ std::shared_ptr<Visitor> visitor(it->second->makeVisitor(_component, *libIter->second, params));
if (!visitor.get()) {
error << "Factory function in '" << str << "' failed.";
}
@@ -530,8 +523,8 @@ VisitorThread::onCreateVisitor(
LOG(error, "Got exception we can't handle: %s", e.what());
assert(false);
}
- _metrics.createdVisitors[visitor->getLoadType()].inc(1);
- visitorTimer.stop(_metrics.averageVisitorCreationTime[visitor->getLoadType()]);
+ _metrics.createdVisitors.inc(1);
+ visitorTimer.stop(_metrics.averageVisitorCreationTime);
} else {
// Send reply
auto reply = std::make_shared<api::CreateVisitorReply>(*cmd);
diff --git a/storage/src/vespa/storage/visiting/visitorthread.h b/storage/src/vespa/storage/visiting/visitorthread.h
index a682544ec23..6df4ddd8819 100644
--- a/storage/src/vespa/storage/visiting/visitorthread.h
+++ b/storage/src/vespa/storage/visiting/visitorthread.h
@@ -54,14 +54,13 @@ class VisitorThread : public framework::Runnable,
metrics::MetricTimer _timer;
Type _type;
- Event() : _visitorId(0), _message(), _timer(), _type(NONE) {}
- Event(Event&& other);
- Event& operator= (Event&& other);
+ Event() noexcept : _visitorId(0), _message(), _timer(), _type(NONE) {}
+ Event(Event&& other) noexcept;
+ Event& operator= (Event&& other) noexcept;
Event(const Event& other) = delete;
Event& operator= (const Event& other) = delete;
Event(api::VisitorId visitor, mbus::Reply::UP reply);
- Event(api::VisitorId visitor,
- const std::shared_ptr<api::StorageMessage>& msg);
+ Event(api::VisitorId visitor, const std::shared_ptr<api::StorageMessage>& msg);
~Event();
bool empty() const noexcept {
diff --git a/storage/src/vespa/storage/visiting/visitorthreadmetrics.cpp b/storage/src/vespa/storage/visiting/visitorthreadmetrics.cpp
new file mode 100644
index 00000000000..df58d14c81e
--- /dev/null
+++ b/storage/src/vespa/storage/visiting/visitorthreadmetrics.cpp
@@ -0,0 +1,27 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "visitorthreadmetrics.h"
+
+namespace storage {
+
+// TODO Vespa 8 all metrics with .sum in the name should have that removed.
+VisitorThreadMetrics::VisitorThreadMetrics(const std::string& name, const std::string& desc)
+ : metrics::MetricSet(name, {{"visitor"},{"partofsum"},{"thread"}}, desc),
+ queueSize("queuesize", {}, "Size of input message queue.", this),
+ averageQueueWaitingTime("averagequeuewait.sum", {}, "Average time an operation spends in input queue.", this),
+ averageVisitorLifeTime("averagevisitorlifetime.sum", {}, "Average lifetime of a visitor", this),
+ averageVisitorCreationTime("averagevisitorcreationtime", {}, "Average time spent creating a visitor instance", this),
+ averageMessageSendTime("averagemessagesendtime.sum", {}, "Average time it takes for messages to be sent to their target (and be replied to)", this),
+ averageProcessingTime("averageprocessingtime.sum", {}, "Average time visitor uses in handleDocuments() call", this),
+ createdVisitors("created.sum", {}, "Number of visitors created.", this),
+ abortedVisitors("aborted", {}, "Number of visitors aborted.", this),
+ completedVisitors("completed.sum", {}, "Number of visitors completed", this),
+ failedVisitors("failed.sum", {}, "Number of visitors failed", this),
+ visitorDestinationFailureReplies("destination_failure_replies", {},"Number of failure replies received from the visitor destination", this)
+{
+ queueSize.unsetOnZeroValue();
+}
+
+VisitorThreadMetrics::~VisitorThreadMetrics() = default;
+
+}
diff --git a/storage/src/vespa/storage/visiting/visitorthreadmetrics.h b/storage/src/vespa/storage/visiting/visitorthreadmetrics.h
index c21fe09cdb4..e58e1f01f59 100644
--- a/storage/src/vespa/storage/visiting/visitorthreadmetrics.h
+++ b/storage/src/vespa/storage/visiting/visitorthreadmetrics.h
@@ -1,108 +1,30 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @class storage::VisitorThreadMetrics
- * @ingroup visiting
- *
- * @brief Metrics for the visitor threads.
- *
- * @version $Id$
- */
#pragma once
-#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/metricset.h>
namespace storage {
struct VisitorThreadMetrics : public metrics::MetricSet
{
- typedef metrics::DoubleAverageMetric DOUBLE;
- typedef metrics::LongAverageMetric COUNT;
-
- metrics::LongAverageMetric queueSize;
- metrics::LoadMetric<DOUBLE> averageQueueWaitingTime;
- metrics::LoadMetric<DOUBLE> averageVisitorLifeTime;
- metrics::LoadMetric<DOUBLE> averageVisitorCreationTime;
- metrics::LoadMetric<DOUBLE> averageMessageSendTime;
- metrics::LoadMetric<DOUBLE> averageProcessingTime;
- metrics::LoadMetric<COUNT> createdVisitors;
- metrics::LoadMetric<COUNT> abortedVisitors;
- metrics::LoadMetric<COUNT> completedVisitors;
- metrics::LoadMetric<COUNT> failedVisitors;
- metrics::LoadMetric<COUNT> visitorDestinationFailureReplies;
-
- VisitorThreadMetrics(const std::string& name,
- const std::string& desc,
- const metrics::LoadTypeSet& loadTypes)
- : metrics::MetricSet(name, {{"visitor"},{"partofsum"},{"thread"}}, desc),
- queueSize("queuesize", {},
- "Size of input message queue.", this),
- averageQueueWaitingTime(
- loadTypes,
- DOUBLE("averagequeuewait",
- {},
- "Average time an operation spends in input queue."),
- this),
- averageVisitorLifeTime(
- loadTypes,
- DOUBLE("averagevisitorlifetime",
- {},
- "Average lifetime of a visitor"),
- this),
- averageVisitorCreationTime(
- loadTypes,
- DOUBLE("averagevisitorcreationtime",
- {},
- "Average time spent creating a visitor instance"),
- this),
- averageMessageSendTime(
- loadTypes,
- DOUBLE("averagemessagesendtime",
- {},
- "Average time it takes for messages to be sent to "
- "their target (and be replied to)"),
- this),
- averageProcessingTime(
- loadTypes,
- DOUBLE("averageprocessingtime",
- {},
- "Average time visitor uses in handleDocuments() call"),
- this),
- createdVisitors(
- loadTypes,
- COUNT("created",
- {},
- "Number of visitors created."),
- this),
- abortedVisitors(
- loadTypes,
- COUNT("aborted",
- {},
- "Number of visitors aborted."),
- this),
- completedVisitors(
- loadTypes,
- COUNT("completed",
- {},
- "Number of visitors completed"),
- this),
- failedVisitors(
- loadTypes,
- COUNT("failed",
- {},
- "Number of visitors failed"),
- this),
- visitorDestinationFailureReplies(
- loadTypes,
- COUNT("destination_failure_replies",
- {},
- "Number of failure replies received from "
- "the visitor destination"),
- this)
- {
- queueSize.unsetOnZeroValue();
- }
-
+ using DoubleAverageMetric = metrics::DoubleAverageMetric;
+ using LongAverageMetric = metrics::LongAverageMetric;
+
+ LongAverageMetric queueSize;
+ DoubleAverageMetric averageQueueWaitingTime;
+ DoubleAverageMetric averageVisitorLifeTime;
+ DoubleAverageMetric averageVisitorCreationTime;
+ DoubleAverageMetric averageMessageSendTime;
+ DoubleAverageMetric averageProcessingTime;
+ LongAverageMetric createdVisitors;
+ LongAverageMetric abortedVisitors;
+ LongAverageMetric completedVisitors;
+ LongAverageMetric failedVisitors;
+ LongAverageMetric visitorDestinationFailureReplies;
+
+ VisitorThreadMetrics(const std::string& name, const std::string& desc);
+ ~VisitorThreadMetrics() override;
};
}
-
diff --git a/storageapi/src/tests/mbusprot/storageprotocoltest.cpp b/storageapi/src/tests/mbusprot/storageprotocoltest.cpp
index e413a62ae39..5637110f341 100644
--- a/storageapi/src/tests/mbusprot/storageprotocoltest.cpp
+++ b/storageapi/src/tests/mbusprot/storageprotocoltest.cpp
@@ -56,7 +56,6 @@ struct StorageProtocolTest : TestWithParam<vespalib::Version> {
document::Bucket _bucket;
document::BucketId _dummy_remap_bucket{17, 12345};
BucketInfo _dummy_bucket_info{1,2,3,4,5, true, false, 48};
- documentapi::LoadTypeSet _loadTypes;
mbusprot::StorageProtocol _protocol;
static auto constexpr CONDITION_STRING = "There's just one condition";
@@ -66,9 +65,8 @@ struct StorageProtocolTest : TestWithParam<vespalib::Version> {
_testDocId(_testDoc->getId()),
_bucket_id(16, 0x51),
_bucket(makeDocumentBucket(_bucket_id)),
- _protocol(_docMan.getTypeRepoSP(), _loadTypes)
+ _protocol(_docMan.getTypeRepoSP())
{
- _loadTypes.addLoadType(34, "foo", documentapi::Priority::PRI_NORMAL_2);
}
~StorageProtocolTest();
@@ -115,7 +113,8 @@ namespace {
}
TEST_F(StorageProtocolTest, testAddress50) {
- StorageMessageAddress address("foo", lib::NodeType::STORAGE, 3);
+ vespalib::string cluster("foo");
+ StorageMessageAddress address(&cluster, lib::NodeType::STORAGE, 3);
EXPECT_EQ(vespalib::string("storage/cluster.foo/storage/3/default"),
address.to_mbus_route().toString());
}
@@ -816,25 +815,25 @@ TEST_P(StorageProtocolTest, serialized_size_is_used_to_set_approx_size_of_storag
}
TEST_P(StorageProtocolTest, track_memory_footprint_for_some_messages) {
- EXPECT_EQ(64u, sizeof(StorageMessage));
- EXPECT_EQ(80u, sizeof(StorageReply));
- EXPECT_EQ(104u, sizeof(BucketReply));
+ EXPECT_EQ(72u, sizeof(StorageMessage));
+ EXPECT_EQ(88u, sizeof(StorageReply));
+ EXPECT_EQ(112u, sizeof(BucketReply));
EXPECT_EQ(8u, sizeof(document::BucketId));
EXPECT_EQ(16u, sizeof(document::Bucket));
EXPECT_EQ(32u, sizeof(BucketInfo));
- EXPECT_EQ(136u, sizeof(BucketInfoReply));
- EXPECT_EQ(280u, sizeof(PutReply));
- EXPECT_EQ(264u, sizeof(UpdateReply));
- EXPECT_EQ(256u, sizeof(RemoveReply));
- EXPECT_EQ(344u, sizeof(GetReply));
- EXPECT_EQ(80u, sizeof(StorageCommand));
- EXPECT_EQ(104u, sizeof(BucketCommand));
- EXPECT_EQ(104u, sizeof(BucketInfoCommand));
- EXPECT_EQ(104u + sizeof(std::string), sizeof(TestAndSetCommand));
- EXPECT_EQ(136u + sizeof(std::string), sizeof(PutCommand));
- EXPECT_EQ(136u + sizeof(std::string), sizeof(UpdateCommand));
- EXPECT_EQ(216u + sizeof(std::string), sizeof(RemoveCommand));
- EXPECT_EQ(288u, sizeof(GetCommand));
+ EXPECT_EQ(144u, sizeof(BucketInfoReply));
+ EXPECT_EQ(288u, sizeof(PutReply));
+ EXPECT_EQ(272u, sizeof(UpdateReply));
+ EXPECT_EQ(264u, sizeof(RemoveReply));
+ EXPECT_EQ(352u, sizeof(GetReply));
+ EXPECT_EQ(88u, sizeof(StorageCommand));
+ EXPECT_EQ(112u, sizeof(BucketCommand));
+ EXPECT_EQ(112u, sizeof(BucketInfoCommand));
+ EXPECT_EQ(112u + sizeof(std::string), sizeof(TestAndSetCommand));
+ EXPECT_EQ(144u + sizeof(std::string), sizeof(PutCommand));
+ EXPECT_EQ(144u + sizeof(std::string), sizeof(UpdateCommand));
+ EXPECT_EQ(224u + sizeof(std::string), sizeof(RemoveCommand));
+ EXPECT_EQ(296u, sizeof(GetCommand));
}
} // storage::api
diff --git a/storageapi/src/tests/messageapi/storage_message_address_test.cpp b/storageapi/src/tests/messageapi/storage_message_address_test.cpp
index f7f254e9119..edcf795368a 100644
--- a/storageapi/src/tests/messageapi/storage_message_address_test.cpp
+++ b/storageapi/src/tests/messageapi/storage_message_address_test.cpp
@@ -9,8 +9,8 @@ namespace storage::api {
namespace {
-size_t hash_of(vespalib::stringref cluster, const lib::NodeType& type, uint16_t index) {
- return StorageMessageAddress(cluster, type, index).internal_storage_hash();
+size_t hash_of(const vespalib::string & cluster, const lib::NodeType& type, uint16_t index) {
+ return StorageMessageAddress(&cluster, type, index).internal_storage_hash();
}
}
@@ -32,8 +32,8 @@ TEST(StorageMessageAddressTest, storage_hash_covers_all_expected_fields) {
EXPECT_NE(hash_of("foo", lib::NodeType::STORAGE, 0),
hash_of("foo", lib::NodeType::STORAGE, 1));
- EXPECT_EQ(88u, sizeof(StorageMessageAddress));
- EXPECT_EQ(64u, sizeof(StorageMessage));
+ EXPECT_EQ(16u, sizeof(StorageMessageAddress));
+ EXPECT_EQ(72u, sizeof(StorageMessage));
EXPECT_EQ(16u, sizeof(mbus::Trace));
}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp
index 2c7b4a1e6f8..45d9d2bd711 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp
@@ -92,7 +92,7 @@ ProtocolSerialization5_0::onEncodeCommand(GBBuf& buf, const api::StorageCommand&
buf.putLong(msg.getMsgId());
buf.putByte(msg.getPriority());
buf.putShort(msg.getSourceIndex());
- buf.putInt(msg.getLoadType().getId());
+ buf.putInt(0); // LoadType 'default'
}
void
@@ -102,15 +102,12 @@ ProtocolSerialization5_0::onDecodeCommand(BBuf& buf, api::StorageCommand& msg) c
uint8_t priority = SH::getByte(buf);
msg.setPriority(priority);
msg.setSourceIndex(SH::getShort(buf));
- (void)SH::getInt(buf);
+ (void)SH::getInt(buf); // LoadType
}
-ProtocolSerialization5_0::ProtocolSerialization5_0(
- const std::shared_ptr<const document::DocumentTypeRepo>& repo,
- const documentapi::LoadTypeSet& loadTypes)
- : ProtocolSerialization4_2(repo),
- _loadTypes(loadTypes)
+ProtocolSerialization5_0::ProtocolSerialization5_0(const std::shared_ptr<const document::DocumentTypeRepo>& repo)
+ : ProtocolSerialization4_2(repo)
{
}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.h b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.h
index 67f02aa2d2a..8d38db89a08 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.h
@@ -2,17 +2,12 @@
#pragma once
#include "protocolserialization4_2.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
namespace storage::mbusprot {
class ProtocolSerialization5_0 : public ProtocolSerialization4_2 {
-private:
- const documentapi::LoadTypeSet& _loadTypes;
-
public:
- ProtocolSerialization5_0(const std::shared_ptr<const document::DocumentTypeRepo>&,
- const documentapi::LoadTypeSet& loadTypes);
+ ProtocolSerialization5_0(const std::shared_ptr<const document::DocumentTypeRepo>&);
document::Bucket getBucket(document::ByteBuffer& buf) const override;
void putBucket(const document::Bucket& bucket, vespalib::GrowableByteBuffer& buf) const override;
@@ -73,9 +68,6 @@ public:
SRep::UP onDecodeCreateVisitorReply(const SCmd& cmd, BBuf& buf) const override;
void onDecodeCommand(BBuf& buf, api::StorageCommand& msg) const override;
void onDecodeReply(BBuf&, api::StorageReply&) const override;
-
-protected:
- const documentapi::LoadTypeSet& loadTypes() const noexcept { return _loadTypes; };
};
}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.cpp b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.cpp
index 0b1f66127ba..b289c1661a0 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.cpp
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.cpp
@@ -44,9 +44,8 @@ ProtocolSerialization5_1::putBucketInfo(
}
ProtocolSerialization5_1::ProtocolSerialization5_1(
- const std::shared_ptr<const document::DocumentTypeRepo>& repo,
- const documentapi::LoadTypeSet& loadTypes)
- : ProtocolSerialization5_0(repo, loadTypes)
+ const std::shared_ptr<const document::DocumentTypeRepo>& repo)
+ : ProtocolSerialization5_0(repo)
{
}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.h b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.h
index 5df0d757ce2..b46257a2182 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_1.h
@@ -3,8 +3,7 @@
#include "protocolserialization5_0.h"
-namespace storage {
-namespace mbusprot {
+namespace storage::mbusprot {
class ProtocolSerialization5_1 : public ProtocolSerialization5_0
{
@@ -13,8 +12,7 @@ class ProtocolSerialization5_1 : public ProtocolSerialization5_0
BUCKET_ACTIVE = 0x2,
};
public:
- ProtocolSerialization5_1(const std::shared_ptr<const document::DocumentTypeRepo>&,
- const documentapi::LoadTypeSet& loadTypes);
+ ProtocolSerialization5_1(const std::shared_ptr<const document::DocumentTypeRepo>&);
api::BucketInfo getBucketInfo(document::ByteBuffer& buf) const override;
void putBucketInfo(const api::BucketInfo& info, vespalib::GrowableByteBuffer& buf) const override;
@@ -33,5 +31,4 @@ protected:
SCmd::UP onDecodeCreateBucketCommand(BBuf&) const override;
};
-} // mbusprot
-} // storage
+}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_2.h b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_2.h
index f6f9443248c..50200edcbcf 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_2.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_2.h
@@ -12,9 +12,8 @@ namespace storage::mbusprot {
class ProtocolSerialization5_2 : public ProtocolSerialization5_1
{
public:
- ProtocolSerialization5_2(const std::shared_ptr<const document::DocumentTypeRepo>& repo,
- const documentapi::LoadTypeSet & loadTypes)
- : ProtocolSerialization5_1(repo, loadTypes)
+ ProtocolSerialization5_2(const std::shared_ptr<const document::DocumentTypeRepo>& repo)
+ : ProtocolSerialization5_1(repo)
{}
protected:
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.cpp b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.cpp
index 930879082ed..cd66928877c 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.cpp
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.cpp
@@ -3,12 +3,10 @@
#include "protocolserialization6_0.h"
#include "serializationhelper.h"
-namespace storage {
-namespace mbusprot {
+namespace storage::mbusprot {
-ProtocolSerialization6_0::ProtocolSerialization6_0(const std::shared_ptr<const document::DocumentTypeRepo> &repo,
- const documentapi::LoadTypeSet &loadTypes)
- : ProtocolSerialization5_2(repo, loadTypes)
+ProtocolSerialization6_0::ProtocolSerialization6_0(const std::shared_ptr<const document::DocumentTypeRepo> &repo)
+ : ProtocolSerialization5_2(repo)
{
}
@@ -40,4 +38,3 @@ ProtocolSerialization6_0::putBucketSpace(document::BucketSpace bucketSpace, vesp
}
}
-}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.h b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.h
index 5c4e6b2ec63..efce45ce844 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization6_0.h
@@ -3,10 +3,8 @@
#pragma once
#include "protocolserialization5_2.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
-namespace storage {
-namespace mbusprot {
+namespace storage::mbusprot {
/**
* Protocol serialization version adding decoding and encoding
@@ -15,8 +13,7 @@ namespace mbusprot {
class ProtocolSerialization6_0 : public ProtocolSerialization5_2
{
public:
- ProtocolSerialization6_0(const std::shared_ptr<const document::DocumentTypeRepo> &repo,
- const documentapi::LoadTypeSet &loadTypes);
+ ProtocolSerialization6_0(const std::shared_ptr<const document::DocumentTypeRepo> &repo);
document::Bucket getBucket(document::ByteBuffer &buf) const override;
void putBucket(const document::Bucket &bucket, vespalib::GrowableByteBuffer &buf) const override;
@@ -25,4 +22,3 @@ public:
};
}
-}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.cpp b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.cpp
index b356ce59999..98f76b4afb7 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.cpp
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.cpp
@@ -14,11 +14,9 @@
namespace storage::mbusprot {
-ProtocolSerialization7::ProtocolSerialization7(std::shared_ptr<const document::DocumentTypeRepo> repo,
- const documentapi::LoadTypeSet& load_types)
+ProtocolSerialization7::ProtocolSerialization7(std::shared_ptr<const document::DocumentTypeRepo> repo)
: ProtocolSerialization(),
- _repo(std::move(repo)),
- _load_types(load_types)
+ _repo(std::move(repo))
{
}
@@ -113,7 +111,6 @@ void write_request_header(vespalib::GrowableByteBuffer& buf, const api::StorageC
hdr.set_message_id(cmd.getMsgId());
hdr.set_priority(cmd.getPriority());
hdr.set_source_index(cmd.getSourceIndex());
- hdr.set_loadtype_id(cmd.getLoadType().getId());
uint8_t dest[128]; // Only primitive fields, should be plenty large enough.
auto encoded_size = static_cast<uint32_t>(hdr.ByteSizeLong());
@@ -232,12 +229,10 @@ class RequestDecoder {
protobuf::RequestHeader _hdr;
::google::protobuf::Arena _arena;
ProtobufType* _proto_obj;
- const documentapi::LoadTypeSet& _load_types;
public:
- RequestDecoder(document::ByteBuffer& in_buf, const documentapi::LoadTypeSet& load_types)
+ RequestDecoder(document::ByteBuffer& in_buf)
: _arena(),
- _proto_obj(::google::protobuf::Arena::Create<ProtobufType>(&_arena)),
- _load_types(load_types)
+ _proto_obj(::google::protobuf::Arena::Create<ProtobufType>(&_arena))
{
decode_request_header(in_buf, _hdr);
assert(in_buf.getRemaining() <= INT_MAX);
@@ -308,7 +303,7 @@ void encode_response(vespalib::GrowableByteBuffer& out_buf, const api::StorageRe
template <typename ProtobufType, typename Func>
std::unique_ptr<api::StorageCommand>
ProtocolSerialization7::decode_request(document::ByteBuffer& in_buf, Func&& f) const {
- RequestDecoder<ProtobufType> dec(in_buf, _load_types);
+ RequestDecoder<ProtobufType> dec(in_buf);
const auto& req = dec.request();
auto cmd = f(req);
dec.transfer_meta_information_to(*cmd);
diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.h b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.h
index e1d08691bc1..8f9a5d8df8d 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization7.h
@@ -3,7 +3,6 @@
#pragma once
#include "protocolserialization.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
namespace storage::mbusprot {
@@ -13,13 +12,10 @@ namespace storage::mbusprot {
*/
class ProtocolSerialization7 final : public ProtocolSerialization {
const std::shared_ptr<const document::DocumentTypeRepo> _repo;
- const documentapi::LoadTypeSet& _load_types;
public:
- ProtocolSerialization7(std::shared_ptr<const document::DocumentTypeRepo> repo,
- const documentapi::LoadTypeSet& load_types);
+ explicit ProtocolSerialization7(std::shared_ptr<const document::DocumentTypeRepo> repo);
const document::DocumentTypeRepo& type_repo() const noexcept { return *_repo; }
- const documentapi::LoadTypeSet& load_type_set() const noexcept { return _load_types; }
// Put
void onEncode(GBBuf&, const api::PutCommand&) const override;
diff --git a/storageapi/src/vespa/storageapi/mbusprot/storagemessage.h b/storageapi/src/vespa/storageapi/mbusprot/storagemessage.h
index c63271a8956..edeab31ec8a 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/storagemessage.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/storagemessage.h
@@ -12,7 +12,7 @@ public:
virtual ~StorageMessage() {}
virtual api::StorageMessage::SP getInternalMessage() = 0;
- virtual storage::api::StorageMessage::CSP getInternalMessage() const = 0;
+ virtual api::StorageMessage::CSP getInternalMessage() const = 0;
};
diff --git a/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.cpp b/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.cpp
index b5107e68454..f6e68b3dd04 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.cpp
+++ b/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.cpp
@@ -15,13 +15,12 @@ namespace storage::mbusprot {
mbus::string StorageProtocol::NAME = "StorageProtocol";
-StorageProtocol::StorageProtocol(const std::shared_ptr<const document::DocumentTypeRepo> repo,
- const documentapi::LoadTypeSet& loadTypes)
- : _serializer5_0(repo, loadTypes),
- _serializer5_1(repo, loadTypes),
- _serializer5_2(repo, loadTypes),
- _serializer6_0(repo, loadTypes),
- _serializer7_0(repo, loadTypes)
+StorageProtocol::StorageProtocol(const std::shared_ptr<const document::DocumentTypeRepo> repo)
+ : _serializer5_0(repo),
+ _serializer5_1(repo),
+ _serializer5_2(repo),
+ _serializer6_0(repo),
+ _serializer7_0(repo)
{
}
diff --git a/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.h b/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.h
index 40f2d26d833..ad9ee908424 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.h
+++ b/storageapi/src/vespa/storageapi/mbusprot/storageprotocol.h
@@ -15,8 +15,7 @@ public:
static mbus::string NAME;
- StorageProtocol(const std::shared_ptr<const document::DocumentTypeRepo>,
- const documentapi::LoadTypeSet& loadTypes);
+ explicit StorageProtocol(const std::shared_ptr<const document::DocumentTypeRepo>);
~StorageProtocol() override;
const mbus::string& getName() const override { return NAME; }
@@ -29,7 +28,7 @@ private:
ProtocolSerialization5_1 _serializer5_1;
ProtocolSerialization5_2 _serializer5_2;
ProtocolSerialization6_0 _serializer6_0;
- ProtocolSerialization7 _serializer7_0;
+ ProtocolSerialization7 _serializer7_0;
};
}
diff --git a/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.cpp b/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.cpp
index 67e4d835e0c..3f64a133b5f 100644
--- a/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.cpp
+++ b/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.cpp
@@ -5,13 +5,6 @@
namespace storage::api {
-BucketInfoReply::BucketInfoReply(const BucketInfoCommand& cmd,
- const ReturnCode& code)
- : BucketReply(cmd, code),
- _result()
-{
-}
-
void
BucketInfoReply::print(std::ostream& out, bool verbose,
const std::string& indent) const
diff --git a/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.h b/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.h
index 5b784267da2..a9f206787cb 100644
--- a/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.h
+++ b/storageapi/src/vespa/storageapi/messageapi/bucketinforeply.h
@@ -22,7 +22,10 @@ class BucketInfoReply : public BucketReply {
BucketInfo _result;
protected:
- BucketInfoReply(const BucketInfoCommand& cmd, const ReturnCode& code = ReturnCode(ReturnCode::OK));
+ BucketInfoReply(const BucketInfoCommand& cmd)
+ : BucketReply(cmd),
+ _result()
+ {}
public:
DECLARE_POINTER_TYPEDEFS(BucketInfoReply);
diff --git a/storageapi/src/vespa/storageapi/messageapi/bucketreply.cpp b/storageapi/src/vespa/storageapi/messageapi/bucketreply.cpp
index e5fb7764aeb..895b6dcef24 100644
--- a/storageapi/src/vespa/storageapi/messageapi/bucketreply.cpp
+++ b/storageapi/src/vespa/storageapi/messageapi/bucketreply.cpp
@@ -9,14 +9,6 @@ using document::BucketId;
namespace storage::api {
-BucketReply::BucketReply(const BucketCommand& cmd,
- const ReturnCode& code)
- : StorageReply(cmd, code),
- _bucket(cmd.getBucket()),
- _originalBucket(cmd.getOriginalBucketId())
-{
-}
-
void
BucketReply::remapBucketId(const BucketId& bucket) {
if (_originalBucket.getRawId() == 0) {
diff --git a/storageapi/src/vespa/storageapi/messageapi/bucketreply.h b/storageapi/src/vespa/storageapi/messageapi/bucketreply.h
index 5b4e6963fd9..9fe04dfe47d 100644
--- a/storageapi/src/vespa/storageapi/messageapi/bucketreply.h
+++ b/storageapi/src/vespa/storageapi/messageapi/bucketreply.h
@@ -9,6 +9,7 @@
#pragma once
#include "storagereply.h"
+#include "bucketcommand.h"
namespace storage::api {
@@ -19,7 +20,11 @@ class BucketReply : public StorageReply {
document::BucketId _originalBucket;
protected:
- BucketReply(const BucketCommand& cmd, const ReturnCode& code = ReturnCode(ReturnCode::OK));
+ BucketReply(const BucketCommand& cmd)
+ : StorageReply(cmd),
+ _bucket(cmd.getBucket()),
+ _originalBucket(cmd.getOriginalBucketId())
+ { }
public:
DECLARE_POINTER_TYPEDEFS(BucketReply);
diff --git a/storageapi/src/vespa/storageapi/messageapi/returncode.cpp b/storageapi/src/vespa/storageapi/messageapi/returncode.cpp
index dbe2f602703..e2184e19a33 100644
--- a/storageapi/src/vespa/storageapi/messageapi/returncode.cpp
+++ b/storageapi/src/vespa/storageapi/messageapi/returncode.cpp
@@ -5,18 +5,7 @@
namespace storage::api {
-ReturnCode::ReturnCode()
- : _result(OK),
- _message()
-{}
-
ReturnCode & ReturnCode::operator = (ReturnCode &&) noexcept = default;
-ReturnCode::~ReturnCode() = default;
-
-ReturnCode::ReturnCode(Result result)
- : _result(result),
- _message()
-{}
ReturnCode::ReturnCode(Result result, vespalib::stringref msg)
: _result(result),
@@ -168,13 +157,6 @@ ReturnCode::isBucketDisappearance() const
}
}
-vespalib::stringref
-ReturnCode::getMessage() const {
- return _message
- ? _message->operator vespalib::stringref()
- : vespalib::stringref();
-}
-
bool
ReturnCode::operator==(const ReturnCode& code) const {
return (_result == code._result) && (getMessage() == code.getMessage());
diff --git a/storageapi/src/vespa/storageapi/messageapi/returncode.h b/storageapi/src/vespa/storageapi/messageapi/returncode.h
index bef59a334d9..478aa455c85 100644
--- a/storageapi/src/vespa/storageapi/messageapi/returncode.h
+++ b/storageapi/src/vespa/storageapi/messageapi/returncode.h
@@ -61,16 +61,25 @@ private:
Result _result;
std::unique_ptr<vespalib::string> _message;
public:
- ReturnCode();
- explicit ReturnCode(Result result);
- explicit ReturnCode(Result result, vespalib::stringref msg);
+ ReturnCode()
+ : _result(OK),
+ _message()
+ { }
+ explicit ReturnCode(Result result)
+ : _result(result),
+ _message()
+ {}
+ ReturnCode(Result result, vespalib::stringref msg);
ReturnCode(const ReturnCode &);
ReturnCode & operator = (const ReturnCode &);
ReturnCode(ReturnCode &&) noexcept = default;
ReturnCode & operator = (ReturnCode &&) noexcept;
- ~ReturnCode();
- vespalib::stringref getMessage() const;
+ vespalib::stringref getMessage() const {
+ return _message
+ ? _message->operator vespalib::stringref()
+ : vespalib::stringref();
+ }
Result getResult() const { return _result; }
diff --git a/storageapi/src/vespa/storageapi/messageapi/storagemessage.cpp b/storageapi/src/vespa/storageapi/messageapi/storagemessage.cpp
index 9c5df379d22..892e7199cf3 100644
--- a/storageapi/src/vespa/storageapi/messageapi/storagemessage.cpp
+++ b/storageapi/src/vespa/storageapi/messageapi/storagemessage.cpp
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "storagemessage.h"
-#include <vespa/documentapi/loadtypes/loadtype.h>
#include <vespa/messagebus/routing/verbatimdirective.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
@@ -143,39 +142,47 @@ std::ostream & operator << (std::ostream & os, const StorageMessageAddress & add
return os << addr.toString();
}
-static vespalib::string
-createAddress(vespalib::stringref cluster, const lib::NodeType& type, uint16_t index)
-{
+namespace {
+
+vespalib::string
+createAddress(vespalib::stringref cluster, const lib::NodeType &type, uint16_t index) {
vespalib::asciistream os;
os << STORAGEADDRESS_PREFIX << cluster << '/' << type.toString() << '/' << index << "/default";
return os.str();
}
-size_t
-calculate_node_hash(const lib::NodeType& type, uint16_t index)
-{
- uint16_t buf[] = { type, index };
- return vespalib::hashValue(&buf, sizeof(buf));
+uint32_t
+calculate_node_hash(const lib::NodeType &type, uint16_t index) {
+ uint16_t buf[] = {type, index};
+ size_t hash = vespalib::hashValue(&buf, sizeof(buf));
+ return uint32_t(hash & 0xffffffffl) ^ uint32_t(hash >> 32);
+}
+
+vespalib::string Empty;
+
}
// TODO we ideally want this removed. Currently just in place to support usage as map key when emplacement not available
-StorageMessageAddress::StorageMessageAddress()
- : _cluster(),
+StorageMessageAddress::StorageMessageAddress() noexcept
+ : _cluster(&Empty),
_precomputed_storage_hash(0),
- _type(nullptr),
+ _type(lib::NodeType::Type::UNKNOWN),
_protocol(Protocol::STORAGE),
_index(0)
{}
-StorageMessageAddress::StorageMessageAddress(vespalib::stringref cluster, const lib::NodeType& type,
- uint16_t index, Protocol protocol)
+StorageMessageAddress::StorageMessageAddress(const vespalib::string * cluster, const lib::NodeType& type, uint16_t index) noexcept
+ : StorageMessageAddress(cluster, type, index, Protocol::STORAGE)
+{ }
+
+StorageMessageAddress::StorageMessageAddress(const vespalib::string * cluster, const lib::NodeType& type,
+ uint16_t index, Protocol protocol) noexcept
: _cluster(cluster),
_precomputed_storage_hash(calculate_node_hash(type, index)),
- _type(&type),
+ _type(type.getType()),
_protocol(protocol),
_index(index)
-{
-}
+{ }
StorageMessageAddress::~StorageMessageAddress() = default;
@@ -183,50 +190,20 @@ mbus::Route
StorageMessageAddress::to_mbus_route() const
{
mbus::Route result;
- auto address_as_str = createAddress(_cluster, *_type, _index);
+ auto address_as_str = createAddress(getCluster(), lib::NodeType::get(_type), _index);
std::vector<mbus::IHopDirective::SP> directives;
directives.emplace_back(std::make_shared<mbus::VerbatimDirective>(std::move(address_as_str)));
result.addHop(mbus::Hop(std::move(directives), false));
return result;
}
-uint16_t
-StorageMessageAddress::getIndex() const
-{
- if (!_type) {
- throw vespalib::IllegalStateException("Cannot retrieve node index out of external address", VESPA_STRLOC);
- }
- return _index;
-}
-
-const lib::NodeType&
-StorageMessageAddress::getNodeType() const
-{
- if (!_type) {
- throw vespalib::IllegalStateException("Cannot retrieve node type out of external address", VESPA_STRLOC);
- }
- return *_type;
-}
-
-const vespalib::string&
-StorageMessageAddress::getCluster() const
-{
- if (!_type) {
- throw vespalib::IllegalStateException("Cannot retrieve cluster out of external address", VESPA_STRLOC);
- }
- return _cluster;
-}
-
bool
-StorageMessageAddress::operator==(const StorageMessageAddress& other) const
+StorageMessageAddress::operator==(const StorageMessageAddress& other) const noexcept
{
if (_protocol != other._protocol) return false;
if (_type != other._type) return false;
- if (_type) {
- if (_index != other._index) return false;
- if (_type != other._type) return false;
- if (_cluster != other._cluster) return false;
- }
+ if (_index != other._index) return false;
+ if (getCluster() != other.getCluster()) return false;
return true;
}
@@ -242,15 +219,15 @@ void
StorageMessageAddress::print(vespalib::asciistream & out) const
{
out << "StorageMessageAddress(";
- if (_protocol == STORAGE) {
+ if (_protocol == Protocol::STORAGE) {
out << "Storage protocol";
} else {
out << "Document protocol";
}
- if (!_type) {
+ if (_type == lib::NodeType::Type::UNKNOWN) {
out << ", " << to_mbus_route().toString() << ")";
} else {
- out << ", cluster " << _cluster << ", nodetype " << *_type
+ out << ", cluster " << getCluster() << ", nodetype " << lib::NodeType::get(_type)
<< ", index " << _index << ")";
}
}
@@ -258,12 +235,12 @@ StorageMessageAddress::print(vespalib::asciistream & out) const
TransportContext::~TransportContext() = default;
StorageMessage::Id
-StorageMessage::generateMsgId()
+StorageMessage::generateMsgId() noexcept
{
return _G_lastMsgId.fetch_add(1, std::memory_order_relaxed);
}
-StorageMessage::StorageMessage(const MessageType& type, Id id)
+StorageMessage::StorageMessage(const MessageType& type, Id id) noexcept
: _type(type),
_msgId(id),
_address(),
@@ -273,7 +250,7 @@ StorageMessage::StorageMessage(const MessageType& type, Id id)
{
}
-StorageMessage::StorageMessage(const StorageMessage& other, Id id)
+StorageMessage::StorageMessage(const StorageMessage& other, Id id) noexcept
: _type(other._type),
_msgId(id),
_address(),
@@ -285,13 +262,8 @@ StorageMessage::StorageMessage(const StorageMessage& other, Id id)
StorageMessage::~StorageMessage() = default;
-const documentapi::LoadType&
-StorageMessage::getLoadType() const {
- return documentapi::LoadType::DEFAULT;
-}
-
void
-StorageMessage::setNewMsgId()
+StorageMessage::setNewMsgId() noexcept
{
_msgId = generateMsgId();
}
diff --git a/storageapi/src/vespa/storageapi/messageapi/storagemessage.h b/storageapi/src/vespa/storageapi/messageapi/storagemessage.h
index 98552e473c1..acf651d8816 100644
--- a/storageapi/src/vespa/storageapi/messageapi/storagemessage.h
+++ b/storageapi/src/vespa/storageapi/messageapi/storagemessage.h
@@ -21,7 +21,6 @@
#include <iosfwd>
namespace vespalib { class asciistream; }
-namespace documentapi { class LoadType; }
// The following macros are provided as a way to write storage messages simply.
// They implement the parts of the code that can easily be automaticly
// generated.
@@ -241,16 +240,16 @@ public:
MessageType(const MessageType &) = delete;
MessageType& operator=(const MessageType &) = delete;
~MessageType();
- Id getId() const { return _id; }
- static Id getMaxId() { return MESSAGETYPE_MAX_ID; }
- const vespalib::string& getName() const { return _name; }
- bool isReply() const { return (_replyOf != 0); }
+ Id getId() const noexcept { return _id; }
+ static Id getMaxId() noexcept { return MESSAGETYPE_MAX_ID; }
+ const vespalib::string& getName() const noexcept { return _name; }
+ bool isReply() const noexcept { return (_replyOf != 0); }
/** Only valid to call on replies. */
- const MessageType& getCommandType() const { return *_replyOf; }
+ const MessageType& getCommandType() const noexcept { return *_replyOf; }
/** Only valid to call on commands. */
- const MessageType& getReplyType() const { return *_reply; }
- bool operator==(const MessageType& type) const { return (_id == type._id); }
- bool operator!=(const MessageType& type) const { return (_id != type._id); }
+ const MessageType& getReplyType() const noexcept { return *_reply; }
+ bool operator==(const MessageType& type) const noexcept { return (_id == type._id); }
+ bool operator!=(const MessageType& type) const noexcept { return (_id != type._id); }
void print(std::ostream& out, bool verbose, const std::string& indent) const override;
};
@@ -263,40 +262,44 @@ public:
*/
class StorageMessageAddress {
public:
- enum Protocol { STORAGE, DOCUMENT };
+ enum class Protocol : uint8_t { STORAGE, DOCUMENT };
private:
- vespalib::string _cluster;
+ const vespalib::string *_cluster;
// Used for internal VDS addresses only
- size_t _precomputed_storage_hash;
- const lib::NodeType* _type;
- Protocol _protocol;
- uint16_t _index;
+ uint32_t _precomputed_storage_hash;
+ lib::NodeType::Type _type;
+ Protocol _protocol;
+ uint16_t _index;
public:
- StorageMessageAddress(); // Only to be used when transient default ctor semantics are needed by containers
- StorageMessageAddress(vespalib::stringref clusterName,
- const lib::NodeType& type, uint16_t index,
- Protocol protocol = STORAGE);
+ StorageMessageAddress() noexcept; // Only to be used when transient default ctor semantics are needed by containers
+ StorageMessageAddress(const vespalib::string * cluster, const lib::NodeType& type, uint16_t index) noexcept;
+ StorageMessageAddress(const vespalib::string * cluster, const lib::NodeType& type, uint16_t index, Protocol protocol) noexcept;
~StorageMessageAddress();
- void setProtocol(Protocol p) { _protocol = p; }
+ void setProtocol(Protocol p) noexcept { _protocol = p; }
mbus::Route to_mbus_route() const;
- Protocol getProtocol() const { return _protocol; }
- uint16_t getIndex() const;
- const lib::NodeType& getNodeType() const;
- const vespalib::string& getCluster() const;
+ Protocol getProtocol() const noexcept { return _protocol; }
+ uint16_t getIndex() const noexcept { return _index; }
+ lib::NodeType::Type getNodeType() const noexcept { return _type; }
+ const vespalib::string& getCluster() const noexcept { return *_cluster; }
// Returns precomputed hash over <type, index> pair. Other fields not included.
- [[nodiscard]] size_t internal_storage_hash() const noexcept {
+ [[nodiscard]] uint32_t internal_storage_hash() const noexcept {
return _precomputed_storage_hash;
}
- bool operator==(const StorageMessageAddress& other) const;
+ bool operator==(const StorageMessageAddress& other) const noexcept;
vespalib::string toString() const;
friend std::ostream & operator << (std::ostream & os, const StorageMessageAddress & addr);
-
+ static StorageMessageAddress create(const vespalib::string * cluster, const lib::NodeType& type, uint16_t index) noexcept {
+ return api::StorageMessageAddress(cluster, type, index);
+ }
+ static StorageMessageAddress createDocApi(const vespalib::string * cluster, const lib::NodeType& type, uint16_t index) noexcept {
+ return api::StorageMessageAddress(cluster, type, index, Protocol::DOCUMENT);
+ }
private:
void print(vespalib::asciistream & out) const;
};
@@ -349,47 +352,47 @@ public:
static const char* getPriorityString(Priority);
private:
+ static document::Bucket getDummyBucket() noexcept { return document::Bucket(document::BucketSpace::invalid(), document::BucketId()); }
mutable std::unique_ptr<TransportContext> _transportContext;
protected:
- static Id generateMsgId();
+ static Id generateMsgId() noexcept;
- const MessageType& _type;
- Id _msgId;
- std::unique_ptr<StorageMessageAddress> _address;
- vespalib::Trace _trace;
- uint32_t _approxByteSize;
- Priority _priority;
+ const MessageType& _type;
+ Id _msgId;
+ StorageMessageAddress _address;
+ vespalib::Trace _trace;
+ uint32_t _approxByteSize;
+ Priority _priority;
- StorageMessage(const MessageType& code, Id id);
- StorageMessage(const StorageMessage&, Id id);
+ StorageMessage(const MessageType& code, Id id) noexcept;
+ StorageMessage(const StorageMessage&, Id id) noexcept;
- static document::Bucket getDummyBucket() { return document::Bucket(document::BucketSpace::invalid(), document::BucketId()); }
public:
StorageMessage& operator=(const StorageMessage&) = delete;
StorageMessage(const StorageMessage&) = delete;
~StorageMessage() override;
- Id getMsgId() const { return _msgId; }
+ Id getMsgId() const noexcept { return _msgId; }
/** Method used by storage commands to set a new id. */
- void setNewMsgId();
+ void setNewMsgId() noexcept;
/**
* Set the id of this message. Typically used to set the id to a
* unique value previously generated with the generateMsgId method.
**/
- void forceMsgId(Id msgId) { _msgId = msgId; }
+ void forceMsgId(Id msgId) noexcept { _msgId = msgId; }
- const MessageType& getType() const { return _type; }
+ const MessageType& getType() const noexcept { return _type; }
- void setPriority(Priority p) { _priority = p; }
- Priority getPriority() const { return _priority; }
+ void setPriority(Priority p) noexcept { _priority = p; }
+ Priority getPriority() const noexcept { return _priority; }
- const StorageMessageAddress* getAddress() const { return _address.get(); }
+ const StorageMessageAddress* getAddress() const noexcept { return (_address.getNodeType() != lib::NodeType::Type::UNKNOWN) ? &_address : nullptr; }
- void setAddress(const StorageMessageAddress& address) {
- _address = std::make_unique<StorageMessageAddress>(address);
+ void setAddress(const StorageMessageAddress& address) noexcept {
+ _address = address;
}
/**
@@ -400,7 +403,7 @@ public:
return _approxByteSize;
}
- void setApproxByteSize(uint32_t value) {
+ void setApproxByteSize(uint32_t value) noexcept {
_approxByteSize = value;
}
@@ -409,11 +412,11 @@ public:
* created, whether it was a storageprotocol message, a documentprotocol
* message, or an RPC call.
*/
- void setTransportContext(std::unique_ptr<TransportContext> context) {
+ void setTransportContext(std::unique_ptr<TransportContext> context) noexcept {
_transportContext = std::move(context);
}
- std::unique_ptr<TransportContext> getTransportContext() const {
+ std::unique_ptr<TransportContext> getTransportContext() const noexcept {
return std::move(_transportContext);
}
@@ -427,16 +430,14 @@ public:
*/
virtual bool callHandler(MessageHandler&, const StorageMessage::SP&) const = 0;
- const documentapi::LoadType& getLoadType() const;
-
- mbus::Trace && steal_trace() { return std::move(_trace); }
- mbus::Trace& getTrace() { return _trace; }
- const mbus::Trace& getTrace() const { return _trace; }
+ mbus::Trace && steal_trace() noexcept { return std::move(_trace); }
+ mbus::Trace& getTrace() noexcept { return _trace; }
+ const mbus::Trace& getTrace() const noexcept { return _trace; }
/**
Sets the trace object for this message.
*/
- void setTrace(vespalib::Trace && trace) { _trace = std::move(trace); }
+ void setTrace(vespalib::Trace && trace) noexcept { _trace = std::move(trace); }
/**
* Cheap version of tostring().
@@ -444,7 +445,7 @@ public:
virtual vespalib::string getSummary() const;
virtual document::Bucket getBucket() const { return getDummyBucket(); }
- document::BucketId getBucketId() const { return getBucket().getBucketId(); }
+ document::BucketId getBucketId() const noexcept { return getBucket().getBucketId(); }
virtual bool hasSingleBucketId() const { return false; }
virtual LockingRequirements lockingRequirements() const noexcept {
// Safe default: assume exclusive locking is required.
diff --git a/storageapi/src/vespa/storageapi/messageapi/storagereply.cpp b/storageapi/src/vespa/storageapi/messageapi/storagereply.cpp
index 2bb9fabd7d5..b5cbd3eae54 100644
--- a/storageapi/src/vespa/storageapi/messageapi/storagereply.cpp
+++ b/storageapi/src/vespa/storageapi/messageapi/storagereply.cpp
@@ -6,9 +6,13 @@
namespace storage::api {
+StorageReply::StorageReply(const StorageCommand& cmd)
+ : StorageReply(cmd, ReturnCode())
+{}
+
StorageReply::StorageReply(const StorageCommand& cmd, ReturnCode code)
: StorageMessage(cmd.getType().getReplyType(), cmd.getMsgId()),
- _result(code)
+ _result(std::move(code))
{
setPriority(cmd.getPriority());
if (cmd.getAddress()) {
@@ -26,10 +30,8 @@ StorageReply::StorageReply(const StorageCommand& cmd, ReturnCode code)
StorageReply::~StorageReply() = default;
void
-StorageReply::print(std::ostream& out, bool verbose,
- const std::string& indent) const
+StorageReply::print(std::ostream& out, bool , const std::string& ) const
{
- (void) verbose; (void) indent;
out << "StorageReply(" << _type.getName() << ", " << _result << ")";
}
diff --git a/storageapi/src/vespa/storageapi/messageapi/storagereply.h b/storageapi/src/vespa/storageapi/messageapi/storagereply.h
index 53516949110..e423e3b5bf9 100644
--- a/storageapi/src/vespa/storageapi/messageapi/storagereply.h
+++ b/storageapi/src/vespa/storageapi/messageapi/storagereply.h
@@ -23,8 +23,8 @@ class StorageReply : public StorageMessage {
ReturnCode _result;
protected:
- explicit StorageReply(const StorageCommand& cmd,
- ReturnCode code = ReturnCode(ReturnCode::OK));
+ explicit StorageReply(const StorageCommand& cmd);
+ StorageReply(const StorageCommand& cmd, ReturnCode code);
public:
~StorageReply() override;
diff --git a/storageframework/src/vespa/storageframework/generic/metric/metricupdatehook.h b/storageframework/src/vespa/storageframework/generic/metric/metricupdatehook.h
index fb9606f33e0..6292fe9a598 100644
--- a/storageframework/src/vespa/storageframework/generic/metric/metricupdatehook.h
+++ b/storageframework/src/vespa/storageframework/generic/metric/metricupdatehook.h
@@ -9,10 +9,12 @@
#include <mutex>
+namespace metrics { class MetricLockGuard; }
+
namespace storage::framework {
struct MetricUpdateHook {
- using MetricLockGuard = std::unique_lock<std::mutex>;
+ using MetricLockGuard = metrics::MetricLockGuard;
virtual ~MetricUpdateHook() = default;
virtual void updateMetrics(const MetricLockGuard &) = 0;
diff --git a/storageframework/src/vespa/storageframework/generic/status/htmlstatusreporter.cpp b/storageframework/src/vespa/storageframework/generic/status/htmlstatusreporter.cpp
index 9b5efef1fbf..c195a83038e 100644
--- a/storageframework/src/vespa/storageframework/generic/status/htmlstatusreporter.cpp
+++ b/storageframework/src/vespa/storageframework/generic/status/htmlstatusreporter.cpp
@@ -2,8 +2,7 @@
#include "htmlstatusreporter.h"
-namespace storage {
-namespace framework {
+namespace storage::framework {
HtmlStatusReporter::HtmlStatusReporter(vespalib::stringref id,
vespalib::stringref name)
@@ -11,9 +10,7 @@ HtmlStatusReporter::HtmlStatusReporter(vespalib::stringref id,
{
}
-HtmlStatusReporter::~HtmlStatusReporter()
-{
-}
+HtmlStatusReporter::~HtmlStatusReporter() = default;
void
HtmlStatusReporter::reportHtmlHeader(std::ostream& out,
@@ -52,5 +49,4 @@ HtmlStatusReporter::reportStatus(std::ostream& out,
return true;
}
-} // framework
-} // storage
+}
diff --git a/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp b/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp
index d770a4d759b..087a3be86d3 100644
--- a/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp
+++ b/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp
@@ -6,10 +6,10 @@
#include <vespa/searchlib/fef/matchdata.h>
#include <vespa/searchlib/fef/feature_resolver.h>
#include <vespa/searchvisitor/hitcollector.h>
-#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/eval/engine_or_factory.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/eval/value.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
using namespace document;
@@ -18,10 +18,11 @@ using namespace vespalib;
using namespace vdslib;
using namespace vsm;
using vespalib::nbostream;
-using vespalib::eval::EngineOrFactory;
-using vespalib::eval::Value;
using vespalib::eval::DoubleValue;
+using vespalib::eval::SimpleValue;
using vespalib::eval::TensorSpec;
+using vespalib::eval::Value;
+
namespace streaming {
@@ -253,7 +254,7 @@ public:
~MyRankProgram();
virtual void run(uint32_t docid, const std::vector<search::fef::TermFieldMatchData> &) override {
_boxed_double = std::make_unique<DoubleValue>(docid + 30);
- _tensor = EngineOrFactory::get().from_spec(TensorSpec("tensor(x{})").add({{"x", "a"}}, docid + 20));
+ _tensor = SimpleValue::from_spec(TensorSpec("tensor(x{})").add({{"x", "a"}}, docid + 20));
_fooValue.as_number = docid + 10;
_barValue.as_object = *_boxed_double;
_bazValue.as_object = *_tensor;
@@ -308,9 +309,8 @@ HitCollectorTest::testFeatureSet()
EXPECT_TRUE(!f[2].is_double());
EXPECT_TRUE(f[2].is_data());
{
- auto engine = EngineOrFactory::get();
nbostream buf(f[2].as_data().data, f[2].as_data().size);
- auto actual = engine.to_spec(*engine.decode(buf));
+ auto actual = spec_from_value(*SimpleValue::from_stream(buf));
auto expect = TensorSpec("tensor(x{})").add({{"x", "a"}}, 23);
EXPECT_EQUAL(actual, expect);
}
diff --git a/streamingvisitors/src/vespa/searchvisitor/hitcollector.cpp b/streamingvisitors/src/vespa/searchvisitor/hitcollector.cpp
index 12dce7d376c..b0cb058d762 100644
--- a/streamingvisitors/src/vespa/searchvisitor/hitcollector.cpp
+++ b/streamingvisitors/src/vespa/searchvisitor/hitcollector.cpp
@@ -4,7 +4,7 @@
#include <vespa/searchlib/fef/feature_resolver.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <algorithm>
-#include <vespa/eval/eval/engine_or_factory.h>
+#include <vespa/eval/eval/value_codec.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/log/log.h>
@@ -164,7 +164,7 @@ HitCollector::getFeatureSet(IRankProgram &rankProgram,
auto obj = resolver.resolve(j).as_object(docId);
if (! obj.get().is_double()) {
vespalib::nbostream buf;
- vespalib::eval::EngineOrFactory::get().encode(obj.get(), buf);
+ encode_value(obj.get(), buf);
f[j].set_data(vespalib::Memory(buf.peek(), buf.size()));
} else {
f[j].set_double(obj.get().as_double());
diff --git a/travis/detect-what-to-build.sh b/travis/detect-what-to-build.sh
new file mode 100755
index 00000000000..12bf892d419
--- /dev/null
+++ b/travis/detect-what-to-build.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+if (( ${#BASH_SOURCE[@]} == 1 )); then
+ echo "This script must be sourced."
+ exit 1
+fi
+
+if [[ $TRAVIS_PULL_REQUEST == false ]]; then
+ export SHOULD_BUILD=all
+ return 0
+fi
+
+# Future use
+#JSON=$(curl -sLf https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST)
+#PR_TITLE=$(jq -re '.title' <<< "$JSON")
+
+JSON=$(curl -sLf https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST/commits)
+COMMITS=$(jq -re '.[].sha' <<< "$JSON")
+
+FILES=$(for C in $COMMITS; do JSON=$(curl -sLf https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/$C); jq -re '.files[].filename' <<< "$JSON"; done)
+
+if [[ -z $FILES ]]; then
+ SHOULD_BUILD=all
+elif ! grep -v -E "(\.h|\.hh|\.hxx|\.c|\.cpp|\.cxx)$" <<< "$FILES" &> /dev/null; then
+ SHOULD_BUILD=cpp
+elif ! grep -v -E "(\.java)$" <<< "$FILES" &> /dev/null; then
+ SHOULD_BUILD=java
+else
+ SHOULD_BUILD=all
+fi
+
+export SHOULD_BUILD
+
diff --git a/travis/travis-build-full.sh b/travis/travis-build-full.sh
deleted file mode 100755
index 46268a964c2..00000000000
--- a/travis/travis-build-full.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-set -e
-
-export SOURCE_DIR=/source
-export NUM_THREADS=6
-export MALLOC_ARENA_MAX=1
-export MAVEN_OPTS="-Xss1m -Xms128m -Xmx2g"
-source /etc/profile.d/enable-devtoolset-9.sh
-source /etc/profile.d/enable-rh-maven35.sh
-
-ccache --max-size=1600M
-ccache --set-config=compression=true
-ccache -p
-
-cd ${SOURCE_DIR}
-env VESPA_MAVEN_EXTRA_OPTS="--no-snapshot-updates --batch-mode --threads ${NUM_THREADS}" sh ./bootstrap.sh java
-mvn -V install --no-snapshot-updates --batch-mode --threads ${NUM_THREADS}
-cmake3 -DVESPA_UNPRIVILEGED=no .
-make -j ${NUM_THREADS}
-ctest3 --output-on-failure -j ${NUM_THREADS}
-ccache --show-stats
-make install
diff --git a/travis/travis-build.sh b/travis/travis-build.sh
new file mode 100755
index 00000000000..47d1496b0cf
--- /dev/null
+++ b/travis/travis-build.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+set -e
+
+readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd )"
+readonly NUM_THREADS=$(( $(nproc) + 2 ))
+
+source /etc/profile.d/enable-devtoolset-9.sh
+source /etc/profile.d/enable-rh-maven35.sh
+
+export MALLOC_ARENA_MAX=1
+export MAVEN_OPTS="-Xss1m -Xms128m -Xmx2g"
+export VESPA_MAVEN_EXTRA_OPTS="${VESPA_MAVEN_EXTRA_OPTS:+${VESPA_MAVEN_EXTRA_OPTS} }--no-snapshot-updates --batch-mode --threads ${NUM_THREADS}"
+
+ccache --max-size=1600M
+ccache --set-config=compression=true
+ccache -p
+
+if ! source $SOURCE_DIR/travis/detect-what-to-build.sh; then
+ echo "Could not detect what to build."
+ SHOULD_BUILD=all
+fi
+
+echo "Building: $SHOULD_BUILD"
+
+cd ${SOURCE_DIR}
+
+case $SHOULD_BUILD in
+ cpp)
+ ./bootstrap.sh full
+ cmake3 -DVESPA_UNPRIVILEGED=no .
+ make -j ${NUM_THREADS}
+ ctest3 --output-on-failure -j ${NUM_THREADS}
+ ccache --show-stats
+ ;;
+ java)
+ ./bootstrap.sh java
+ mvn -V $VESPA_MAVEN_EXTRA_OPTS install
+ ;;
+ *)
+ ./bootstrap.sh java
+ mvn -V $VESPA_MAVEN_EXTRA_OPTS install
+ cmake3 -DVESPA_UNPRIVILEGED=no .
+ make -j ${NUM_THREADS}
+ ctest3 --output-on-failure -j ${NUM_THREADS}
+ ccache --show-stats
+ make install
+ ;;
+esac
+
+
diff --git a/travis/travis.sh b/travis/travis.sh
index 315771b43b9..1ea4d43dd66 100755
--- a/travis/travis.sh
+++ b/travis/travis.sh
@@ -14,5 +14,6 @@ DOCKER_IMAGE=vespaengine/vespa-build-centos7:latest
bell &
docker run --rm -v ${HOME}/.m2:/root/.m2 -v ${HOME}/.ccache:/root/.ccache -v $(pwd):/source \
- --entrypoint /source/travis/travis-build-full.sh ${DOCKER_IMAGE}
+ -e TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG -e TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST \
+ --entrypoint /source/travis/travis-build.sh ${DOCKER_IMAGE}
exit $?
diff --git a/vbench/src/tests/handler_thread/handler_thread_test.cpp b/vbench/src/tests/handler_thread/handler_thread_test.cpp
index 37c3b8ed796..9420fc7feba 100644
--- a/vbench/src/tests/handler_thread/handler_thread_test.cpp
+++ b/vbench/src/tests/handler_thread/handler_thread_test.cpp
@@ -6,12 +6,15 @@ using namespace vbench;
struct MyHandler : Handler<int> {
std::vector<int> values;
+ ~MyHandler() override;
void handle(std::unique_ptr<int> value) override {
values.push_back(*value);
vespalib::Thread::sleep(10); // for improved coverage
}
};
+MyHandler::~MyHandler() = default;
+
TEST("handler thread") {
MyHandler handler;
HandlerThread<int> th(handler);
diff --git a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp
index e52ad78c2ba..6ac521a0f01 100644
--- a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp
+++ b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp
@@ -94,6 +94,8 @@ RedundancyGroupDistribution::RedundancyGroupDistribution(
assert(_values.front() >= _values.back());
}
+RedundancyGroupDistribution::~RedundancyGroupDistribution() = default;
+
void
RedundancyGroupDistribution::print(std::ostream& out,
bool, const std::string&) const
diff --git a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h
index 73013b6ce81..ab0efcc8a2c 100644
--- a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h
+++ b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h
@@ -31,6 +31,8 @@ public:
RedundancyGroupDistribution(const RedundancyGroupDistribution& spec,
uint16_t redundancy);
+ ~RedundancyGroupDistribution() override;
+
uint16_t size() const { return _values.size(); }
uint16_t operator[](uint16_t i) const { return _values[i]; }
diff --git a/vdslib/src/vespa/vdslib/state/nodetype.cpp b/vdslib/src/vespa/vdslib/state/nodetype.cpp
index 915b1548f88..7a52dbf6116 100644
--- a/vdslib/src/vespa/vdslib/state/nodetype.cpp
+++ b/vdslib/src/vespa/vdslib/state/nodetype.cpp
@@ -3,15 +3,15 @@
#include "nodetype.h"
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
+#include <cassert>
-namespace storage {
-namespace lib {
+namespace storage::lib {
// WARNING: Because static initialization happen in random order, the State
// class use these enum values directly during static initialization since
// these objects may yet not exist. Update in State if you change this.
-const NodeType NodeType::STORAGE("storage", 0);
-const NodeType NodeType::DISTRIBUTOR("distributor", 1);
+const NodeType NodeType::STORAGE("storage", NodeType::Type::STORAGE);
+const NodeType NodeType::DISTRIBUTOR("distributor", NodeType::Type::DISTRIBUTOR);
const NodeType&
NodeType::get(vespalib::stringref serialized)
@@ -26,8 +26,22 @@ NodeType::get(vespalib::stringref serialized)
"Unknown node type " + serialized + " given.", VESPA_STRLOC);
}
-NodeType::NodeType(vespalib::stringref name, uint16_t enumValue)
- : _enumValue(enumValue), _name(name)
+const NodeType&
+NodeType::get(Type type) noexcept
+{
+ switch (type) {
+ case Type::STORAGE:
+ return STORAGE;
+ case Type::DISTRIBUTOR:
+ return DISTRIBUTOR;
+ case Type::UNKNOWN:
+ assert(type != Type::UNKNOWN);
+ }
+ abort();
+}
+
+NodeType::NodeType(vespalib::stringref name, Type type) noexcept
+ : _type(type), _name(name)
{
}
@@ -39,5 +53,4 @@ vespalib::asciistream & operator << (vespalib::asciistream & os, const NodeType
return os << n.toString();
}
-} // lib
-} // storage
+}
diff --git a/vdslib/src/vespa/vdslib/state/nodetype.h b/vdslib/src/vespa/vdslib/state/nodetype.h
index 35edd83fdac..86d683384e6 100644
--- a/vdslib/src/vespa/vdslib/state/nodetype.h
+++ b/vdslib/src/vespa/vdslib/state/nodetype.h
@@ -10,44 +10,47 @@
#pragma once
#include <vespa/vespalib/stllike/string.h>
-#include <stdint.h>
namespace vespalib {
class asciistream;
}
-namespace storage {
-namespace lib {
+namespace storage::lib {
class NodeType {
- typedef vespalib::asciistream asciistream;
- uint16_t _enumValue;
- vespalib::string _name;
-
- NodeType(vespalib::stringref name, uint16_t enumValue);
-
public:
+ NodeType(const NodeType &) = delete;
+ NodeType & operator = (const NodeType &) = delete;
+ NodeType(NodeType &&) = delete;
+ NodeType & operator =(NodeType &&) = delete;
+ enum class Type : uint8_t {STORAGE = 0, DISTRIBUTOR = 1, UNKNOWN = 2};
static const NodeType DISTRIBUTOR;
static const NodeType STORAGE;
/** Throws vespalib::IllegalArgumentException if invalid state given. */
static const NodeType& get(vespalib::stringref serialized);
- const vespalib::string& serialize() const { return _name; }
+ static const NodeType& get(Type type) noexcept;
+ const vespalib::string& serialize() const noexcept { return _name; }
- operator uint16_t() const { return _enumValue; }
+ Type getType() const noexcept { return _type; }
+ operator uint16_t() const noexcept { return static_cast<uint16_t>(_type); }
- const vespalib::string & toString() const { return _name; }
- bool operator==(const NodeType& other) const { return (&other == this); }
- bool operator!=(const NodeType& other) const { return (&other != this); }
+ const vespalib::string & toString() const noexcept { return _name; }
+ bool operator==(const NodeType& other) const noexcept { return (&other == this); }
+ bool operator!=(const NodeType& other) const noexcept { return (&other != this); }
- bool operator<(const NodeType& other) const {
+ bool operator<(const NodeType& other) const noexcept {
return (&other == this ? false : *this == NodeType::DISTRIBUTOR);
}
+private:
+ Type _type;
+ vespalib::string _name;
+
+ NodeType(vespalib::stringref name, Type type) noexcept;
};
std::ostream & operator << (std::ostream & os, const NodeType & n);
vespalib::asciistream & operator << (vespalib::asciistream & os, const NodeType & n);
-} // lib
-} // storage
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
index 724a3059f6d..ef38ca8c6ad 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
@@ -38,7 +38,9 @@ import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -85,7 +87,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
private final MutableX509KeyManager identityKeyManager = new MutableX509KeyManager();
private final SSLContext identitySslContext;
- private final LoadingCache<AthenzRole, SSLContext> roleSslContextCache;
+ private final LoadingCache<AthenzRole, X509Certificate> roleSslCertCache;
+ private final Map<AthenzRole, MutableX509KeyManager> roleKeyManagerCache;
private final LoadingCache<AthenzRole, ZToken> roleSpecificRoleTokenCache;
private final LoadingCache<AthenzDomain, ZToken> domainSpecificRoleTokenCache;
private final LoadingCache<AthenzDomain, AthenzAccessToken> domainSpecificAccessTokenCache;
@@ -119,7 +122,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
this.clock = clock;
this.identity = new AthenzService(config.domain(), config.service());
this.ztsEndpoint = URI.create(config.ztsUrl());
- roleSslContextCache = createCache(ROLE_SSL_CONTEXT_EXPIRY, this::createRoleSslContext);
+ roleSslCertCache = createCache(ROLE_SSL_CONTEXT_EXPIRY, this::requestRoleCertificate);
+ roleKeyManagerCache = new HashMap<>();
roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
@@ -194,9 +198,15 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public SSLContext getRoleSslContext(String domain, String role) {
- // This ssl context should ideally be cached as it is quite expensive to create.
try {
- return roleSslContextCache.get(new AthenzRole(new AthenzDomain(domain), role));
+ AthenzRole athenzRole = new AthenzRole(new AthenzDomain(domain), role);
+ // Make sure to request a certificate which triggers creating a new key manager for this role
+ X509Certificate x509Certificate = roleSslCertCache.get(athenzRole);
+ MutableX509KeyManager keyManager = roleKeyManagerCache.get(athenzRole);
+ return new SslContextBuilder()
+ .withKeyManager(keyManager)
+ .withTrustStore(trustStore)
+ .build();
} catch (Exception e) {
throw new AthenzIdentityProviderException("Could not retrieve role certificate: " + e.getMessage(), e);
}
@@ -265,17 +275,24 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
new char[0]);
}
- private SSLContext createRoleSslContext(AthenzRole role) {
+ private X509Certificate requestRoleCertificate(AthenzRole role) {
Pkcs10Csr csr = csrGenerator.generateRoleCsr(identity, role, credentials.getIdentityDocument().providerUniqueId(), credentials.getKeyPair());
try (ZtsClient client = createZtsClient()) {
X509Certificate roleCertificate = client.getRoleCertificate(role, csr);
- return new SslContextBuilder()
- .withKeyStore(credentials.getKeyPair().getPrivate(), roleCertificate)
- .withTrustStore(trustStore)
- .build();
+ updateRoleKeyManager(role, roleCertificate);
+ return roleCertificate;
}
}
+ private void updateRoleKeyManager(AthenzRole role, X509Certificate certificate) {
+ MutableX509KeyManager keyManager = roleKeyManagerCache.computeIfAbsent(role, r -> new MutableX509KeyManager());
+ keyManager.updateKeystore(
+ KeyStoreBuilder.withType(PKCS12)
+ .withKeyEntry("default", credentials.getKeyPair().getPrivate(), certificate)
+ .build(),
+ new char[0]);
+ }
+
private ZToken createRoleToken(AthenzRole athenzRole) {
try (ZtsClient client = createZtsClient()) {
return client.getRoleToken(athenzRole);
diff --git a/vespaclient/src/vespa/vespaclient/vdsstates/statesapp.cpp b/vespaclient/src/vespa/vespaclient/vdsstates/statesapp.cpp
index 9393562bf28..a468dd98698 100644
--- a/vespaclient/src/vespa/vespaclient/vdsstates/statesapp.cpp
+++ b/vespaclient/src/vespa/vespaclient/vdsstates/statesapp.cpp
@@ -1,8 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/defaults.h>
-#include <vespa/fnet/frt/frt.h>
#include <vespa/slobrok/sbmirror.h>
+#include <vespa/fnet/frt/supervisor.h>
+#include <vespa/fnet/frt/target.h>
+#include <vespa/fnet/frt/rpcrequest.h>
#include <vespa/vdslib/distribution/distribution.h>
#include <vespa/vdslib/state/clusterstate.h>
#include <vespa/vespalib/util/programoptions.h>
diff --git a/vespaclient/src/vespa/vespaclient/vesparoute/application.cpp b/vespaclient/src/vespa/vespaclient/vesparoute/application.cpp
index ae64db4d452..468c6b859ed 100644
--- a/vespaclient/src/vespa/vespaclient/vesparoute/application.cpp
+++ b/vespaclient/src/vespa/vespaclient/vesparoute/application.cpp
@@ -25,7 +25,6 @@ using document::DocumentTypeRepo;
namespace vesparoute {
Application::Application() :
- _loadTypes(),
_net(),
_mbus(),
_params()
@@ -54,7 +53,7 @@ Application::Main()
*_net,
mbus::MessageBusParams()
.setRetryPolicy(mbus::IRetryPolicy::SP())
- .addProtocol(std::make_shared<documentapi::DocumentProtocol>(_loadTypes, repo)));
+ .addProtocol(std::make_shared<documentapi::DocumentProtocol>(repo)));
mbus::ConfigAgent cfg(*_mbus);
cfg.configure(ConfigGetter<MessagebusConfig>::getConfig(_params.getRoutingConfigId()));
diff --git a/vespaclient/src/vespa/vespaclient/vesparoute/application.h b/vespaclient/src/vespa/vespaclient/vesparoute/application.h
index 697319befcc..89f025472f5 100644
--- a/vespaclient/src/vespa/vespaclient/vesparoute/application.h
+++ b/vespaclient/src/vespa/vespaclient/vesparoute/application.h
@@ -6,7 +6,6 @@
#include <vespa/messagebus/routing/hopblueprint.h>
#include "mynetwork.h"
#include "params.h"
-#include <vespa/documentapi/loadtypes/loadtypeset.h>
namespace vesparoute {
@@ -15,7 +14,6 @@ namespace vesparoute {
*/
class Application : public FastOS_Application {
private:
- documentapi::LoadTypeSet _loadTypes;
std::unique_ptr<MyNetwork> _net;
std::unique_ptr<mbus::MessageBus> _mbus;
Params _params;
diff --git a/vespajlib/pom.xml b/vespajlib/pom.xml
index 302a3c6f5bf..68639d30ab2 100644
--- a/vespajlib/pom.xml
+++ b/vespajlib/pom.xml
@@ -78,6 +78,11 @@
<artifactId>jackson-databind</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java b/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java
index 95fccd3fce8..9779aea0e4a 100644
--- a/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java
+++ b/vespajlib/src/main/java/com/yahoo/collections/TinyIdentitySet.java
@@ -18,7 +18,7 @@ import java.util.Set;
* in IdentityHashMap, where the key set is often used as an identity set.
* </p>
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
* @since 5.1.4
* @see java.util.IdentityHashMap
*
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/CompletableFutures.java b/vespajlib/src/main/java/com/yahoo/concurrent/CompletableFutures.java
new file mode 100644
index 00000000000..b1fa6a9438d
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/CompletableFutures.java
@@ -0,0 +1,67 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.concurrent;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Helper for {@link java.util.concurrent.CompletableFuture} / {@link java.util.concurrent.CompletionStage}.
+ *
+ * @author bjorncs
+ */
+public class CompletableFutures {
+
+ private CompletableFutures() {}
+
+ /**
+ * Returns a new completable future that is either
+ * - completed when any of the provided futures complete without exception
+ * - completed exceptionally once all provided futures complete exceptionally
+ */
+ public static <T> CompletableFuture<T> firstOf(List<CompletableFuture<T>> futures) {
+ class Combiner {
+ final Object monitor = new Object();
+ final CompletableFuture<T> combined = new CompletableFuture<>();
+ final int futuresCount;
+
+ Throwable error = null;
+ int exceptionCount = 0;
+
+ Combiner(int futuresCount) { this.futuresCount = futuresCount; }
+
+ void onCompletion(T value, Throwable error) {
+ if (combined.isDone()) return;
+ T valueToComplete = null;
+ Throwable exceptionToComplete = null;
+
+ synchronized (monitor) {
+ if (value != null) {
+ valueToComplete = value;
+ } else {
+ if (this.error == null) {
+ this.error = error;
+ } else {
+ this.error.addSuppressed(error);
+ }
+ if (++exceptionCount == futuresCount) {
+ exceptionToComplete = this.error;
+ }
+ }
+ }
+ if (valueToComplete != null) {
+ combined.complete(value);
+ } else if (exceptionToComplete != null) {
+ combined.completeExceptionally(exceptionToComplete);
+ }
+ }
+ }
+
+ int size = futures.size();
+ if (size == 0) throw new IllegalArgumentException();
+ if (size == 1) return futures.get(0);
+ Combiner combiner = new Combiner(size);
+ futures.forEach(future -> future.whenComplete(combiner::onCompletion));
+ return combiner.combined;
+ }
+
+}
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/LocalInstance.java b/vespajlib/src/main/java/com/yahoo/concurrent/LocalInstance.java
index 1e929f3ee36..1f886c6f34a 100644
--- a/vespajlib/src/main/java/com/yahoo/concurrent/LocalInstance.java
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/LocalInstance.java
@@ -10,12 +10,12 @@ import com.yahoo.concurrent.ThreadLocalDirectory.Updater;
* {@link ThreadLocal} in ThreadLocalDirectory if possible, but has no user
* available methods.
*
- * @param AGGREGATOR
+ * @param <AGGREGATOR>
* the structure to insert produced data into
- * @param SAMPLE
+ * @param <SAMPLE>
* type of produced data to insert from each participating thread
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
*/
public final class LocalInstance<AGGREGATOR, SAMPLE> {
/**
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/ThreadLocalDirectory.java b/vespajlib/src/main/java/com/yahoo/concurrent/ThreadLocalDirectory.java
index 5ab1c88775a..016ad167e98 100644
--- a/vespajlib/src/main/java/com/yahoo/concurrent/ThreadLocalDirectory.java
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/ThreadLocalDirectory.java
@@ -95,7 +95,7 @@ public final class ThreadLocalDirectory<AGGREGATOR, SAMPLE> {
* This might be an empty list, creating a new counter set to zero, or
* even copying the current state of LocalInstance.current.
* LocalInstance.current will be set to the value received from this
- * factory after invokation this method.
+ * factory after invocation this method.
*
* <p>
* The first time this method is invoked for a thread, previous will be
@@ -223,7 +223,7 @@ public final class ThreadLocalDirectory<AGGREGATOR, SAMPLE> {
// Has to set registered before adding to the list. Otherwise, the
// instance might be removed from the list, set as unregistered, and
// then the local thread might happily remove that information. The Java
- // memory model is a guarantuee for the minimum amount of visibility,
+ // memory model is a guarantee for the minimum amount of visibility,
// not a definition of the actual amount.
q.setRegistered(true);
synchronized (directoryLock) {
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/JobMetrics.java b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/JobMetrics.java
index a43e2156025..483057a828d 100644
--- a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/JobMetrics.java
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/JobMetrics.java
@@ -22,7 +22,7 @@ public class JobMetrics {
/** Record a run for given job */
public void recordRunOf(String job) {
- incompleteRuns.compute(job, (ignored, run) -> run == null ? 1 : ++run);
+ incompleteRuns.merge(job, 1L, Long::sum);
}
/** Record successful run of given job */
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
index 2c123779a1e..2690edc9407 100644
--- a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
@@ -11,6 +11,7 @@ import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -21,7 +22,7 @@ import java.util.logging.Logger;
* @author mpolden
* @author jonmv
*/
-public abstract class Maintainer implements Runnable, AutoCloseable {
+public abstract class Maintainer implements Runnable {
protected final Logger log = Logger.getLogger(this.getClass().getName());
@@ -30,6 +31,7 @@ public abstract class Maintainer implements Runnable, AutoCloseable {
private final JobMetrics jobMetrics;
private final Duration interval;
private final ScheduledExecutorService service;
+ private AtomicBoolean shutDown = new AtomicBoolean();
public Maintainer(String name, Duration interval, Instant startedAt, JobControl jobControl, JobMetrics jobMetrics, List<String> clusterHostnames) {
this(name, interval, staggeredDelay(interval, startedAt, HostName.getLocalhost(), clusterHostnames), jobControl, jobMetrics);
@@ -60,10 +62,16 @@ public abstract class Maintainer implements Runnable, AutoCloseable {
log.log(Level.FINE, () -> "Finished " + this.getClass().getSimpleName());
}
- @Override
- public void close() {
+ /** Starts shutdown of this, typically by shutting down executors. {@link #awaitShutdown()} waits for shutdown to complete. */
+ public void shutdown() {
+ if ( ! shutDown.getAndSet(true))
+ service.shutdown();
+ }
+
+ /** Waits for shutdown to complete, calling {@link #shutdown} if this hasn't been done already. */
+ public void awaitShutdown() {
+ shutdown();
var timeout = Duration.ofSeconds(30);
- service.shutdown();
try {
if (!service.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS)) {
log.log(Level.WARNING, "Maintainer " + name() + " failed to shutdown " +
diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/CompletableFuturesTest.java b/vespajlib/src/test/java/com/yahoo/concurrent/CompletableFuturesTest.java
new file mode 100644
index 00000000000..cf9c36537d9
--- /dev/null
+++ b/vespajlib/src/test/java/com/yahoo/concurrent/CompletableFuturesTest.java
@@ -0,0 +1,66 @@
+package com.yahoo.concurrent;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author bjorncs
+ */
+class CompletableFuturesTest {
+
+ @Test
+ public void firstof_completes_when_first_futures_has_completed() {
+ CompletableFuture<String> f1 = new CompletableFuture<>();
+ CompletableFuture<String> f2 = new CompletableFuture<>();
+ CompletableFuture<String> f3 = new CompletableFuture<>();
+ CompletableFuture<String> result = CompletableFutures.firstOf(List.of(f1, f2, f3));
+ f1.complete("success");
+ assertTrue(result.isDone());
+ assertFalse(result.isCompletedExceptionally());
+ assertEquals("success", result.join());
+ }
+
+ @Test
+ public void firstof_completes_if_any_futures_completes() {
+ CompletableFuture<String> f1 = new CompletableFuture<>();
+ CompletableFuture<String> f2 = new CompletableFuture<>();
+ CompletableFuture<String> f3 = new CompletableFuture<>();
+ CompletableFuture<String> result = CompletableFutures.firstOf(List.of(f1, f2, f3));
+ f1.completeExceptionally(new Throwable("t1"));
+ f2.completeExceptionally(new Throwable("t2"));
+ f3.complete("success");
+ assertTrue(result.isDone());
+ assertFalse(result.isCompletedExceptionally());
+ assertEquals("success", result.join());
+ }
+
+ @Test
+ public void firstof_completes_exceptionally_when_all_futures_have_complete_exceptionally() {
+ CompletableFuture<String> f1 = new CompletableFuture<>();
+ CompletableFuture<String> f2 = new CompletableFuture<>();
+ CompletableFuture<String> f3 = new CompletableFuture<>();
+ CompletableFuture<String> result = CompletableFutures.firstOf(List.of(f1, f2, f3));
+ f1.completeExceptionally(new Throwable("t1"));
+ f2.completeExceptionally(new Throwable("t2"));
+ f3.completeExceptionally(new Throwable("t3"));
+ assertTrue(result.isDone());
+ assertTrue(result.isCompletedExceptionally());
+ try {
+ result.join();
+ fail("Exception expected");
+ } catch (CompletionException e) {
+ Throwable cause = e.getCause();
+ assertEquals("t1", cause.getMessage());
+ assertEquals(2, cause.getSuppressed().length);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt
index dbcf2beadd8..a5e6b24abb2 100644
--- a/vespalib/CMakeLists.txt
+++ b/vespalib/CMakeLists.txt
@@ -94,6 +94,7 @@ vespa_define_module(
src/tests/rendezvous
src/tests/runnable_pair
src/tests/sha1
+ src/tests/shared_string_repo
src/tests/sharedptr
src/tests/signalhandler
src/tests/simple_thread_bundle
diff --git a/vespalib/src/tests/array/array_test.cpp b/vespalib/src/tests/array/array_test.cpp
index c0189ad8ad6..a5dfd1472a6 100644
--- a/vespalib/src/tests/array/array_test.cpp
+++ b/vespalib/src/tests/array/array_test.cpp
@@ -4,6 +4,7 @@
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/testkit/testapp.h>
#include <deque>
+#include <atomic>
using namespace vespalib;
@@ -28,7 +29,7 @@ std::ostream & operator << (std::ostream & os, const Array<T> & a)
class Clever {
public:
Clever() : _counter(&_global) { (*_counter)++; }
- Clever(volatile size_t * counter) :
+ Clever(std::atomic<size_t> * counter) :
_counter(counter)
{
(*_counter)++;
@@ -54,8 +55,8 @@ public:
static size_t getGlobal() { return _global; }
bool operator == (const Clever & b) const { return _counter == b._counter; }
private:
- volatile size_t * _counter;
- static size_t _global;
+ std::atomic<size_t> * _counter;
+ static std::atomic<size_t> _global;
};
std::ostream & operator << (std::ostream & os, const Clever & clever)
@@ -114,7 +115,7 @@ TEST("test basic array functionality")
testArray(a, b);
EXPECT_TRUE(a == a);
EXPECT_FALSE(a == b);
- size_t counter(0);
+ std::atomic<size_t> counter(0);
testArray(Clever(&counter), Clever(&counter));
EXPECT_EQUAL(0ul, counter);
}
@@ -155,11 +156,11 @@ TEST("test that organic growth is by 2 in N and reserve resize are exact")
EXPECT_EQUAL(2048u, c.capacity());
}
-size_t Clever::_global = 0;
+std::atomic<size_t> Clever::_global = 0;
TEST("test complicated")
{
- volatile size_t counter(0);
+ std::atomic<size_t> counter(0);
{
EXPECT_EQUAL(0ul, Clever::getGlobal());
Clever c(&counter);
diff --git a/vespalib/src/tests/net/selector/selector_test.cpp b/vespalib/src/tests/net/selector/selector_test.cpp
index 7d7a147bcb2..5c91dfdc122 100644
--- a/vespalib/src/tests/net/selector/selector_test.cpp
+++ b/vespalib/src/tests/net/selector/selector_test.cpp
@@ -77,7 +77,12 @@ struct Fixture {
}
Fixture &poll(int timeout_ms = 60000) {
selector.poll(timeout_ms);
- selector.dispatch(*this);
+ auto dispatchResult = selector.dispatch(*this);
+ if (wakeup) {
+ EXPECT_TRUE(dispatchResult == SelectorDispatchResult::WAKEUP_CALLED);
+ } else {
+ EXPECT_TRUE(dispatchResult == SelectorDispatchResult::NO_WAKEUP);
+ }
return *this;
}
void verify(bool expect_wakeup, std::vector<std::pair<bool,bool> > expect_events) {
diff --git a/vespalib/src/tests/shared_string_repo/CMakeLists.txt b/vespalib/src/tests/shared_string_repo/CMakeLists.txt
new file mode 100644
index 00000000000..3911deb9e91
--- /dev/null
+++ b/vespalib/src/tests/shared_string_repo/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_shared_string_repo_test_app TEST
+ SOURCES
+ shared_string_repo_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_shared_string_repo_test_app COMMAND vespalib_shared_string_repo_test_app)
diff --git a/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp b/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp
new file mode 100644
index 00000000000..e8f39c88afe
--- /dev/null
+++ b/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp
@@ -0,0 +1,285 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/util/shared_string_repo.h>
+#include <vespa/vespalib/util/rendezvous.h>
+#include <vespa/vespalib/util/time.h>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vector>
+#include <map>
+#include <xxhash.h>
+
+using namespace vespalib;
+using make_string_short::fmt;
+using Handle = SharedStringRepo::Handle;
+
+bool verbose = false;
+double budget = 0.10;
+size_t work_size = 4096;
+
+//-----------------------------------------------------------------------------
+
+std::vector<vespalib::string> make_strings(size_t cnt) {
+ std::vector<vespalib::string> strings;
+ strings.reserve(cnt);
+ for (size_t i = 0; i < cnt; ++i) {
+ strings.push_back(fmt("str_%zu", i));
+ }
+ return strings;
+}
+
+std::vector<vespalib::string> copy_strings(const std::vector<vespalib::string> &strings) {
+ std::vector<vespalib::string> result;
+ result.reserve(strings.size());
+ for (const auto &str: strings) {
+ result.push_back(str);
+ }
+ return result;
+}
+
+std::vector<std::pair<vespalib::string, uint64_t>> copy_and_hash(const std::vector<vespalib::string> &strings) {
+ std::vector<std::pair<vespalib::string, uint64_t>> result;
+ result.reserve(strings.size());
+ for (const auto &str: strings) {
+ result.emplace_back(str, XXH3_64bits(str.data(), str.size()));
+ }
+ return result;
+}
+
+std::vector<uint32_t> local_enum(const std::vector<vespalib::string> &strings) {
+ hash_map<vespalib::string, uint32_t> map(strings.size() * 2);
+ std::vector<uint32_t> result;
+ result.reserve(strings.size());
+ for (const auto &str: strings) {
+ result.push_back(map.insert(std::make_pair(str, map.size())).first->second);
+ }
+ return result;
+}
+
+std::vector<Handle> resolve_strings(const std::vector<vespalib::string> &strings) {
+ std::vector<Handle> handles;
+ handles.reserve(strings.size());
+ for (size_t i = 0; i < strings.size(); ++i) {
+ handles.emplace_back(strings[i]);
+ }
+ return handles;
+}
+
+std::vector<vespalib::string> get_strings(const std::vector<Handle> &handles) {
+ std::vector<vespalib::string> strings;
+ strings.reserve(handles.size());
+ for (size_t i = 0; i < handles.size(); ++i) {
+ strings.push_back(handles[i].as_string());
+ }
+ return strings;
+}
+
+std::unique_ptr<SharedStringRepo::StrongHandles> make_strong_handles(const std::vector<vespalib::string> &strings) {
+ auto result = std::make_unique<SharedStringRepo::StrongHandles>(strings.size());
+ for (const auto &str: strings) {
+ result->add(str);
+ }
+ return result;
+}
+
+std::unique_ptr<SharedStringRepo::WeakHandles> make_weak_handles(const SharedStringRepo::HandleView &view) {
+ auto result = std::make_unique<SharedStringRepo::WeakHandles>(view.handles().size());
+ for (uint32_t handle: view.handles()) {
+ result->add(handle);
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+struct Avg : Rendezvous<double, double> {
+ Avg(size_t n) : Rendezvous<double, double>(n) {}
+ void mingle() override {
+ double sum = 0;
+ for (size_t i = 0; i < size(); ++i) {
+ sum += in(i);
+ }
+ double result = sum / size();
+ for (size_t i = 0; i < size(); ++i) {
+ out(i) = result;
+ }
+ }
+ double operator()(double value) { return rendezvous(value); }
+};
+
+struct Vote : Rendezvous<bool, bool> {
+ Vote(size_t n) : Rendezvous<bool, bool>(n) {}
+ void mingle() override {
+ size_t true_cnt = 0;
+ size_t false_cnt = 0;
+ for (size_t i = 0; i < size(); ++i) {
+ if (in(i)) {
+ ++true_cnt;
+ } else {
+ ++false_cnt;
+ }
+ }
+ bool result = (true_cnt > false_cnt);
+ for (size_t i = 0; i < size(); ++i) {
+ out(i) = result;
+ }
+ }
+ size_t num_threads() const { return size(); }
+ bool operator()(bool flag) { return rendezvous(flag); }
+};
+
+//-----------------------------------------------------------------------------
+
+template <typename T>
+void verify_equal(const std::vector<T> &a, const std::vector<T> &b) {
+ ASSERT_EQUAL(a.size(), b.size());
+ for (size_t i = 0; i < a.size(); ++i) {
+ EXPECT_TRUE(a[i] == b[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+struct Fixture {
+ Avg avg;
+ Vote vote;
+ std::vector<vespalib::string> work;
+ steady_time start_time;
+ std::map<vespalib::string,double> time_ms;
+ Fixture(size_t num_threads)
+ : avg(num_threads), vote(num_threads), work(make_strings(work_size)), start_time(steady_clock::now()) {}
+ ~Fixture() {
+ if (verbose) {
+ fprintf(stderr, "benchmark results for %zu threads:\n", vote.num_threads());
+ for (const auto &[tag, ms_cost]: time_ms) {
+ fprintf(stderr, " %s: %g ms\n", tag.c_str(), ms_cost);
+ }
+ }
+ }
+ bool has_budget() {
+ return to_s(steady_clock::now() - start_time) < budget;
+ }
+ template <typename F>
+ void measure_task(const vespalib::string &tag, bool is_master, F &&task) {
+ auto before = steady_clock::now();
+ task();
+ double ms_cost = to_s(steady_clock::now() - before) * 1000.0;
+ double avg_ms = avg(ms_cost);
+ if (is_master) {
+ if (time_ms.count(tag) > 0) {
+ time_ms[tag] = std::min(time_ms[tag], avg_ms);
+ } else {
+ time_ms[tag] = avg_ms;
+ }
+ }
+ }
+ void benchmark(bool is_master) {
+ for (bool once_more = true; vote(once_more); once_more = has_budget()) {
+ std::vector<vespalib::string> copy_strings_result;
+ std::vector<std::pair<vespalib::string,uint64_t>> copy_and_hash_result;
+ std::vector<uint32_t> local_enum_result;
+ std::vector<Handle> resolve_result;
+ std::vector<Handle> copy_handles_result;
+ std::vector<Handle> resolve_again_result;
+ std::vector<vespalib::string> get_result;
+ std::unique_ptr<SharedStringRepo::StrongHandles> strong;
+ std::unique_ptr<SharedStringRepo::WeakHandles> weak;
+ auto copy_strings_task = [&](){ copy_strings_result = copy_strings(work); };
+ auto copy_and_hash_task = [&](){ copy_and_hash_result = copy_and_hash(work); };
+ auto local_enum_task = [&](){ local_enum_result = local_enum(work); };
+ auto resolve_task = [&](){ resolve_result = resolve_strings(work); };
+ auto copy_handles_task = [&](){ copy_handles_result = resolve_result; };
+ auto resolve_again_task = [&](){ resolve_again_result = resolve_strings(work); };
+ auto get_task = [&](){ get_result = get_strings(resolve_result); };
+ auto reclaim_task = [&]() { resolve_again_result.clear(); };
+ auto reclaim_last_task = [&]() { resolve_result.clear(); };
+ auto make_strong_task = [&]() { strong = make_strong_handles(work); };
+ auto make_weak_task = [&]() { weak = make_weak_handles(strong->view()); };
+ auto free_weak_task = [&]() { weak.reset(); };
+ auto free_strong_task = [&]() { strong.reset(); };
+ measure_task("[01] copy strings", is_master, copy_strings_task);
+ measure_task("[02] copy and hash", is_master, copy_and_hash_task);
+ measure_task("[03] local enum", is_master, local_enum_task);
+ measure_task("[04] resolve", is_master, resolve_task);
+ measure_task("[05] copy handles", is_master, copy_handles_task);
+ measure_task("[06] resolve again", is_master, resolve_again_task);
+ verify_equal(resolve_result, resolve_again_result);
+ measure_task("[07] as_string", is_master, get_task);
+ verify_equal(get_result, work);
+ measure_task("[08] reclaim", is_master, reclaim_task);
+ copy_handles_result.clear();
+ measure_task("[09] reclaim last", is_master, reclaim_last_task);
+ measure_task("[10] make strong handles", is_master, make_strong_task);
+ measure_task("[11] make weak handles", is_master, make_weak_task);
+ measure_task("[12] free weak handles", is_master, free_weak_task);
+ measure_task("[13] free strong handles", is_master, free_strong_task);
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+TEST("require that basic usage works") {
+ Handle empty;
+ Handle foo("foo");
+ Handle bar("bar");
+ Handle empty2;
+ Handle foo2("foo");
+ Handle bar2(bar);
+ EXPECT_EQUAL(empty.id(), 0u);
+ EXPECT_TRUE(empty.id() != foo.id());
+ EXPECT_TRUE(empty.id() != bar.id());
+ EXPECT_TRUE(foo.id() != bar.id());
+ EXPECT_EQUAL(empty.id(), empty2.id());
+ EXPECT_EQUAL(foo.id(), foo2.id());
+ EXPECT_EQUAL(bar.id(), bar2.id());
+ EXPECT_EQUAL(empty.as_string(), vespalib::string(""));
+ EXPECT_EQUAL(foo.as_string(), vespalib::string("foo"));
+ EXPECT_EQUAL(bar.as_string(), vespalib::string("bar"));
+ EXPECT_EQUAL(foo2.as_string(), vespalib::string("foo"));
+ EXPECT_EQUAL(bar2.as_string(), vespalib::string("bar"));
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_MT_F("test shared string repo operations with 1 threads", 1, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 2 threads", 2, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 4 threads", 4, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 8 threads", 8, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 16 threads", 16, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 32 threads", 32, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+TEST_MT_F("test shared string repo operations with 64 threads", 64, Fixture(num_threads)) {
+ f1.benchmark(thread_id == 0);
+}
+
+//-----------------------------------------------------------------------------
+
+int main(int argc, char **argv) {
+ TEST_MASTER.init(__FILE__);
+ if ((argc == 2) && (argv[1] == std::string("verbose"))) {
+ verbose = true;
+ budget = 30.0;
+ work_size = 128000;
+ }
+ TEST_RUN_ALL();
+ return (TEST_MASTER.fini() ? 0 : 1);
+}
diff --git a/vespalib/src/tests/stllike/hash_test.cpp b/vespalib/src/tests/stllike/hash_test.cpp
index 8c017ef69b4..561c7b34035 100644
--- a/vespalib/src/tests/stllike/hash_test.cpp
+++ b/vespalib/src/tests/stllike/hash_test.cpp
@@ -7,6 +7,7 @@
#include <vespa/vespalib/stllike/allocator.h>
#include <cstddef>
#include <algorithm>
+#include <atomic>
using namespace vespalib;
using std::make_pair;
@@ -172,7 +173,7 @@ TEST("test hash map iterator stability")
class Clever {
public:
Clever() : _counter(&_global) { (*_counter)++; }
- Clever(volatile size_t * counter) :
+ Clever(std::atomic<size_t> * counter) :
_counter(counter)
{
(*_counter)++;
@@ -197,15 +198,15 @@ public:
~Clever() { (*_counter)--; }
static size_t getGlobal() { return _global; }
private:
- volatile size_t * _counter;
- static size_t _global;
+ std::atomic<size_t> * _counter;
+ static std::atomic<size_t> _global;
};
-size_t Clever::_global = 0;
+std::atomic<size_t> Clever::_global = 0;
TEST("test hash map resizing")
{
- volatile size_t counter(0);
+ std::atomic<size_t> counter(0);
{
EXPECT_EQUAL(0ul, Clever::getGlobal());
Clever c(&counter);
diff --git a/vespalib/src/tests/stllike/hashtable_test.cpp b/vespalib/src/tests/stllike/hashtable_test.cpp
index 877a5dddcb5..cbd8b28d9a8 100644
--- a/vespalib/src/tests/stllike/hashtable_test.cpp
+++ b/vespalib/src/tests/stllike/hashtable_test.cpp
@@ -7,6 +7,7 @@
#include <vespa/vespalib/testkit/testapp.h>
#include <memory>
#include <vector>
+#include <vespa/vespalib/stllike/hash_map.h>
using vespalib::hashtable;
using std::vector;
@@ -38,17 +39,12 @@ TEST("require that hashtable can store unique_ptrs") {
// it = table.find(42); // This will crash, since the key is removed.
}
-template<typename To, typename Entry>
-struct First : std::unary_function<To, Entry> {
- To &operator()(Entry& p) const { return p.first; }
- const To& operator()(const Entry& p) const { return p.first; }
-};
template <typename K, typename V> using Entry =
std::pair<K, std::unique_ptr<V>>;
typedef hashtable<int, Entry<int, int>,
vespalib::hash<int>, std::equal_to<int>,
- First<int, Entry<int, int>>> PairHashtable;
+ Select1st<Entry<int, int>>> PairHashtable;
TEST("require that hashtable can store pairs of <key, unique_ptr to value>") {
PairHashtable table(100);
@@ -73,6 +69,55 @@ TEST("require that hashtable<int> can be copied") {
EXPECT_EQUAL(42, *table2.find(42));
}
+TEST("require that you can insert duplicates") {
+ using Pair = std::pair<int, vespalib::string>;
+ using Map = hashtable<int, Pair, vespalib::hash<int>, std::equal_to<int>, Select1st<Pair>>;
+
+ Map m(1);
+ EXPECT_EQUAL(0u, m.size());
+ EXPECT_EQUAL(8u, m.capacity());
+ auto res = m.insert(Pair(1, "1"));
+ EXPECT_TRUE(res.second);
+ EXPECT_EQUAL(1u, m.size());
+ EXPECT_EQUAL(8u, m.capacity());
+ res = m.insert(Pair(1, "1.2"));
+ EXPECT_FALSE(res.second);
+ auto found = m.find(1);
+ ASSERT_TRUE(found != m.end());
+ EXPECT_EQUAL(found->second, "1");
+
+ m.force_insert(Pair(1, "1.2"));
+ EXPECT_EQUAL(2u, m.size());
+ EXPECT_EQUAL(8u, m.capacity());
+ m.force_insert(Pair(1, "1.3"));
+ EXPECT_EQUAL(3u, m.size());
+ EXPECT_EQUAL(16u, m.capacity()); // Resize has been conducted
+ Pair expected[3] = {{1,"1"},{1,"1.2"},{1,"1.3"}};
+ size_t index(0);
+ for (const auto & e : m) {
+ EXPECT_EQUAL(expected[index].first, e.first);
+ EXPECT_EQUAL(expected[index].second, e.second);
+ index++;
+ }
+ found = m.find(1);
+ ASSERT_TRUE(found != m.end());
+ EXPECT_EQUAL(found->second, "1");
+
+ m.erase(1);
+ EXPECT_EQUAL(2u, m.size());
+ EXPECT_EQUAL(16u, m.capacity());
+ found = m.find(1);
+ ASSERT_TRUE(found != m.end());
+ EXPECT_EQUAL(found->second, "1.3");
+
+ m.erase(1);
+ EXPECT_EQUAL(1u, m.size());
+ EXPECT_EQUAL(16u, m.capacity());
+ found = m.find(1);
+ ASSERT_TRUE(found != m.end());
+ EXPECT_EQUAL(found->second, "1.2");
+}
+
template<typename To, typename Vector>
struct FirstInVector : std::unary_function<To, Vector> {
To &operator()(Vector& v) const { return v[0]; }
diff --git a/vespalib/src/vespa/vespalib/crypto/CMakeLists.txt b/vespalib/src/vespa/vespalib/crypto/CMakeLists.txt
index 6000156fcfa..299e3402e23 100644
--- a/vespalib/src/vespa/vespalib/crypto/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/crypto/CMakeLists.txt
@@ -4,6 +4,7 @@ vespa_add_library(vespalib_vespalib_crypto OBJECT
crypto_exception.cpp
openssl_crypto_impl.cpp
private_key.cpp
+ random.cpp
x509_certificate.cpp
DEPENDS
)
diff --git a/vespalib/src/vespa/vespalib/crypto/random.cpp b/vespalib/src/vespa/vespalib/crypto/random.cpp
new file mode 100644
index 00000000000..49200706839
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/crypto/random.cpp
@@ -0,0 +1,13 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "random.h"
+#include <openssl/rand.h>
+
+namespace vespalib::crypto {
+
+void random_buffer(unsigned char* buf, size_t len) noexcept {
+ if (::RAND_bytes(buf, len) != 1) {
+ abort();
+ }
+}
+
+}
diff --git a/vespalib/src/vespa/vespalib/crypto/random.h b/vespalib/src/vespa/vespalib/crypto/random.h
new file mode 100644
index 00000000000..a97f8df2bc2
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/crypto/random.h
@@ -0,0 +1,11 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+#include <cstddef>
+
+namespace vespalib::crypto {
+
+// Fills `buf` with `len` bytes of cryptographically secure pseudo-random data.
+// Aborts the process if CSPRNG somehow fails.
+void random_buffer(unsigned char* buf, size_t len) noexcept;
+
+}
diff --git a/vespalib/src/vespa/vespalib/data/slime/symbol.h b/vespalib/src/vespa/vespalib/data/slime/symbol.h
index 20cf6a26d66..93dd0d9b69a 100644
--- a/vespalib/src/vespa/vespalib/data/slime/symbol.h
+++ b/vespalib/src/vespa/vespalib/data/slime/symbol.h
@@ -22,8 +22,8 @@ public:
Symbol(uint32_t v) : _value(v) {}
bool undefined() const { return (_value == UNDEFINED); }
uint32_t getValue() const { return _value; }
- bool operator<(const Symbol &rhs) const { return (_value < rhs._value); }
- bool operator==(const Symbol &rhs) const { return (_value == rhs._value); }
+ bool operator<(const Symbol &rhs) const noexcept { return (_value < rhs._value); }
+ bool operator==(const Symbol &rhs) const noexcept { return (_value == rhs._value); }
};
} // namespace vespalib::slime
diff --git a/vespalib/src/vespa/vespalib/net/async_resolver.cpp b/vespalib/src/vespa/vespalib/net/async_resolver.cpp
index bc918434077..c9ff9588fba 100644
--- a/vespalib/src/vespa/vespalib/net/async_resolver.cpp
+++ b/vespalib/src/vespa/vespalib/net/async_resolver.cpp
@@ -2,6 +2,7 @@
#include "async_resolver.h"
#include "socket_spec.h"
+#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/log/log.h>
LOG_SETUP(".vespalib.net.async_resolver");
@@ -100,7 +101,7 @@ AsyncResolver::CachingHostResolver::store(const vespalib::string &host_name, con
assert(_map.size() == _queue.size());
}
-AsyncResolver::CachingHostResolver::CachingHostResolver(Clock::SP clock, HostResolver::SP resolver, size_t max_cache_size, seconds max_result_age)
+AsyncResolver::CachingHostResolver::CachingHostResolver(Clock::SP clock, HostResolver::SP resolver, size_t max_cache_size, seconds max_result_age) noexcept
: _clock(std::move(clock)),
_resolver(std::move(resolver)),
_max_cache_size(max_cache_size),
@@ -149,15 +150,20 @@ AsyncResolver::SP AsyncResolver::_shared_resolver(nullptr);
AsyncResolver::AsyncResolver(HostResolver::SP resolver, size_t num_threads)
: _resolver(std::move(resolver)),
- _executor(num_threads, 128*1024, async_resolver_executor_thread)
+ _executor(std::make_unique<ThreadStackExecutor>(num_threads, 128*1024, async_resolver_executor_thread))
{
}
void
+AsyncResolver::wait_for_pending_resolves() {
+ _executor->sync();
+}
+
+void
AsyncResolver::resolve_async(const vespalib::string &spec, ResultHandler::WP result_handler)
{
auto task = std::make_unique<ResolveTask>(spec, *_resolver, std::move(result_handler));
- auto rejected = _executor.execute(std::move(task));
+ auto rejected = _executor->execute(std::move(task));
assert(!rejected);
}
diff --git a/vespalib/src/vespa/vespalib/net/async_resolver.h b/vespalib/src/vespa/vespalib/net/async_resolver.h
index 590e6672922..3ead0802234 100644
--- a/vespalib/src/vespa/vespalib/net/async_resolver.h
+++ b/vespalib/src/vespa/vespalib/net/async_resolver.h
@@ -4,7 +4,7 @@
#include "socket_address.h"
#include "socket_spec.h"
-#include <vespa/vespalib/util/threadstackexecutor.h>
+#include <vespa/vespalib/util/threadexecutor.h>
#include <vespa/vespalib/util/arrayqueue.hpp>
#include <chrono>
#include <memory>
@@ -104,7 +104,7 @@ private:
void store(const vespalib::string &host_name, const vespalib::string &ip_address);
public:
- CachingHostResolver(Clock::SP clock, HostResolver::SP resolver, size_t max_cache_size, seconds max_result_age);
+ CachingHostResolver(Clock::SP clock, HostResolver::SP resolver, size_t max_cache_size, seconds max_result_age) noexcept;
vespalib::string ip_address(const vespalib::string &host_name) override;
};
@@ -117,15 +117,15 @@ private:
void run() override;
};
- HostResolver::SP _resolver;
- ThreadStackExecutor _executor;
- static std::mutex _shared_lock;
- static AsyncResolver::SP _shared_resolver;
+ HostResolver::SP _resolver;
+ std::unique_ptr<SyncableThreadExecutor> _executor;
+ static std::mutex _shared_lock;
+ static AsyncResolver::SP _shared_resolver;
AsyncResolver(HostResolver::SP resolver, size_t num_threads);
public:
void resolve_async(const vespalib::string &spec, ResultHandler::WP result_handler);
- void wait_for_pending_resolves() { _executor.sync(); }
+ void wait_for_pending_resolves();
static AsyncResolver::SP create(Params params);
static AsyncResolver::SP get_shared();
};
diff --git a/vespalib/src/vespa/vespalib/net/selector.h b/vespalib/src/vespa/vespalib/net/selector.h
index 6b1967ddcd9..24b3abc806e 100644
--- a/vespalib/src/vespa/vespalib/net/selector.h
+++ b/vespalib/src/vespa/vespalib/net/selector.h
@@ -31,6 +31,7 @@ public:
};
//-----------------------------------------------------------------------------
+enum class SelectorDispatchResult {WAKEUP_CALLED, NO_WAKEUP};
template <typename Context>
class Selector
@@ -55,11 +56,13 @@ public:
void poll(int timeout_ms) { _events.extract(_epoll, timeout_ms); }
size_t num_events() const { return _events.size(); }
template <typename Handler>
- void dispatch(Handler &handler) {
+ SelectorDispatchResult dispatch(Handler &handler) {
+ SelectorDispatchResult result = SelectorDispatchResult::NO_WAKEUP;
for (const auto &evt: _events) {
if (evt.data.ptr == nullptr) {
_wakeup_pipe.read_tokens();
handler.handle_wakeup();
+ result = SelectorDispatchResult::WAKEUP_CALLED;
} else {
Context &ctx = *((Context *)(evt.data.ptr));
bool read = ((evt.events & (EPOLLIN | EPOLLERR | EPOLLHUP)) != 0);
@@ -67,6 +70,7 @@ public:
handler.handle_event(ctx, read, write);
}
}
+ return result;
}
};
diff --git a/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.cpp b/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.cpp
index 0a06a36c074..94b1f82bb22 100644
--- a/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.cpp
+++ b/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.cpp
@@ -57,14 +57,14 @@ bool matches_all_policy_requirements(const PeerCredentials& peer_creds, const Pe
class PolicyConfiguredCertificateVerifier : public CertificateVerificationCallback {
AuthorizedPeers _authorized_peers;
public:
- explicit PolicyConfiguredCertificateVerifier(AuthorizedPeers authorized_peers);
+ explicit PolicyConfiguredCertificateVerifier(AuthorizedPeers authorized_peers) noexcept;
~PolicyConfiguredCertificateVerifier() override;
bool verify(const PeerCredentials& peer_creds) const override;
};
-PolicyConfiguredCertificateVerifier::PolicyConfiguredCertificateVerifier(AuthorizedPeers authorized_peers)
+PolicyConfiguredCertificateVerifier::PolicyConfiguredCertificateVerifier(AuthorizedPeers authorized_peers) noexcept
: _authorized_peers(std::move(authorized_peers)) {}
PolicyConfiguredCertificateVerifier::~PolicyConfiguredCertificateVerifier() = default;
diff --git a/vespalib/src/vespa/vespalib/stllike/hash_map.h b/vespalib/src/vespa/vespalib/stllike/hash_map.h
index 29a5ef01a9f..6a8fcf29d42 100644
--- a/vespalib/src/vespa/vespalib/stllike/hash_map.h
+++ b/vespalib/src/vespa/vespalib/stllike/hash_map.h
@@ -26,7 +26,8 @@ public:
hash_map & operator = (hash_map &&) noexcept = default;
hash_map(const hash_map &) = default;
hash_map & operator = (const hash_map &) = default;
- hash_map(size_t reserveSize=0);
+ hash_map();
+ explicit hash_map(size_t reserveSize);
hash_map(size_t reserveSize, H hasher, EQ equality);
hash_map(std::initializer_list<value_type> input);
~hash_map() noexcept;
diff --git a/vespalib/src/vespa/vespalib/stllike/hash_map.hpp b/vespalib/src/vespa/vespalib/stllike/hash_map.hpp
index 61789f6e2be..900d6ff238d 100644
--- a/vespalib/src/vespa/vespalib/stllike/hash_map.hpp
+++ b/vespalib/src/vespa/vespalib/stllike/hash_map.hpp
@@ -8,8 +8,13 @@
namespace vespalib {
template <typename K, typename V, typename H, typename EQ, typename M>
+hash_map<K, V, H, EQ, M>::hash_map() :
+ _ht(0)
+{ }
+
+template <typename K, typename V, typename H, typename EQ, typename M>
hash_map<K, V, H, EQ, M>::hash_map(size_t reserveSize) :
- _ht(reserveSize)
+ _ht(reserveSize)
{ }
template <typename K, typename V, typename H, typename EQ, typename M>
diff --git a/vespalib/src/vespa/vespalib/stllike/hash_set.h b/vespalib/src/vespa/vespalib/stllike/hash_set.h
index 0c3f2dcb220..e671a2d8b9c 100644
--- a/vespalib/src/vespa/vespalib/stllike/hash_set.h
+++ b/vespalib/src/vespa/vespalib/stllike/hash_set.h
@@ -23,7 +23,8 @@ public:
hash_set & operator = (hash_set &&) noexcept = default;
hash_set(const hash_set &) = default;
hash_set & operator = (const hash_set &) = default;
- hash_set(size_t reserveSize=0);
+ hash_set();
+ explicit hash_set(size_t reserveSize);
hash_set(size_t reserveSize, const H & hasher, const EQ & equal);
template <typename InputIterator>
hash_set(InputIterator first, InputIterator last);
diff --git a/vespalib/src/vespa/vespalib/stllike/hash_set.hpp b/vespalib/src/vespa/vespalib/stllike/hash_set.hpp
index 3e48e62f2c7..892d0d28fb6 100644
--- a/vespalib/src/vespa/vespalib/stllike/hash_set.hpp
+++ b/vespalib/src/vespa/vespalib/stllike/hash_set.hpp
@@ -8,6 +8,11 @@
namespace vespalib {
template<typename K, typename H, typename EQ, typename M>
+hash_set<K, H, EQ, M>::hash_set()
+ : _ht(0)
+{ }
+
+template<typename K, typename H, typename EQ, typename M>
hash_set<K, H, EQ, M>::hash_set(size_t reserveSize)
: _ht(reserveSize)
{ }
diff --git a/vespalib/src/vespa/vespalib/stllike/hashtable.cpp b/vespalib/src/vespa/vespalib/stllike/hashtable.cpp
index 52639fd6275..1b62149d96e 100644
--- a/vespalib/src/vespa/vespalib/stllike/hashtable.cpp
+++ b/vespalib/src/vespa/vespalib/stllike/hashtable.cpp
@@ -14,19 +14,6 @@ static const unsigned long __stl_prime_list[] =
402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
};
-static const unsigned long __simple_modulator_list[] =
-{
- 0x8ul,
- 0x10ul, 0x20ul, 0x40ul, 0x80ul,
- 0x100ul, 0x200ul, 0x400ul, 0x800ul,
- 0x1000ul, 0x2000ul, 0x4000ul, 0x8000ul,
- 0x10000ul, 0x20000ul, 0x40000ul, 0x80000ul,
- 0x100000ul, 0x200000ul, 0x400000ul, 0x800000ul,
- 0x1000000ul, 0x2000000ul, 0x4000000ul, 0x8000000ul,
- 0x10000000ul, 0x20000000ul, 0x40000000ul, 0x80000000ul,
- 0x100000000ul
-};
-
}
namespace vespalib {
@@ -41,15 +28,9 @@ hashtable_base::getModulo(size_t newSize, const unsigned long * list, size_t sz)
}
size_t
-hashtable_base::getModuloStl(size_t newSize)
-{
- return getModulo(newSize, __stl_prime_list, sizeof(__stl_prime_list)/sizeof(__stl_prime_list[0]));
-}
-
-size_t
-hashtable_base::getModuloSimple(size_t newSize)
+hashtable_base::getModuloStl(size_t size)
{
- return getModulo(newSize, __simple_modulator_list, sizeof(__simple_modulator_list)/sizeof(__simple_modulator_list[0]));
+ return getModulo(size, __stl_prime_list, sizeof(__stl_prime_list)/sizeof(__stl_prime_list[0]));
}
}
diff --git a/vespalib/src/vespa/vespalib/stllike/hashtable.h b/vespalib/src/vespa/vespalib/stllike/hashtable.h
index ba9993c5a37..4e1f14843cc 100644
--- a/vespalib/src/vespa/vespalib/stllike/hashtable.h
+++ b/vespalib/src/vespa/vespalib/stllike/hashtable.h
@@ -50,7 +50,7 @@ namespace vespalib {
class hashtable_base
{
public:
- typedef unsigned int next_t;
+ using next_t = uint32_t;
/**
* This is a standard modulator that does modulo/hashTableSize.
* Hashtable size is selected from a a set of prime numbers.
@@ -79,8 +79,10 @@ public:
private:
next_t _mask;
};
- static size_t getModuloStl(size_t newSize);
- static size_t getModuloSimple(size_t newSize);
+ static size_t getModuloStl(size_t size);
+ static size_t getModuloSimple(size_t size) {
+ return std::max(size_t(8), roundUp2inN(size));
+ }
protected:
struct DefaultMoveHandler
{
@@ -98,11 +100,11 @@ class hash_node {
public:
using next_t=hashtable_base::next_t;
enum {npos=-1u, invalid=-2u};
- hash_node() : _next(invalid) {}
+ hash_node() : _node(), _next(invalid) {}
hash_node(const V & node, next_t next=npos)
- : _next(next), _node(node) {}
+ : _node(node), _next(next) {}
hash_node(V &&node, next_t next=npos)
- : _next(next), _node(std::move(node)) {}
+ : _node(std::move(node)), _next(next) {}
hash_node(hash_node &&) noexcept = default;
hash_node &operator=(hash_node &&) noexcept = default;
hash_node(const hash_node &) = default; // These will not be created
@@ -119,8 +121,8 @@ public:
bool valid() const { return _next != invalid; }
bool hasNext() const { return valid() && (_next != npos); }
private:
- next_t _next;
V _node;
+ next_t _next;
};
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator = hashtable_base::prime_modulator>
@@ -129,7 +131,7 @@ class hashtable : public hashtable_base
private:
using Node=hash_node<Value>;
protected:
- typedef vespalib::Array<Node> NodeStore;
+ using NodeStore = vespalib::Array<Node>;
virtual void move(NodeStore && oldStore);
public:
class const_iterator;
@@ -246,6 +248,9 @@ public:
insert_result insert(V && node) {
return insertInternal(std::forward<V>(node));
}
+ // This will insert unconditionally, without checking presence, and might cause duplicates.
+ // Use at you own risk.
+ void force_insert(Value && value);
/// This gives faster iteration than can be achieved by the iterators.
template <typename Func>
@@ -274,10 +279,10 @@ public:
size_t getMemoryUsed() const;
protected:
- /// These two methods are only for the ones that know what they are doing.
- /// valid input here are stuff returned from iterator.getInternalIndex.
template <typename V>
insert_result insertInternal(V && node);
+ /// These two methods are only for the ones that know what they are doing.
+ /// valid input here are stuff returned from iterator.getInternalIndex.
Value & getByInternalIndex(size_t index) { return _nodes[index].getValue(); }
const Value & getByInternalIndex(size_t index) const { return _nodes[index].getValue(); }
template <typename MoveHandler>
diff --git a/vespalib/src/vespa/vespalib/stllike/hashtable.hpp b/vespalib/src/vespa/vespalib/stllike/hashtable.hpp
index 787f2580375..15510d608da 100644
--- a/vespalib/src/vespa/vespalib/stllike/hashtable.hpp
+++ b/vespalib/src/vespa/vespalib/stllike/hashtable.hpp
@@ -3,9 +3,32 @@
#include "hashtable.h"
#include <vespa/vespalib/util/array.hpp>
+#include <algorithm>
namespace vespalib {
+namespace {
+
+/// TODO Currently we require that you have atleast one element in _nodes to avoid one extra branch
+/// However that means that empty unused hashtables are larger than necessary.
+/// This we should probably reconsider.
+template<typename Modulator>
+uint32_t
+computeModulo(size_t size) {
+ return (size > 0) ? Modulator::selectHashTableSize(roundUp2inN(size) / 3) : 1;
+}
+
+template <typename NodeStore>
+NodeStore
+createStore(size_t size, uint32_t modulo) {
+ size = (size > 0) ? roundUp2inN(std::max(size_t(modulo), roundUp2inN(size))) : 1;
+ NodeStore store;
+ store.reserve(size);
+ store.resize(modulo);
+ return store;
+}
+
+}
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
void hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::swap(hashtable & rhs)
{
@@ -19,26 +42,19 @@ void hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::swap(hashtable &
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::hashtable(size_t reservedSpace) :
- _modulator(1),
+ _modulator(computeModulo<Modulator>(reservedSpace)),
_count(0),
- _nodes(1)
-{
- if (reservedSpace > 0) {
- resize(reservedSpace);
- }
-}
+ _nodes(createStore<NodeStore>(reservedSpace, _modulator.getTableSize()))
+{ }
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::hashtable(size_t reservedSpace, const Hash & hasher, const Equal & equal) :
- _modulator(1),
+ _modulator(computeModulo<Modulator>(reservedSpace)),
_count(0),
- _nodes(1),
+ _nodes(createStore<NodeStore>(reservedSpace, _modulator.getTableSize())),
_hasher(hasher),
_equal(equal)
{
- if (reservedSpace > 0) {
- resize(reservedSpace);
- }
}
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
@@ -144,7 +160,7 @@ hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::insertInternal(V && n
_nodes[h] = std::forward<V>(node);
_count++;
return insert_result(iterator(this, h), true);
- } else if (_nodes.size() <= _nodes.capacity()) {
+ } else {
for (next_t c(h); c != Node::npos; c = _nodes[c].getNext()) {
if (_equal(_keyExtractor(_nodes[c].getValue()), _keyExtractor(node))) {
return insert_result(iterator(this, c), false);
@@ -161,15 +177,36 @@ hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::insertInternal(V && n
resize(_nodes.capacity()*2);
return insertInternal(std::forward<V>(node));
}
+ }
+}
+
+
+template <typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator>
+void
+hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::force_insert(Value && value)
+{
+ const next_t h = hash(_keyExtractor(value));
+ if ( ! _nodes[h].valid() ) {
+ _nodes[h] = std::move(value);
+ _count++;
} else {
- resize(_nodes.capacity()*2);
- return insertInternal(std::forward<V>(node));
+ if (_nodes.size() < _nodes.capacity()) {
+ const next_t p(_nodes[h].getNext());
+ const next_t newIdx(_nodes.size());
+ _nodes[h].setNext(newIdx);
+ new (_nodes.push_back_fast()) Node(std::move(value), p);
+ _count++;
+ } else {
+ resize(_nodes.capacity()*2);
+ force_insert(std::move(value));
+ }
}
}
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
template<typename MoveHandler>
-void hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::reclaim(MoveHandler & moveHandler, next_t node)
+void
+hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::reclaim(MoveHandler & moveHandler, next_t node)
{
size_t last(_nodes.size()-1);
if (last >= getTableSize()) {
@@ -187,7 +224,8 @@ void hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::reclaim(MoveHand
template< typename Key, typename Value, typename Hash, typename Equal, typename KeyExtract, typename Modulator >
template <typename Func>
-void hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::for_each(Func func) const
+void
+hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::for_each(Func func) const
{
uint32_t i(0);
for (; i < _modulator.getTableSize(); i++) {
@@ -232,14 +270,8 @@ template< typename Key, typename Value, typename Hash, typename Equal, typename
void
hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::resize(size_t newSize)
{
- newSize = roundUp2inN(newSize);
- next_t newModulo = Modulator::selectHashTableSize(newSize/3);
- if (newModulo > newSize) {
- newSize = newModulo;
- }
- NodeStore newStore;
- newStore.reserve(roundUp2inN(newSize));
- newStore.resize(newModulo);
+ next_t newModulo = computeModulo<Modulator>(newSize);
+ NodeStore newStore = createStore<NodeStore>(newSize, newModulo);
_modulator = Modulator(newModulo);
_count = 0;
_nodes.swap(newStore);
@@ -250,9 +282,9 @@ template< typename Key, typename Value, typename Hash, typename Equal, typename
void
hashtable<Key, Value, Hash, Equal, KeyExtract, Modulator>::move(NodeStore && oldStore)
{
- for(typename NodeStore::iterator it(oldStore.begin()), mt(oldStore.end()); it != mt; it++) {
- if (it->valid()) {
- insert(std::move(it->getValue()));
+ for (auto & entry : oldStore) {
+ if (entry.valid()) {
+ force_insert(std::move(entry.getValue()));
}
}
}
diff --git a/vespalib/src/vespa/vespalib/stllike/string.h b/vespalib/src/vespa/vespalib/stllike/string.h
index 1ca0ef1da77..05b04575ec1 100644
--- a/vespalib/src/vespa/vespalib/stllike/string.h
+++ b/vespalib/src/vespa/vespalib/stllike/string.h
@@ -631,6 +631,7 @@ template<uint32_t StackSize>
small_string<StackSize>
operator + (const char * a, const small_string<StackSize> & b);
+#if __cplusplus < 201709L || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ < 10)
template<typename T, uint32_t StackSize>
bool
operator == (const T& a, const small_string<StackSize>& b) noexcept
@@ -644,6 +645,7 @@ operator != (const T& a, const small_string<StackSize>& b) noexcept
{
return b != a;
}
+#endif
template<typename T, uint32_t StackSize>
bool
diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt
index 610310fd43c..5a82fb200e0 100644
--- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt
@@ -12,6 +12,7 @@ vespa_add_library(vespalib_vespalib_util OBJECT
benchmark_timer.cpp
blockingthreadstackexecutor.cpp
box.cpp
+ child_process.cpp
classname.cpp
closuretask.cpp
compress.cpp
@@ -42,10 +43,10 @@ vespa_add_library(vespalib_vespalib_util OBJECT
runnable_pair.cpp
sequence.cpp
sha1.cpp
+ shared_string_repo.cpp
sig_catch.cpp
signalhandler.cpp
simple_thread_bundle.cpp
- child_process.cpp
stash.cpp
string_hash.cpp
stringfmt.cpp
diff --git a/vespalib/src/vespa/vespalib/util/shared_string_repo.cpp b/vespalib/src/vespa/vespalib/util/shared_string_repo.cpp
new file mode 100644
index 00000000000..a5ec9540a1b
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/util/shared_string_repo.cpp
@@ -0,0 +1,54 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "shared_string_repo.h"
+
+namespace vespalib {
+
+SharedStringRepo::Partition::~Partition() = default;
+
+void
+SharedStringRepo::Partition::make_entries(size_t hint)
+{
+ hint = std::max(hint, _entries.size() + 1);
+ size_t want_mem = roundUp2inN(hint * sizeof(Entry));
+ size_t want_entries = want_mem / sizeof(Entry);
+ _entries.reserve(want_entries);
+ while (_entries.size() < _entries.capacity()) {
+ _entries.emplace_back(_free);
+ _free = (_entries.size() - 1);
+ }
+}
+
+SharedStringRepo::SharedStringRepo() = default;
+SharedStringRepo::~SharedStringRepo() = default;
+
+SharedStringRepo &
+SharedStringRepo::get()
+{
+ static SharedStringRepo repo;
+ return repo;
+}
+
+SharedStringRepo::WeakHandles::WeakHandles(size_t expect_size)
+ : _handles()
+{
+ _handles.reserve(expect_size);
+}
+
+SharedStringRepo::WeakHandles::~WeakHandles() = default;
+
+SharedStringRepo::StrongHandles::StrongHandles(size_t expect_size)
+ : _repo(SharedStringRepo::get()),
+ _handles()
+{
+ _handles.reserve(expect_size);
+}
+
+SharedStringRepo::StrongHandles::~StrongHandles()
+{
+ for (uint32_t handle: _handles) {
+ _repo.reclaim(handle);
+ }
+}
+
+}
diff --git a/vespalib/src/vespa/vespalib/util/shared_string_repo.h b/vespalib/src/vespa/vespalib/util/shared_string_repo.h
new file mode 100644
index 00000000000..afdd3a289f9
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/util/shared_string_repo.h
@@ -0,0 +1,238 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "spin_lock.h"
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vespalib/stllike/identity.h>
+#include <vespa/vespalib/stllike/hashtable.hpp>
+#include <xxhash.h>
+#include <mutex>
+#include <vector>
+#include <array>
+
+namespace vespalib {
+
+/**
+ * This class implements application-wide in-memory string
+ * interning. Each string stored in the repo will be assigned a unique
+ * 32-bit id that can be used by the application to check for
+ * equality. The repo can never be shrunk in size, but ids can be
+ * re-used when the corresponding strings are evicted from the
+ * repo. Handle objects are used to track which strings are in use.
+ **/
+class SharedStringRepo {
+private:
+ static constexpr int NUM_PARTS = 64;
+ static constexpr int PART_BITS = 6;
+ static constexpr int PART_MASK = 0x3f;
+
+ struct AltKey {
+ vespalib::stringref str;
+ uint32_t hash;
+ };
+
+ class alignas(64) Partition {
+ public:
+ struct Entry {
+ static constexpr uint32_t npos = -1;
+ uint32_t hash;
+ uint32_t ref_cnt;
+ vespalib::string str;
+ explicit Entry(uint32_t next) noexcept : hash(), ref_cnt(next), str() {}
+ uint32_t init(const AltKey &key) {
+ uint32_t next = ref_cnt;
+ hash = key.hash;
+ ref_cnt = 1;
+ str = key.str;
+ return next;
+ }
+ void fini(uint32_t next) {
+ ref_cnt = next;
+ }
+ };
+ struct Key {
+ uint32_t idx;
+ uint32_t hash;
+ };
+ struct Hash {
+ uint32_t operator()(const Key &key) const { return key.hash; }
+ uint32_t operator()(const AltKey &key) const { return key.hash; }
+ };
+ struct Equal {
+ const std::vector<Entry> &entries;
+ Equal(const std::vector<Entry> &entries_in) : entries(entries_in) {}
+ Equal(const Equal &rhs) = default;
+ bool operator()(const Key &a, const Key &b) const { return (a.idx == b.idx); }
+ bool operator()(const Key &a, const AltKey &b) const { return ((a.hash == b.hash) && (entries[a.idx].str == b.str)); }
+ };
+ using HashType = hashtable<Key,Key,Hash,Equal,Identity,hashtable_base::and_modulator>;
+
+ private:
+ SpinLock _lock;
+ std::vector<Entry> _entries;
+ uint32_t _free;
+ HashType _hash;
+
+ void make_entries(size_t hint);
+
+ uint32_t make_entry(const AltKey &alt_key) {
+ if (__builtin_expect(_free == Entry::npos, false)) {
+ make_entries(_entries.size() * 2);
+ }
+ uint32_t idx = _free;
+ _free = _entries[idx].init(alt_key);
+ return idx;
+ }
+
+ public:
+ Partition()
+ : _lock(), _entries(), _free(Entry::npos), _hash(128, Hash(), Equal(_entries))
+ {
+ make_entries(64);
+ }
+ ~Partition();
+
+ uint32_t resolve(const AltKey &alt_key) {
+ std::lock_guard guard(_lock);
+ auto pos = _hash.find(alt_key);
+ if (pos != _hash.end()) {
+ ++_entries[pos->idx].ref_cnt;
+ return pos->idx;
+ } else {
+ uint32_t idx = make_entry(alt_key);
+ _hash.force_insert(Key{idx, alt_key.hash});
+ return idx;
+ }
+ }
+
+ vespalib::string as_string(uint32_t idx) {
+ std::lock_guard guard(_lock);
+ return _entries[idx].str;
+ }
+
+ void copy(uint32_t idx) {
+ std::lock_guard guard(_lock);
+ ++_entries[idx].ref_cnt;
+ }
+
+ void reclaim(uint32_t idx) {
+ std::lock_guard guard(_lock);
+ Entry &entry = _entries[idx];
+ if (--entry.ref_cnt == 0) {
+ _hash.erase(Key{idx, entry.hash});
+ entry.fini(_free);
+ _free = idx;
+ }
+ }
+ };
+
+ std::array<Partition,NUM_PARTS> _partitions;
+
+ SharedStringRepo();
+ ~SharedStringRepo();
+
+ uint32_t resolve(vespalib::stringref str) {
+ if (!str.empty()) {
+ uint64_t full_hash = XXH3_64bits(str.data(), str.size());
+ uint32_t part = full_hash & PART_MASK;
+ uint32_t local_hash = full_hash >> PART_BITS;
+ uint32_t local_idx = _partitions[part].resolve(AltKey{str, local_hash});
+ return (((local_idx << PART_BITS) | part) + 1);
+ } else {
+ return 0;
+ }
+ }
+
+ vespalib::string as_string(uint32_t id) {
+ if (id != 0) {
+ uint32_t part = (id - 1) & PART_MASK;
+ uint32_t local_idx = (id - 1) >> PART_BITS;
+ return _partitions[part].as_string(local_idx);
+ } else {
+ return {};
+ }
+ }
+
+ uint32_t copy(uint32_t id) {
+ if (id != 0) {
+ uint32_t part = (id - 1) & PART_MASK;
+ uint32_t local_idx = (id - 1) >> PART_BITS;
+ _partitions[part].copy(local_idx);
+ }
+ return id;
+ }
+
+ void reclaim(uint32_t id) {
+ if (id != 0) {
+ uint32_t part = (id - 1) & PART_MASK;
+ uint32_t local_idx = (id - 1) >> PART_BITS;
+ _partitions[part].reclaim(local_idx);
+ }
+ }
+
+public:
+ static SharedStringRepo &get();
+
+ // A single stand-alone string handle with ownership
+ class Handle {
+ private:
+ uint32_t _id;
+ public:
+ Handle() : _id(0) {}
+ Handle(vespalib::stringref str) : _id(get().resolve(str)) {}
+ Handle(const Handle &rhs) : _id(get().copy(rhs._id)) {}
+ Handle &operator=(const Handle &rhs) {
+ get().reclaim(_id);
+ _id = get().copy(rhs._id);
+ return *this;
+ }
+ Handle(Handle &&rhs) noexcept : _id(rhs._id) {
+ rhs._id = 0;
+ }
+ Handle &operator=(Handle &&rhs) {
+ get().reclaim(_id);
+ _id = rhs._id;
+ rhs._id = 0;
+ return *this;
+ }
+ bool operator==(const Handle &rhs) const { return (_id == rhs._id); }
+ uint32_t id() const { return _id; }
+ vespalib::string as_string() const { return get().as_string(_id); }
+ ~Handle() { get().reclaim(_id); }
+ };
+
+ // Read-only access to a collection of string handles
+ class HandleView {
+ private:
+ const std::vector<uint32_t> &_handles;
+ public:
+ HandleView(const std::vector<uint32_t> &handles_in) : _handles(handles_in) {}
+ const std::vector<uint32_t> &handles() const { return _handles; }
+ };
+
+ // A collection of string handles without ownership
+ class WeakHandles {
+ private:
+ std::vector<uint32_t> _handles;
+ public:
+ WeakHandles(size_t expect_size);
+ ~WeakHandles();
+ void add(uint32_t handle) { _handles.push_back(handle); }
+ HandleView view() const { return HandleView(_handles); }
+ };
+
+ // A collection of string handles with ownership
+ class StrongHandles {
+ private:
+ SharedStringRepo &_repo;
+ std::vector<uint32_t> _handles;
+ public:
+ StrongHandles(size_t expect_size);
+ ~StrongHandles();
+ void add(vespalib::stringref str) { _handles.push_back(_repo.resolve(str)); }
+ HandleView view() const { return HandleView(_handles); }
+ };
+};
+
+}
diff --git a/vespalib/src/vespa/vespalib/util/threadexecutor.h b/vespalib/src/vespa/vespalib/util/threadexecutor.h
index 61a5d9d5ac7..7d06007d7be 100644
--- a/vespalib/src/vespa/vespalib/util/threadexecutor.h
+++ b/vespalib/src/vespa/vespalib/util/threadexecutor.h
@@ -32,6 +32,11 @@ public:
* Sets a new upper limit for accepted number of tasks.
*/
virtual void setTaskLimit(uint32_t taskLimit) = 0;
+
+ /**
+ * Gets the limit for accepted number of tasks.
+ */
+ virtual uint32_t getTaskLimit() const = 0;
};
/**
diff --git a/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.cpp b/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.cpp
index 28ee2da2d8c..01546b80d66 100644
--- a/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.cpp
+++ b/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.cpp
@@ -174,6 +174,13 @@ ThreadStackExecutorBase::setTaskLimit(uint32_t taskLimit)
internalSetTaskLimit(taskLimit);
}
+uint32_t
+ThreadStackExecutorBase::getTaskLimit() const
+{
+ unique_lock guard(_lock);
+ return _taskLimit;
+}
+
void
ThreadStackExecutorBase::wakeup() {
// Nothing to do here as workers are always attentive.
diff --git a/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.h b/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.h
index c86597ca153..c0653c19516 100644
--- a/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.h
+++ b/vespalib/src/vespa/vespalib/util/threadstackexecutorbase.h
@@ -211,6 +211,8 @@ public:
size_t getNumThreads() const override;
void setTaskLimit(uint32_t taskLimit) override;
+ uint32_t getTaskLimit() const override;
+
void wakeup() override;
/**
diff --git a/vespalib/src/vespa/vespalib/websocket/websocket_server.cpp b/vespalib/src/vespa/vespalib/websocket/websocket_server.cpp
index 171b7dabc1d..d3ef13e78d7 100644
--- a/vespalib/src/vespa/vespalib/websocket/websocket_server.cpp
+++ b/vespalib/src/vespa/vespalib/websocket/websocket_server.cpp
@@ -7,8 +7,7 @@
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/host_name.h>
-namespace vespalib {
-namespace ws {
+namespace vespalib::ws {
namespace {
@@ -116,7 +115,13 @@ void handle_upgrade(Connection &conn, Request &req) {
} // namespace vespalib::ws::<unnamed>
-WebsocketServer::StaticPage::~StaticPage() {}
+WebsocketServer::StaticPage::StaticPage(const vespalib::string & type, const vespalib::string & content_in)
+ : content_type(type),
+ content(content_in)
+{}
+WebsocketServer::StaticPage::StaticPage(const StaticPage &) = default;
+WebsocketServer::StaticPage & WebsocketServer::StaticPage::operator = (const StaticPage &) = default;
+WebsocketServer::StaticPage::~StaticPage() = default;
WebsocketServer::WebsocketServer(int port_in, StaticRepo &&repo)
: _acceptor(port_in, *this),
@@ -125,7 +130,7 @@ WebsocketServer::WebsocketServer(int port_in, StaticRepo &&repo)
{
}
-WebsocketServer::~WebsocketServer() {}
+WebsocketServer::~WebsocketServer() = default;
void
WebsocketServer::handle(std::unique_ptr<Socket> socket)
@@ -156,5 +161,4 @@ WebsocketServer::handle(std::unique_ptr<Socket> socket)
}
}
-} // namespace vespalib::ws
-} // namespace vespalib
+}
diff --git a/vespalib/src/vespa/vespalib/websocket/websocket_server.h b/vespalib/src/vespa/vespalib/websocket/websocket_server.h
index 31f657ddc1b..03b3da72134 100644
--- a/vespalib/src/vespa/vespalib/websocket/websocket_server.h
+++ b/vespalib/src/vespa/vespalib/websocket/websocket_server.h
@@ -7,12 +7,14 @@
#include <vespa/vespalib/stllike/string.h>
#include <map>
-namespace vespalib {
-namespace ws {
+namespace vespalib::ws {
class WebsocketServer : public Handler<Socket> {
public:
struct StaticPage {
+ StaticPage(const vespalib::string & type, const vespalib::string & content_in);
+ StaticPage(const StaticPage &);
+ StaticPage & operator = (const StaticPage &);
StaticPage(StaticPage &&) = default;
StaticPage & operator = (StaticPage &&) = default;
~StaticPage();
@@ -28,10 +30,9 @@ private:
public:
WebsocketServer(int port_in, StaticRepo &&repo = StaticRepo());
- ~WebsocketServer();
+ ~WebsocketServer() override;
void handle(std::unique_ptr<Socket> socket) override;
int port() { return _acceptor.port(); }
};
} // namespace vespalib::ws
-} // namespace vespalib
diff --git a/vespalog/src/vespa/log/bufferedlogger.cpp b/vespalog/src/vespa/log/bufferedlogger.cpp
index 5c243b86f86..63663e0705b 100644
--- a/vespalog/src/vespa/log/bufferedlogger.cpp
+++ b/vespalog/src/vespa/log/bufferedlogger.cpp
@@ -38,6 +38,10 @@ public:
uint64_t _timestamp;
Logger* _logger;
+ Entry(const Entry &);
+ Entry & operator=(const Entry &);
+ Entry(Entry &&) noexcept;
+ Entry & operator=(Entry &&) noexcept;
Entry(Logger::LogLevel level, const char* file, int line,
const std::string& token, const std::string& message,
uint64_t timestamp, Logger&);
@@ -137,7 +141,11 @@ BackingBuffer::Entry::Entry(Logger::LogLevel level, const char* file, int line,
{
}
-BackingBuffer::Entry::~Entry() { }
+BackingBuffer::Entry::Entry(const Entry &) = default;
+BackingBuffer::Entry & BackingBuffer::Entry::operator =(const Entry &) = default;
+BackingBuffer::Entry::Entry(Entry &&) noexcept = default;
+BackingBuffer::Entry & BackingBuffer::Entry::operator=(Entry &&) noexcept = default;
+BackingBuffer::Entry::~Entry() = default;
bool
BackingBuffer::Entry::operator==(const Entry& entry) const
diff --git a/vespamalloc/src/vespamalloc/malloc/common.h b/vespamalloc/src/vespamalloc/malloc/common.h
index 36f1bd0521d..b1b26f6b350 100644
--- a/vespamalloc/src/vespamalloc/malloc/common.h
+++ b/vespamalloc/src/vespamalloc/malloc/common.h
@@ -15,7 +15,8 @@ namespace vespamalloc {
#define NUM_SIZE_CLASSES 32 // Max 64G
-#define NUM_THREADS 16384
+static constexpr uint32_t NUM_THREADS = 16384;
+
#define UNUSED(a)
#ifdef ENABLE_DEBUG
#define DEBUG(a) a
diff --git a/vespamalloc/src/vespamalloc/malloc/datasegment.h b/vespamalloc/src/vespamalloc/malloc/datasegment.h
index ab23f2207e3..5c1c1f06088 100644
--- a/vespamalloc/src/vespamalloc/malloc/datasegment.h
+++ b/vespamalloc/src/vespamalloc/malloc/datasegment.h
@@ -28,7 +28,7 @@ public:
static size_t adjustedClassSize(SizeClassT sc) { return (sc > 0x400) ? (sc - 0x400) << 16 : sc; }
size_t dataSize() const { return (const char*)end() - (const char*)start(); }
size_t textSize() const { return size_t(start()); }
- size_t infoThread(FILE * os, int level, int thread, SizeClassT sct) const __attribute__((noinline));
+ size_t infoThread(FILE * os, int level, uint32_t thread, SizeClassT sct, uint32_t maxThreadId=0) const __attribute__((noinline));
void info(FILE * os, size_t level) __attribute__((noinline));
void setupLog(size_t noMemLogLevel, size_t bigMemLogLevel,
size_t bigLimit, size_t bigIncrement,
diff --git a/vespamalloc/src/vespamalloc/malloc/datasegment.hpp b/vespamalloc/src/vespamalloc/malloc/datasegment.hpp
index 840088fd843..355c9e9daad 100644
--- a/vespamalloc/src/vespamalloc/malloc/datasegment.hpp
+++ b/vespamalloc/src/vespamalloc/malloc/datasegment.hpp
@@ -6,9 +6,7 @@
namespace vespamalloc {
template<typename MemBlockPtrT>
-DataSegment<MemBlockPtrT>::~DataSegment()
-{
-}
+DataSegment<MemBlockPtrT>::~DataSegment() = default;
#define INIT_LOG_LIMIT 0x400000000ul // 16G
@@ -48,19 +46,19 @@ void * DataSegment<MemBlockPtrT>::getBlock(size_t & oldBlockSize, SizeClassT sc)
oldBlockSize = ((oldBlockSize + (minBlockSize-1))/minBlockSize)*minBlockSize;
size_t numBlocks((oldBlockSize + (BlockSize-1))/BlockSize);
size_t blockSize = BlockSize * numBlocks;
- void * newBlock(NULL);
+ void * newBlock(nullptr);
{
Guard sync(_mutex);
newBlock = _freeList.sub(numBlocks);
- if ( newBlock == NULL ) {
+ if ( newBlock == nullptr ) {
newBlock = _unMappedList.sub(numBlocks);
- if ( newBlock == NULL ) {
+ if ( newBlock == nullptr ) {
size_t nextBlock(blockId(end()));
size_t startBlock = _freeList.lastBlock(nextBlock);
if (startBlock) {
size_t adjustedBlockSize = blockSize - BlockSize*(nextBlock-startBlock);
newBlock = _osMemory.get(adjustedBlockSize);
- if (newBlock != NULL) {
+ if (newBlock != nullptr) {
assert (newBlock == fromBlockId(nextBlock));
_freeList.removeLastBlock();
newBlock = fromBlockId(startBlock);
@@ -79,9 +77,9 @@ void * DataSegment<MemBlockPtrT>::getBlock(size_t & oldBlockSize, SizeClassT sc)
}
}
if (newBlock == (void *) -1) {
- newBlock = NULL;
+ newBlock = nullptr;
blockSize = 0;
- } else if (newBlock == NULL) {
+ } else if (newBlock == nullptr) {
blockSize = 0;
} else {
assert(blockId(newBlock)+numBlocks < BlockCount);
@@ -95,7 +93,7 @@ void * DataSegment<MemBlockPtrT>::getBlock(size_t & oldBlockSize, SizeClassT sc)
}
}
oldBlockSize = blockSize;
- if (newBlock == NULL) {
+ if (newBlock == nullptr) {
static int recurse = 0;
if (recurse++ == 0) {
perror("Failed extending datasegment: ");
@@ -103,7 +101,7 @@ void * DataSegment<MemBlockPtrT>::getBlock(size_t & oldBlockSize, SizeClassT sc)
MemBlockPtrT::dumpInfo(_noMemLogLevel);
sleep(2);
}
- return NULL;
+ return nullptr;
}
checkAndLogBigSegment();
return newBlock;
@@ -161,17 +159,30 @@ void DataSegment<MemBlockPtrT>::returnBlock(void *ptr)
}
}
+namespace {
+
+std::vector<uint32_t>
+createHistogram(bool allThreads, uint32_t maxThreads) {
+ if (allThreads) {
+ return std::vector<uint32_t>(maxThreads, 0);
+ }
+ return std::vector<uint32_t>();
+}
+
+}
template<typename MemBlockPtrT>
-size_t DataSegment<MemBlockPtrT>::infoThread(FILE * os, int level, int thread, SizeClassT sct) const
+size_t DataSegment<MemBlockPtrT>::infoThread(FILE * os, int level, uint32_t thread, SizeClassT sct, uint32_t maxThreadId) const
{
- typedef CallGraph<typename MemBlockPtrT::Stack, 0x10000, Index> CallGraphLT;
+ using CallGraphLT = CallGraph<typename MemBlockPtrT::Stack, 0x10000, Index>;
+ bool allThreads(thread == 0);
size_t usedCount(0);
size_t checkedCount(0);
size_t allocatedCount(0);
size_t notAccounted(0);
size_t invalidCallStacks(0);
- std::unique_ptr<CallGraphLT> callGraph(new CallGraphLT);
- for(size_t i=0; i < NELEMS(_blockList); ) {
+ std::unique_ptr<CallGraphLT> callGraph = std::make_unique<CallGraphLT>();
+ std::vector<uint32_t> threadHistogram = createHistogram(allThreads, maxThreadId);
+ for (size_t i=0; i < NELEMS(_blockList); ) {
const BlockT & b = _blockList[i];
SizeClassT sc = b.sizeClass();
if (sc == sct) {
@@ -182,8 +193,11 @@ size_t DataSegment<MemBlockPtrT>::infoThread(FILE * os, int level, int thread, S
checkedCount++;
if (mem.allocated()) {
allocatedCount++;
- if (mem.threadId() == thread) {
+ if (allThreads || (mem.threadId() == thread)) {
usedCount++;
+ if (mem.threadId() < threadHistogram.size()) {
+ threadHistogram[mem.threadId()]++;
+ }
if (usedCount < _allocs2Show) {
mem.info(os, level);
}
@@ -210,8 +224,13 @@ size_t DataSegment<MemBlockPtrT>::infoThread(FILE * os, int level, int thread, S
i++;
}
}
- fprintf(os, "\nCallTree(Checked=%ld, GlobalAlloc=%ld(%ld%%)," "ByMeAlloc=%ld(%2.2f%%) NotAccountedDue2FullGraph=%ld InvalidCallStacks=%ld:\n",
- checkedCount, allocatedCount, checkedCount ? allocatedCount*100/checkedCount : 0,
+ if (checkedCount == 0) {
+ return 0;
+ }
+
+ fprintf(os, "\nCallTree SC %d(Checked=%ld, GlobalAlloc=%ld(%ld%%)," "By%sAlloc=%ld(%2.2f%%) NotAccountedDue2FullGraph=%ld InvalidCallStacks=%ld:\n",
+ sct, checkedCount, allocatedCount, checkedCount ? allocatedCount*100/checkedCount : 0,
+ allThreads ? "Us" : "Me",
usedCount, checkedCount ? static_cast<double>(usedCount*100)/checkedCount : 0.0, notAccounted, invalidCallStacks);
if ( ! callGraph->empty()) {
Aggregator agg;
@@ -221,7 +240,34 @@ size_t DataSegment<MemBlockPtrT>::infoThread(FILE * os, int level, int thread, S
ost << agg;
fprintf(os, "%s\n", ost.c_str());
}
- fprintf(os, " count(%ld)", usedCount);
+ if ( !threadHistogram.empty()) {
+ uint32_t nonZeroCount(0);
+ for (uint32_t i(0); i < threadHistogram.size(); i++) {
+ if (threadHistogram[i] > 0) {
+ nonZeroCount++;
+ }
+ }
+ using Pair = std::pair<uint32_t, uint32_t>;
+ std::vector<Pair> orderedHisto;
+ orderedHisto.reserve(nonZeroCount);
+ for (uint32_t i(0); i < threadHistogram.size(); i++) {
+ if (threadHistogram[i] > 0) {
+ orderedHisto.emplace_back(i, threadHistogram[i]);
+ }
+ }
+ std::sort(orderedHisto.begin(), orderedHisto.end(), [](const Pair & a, const Pair & b) { return a.second > b.second;});
+ fprintf(os, "ThreadHistogram SC %d: [", sct);
+
+ bool first(true);
+ for (const Pair & entry : orderedHisto) {
+ if ( !first) {
+ fprintf(os, ", ");
+ }
+ fprintf(os, "{%u, %u}", entry.first, entry.second);
+ first = false;
+ }
+ fprintf(os, " ]");
+ }
return usedCount;
}
@@ -308,7 +354,7 @@ void DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::add(size_t startIndex)
size_t numBlocks(_blockList[startIndex].freeChainLength());
for (i=0; (i < _count) && (_freeStartIndex[i] < startIndex); i++) { }
size_t prevIndex(0), nextIndex(0);
- BlockT * prev(NULL), * next(NULL);
+ BlockT * prev(nullptr), * next(nullptr);
if (i > 0) {
prevIndex = _freeStartIndex[i-1];
prev = & _blockList[prevIndex];
@@ -352,7 +398,7 @@ template<typename MemBlockPtrT>
template <int MaxCount>
void * DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::sub(size_t numBlocks)
{
- void * block(NULL);
+ void * block(nullptr);
size_t bestFitIndex(_count);
int bestLeft(INT_MAX);
for(size_t i=0; i < _count; i++) {
diff --git a/vespamalloc/src/vespamalloc/malloc/mallocdst.h b/vespamalloc/src/vespamalloc/malloc/mallocdst.h
index c1fe9b4528a..92a37997292 100644
--- a/vespamalloc/src/vespamalloc/malloc/mallocdst.h
+++ b/vespamalloc/src/vespamalloc/malloc/mallocdst.h
@@ -10,7 +10,7 @@ typedef ThreadListT<MemBlockBoundsCheck, Stat> ThreadList;
typedef MemoryWatcher<MemBlockBoundsCheck, ThreadList> Allocator;
static char _Gmem[sizeof(Allocator)];
-static Allocator *_GmemP = NULL;
+static Allocator *_GmemP = nullptr;
template <size_t MaxSizeClassMultiAllocC, size_t StackTraceLen>
void MemBlockBoundsCheckBaseT<MaxSizeClassMultiAllocC, StackTraceLen>::dumpInfo(size_t level)
diff --git a/vespamalloc/src/vespamalloc/malloc/memblock.h b/vespamalloc/src/vespamalloc/malloc/memblock.h
index e8d8e274678..3f55e33b23e 100644
--- a/vespamalloc/src/vespamalloc/malloc/memblock.h
+++ b/vespamalloc/src/vespamalloc/malloc/memblock.h
@@ -31,11 +31,11 @@ public:
void setExact(size_t) { }
void setExact(size_t, std::align_val_t ) { }
void alloc(bool ) { }
- void setThreadId(int ) { }
+ void setThreadId(uint32_t ) { }
void free() { }
size_t size() const { return 0; }
bool allocated() const { return false; }
- int threadId() const { return 0; }
+ uint32_t threadId() const { return 0; }
void info(FILE *, unsigned level=0) const { (void) level; }
Stack * callStack() { return nullptr; }
size_t callStackLen() const { return 0; }
diff --git a/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.h b/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.h
index 1860f2f36d3..90445666063 100644
--- a/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.h
+++ b/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.h
@@ -20,11 +20,11 @@ public:
return p ? (p+alignment()) : nullptr;
}
- void setThreadId(int th) { if (_ptr) { static_cast<uint32_t*>(_ptr)[2] = th; } }
+ void setThreadId(uint32_t th) { if (_ptr) { static_cast<uint32_t *>(_ptr)[2] = th; } }
bool allocated() const { return (static_cast<uint32_t*>(_ptr)[3] == ALLOC_MAGIC); }
size_t size() const { return static_cast<const uint32_t *>(_ptr)[0]; }
size_t alignment() const { return static_cast<const uint32_t *>(_ptr)[1]; }
- int threadId() const { return static_cast<int*>(_ptr)[2]; }
+ uint32_t threadId() const { return static_cast<uint32_t *>(_ptr)[2]; }
Stack * callStack() { return reinterpret_cast<Stack *>((char *)_ptr + size() + alignment()); }
const Stack * callStack() const { return reinterpret_cast<const Stack *>((const char *)_ptr + size() + alignment()); }
void fillMemory(size_t sz) {
diff --git a/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.hpp b/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.hpp
index cac24a12714..d4890fac187 100644
--- a/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.hpp
+++ b/vespamalloc/src/vespamalloc/malloc/memblockboundscheck.hpp
@@ -10,7 +10,7 @@ void MemBlockBoundsCheckBaseT<MaxSizeClassMultiAllocC, StackTraceLen>::info(FILE
{
if (validCommon()) {
if (level & 0x02) {
- fprintf(os, "{ %8p(%ld, %d) ", ptr(), size(), threadId());
+ fprintf(os, "{ %8p(%ld, %u) ", ptr(), size(), threadId());
const Stack * cStack = callStack();
for (int i=0; i<int(StackTraceLen);i++) {
if (cStack[i].valid()) {
@@ -21,7 +21,7 @@ void MemBlockBoundsCheckBaseT<MaxSizeClassMultiAllocC, StackTraceLen>::info(FILE
fprintf(os, " }");
}
if (level & 0x01) {
- fprintf(os, " %8p(%ld, %d)", ptr(), size(), threadId());
+ fprintf(os, " %8p(%ld, %u)", ptr(), size(), threadId());
}
if (level == 0) {
fprintf(os, " %8p(%ld)", ptr(), size());
diff --git a/vespamalloc/src/vespamalloc/malloc/threadlist.h b/vespamalloc/src/vespamalloc/malloc/threadlist.h
index 149396a3bff..95ff072d035 100644
--- a/vespamalloc/src/vespamalloc/malloc/threadlist.h
+++ b/vespamalloc/src/vespamalloc/malloc/threadlist.h
@@ -27,22 +27,17 @@ public:
ThreadPool & getCurrent() { return *_myPool; }
size_t getThreadId() const { return (_myPool - _threadVector); }
void enableThreadSupport() {
- if ( ! _isThreaded ) {
- _isThreaded = true;
- }
+ _isThreaded.test_and_set();
}
void info(FILE * os, size_t level=0);
size_t getMaxNumThreads() const { return NELEMS(_threadVector); }
private:
- size_t getThreadCount() const { return _threadCount; }
- size_t getThreadCountAccum() const { return _threadCountAccum; }
ThreadListT(const ThreadListT & tl);
ThreadListT & operator = (const ThreadListT & tl);
- enum {ThreadStackSize=2048*1024};
- volatile bool _isThreaded;
- std::atomic<size_t> _threadCount;
- std::atomic<size_t> _threadCountAccum;
+ std::atomic_flag _isThreaded;
+ std::atomic<uint32_t> _threadCount;
+ std::atomic<uint32_t> _threadCountAccum;
ThreadPool _threadVector[NUM_THREADS];
AllocPoolT<MemBlockPtrT> & _allocPool;
static thread_local ThreadPool * _myPool TLS_LINKAGE;
diff --git a/vespamalloc/src/vespamalloc/malloc/threadlist.hpp b/vespamalloc/src/vespamalloc/malloc/threadlist.hpp
index e437981febc..24f9fc4388c 100644
--- a/vespamalloc/src/vespamalloc/malloc/threadlist.hpp
+++ b/vespamalloc/src/vespamalloc/malloc/threadlist.hpp
@@ -18,9 +18,7 @@ ThreadListT<MemBlockPtrT, ThreadStatT>::ThreadListT(AllocPool & pool) :
}
template <typename MemBlockPtrT, typename ThreadStatT>
-ThreadListT<MemBlockPtrT, ThreadStatT>::~ThreadListT()
-{
-}
+ThreadListT<MemBlockPtrT, ThreadStatT>::~ThreadListT() = default;
template <typename MemBlockPtrT, typename ThreadStatT>
void ThreadListT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level)
@@ -31,16 +29,27 @@ void ThreadListT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level)
const ThreadPool & thread = _threadVector[i];
if (thread.isActive()) {
activeThreads++;
+ peakThreads = i;
+ }
+ }
+ fprintf(os, "#%ld active threads. Peak threads #%ld. %u threads created in total.\n",
+ activeThreads, peakThreads, _threadCountAccum.load());
+ if ((level > 1) && ! ThreadStatT::isDummy()) {
+ for (SizeClassT sc(0); sc < NUM_SIZE_CLASSES; sc++) {
+ _allocPool.dataSegment().infoThread(os, level, 0, sc, _threadCountAccum.load() + 1);
+ }
+ }
+ for (size_t i(0); i < getMaxNumThreads(); i++) {
+ const ThreadPool & thread = _threadVector[i];
+ if (thread.isActive()) {
if ( ! ThreadStatT::isDummy()) {
- fprintf(os, "Thread #%ld = pid # %d\n", i, thread.osThreadId());
if (thread.isUsed()) {
+ fprintf(os, "Thread #%u = pid # %d\n", thread.threadId(), thread.osThreadId());
thread.info(os, level, _allocPool.dataSegment());
}
}
- peakThreads = i;
}
}
- fprintf(os, "#%ld active threads. Peak threads #%ld\n", activeThreads, peakThreads);
}
template <typename MemBlockPtrT, typename ThreadStatT>
@@ -57,7 +66,7 @@ bool ThreadListT<MemBlockPtrT, ThreadStatT>::initThisThread()
{
bool retval(true);
_threadCount.fetch_add(1);
- size_t lidAccum = _threadCountAccum.fetch_add(1);
+ uint32_t lidAccum = _threadCountAccum.fetch_add(1);
long localId(-1);
for(size_t i = 0; (localId < 0) && (i < getMaxNumThreads()); i++) {
ThreadPool & tp = _threadVector[i];
@@ -66,10 +75,11 @@ bool ThreadListT<MemBlockPtrT, ThreadStatT>::initThisThread()
}
}
assert(localId >= 0);
+ assert(size_t(localId) < getMaxNumThreads());
_myPool = &_threadVector[localId];
assert(getThreadId() == size_t(localId));
-
- getCurrent().init(lidAccum);
+ assert(lidAccum < 0xffffffffu);
+ getCurrent().init(lidAccum+1);
return retval;
}
diff --git a/vespamalloc/src/vespamalloc/malloc/threadpool.h b/vespamalloc/src/vespamalloc/malloc/threadpool.h
index 1c3bb8f84c1..f719df026fe 100644
--- a/vespamalloc/src/vespamalloc/malloc/threadpool.h
+++ b/vespamalloc/src/vespamalloc/malloc/threadpool.h
@@ -34,6 +34,7 @@ public:
*/
bool isUsed() const;
int osThreadId() const { return _osThreadId; }
+ uint32_t threadId() const { return _threadId; }
void quit() { _osThreadId = 0; } // Implicit memory barrier
void init(int thrId);
static void setParams(size_t alwayReuseLimit, size_t threadCacheLimit);
@@ -42,17 +43,16 @@ private:
bool hasActuallyBeenUsed() const;
ThreadPoolT(const ThreadPoolT & rhs);
ThreadPoolT & operator =(const ThreadPoolT & rhs);
- unsigned threadId() const { return _threadId; }
- void setThreadId(unsigned th) { _threadId = th; }
+ void setThreadId(uint32_t th) { _threadId = th; }
class AllocFree {
public:
- AllocFree() : _allocFrom(NULL), _freeTo(NULL) { }
+ AllocFree() : _allocFrom(nullptr), _freeTo(nullptr) { }
void init(AllocPool & allocPool, SizeClassT sc) {
- if (_allocFrom == NULL) {
+ if (_allocFrom == nullptr) {
_allocFrom = allocPool.getFree(sc, 1);
- assert(_allocFrom != NULL);
+ assert(_allocFrom != nullptr);
_freeTo = allocPool.getFree(sc, 1);
- assert(_freeTo != NULL);
+ assert(_freeTo != nullptr);
}
}
void swap() {
@@ -67,8 +67,9 @@ private:
AllocPool * _allocPool;
AllocFree _memList[NUM_SIZE_CLASSES];
ThreadStatT _stat[NUM_SIZE_CLASSES];
- unsigned _threadId;
+ uint32_t _threadId;
std::atomic<ssize_t> _osThreadId;
+
static SizeClassT _alwaysReuseSCLimit __attribute__((visibility("hidden")));
static size_t _threadCacheLimit __attribute__((visibility("hidden")));
};
diff --git a/vespamalloc/src/vespamalloc/malloc/threadpool.hpp b/vespamalloc/src/vespamalloc/malloc/threadpool.hpp
index cb44f74ee63..4b5277a6396 100644
--- a/vespamalloc/src/vespamalloc/malloc/threadpool.hpp
+++ b/vespamalloc/src/vespamalloc/malloc/threadpool.hpp
@@ -28,7 +28,7 @@ void ThreadPoolT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level, const
}
}
}
- if (level > 1) {
+ if (level > 2) {
fprintf(os, "BlockList:%ld,%ld,%ld\n", NELEMS(_stat), sizeof(_stat), sizeof(_stat[0]));
size_t sum(0), sumLocal(0);
for (size_t i=0; i < NELEMS(_stat); i++) {
@@ -86,7 +86,7 @@ mallocHelper(size_t exactSize,
template <typename MemBlockPtrT, typename ThreadStatT >
ThreadPoolT<MemBlockPtrT, ThreadStatT>::ThreadPoolT() :
- _allocPool(NULL),
+ _allocPool(nullptr),
_threadId(0),
_osThreadId(0)
{
@@ -170,7 +170,7 @@ bool ThreadPoolT<MemBlockPtrT, ThreadStatT>::hasActuallyBeenUsed() const
{
bool used(false);
for (size_t i=0; !used && (i < NELEMS(_memList)); i++) {
- used = (_memList[i]._allocFrom != NULL
+ used = (_memList[i]._allocFrom != nullptr
&& !_memList[i]._allocFrom->empty()
&& !_memList[i]._freeTo->full());
}
diff --git a/yolean/abi-spec.json b/yolean/abi-spec.json
index 4b68b2527b8..82bf59ebf87 100644
--- a/yolean/abi-spec.json
+++ b/yolean/abi-spec.json
@@ -40,7 +40,8 @@
"public static void uncheckAndIgnore(com.yahoo.yolean.Exceptions$RunnableThrowingIOException, java.lang.Class)",
"public static java.lang.Object uncheck(com.yahoo.yolean.Exceptions$SupplierThrowingIOException)",
"public static varargs java.lang.Object uncheck(com.yahoo.yolean.Exceptions$SupplierThrowingIOException, java.lang.String, java.lang.String[])",
- "public static java.lang.Object uncheckAndIgnore(com.yahoo.yolean.Exceptions$SupplierThrowingIOException, java.lang.Class)"
+ "public static java.lang.Object uncheckAndIgnore(com.yahoo.yolean.Exceptions$SupplierThrowingIOException, java.lang.Class)",
+ "public static java.lang.RuntimeException throwUnchecked(java.lang.Throwable)"
],
"fields": []
},
diff --git a/yolean/src/main/java/com/yahoo/yolean/Exceptions.java b/yolean/src/main/java/com/yahoo/yolean/Exceptions.java
index 063ba70c75d..c377ee3ac37 100644
--- a/yolean/src/main/java/com/yahoo/yolean/Exceptions.java
+++ b/yolean/src/main/java/com/yahoo/yolean/Exceptions.java
@@ -160,4 +160,25 @@ public class Exceptions {
public interface SupplierThrowingIOException<T> {
T get() throws IOException;
}
+
+ /**
+ * Allows treating checked exceptions as unchecked.
+ * Usage:
+ * throw throwUnchecked(e);
+ * The reason for the return type is to allow writing throw at the call site
+ * instead of just calling throwUnchecked. Just calling throwUnchecked
+ * means that the java compiler won't know that the statement will throw an exception,
+ * and will therefore complain on things such e.g. missing return value.
+ */
+ public static RuntimeException throwUnchecked(Throwable e) {
+ throwUncheckedImpl(e);
+ return new RuntimeException(); // Non-null return value to stop tooling from complaining about potential NPE
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Throwable> void throwUncheckedImpl(Throwable t) throws T {
+ throw (T)t;
+ }
+
+
}
diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/stats/LatencyMetrics.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/stats/LatencyMetrics.java
index 22af158faa9..3bfb1fca4d9 100644
--- a/zkfacade/src/main/java/com/yahoo/vespa/curator/stats/LatencyMetrics.java
+++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/stats/LatencyMetrics.java
@@ -77,6 +77,6 @@ public class LatencyMetrics {
'}';
}
- private double secondsWithMillis(Duration duration) { return round(duration.toMillis()) / 1000.0; }
+ private double secondsWithMillis(Duration duration) { return duration.toMillis() / 1000.0; }
private double roundTo3DecimalPlaces(double value) { return round(value * 1000) / 1000.0; }
}
diff --git a/zookeeper-server/CMakeLists.txt b/zookeeper-server/CMakeLists.txt
index b146390046c..2fa0caeb5fb 100644
--- a/zookeeper-server/CMakeLists.txt
+++ b/zookeeper-server/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
add_subdirectory(zookeeper-server-common)
add_subdirectory(zookeeper-server-3.5.6)
-add_subdirectory(zookeeper-server-3.5.8)
+add_subdirectory(zookeeper-server-3.6.2)
diff --git a/zookeeper-server/pom.xml b/zookeeper-server/pom.xml
index 28f18000c2d..9a3425230a5 100644
--- a/zookeeper-server/pom.xml
+++ b/zookeeper-server/pom.xml
@@ -14,7 +14,7 @@
<modules>
<module>zookeeper-server-common</module>
<module>zookeeper-server-3.5.6</module>
- <module>zookeeper-server-3.5.8</module>
+ <module>zookeeper-server-3.6.2</module>
</modules>
<dependencies>
<dependency>
diff --git a/zookeeper-server/zookeeper-server-3.5.6/CMakeLists.txt b/zookeeper-server/zookeeper-server-3.5.6/CMakeLists.txt
index b68994d32e0..0de588e0ad3 100644
--- a/zookeeper-server/zookeeper-server-3.5.6/CMakeLists.txt
+++ b/zookeeper-server/zookeeper-server-3.5.6/CMakeLists.txt
@@ -1,3 +1,4 @@
-# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
install_fat_java_artifact(zookeeper-server-3.5.6)
+# Included when this is the wanted default version (and symlinks for other versions need to be removed)
install_symlink(lib/jars/zookeeper-server-3.5.6-jar-with-dependencies.jar lib/jars/zookeeper-server-jar-with-dependencies.jar)
diff --git a/zookeeper-server/zookeeper-server-3.5.6/pom.xml b/zookeeper-server/zookeeper-server-3.5.6/pom.xml
index e50324a0488..060d1df7b2e 100644
--- a/zookeeper-server/zookeeper-server-3.5.6/pom.xml
+++ b/zookeeper-server/zookeeper-server-3.5.6/pom.xml
@@ -20,7 +20,7 @@
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
- <version>${zookeeper.server.version}</version>
+ <version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
diff --git a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java
new file mode 100644
index 00000000000..d614aecbad2
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java
@@ -0,0 +1,39 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.google.inject.Inject;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.component.AbstractComponent;
+
+import java.nio.file.Path;
+
+/**
+ * Starts or reconfigures zookeeper cluster
+ *
+ * @author hmusum
+ */
+public class ReconfigurableVespaZooKeeperServer extends AbstractComponent implements VespaZooKeeperServer {
+
+ private final VespaQuorumPeer peer;
+
+ @Inject
+ public ReconfigurableVespaZooKeeperServer(Reconfigurer reconfigurer, ZookeeperServerConfig zookeeperServerConfig) {
+ this.peer = new VespaQuorumPeer();
+ reconfigurer.startOrReconfigure(zookeeperServerConfig, this);
+ }
+
+ @Override
+ public void shutdown() {
+ peer.shutdown();
+ }
+
+ public void start(Path configFilePath) {
+ peer.start(configFilePath);
+ }
+
+ @Override
+ public boolean reconfigurable() {
+ return true;
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java
new file mode 100644
index 00000000000..86325f587eb
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java
@@ -0,0 +1,50 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.yahoo.protect.Process;
+import org.apache.zookeeper.server.admin.AdminServer;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * Starts/stops a ZooKeeper server. Extends QuorumPeerMain to be able to call initializeAndRun() and wraps
+ * exceptions so it can be used by code that does not depend on ZooKeeper.
+ *
+ * @author hmusum
+ */
+class VespaQuorumPeer extends QuorumPeerMain {
+
+ public void start(Path path) {
+ initializeAndRun(new String[]{ path.toFile().getAbsolutePath()});
+ }
+
+ public void shutdown() {
+ if (quorumPeer != null) {
+ try {
+ quorumPeer.shutdown();
+ quorumPeer.join(); // Wait for shutdown to complete
+ } catch (RuntimeException|InterruptedException e) {
+ // If shutdown fails, we have no other option than forcing the JVM to stop and letting it be restarted.
+ //
+ // When a VespaZooKeeperServer component receives a new config, the container will try to start a new
+ // server with the new config, this will fail until the old server is deconstructed. If the old server
+ // fails to deconstruct/shut down, the new one will never start and if that happens forcing a restart is
+ // the better option.
+ Process.logAndDie("Failed to shut down ZooKeeper properly, forcing shutdown", e);
+ }
+ }
+ }
+
+ @Override
+ protected void initializeAndRun(String[] args) {
+ try {
+ super.initializeAndRun(args);
+ } catch (QuorumPeerConfig.ConfigException | IOException | AdminServer.AdminServerException e) {
+ throw new RuntimeException("Exception when initializing or running ZooKeeper server", e);
+ }
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java
new file mode 100644
index 00000000000..57ae62c0ebc
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java
@@ -0,0 +1,47 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.admin.ZooKeeperAdmin;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author hmusum
+ */
+@SuppressWarnings("unused") // Created by injection
+public class VespaZooKeeperAdminImpl implements VespaZooKeeperAdmin {
+
+ private static final Logger log = java.util.logging.Logger.getLogger(VespaZooKeeperAdminImpl.class.getName());
+
+ @Override
+ public void reconfigure(String connectionSpec, String joiningServers, String leavingServers) throws ReconfigException {
+ try {
+ ZooKeeperAdmin zooKeeperAdmin = new ZooKeeperAdmin(connectionSpec,
+ (int) sessionTimeout().toMillis(),
+ (event) -> log.log(Level.INFO, event.toString()));
+ long fromConfig = -1;
+ // Using string parameters because the List variant of reconfigure fails to join empty lists (observed on 3.5.6, fixed in 3.7.0)
+ byte[] appliedConfig = zooKeeperAdmin.reconfigure(joiningServers, leavingServers, null, fromConfig, null);
+ log.log(Level.INFO, "Applied ZooKeeper config: " + new String(appliedConfig, StandardCharsets.UTF_8));
+ } catch (KeeperException e) {
+ if (retryOn(e))
+ throw new ReconfigException(e);
+ else
+ throw new RuntimeException(e);
+ } catch (IOException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static boolean retryOn(KeeperException e) {
+ return e instanceof KeeperException.ReconfigInProgress ||
+ e instanceof KeeperException.ConnectionLossException ||
+ e instanceof KeeperException.NewConfigNoQuorum;
+ }
+
+}
+
diff --git a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
index 3c42d881ecc..4dfcbeea444 100644
--- a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
+++ b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
@@ -5,25 +5,42 @@ import com.google.inject.Inject;
import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.AbstractComponent;
+import java.nio.file.Path;
+
/**
- * Main component controlling startup and stop of zookeeper server
- *
* @author Ulf Lilleengen
- * @author Harald Musum
+ * @author hmusum
*/
public class VespaZooKeeperServerImpl extends AbstractComponent implements VespaZooKeeperServer {
- private final ZooKeeperRunner zooKeeperRunner;
+ private final VespaQuorumPeer peer;
+ private final ZooKeeperRunner runner;
@Inject
public VespaZooKeeperServerImpl(ZookeeperServerConfig zookeeperServerConfig) {
- this.zooKeeperRunner = new ZooKeeperRunner(zookeeperServerConfig);
+ this.peer = new VespaQuorumPeer();
+ this.runner = new ZooKeeperRunner(zookeeperServerConfig, this);
}
@Override
public void deconstruct() {
- zooKeeperRunner.shutdown();
+ runner.shutdown();
super.deconstruct();
}
+ @Override
+ public void shutdown() {
+ peer.shutdown();
+ }
+
+ @Override
+ public void start(Path configFilePath) {
+ peer.start(configFilePath);
+ }
+
+ @Override
+ public boolean reconfigurable() {
+ return false;
+ }
+
}
diff --git a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java b/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java
deleted file mode 100644
index 492417cef96..00000000000
--- a/zookeeper-server/zookeeper-server-3.5.6/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.zookeeper;
-
-import com.yahoo.cloud.config.ZookeeperServerConfig;
-import com.yahoo.security.tls.TransportSecurityUtils;
-
-import java.util.logging.Level;
-
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
-import static com.yahoo.vespa.zookeeper.Configurator.zookeeperServerHostnames;
-
-/**
- * Writes zookeeper config and starts zookeeper server.
- *
- * @author Harald Musum
- */
-public class ZooKeeperRunner implements Runnable {
- private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ZooKeeperRunner.class.getName());
- private final Thread zkServerThread;
- private final ZookeeperServerConfig zookeeperServerConfig;
-
- public ZooKeeperRunner(ZookeeperServerConfig zookeeperServerConfig) {
- this.zookeeperServerConfig = zookeeperServerConfig;
- new Configurator(zookeeperServerConfig).writeConfigToDisk(TransportSecurityUtils.getOptions());
- zkServerThread = new Thread(this, "zookeeper server");
- zkServerThread.start();
- }
-
- void shutdown() {
- zkServerThread.interrupt();
- try {
- zkServerThread.join();
- } catch (InterruptedException e) {
- log.log(Level.WARNING, "Error joining server thread on shutdown", e);
- }
- }
-
- @Override
- public void run() {
- String[] args = new String[]{getDefaults().underVespaHome(zookeeperServerConfig.zooKeeperConfigFile())};
- log.log(Level.INFO, "Starting ZooKeeper server with config file " + args[0] +
- ". Trying to establish ZooKeeper quorum (members: " + zookeeperServerHostnames(zookeeperServerConfig) + ")");
- org.apache.zookeeper.server.quorum.QuorumPeerMain.main(args);
- }
-
- public ZookeeperServerConfig zookeeperServerConfig() {
- return zookeeperServerConfig;
- }
-}
diff --git a/zookeeper-server/zookeeper-server-3.5.8/CMakeLists.txt b/zookeeper-server/zookeeper-server-3.5.8/CMakeLists.txt
deleted file mode 100644
index 66765e34997..00000000000
--- a/zookeeper-server/zookeeper-server-3.5.8/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-install_fat_java_artifact(zookeeper-server-3.5.8)
-# TODO: Needs to be included when this is the wanted default version (and other symlinks need to be removed)
-#install_symlink(lib/jars/zookeeper-server-3.5.8-jar-with-dependencies.jar lib/jars/zookeeper-server-jar-with-dependencies.jar)
diff --git a/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java b/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
deleted file mode 100644
index 7f5b6170947..00000000000
--- a/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.zookeeper;
-
-import com.google.inject.Inject;
-import com.yahoo.cloud.config.ZookeeperServerConfig;
-import com.yahoo.component.AbstractComponent;
-import com.yahoo.security.tls.TransportSecurityUtils;
-
-import java.util.logging.Level;
-
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
-import static com.yahoo.vespa.zookeeper.Configurator.zookeeperServerHostnames;
-
-/**
- * Writes zookeeper config and starts zookeeper server.
- *
- * @author Ulf Lilleengen
- * @author Harald Musum
- */
-public class VespaZooKeeperServerImpl extends AbstractComponent implements Runnable, VespaZooKeeperServer {
-
- private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(VespaZooKeeperServerImpl.class.getName());
- private final Thread zkServerThread;
- private final ZookeeperServerConfig zookeeperServerConfig;
-
- @Inject
- public VespaZooKeeperServerImpl(ZookeeperServerConfig zookeeperServerConfig) {
- this.zookeeperServerConfig = zookeeperServerConfig;
- new Configurator(zookeeperServerConfig).writeConfigToDisk(TransportSecurityUtils.getOptions());
- zkServerThread = new Thread(this, "zookeeper server");
- zkServerThread.start();
- }
-
- private void shutdown() {
- zkServerThread.interrupt();
- try {
- zkServerThread.join();
- } catch (InterruptedException e) {
- log.log(Level.WARNING, "Error joining server thread on shutdown", e);
- }
- }
-
- @Override
- public void run() {
- String[] args = new String[]{getDefaults().underVespaHome(zookeeperServerConfig.zooKeeperConfigFile())};
- log.log(Level.INFO, "Starting ZooKeeper server with config file " + args[0] +
- ". Trying to establish ZooKeeper quorum (members: " + zookeeperServerHostnames(zookeeperServerConfig) + ")");
- org.apache.zookeeper.server.quorum.QuorumPeerMain.main(args);
- }
-
- @Override
- public void deconstruct() {
- shutdown();
- super.deconstruct();
- }
-
-}
diff --git a/zookeeper-server/zookeeper-server-3.6.2/CMakeLists.txt b/zookeeper-server/zookeeper-server-3.6.2/CMakeLists.txt
new file mode 100644
index 00000000000..e540353f113
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.6.2/CMakeLists.txt
@@ -0,0 +1,4 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+install_fat_java_artifact(zookeeper-server-3.6.2)
+# TODO: Needs to be included when this is the wanted default version (and symlinks for other versions need to be removed)
+# install_symlink(lib/jars/zookeeper-server-3.6.2-jar-with-dependencies.jar lib/jars/zookeeper-server-jar-with-dependencies.jar)
diff --git a/zookeeper-server/zookeeper-server-3.5.8/pom.xml b/zookeeper-server/zookeeper-server-3.6.2/pom.xml
index e4000285ffa..522bc71df97 100644
--- a/zookeeper-server/zookeeper-server-3.5.8/pom.xml
+++ b/zookeeper-server/zookeeper-server-3.6.2/pom.xml
@@ -8,7 +8,7 @@
<version>7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
- <artifactId>zookeeper-server-3.5.8</artifactId>
+ <artifactId>zookeeper-server-3.6.2</artifactId>
<packaging>container-plugin</packaging>
<version>7-SNAPSHOT</version>
<dependencies>
@@ -20,7 +20,7 @@
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
- <version>3.5.8</version>
+ <version>3.6.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@@ -31,6 +31,21 @@
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
+ <!-- snappy-java and metrics-core are included here
+ to be able to work with ZooKeeper 3.6.2 due to
+ class loading issues -->
+ <dependency>
+ <groupId>io.dropwizard.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ <scope>compile</scope>
+ <version>3.2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.xerial.snappy</groupId>
+ <artifactId>snappy-java</artifactId>
+ <scope>compile</scope>
+ <version>1.1.7</version>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
diff --git a/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java
new file mode 100644
index 00000000000..d614aecbad2
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/ReconfigurableVespaZooKeeperServer.java
@@ -0,0 +1,39 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.google.inject.Inject;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.component.AbstractComponent;
+
+import java.nio.file.Path;
+
+/**
+ * Starts or reconfigures zookeeper cluster
+ *
+ * @author hmusum
+ */
+public class ReconfigurableVespaZooKeeperServer extends AbstractComponent implements VespaZooKeeperServer {
+
+ private final VespaQuorumPeer peer;
+
+ @Inject
+ public ReconfigurableVespaZooKeeperServer(Reconfigurer reconfigurer, ZookeeperServerConfig zookeeperServerConfig) {
+ this.peer = new VespaQuorumPeer();
+ reconfigurer.startOrReconfigure(zookeeperServerConfig, this);
+ }
+
+ @Override
+ public void shutdown() {
+ peer.shutdown();
+ }
+
+ public void start(Path configFilePath) {
+ peer.start(configFilePath);
+ }
+
+ @Override
+ public boolean reconfigurable() {
+ return true;
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java
new file mode 100644
index 00000000000..86325f587eb
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaQuorumPeer.java
@@ -0,0 +1,50 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.yahoo.protect.Process;
+import org.apache.zookeeper.server.admin.AdminServer;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * Starts/stops a ZooKeeper server. Extends QuorumPeerMain to be able to call initializeAndRun() and wraps
+ * exceptions so it can be used by code that does not depend on ZooKeeper.
+ *
+ * @author hmusum
+ */
+class VespaQuorumPeer extends QuorumPeerMain {
+
+ public void start(Path path) {
+ initializeAndRun(new String[]{ path.toFile().getAbsolutePath()});
+ }
+
+ public void shutdown() {
+ if (quorumPeer != null) {
+ try {
+ quorumPeer.shutdown();
+ quorumPeer.join(); // Wait for shutdown to complete
+ } catch (RuntimeException|InterruptedException e) {
+ // If shutdown fails, we have no other option than forcing the JVM to stop and letting it be restarted.
+ //
+ // When a VespaZooKeeperServer component receives a new config, the container will try to start a new
+ // server with the new config, this will fail until the old server is deconstructed. If the old server
+ // fails to deconstruct/shut down, the new one will never start and if that happens forcing a restart is
+ // the better option.
+ Process.logAndDie("Failed to shut down ZooKeeper properly, forcing shutdown", e);
+ }
+ }
+ }
+
+ @Override
+ protected void initializeAndRun(String[] args) {
+ try {
+ super.initializeAndRun(args);
+ } catch (QuorumPeerConfig.ConfigException | IOException | AdminServer.AdminServerException e) {
+ throw new RuntimeException("Exception when initializing or running ZooKeeper server", e);
+ }
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java
new file mode 100644
index 00000000000..57ae62c0ebc
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdminImpl.java
@@ -0,0 +1,47 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.admin.ZooKeeperAdmin;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author hmusum
+ */
+@SuppressWarnings("unused") // Created by injection
+public class VespaZooKeeperAdminImpl implements VespaZooKeeperAdmin {
+
+ private static final Logger log = java.util.logging.Logger.getLogger(VespaZooKeeperAdminImpl.class.getName());
+
+ @Override
+ public void reconfigure(String connectionSpec, String joiningServers, String leavingServers) throws ReconfigException {
+ try {
+ ZooKeeperAdmin zooKeeperAdmin = new ZooKeeperAdmin(connectionSpec,
+ (int) sessionTimeout().toMillis(),
+ (event) -> log.log(Level.INFO, event.toString()));
+ long fromConfig = -1;
+ // Using string parameters because the List variant of reconfigure fails to join empty lists (observed on 3.5.6, fixed in 3.7.0)
+ byte[] appliedConfig = zooKeeperAdmin.reconfigure(joiningServers, leavingServers, null, fromConfig, null);
+ log.log(Level.INFO, "Applied ZooKeeper config: " + new String(appliedConfig, StandardCharsets.UTF_8));
+ } catch (KeeperException e) {
+ if (retryOn(e))
+ throw new ReconfigException(e);
+ else
+ throw new RuntimeException(e);
+ } catch (IOException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static boolean retryOn(KeeperException e) {
+ return e instanceof KeeperException.ReconfigInProgress ||
+ e instanceof KeeperException.ConnectionLossException ||
+ e instanceof KeeperException.NewConfigNoQuorum;
+ }
+
+}
+
diff --git a/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
new file mode 100644
index 00000000000..2a66bebe048
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-3.6.2/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java
@@ -0,0 +1,46 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.google.inject.Inject;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.component.AbstractComponent;
+
+import java.nio.file.Path;
+
+/**
+ * @author Ulf Lilleengen
+ * @author Harald Musum
+ */
+public class VespaZooKeeperServerImpl extends AbstractComponent implements VespaZooKeeperServer {
+
+ private final VespaQuorumPeer peer;
+ private final ZooKeeperRunner runner;
+
+ @Inject
+ public VespaZooKeeperServerImpl(ZookeeperServerConfig zookeeperServerConfig) {
+ this.peer = new VespaQuorumPeer();
+ this.runner = new ZooKeeperRunner(zookeeperServerConfig, this);
+ }
+
+ @Override
+ public void deconstruct() {
+ runner.shutdown();
+ super.deconstruct();
+ }
+
+ @Override
+ public void shutdown() {
+ peer.shutdown();
+ }
+
+ @Override
+ public void start(Path configFilePath) {
+ peer.start(configFilePath);
+ }
+
+ @Override
+ public boolean reconfigurable() {
+ return false;
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java
index ee619727b75..5f8ebf29ccd 100644
--- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java
@@ -79,7 +79,6 @@ public class Configurator {
sb.append("maxClientCnxns=").append(config.maxClientConnections()).append("\n");
sb.append("snapCount=").append(config.snapshotCount()).append("\n");
sb.append("dataDir=").append(getDefaults().underVespaHome(config.dataDir())).append("\n");
- sb.append("clientPort=").append(config.clientPort()).append("\n");
sb.append("secureClientPort=").append(config.secureClientPort()).append("\n");
sb.append("autopurge.purgeInterval=").append(config.autopurge().purgeInterval()).append("\n");
sb.append("autopurge.snapRetainCount=").append(config.autopurge().snapRetainCount()).append("\n");
@@ -92,8 +91,10 @@ public class Configurator {
sb.append("quorumListenOnAllIPs=true").append("\n");
sb.append("standaloneEnabled=false").append("\n");
sb.append("reconfigEnabled=true").append("\n");
+ sb.append("skipACL=yes").append("\n");
+ sb.append("metricsProvider.className=org.apache.zookeeper.metrics.impl.NullMetricsProvider\n");
ensureThisServerIsRepresented(config.myid(), config.server());
- config.server().forEach(server -> addServerToCfg(sb, server));
+ config.server().forEach(server -> addServerToCfg(sb, server, config.clientPort()));
SSLContext sslContext = new SslContextBuilder().build();
sb.append(new TlsQuorumConfig(sslContext, jksKeyStoreFilePath).createConfig(config, transportSecurityOptions));
sb.append(new TlsClientServerConfig(sslContext, jksKeyStoreFilePath).createConfig(config, transportSecurityOptions));
@@ -138,8 +139,27 @@ public class Configurator {
}
}
- private void addServerToCfg(StringBuilder sb, ZookeeperServerConfig.Server server) {
- sb.append("server.").append(server.id()).append("=").append(server.hostname()).append(":").append(server.quorumPort()).append(":").append(server.electionPort()).append("\n");
+ private void addServerToCfg(StringBuilder sb, ZookeeperServerConfig.Server server, int clientPort) {
+ sb.append("server.")
+ .append(server.id())
+ .append("=")
+ .append(server.hostname())
+ .append(":")
+ .append(server.quorumPort())
+ .append(":")
+ .append(server.electionPort());
+ if (server.joining()) {
+ // Servers that are joining an existing cluster must be marked as observers. Note that this will NOT
+ // actually make the server an observer, but prevent it from forming an ensemble independently of the
+ // existing cluster.
+ //
+ // See https://zookeeper.apache.org/doc/r3.6.2/zookeeperReconfig.html#sc_reconfig_modifying
+ sb.append(":")
+ .append("observer");
+ }
+ sb.append(";")
+ .append(clientPort)
+ .append("\n");
}
static Set<String> zookeeperServerHostnames(ZookeeperServerConfig zookeeperServerConfig) {
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/DummyVespaZooKeeperServer.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/DummyVespaZooKeeperServer.java
index 15e888df97e..c0b5b7c035f 100644
--- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/DummyVespaZooKeeperServer.java
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/DummyVespaZooKeeperServer.java
@@ -4,6 +4,8 @@ package com.yahoo.vespa.zookeeper;
import com.google.inject.Inject;
import com.yahoo.component.AbstractComponent;
+import java.nio.file.Path;
+
/**
* A dummy {@link VespaZooKeeperServer} implementation that can be used when a container cluster is not configured with standalone ZK cluster.
*
@@ -13,4 +15,15 @@ public class DummyVespaZooKeeperServer extends AbstractComponent implements Vesp
@Inject public DummyVespaZooKeeperServer() {}
+ @Override
+ public void shutdown() {}
+
+ @Override
+ public void start(Path configFilePath) {}
+
+ @Override
+ public boolean reconfigurable() {
+ return false;
+ }
+
}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ExponentialBackoff.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ExponentialBackoff.java
new file mode 100644
index 00000000000..9f3ca594d38
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ExponentialBackoff.java
@@ -0,0 +1,47 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import java.time.Duration;
+import java.util.Random;
+
+/**
+ * Calculate a delay using an exponential backoff algorithm. Based on ExponentialBackOff in google-http-client.
+ *
+ * @author mpolden
+ */
+public class ExponentialBackoff {
+
+ private static final double RANDOMIZATION_FACTOR = 0.5;
+
+ private final Duration initialDelay;
+ private final Duration maxDelay;
+ private final Random random;
+
+ public ExponentialBackoff(Duration initialDelay, Duration maxDelay) {
+ this(initialDelay, maxDelay, new Random());
+ }
+
+ ExponentialBackoff(Duration initialDelay, Duration maxDelay, Random random) {
+ this.initialDelay = requireNonNegative(initialDelay);
+ this.maxDelay = requireNonNegative(maxDelay);
+ this.random = random;
+ }
+
+ /** Return the delay of given attempt */
+ public Duration delay(int attempt) {
+ if (attempt < 1) throw new IllegalArgumentException("Attempt must be positive");
+ double currentDelay = attempt * initialDelay.toMillis();
+ double delta = RANDOMIZATION_FACTOR * currentDelay;
+ double lowerDelay = currentDelay - delta;
+ double upperDelay = currentDelay + delta;
+ long millis = (long) Math.min(lowerDelay + (random.nextDouble() * (upperDelay - lowerDelay + 1)),
+ maxDelay.toMillis());
+ return Duration.ofMillis(millis);
+ }
+
+ private static Duration requireNonNegative(Duration d) {
+ if (d.isNegative()) throw new IllegalArgumentException("Invalid duration: " + d);
+ return d;
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ReconfigException.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ReconfigException.java
new file mode 100644
index 00000000000..c4bb09eeedf
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ReconfigException.java
@@ -0,0 +1,21 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+/**
+ * Exception used to wrap zookeeper exception when reconfiguration fails in a
+ * class that can be used without depending on ZooKeeper.
+ *
+ * @author hmusum
+ */
+@SuppressWarnings("serial")
+public class ReconfigException extends RuntimeException {
+
+ public ReconfigException(Throwable cause) {
+ super(cause);
+ }
+
+ public ReconfigException(String message) {
+ super(message);
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Reconfigurer.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Reconfigurer.java
new file mode 100644
index 00000000000..e03988c6d4f
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Reconfigurer.java
@@ -0,0 +1,148 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.google.inject.Inject;
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.component.AbstractComponent;
+import com.yahoo.net.HostName;
+import com.yahoo.yolean.Exceptions;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ * Starts zookeeper server and supports reconfiguring zookeeper cluster. Created as a component
+ * without any config injected, to make sure that it is not recreated when config changes.
+ *
+ * @author hmusum
+ */
+public class Reconfigurer extends AbstractComponent {
+
+ private static final Logger log = java.util.logging.Logger.getLogger(Reconfigurer.class.getName());
+
+ private static final Duration MIN_TIMEOUT = Duration.ofMinutes(3);
+ private static final Duration NODE_TIMEOUT = Duration.ofMinutes(1);
+
+ private final ExponentialBackoff backoff = new ExponentialBackoff(Duration.ofSeconds(1), Duration.ofSeconds(10));
+ private final VespaZooKeeperAdmin vespaZooKeeperAdmin;
+ private final Sleeper sleeper;
+
+ private ZooKeeperRunner zooKeeperRunner;
+ private ZookeeperServerConfig activeConfig;
+
+ @Inject
+ public Reconfigurer(VespaZooKeeperAdmin vespaZooKeeperAdmin) {
+ this(vespaZooKeeperAdmin, new Sleeper());
+ }
+
+ Reconfigurer(VespaZooKeeperAdmin vespaZooKeeperAdmin, Sleeper sleeper) {
+ this.vespaZooKeeperAdmin = Objects.requireNonNull(vespaZooKeeperAdmin);
+ this.sleeper = Objects.requireNonNull(sleeper);
+ log.log(Level.FINE, "Created ZooKeeperReconfigurer");
+ }
+
+ void startOrReconfigure(ZookeeperServerConfig newConfig, VespaZooKeeperServer server) {
+ if (zooKeeperRunner == null)
+ zooKeeperRunner = startServer(newConfig, server);
+
+ if (shouldReconfigure(newConfig))
+ reconfigure(newConfig);
+ }
+
+ ZookeeperServerConfig activeConfig() {
+ return activeConfig;
+ }
+
+ void shutdown() {
+ if (zooKeeperRunner != null) {
+ zooKeeperRunner.shutdown();
+ }
+ }
+
+ private boolean shouldReconfigure(ZookeeperServerConfig newConfig) {
+ if (!newConfig.dynamicReconfiguration()) return false;
+ if (activeConfig == null) return false;
+ return !newConfig.equals(activeConfig());
+ }
+
+ private ZooKeeperRunner startServer(ZookeeperServerConfig zookeeperServerConfig, VespaZooKeeperServer server) {
+ ZooKeeperRunner runner = new ZooKeeperRunner(zookeeperServerConfig, server);
+ activeConfig = zookeeperServerConfig;
+ return runner;
+ }
+
+ private void reconfigure(ZookeeperServerConfig newConfig) {
+ Instant reconfigTriggered = Instant.now();
+ List<String> newServers = difference(servers(newConfig), servers(activeConfig));
+ String leavingServers = String.join(",", difference(serverIds(activeConfig), serverIds(newConfig)));
+ String joiningServers = String.join(",", newServers);
+ leavingServers = leavingServers.isEmpty() ? null : leavingServers;
+ joiningServers = joiningServers.isEmpty() ? null : joiningServers;
+ log.log(Level.INFO, "Will reconfigure ZooKeeper cluster. Joining servers: " + joiningServers +
+ ", leaving servers: " + leavingServers);
+ String connectionSpec = localConnectionSpec(activeConfig);
+ Instant now = Instant.now();
+ Instant end = now.plus(reconfigTimeout(newServers.size()));
+ // Loop reconfiguring since we might need to wait until another reconfiguration is finished before we can succeed
+ for (int attempt = 1; now.isBefore(end); attempt++) {
+ try {
+ Instant reconfigStarted = Instant.now();
+ vespaZooKeeperAdmin.reconfigure(connectionSpec, joiningServers, leavingServers);
+ Instant reconfigEnded = Instant.now();
+ log.log(Level.INFO, "Reconfiguration completed in " +
+ Duration.between(reconfigTriggered, reconfigEnded) +
+ ", after " + attempt + " attempt(s). ZooKeeper reconfig call took " +
+ Duration.between(reconfigStarted, reconfigEnded));
+ activeConfig = newConfig;
+ return;
+ } catch (ReconfigException e) {
+ Duration delay = backoff.delay(attempt);
+ log.log(Level.WARNING, "Reconfiguration attempt " + attempt + " failed. Retrying in " + delay +
+ ", time left " + Duration.between(now, end) + ": " +
+ Exceptions.toMessageString(e));
+ sleeper.sleep(delay);
+ } finally {
+ now = Instant.now();
+ }
+ }
+ }
+
+ /** Returns the timeout to use for the given joining server count */
+ private static Duration reconfigTimeout(int joiningServers) {
+ // For reconfig to succeed, the current ensemble must have a majority. When an ensemble grows and the joining
+ // servers outnumber the existing ones, we have to wait for enough of them to start to have a majority.
+ return Duration.ofMillis(Math.max(joiningServers * NODE_TIMEOUT.toMillis(), MIN_TIMEOUT.toMillis()));
+ }
+
+ private static String localConnectionSpec(ZookeeperServerConfig config) {
+ return HostName.getLocalhost() + ":" + config.clientPort();
+ }
+
+ private static List<String> serverIds(ZookeeperServerConfig config) {
+ return config.server().stream()
+ .map(ZookeeperServerConfig.Server::id)
+ .map(String::valueOf)
+ .collect(Collectors.toList());
+ }
+
+ private static List<String> servers(ZookeeperServerConfig config) {
+ // See https://zookeeper.apache.org/doc/r3.5.8/zookeeperReconfig.html#sc_reconfig_clientport for format
+ return config.server().stream()
+ .map(server -> server.id() + "=" + server.hostname() + ":" + server.quorumPort() + ":" +
+ server.electionPort() + ";" + config.clientPort())
+ .collect(Collectors.toList());
+ }
+
+ private static <T> List<T> difference(List<T> list1, List<T> list2) {
+ List<T> copy = new ArrayList<>(list1);
+ copy.removeAll(list2);
+ return copy;
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Sleeper.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Sleeper.java
new file mode 100644
index 00000000000..f09e82628f1
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Sleeper.java
@@ -0,0 +1,22 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import java.time.Duration;
+
+/**
+ * Wrapper around {@link Thread#sleep(long)} that can be overridden in unit tests.
+ *
+ * @author mpolden
+ */
+public class Sleeper {
+
+ public void sleep(Duration duration) {
+ try {
+ Thread.sleep(duration.toMillis());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdmin.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdmin.java
new file mode 100644
index 00000000000..1a7bf483ac5
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperAdmin.java
@@ -0,0 +1,18 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import java.time.Duration;
+
+/**
+ * Interface for administering a zookeeper cluster. Currently only supports reconfiguring a zookeeper cluster.
+ *
+ * @author hmusum
+ */
+public interface VespaZooKeeperAdmin {
+
+ void reconfigure(String connectionSpec, String joiningServers, String leavingServers) throws ReconfigException;
+
+ /* Timeout for connecting to ZooKeeper */
+ default Duration sessionTimeout() { return Duration.ofSeconds(30); }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServer.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServer.java
index 5a1f31a75c3..bb64fcc16ce 100644
--- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServer.java
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServer.java
@@ -1,11 +1,22 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.zookeeper;
+import java.nio.file.Path;
+
/**
- * Interface for a component that writes zookeeper config and starts a zookeeper server.
+ * Interface for a component that starts/stops a ZooKeeper server.
*
- * @author Harald Musum
+ * @author hmusum
*/
public interface VespaZooKeeperServer {
+ /** Shut down the server. Blocks until shutdown has completed */
+ void shutdown();
+
+ /** Start the server with the given config file */
+ void start(Path configFilePath);
+
+ /** Whether this server support dynamic reconfiguration */
+ boolean reconfigurable();
+
}
diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java
new file mode 100644
index 00000000000..812c974f9f8
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java
@@ -0,0 +1,111 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.concurrent.DaemonThreadFactory;
+import com.yahoo.protect.Process;
+import com.yahoo.security.tls.TransportSecurityUtils;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static com.yahoo.vespa.defaults.Defaults.getDefaults;
+import static com.yahoo.vespa.zookeeper.Configurator.zookeeperServerHostnames;
+
+/**
+ * Writes zookeeper config and starts zookeeper server.
+ *
+ * @author Harald Musum
+ */
+public class ZooKeeperRunner implements Runnable {
+
+ private static final Logger log = java.util.logging.Logger.getLogger(ZooKeeperRunner.class.getName());
+ private static final Duration STOP_TIMEOUT = Duration.ofSeconds(10);
+ private static final Duration START_TIMEOUT = Duration.ofMinutes(10);
+
+ private final ExecutorService executorService;
+ private final ZookeeperServerConfig zookeeperServerConfig;
+ private final VespaZooKeeperServer server;
+ private final ExponentialBackoff backoff = new ExponentialBackoff(Duration.ofSeconds(5), Duration.ofSeconds(15));
+ private final Sleeper sleeper = new Sleeper();
+
+ public ZooKeeperRunner(ZookeeperServerConfig zookeeperServerConfig, VespaZooKeeperServer server) {
+ this.zookeeperServerConfig = zookeeperServerConfig;
+ this.server = server;
+ new Configurator(zookeeperServerConfig).writeConfigToDisk(TransportSecurityUtils.getOptions());
+ executorService = Executors.newSingleThreadExecutor(new DaemonThreadFactory("zookeeper server"));
+ executorService.submit(this);
+ }
+
+ void shutdown() {
+ log.log(Level.INFO, "Triggering shutdown");
+ server.shutdown();
+ executorService.shutdownNow();
+ try {
+ if (!executorService.awaitTermination(STOP_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)) {
+ log.log(Level.WARNING, "Failed to shut down within " + STOP_TIMEOUT);
+ }
+ } catch (InterruptedException e) {
+ log.log(Level.WARNING, "Interrupted waiting for executor to complete", e);
+ }
+ }
+
+ @Override
+ public void run() {
+ Path path = Paths.get(getDefaults().underVespaHome(zookeeperServerConfig.zooKeeperConfigFile()));
+
+ // Retry start of server. An already running server might take some time to shut down, starting a new
+ // one will fail in that case, so retry
+ Instant now = Instant.now();
+ Instant end = now.plus(START_TIMEOUT);
+ for (int attempt = 1; now.isBefore(end) && !executorService.isShutdown(); attempt++) {
+ try {
+ log.log(Level.INFO, "Starting ZooKeeper server with config file " + path.toFile().getAbsolutePath() +
+ ". Trying to establish ZooKeeper quorum (members: " +
+ zookeeperServerHostnames(zookeeperServerConfig) + ", attempt: " + attempt + ")");
+ startServer(path); // Will block in a real implementation of VespaZooKeeperServer
+ return;
+ } catch (RuntimeException e) {
+ String messagePart = "Starting " + serverDescription() + " failed on attempt " +
+ attempt;
+ if (server.reconfigurable()) {
+ Duration delay = backoff.delay(attempt);
+ log.log(Level.WARNING, messagePart + ". Retrying in " + delay + ", time left " +
+ Duration.between(now, end), e);
+ sleeper.sleep(delay);
+ } else {
+ Process.logAndDie(messagePart + ". Forcing shutdown", e);
+ }
+ } finally {
+ now = Instant.now();
+ }
+ }
+ }
+
+ private String serverDescription() {
+ return (server.reconfigurable() ? "" : "non-") + "reconfigurable ZooKeeper server";
+ }
+
+ private void startServer(Path path) {
+ // Note: Hack to make this work in ZooKeeper 3.6, where metrics provider class is
+ // loaded by using Thread.currentThread().getContextClassLoader() which does not work
+ // well in the container
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+ try {
+ server.start(path);
+ } catch (Throwable e) {
+ throw new RuntimeException("Starting " + serverDescription() + " failed", e);
+ } finally {
+ Thread.currentThread().setContextClassLoader(tccl);
+ }
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java
index 0356407da3e..0f43fb45d9d 100644
--- a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java
+++ b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java
@@ -2,11 +2,11 @@
package com.yahoo.vespa.zookeeper;
import com.yahoo.cloud.config.ZookeeperServerConfig;
-import com.yahoo.io.IOUtils;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.X509CertificateBuilder;
import com.yahoo.security.X509CertificateUtils;
import com.yahoo.security.tls.TransportSecurityOptions;
+import com.yahoo.yolean.Exceptions;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -15,6 +15,7 @@ import org.junit.rules.TemporaryFolder;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -22,14 +23,14 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Optional;
-import static com.yahoo.cloud.config.ZookeeperServerConfig.TlsForQuorumCommunication;
import static com.yahoo.cloud.config.ZookeeperServerConfig.TlsForClientServerCommunication;
+import static com.yahoo.cloud.config.ZookeeperServerConfig.TlsForQuorumCommunication;
import static com.yahoo.security.KeyAlgorithm.EC;
import static com.yahoo.security.SignatureAlgorithm.SHA256_WITH_ECDSA;
+import static com.yahoo.vespa.defaults.Defaults.getDefaults;
import static com.yahoo.vespa.zookeeper.Configurator.ZOOKEEPER_JUTE_MAX_BUFFER;
import static java.time.Instant.EPOCH;
import static java.time.temporal.ChronoUnit.DAYS;
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -53,7 +54,7 @@ public class ConfiguratorTest {
}
@Test
- public void config_is_written_correctly_when_one_server() throws IOException {
+ public void config_is_written_correctly_when_one_server() {
ZookeeperServerConfig.Builder builder = createConfigBuilderForSingleHost(cfgFile, idFile, jksKeyStoreFile);
new Configurator(builder.build()).writeConfigToDisk(Optional.empty());
validateConfigFileSingleHost(cfgFile);
@@ -61,12 +62,12 @@ public class ConfiguratorTest {
}
@Test
- public void config_is_written_correctly_when_multiple_servers() throws IOException {
+ public void config_is_written_correctly_when_multiple_servers() {
ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
builder.zooKeeperConfigFile(cfgFile.getAbsolutePath());
- builder.server(newServer(0, "foo", 123, 321));
- builder.server(newServer(1, "bar", 234, 432));
- builder.server(newServer(2, "baz", 345, 543));
+ builder.server(newServer(0, "foo", 123, 321, false));
+ builder.server(newServer(1, "bar", 234, 432, false));
+ builder.server(newServer(2, "baz", 345, 543, true));
builder.myidFile(idFile.getAbsolutePath());
builder.myid(1);
new Configurator(builder.build()).writeConfigToDisk(Optional.empty());
@@ -75,7 +76,7 @@ public class ConfiguratorTest {
}
@Test
- public void config_is_written_correctly_with_tls_for_quorum_communication_port_unification() throws IOException {
+ public void config_is_written_correctly_with_tls_for_quorum_communication_port_unification() {
ZookeeperServerConfig.Builder builder = createConfigBuilderForSingleHost(cfgFile, idFile, jksKeyStoreFile);
builder.tlsForQuorumCommunication(TlsForQuorumCommunication.PORT_UNIFICATION);
builder.tlsForClientServerCommunication(TlsForClientServerCommunication.PORT_UNIFICATION);
@@ -86,7 +87,7 @@ public class ConfiguratorTest {
}
@Test
- public void config_is_written_correctly_with_tls_for_quorum_communication_tls_with_port_unification() throws IOException {
+ public void config_is_written_correctly_with_tls_for_quorum_communication_tls_with_port_unification() {
ZookeeperServerConfig.Builder builder = createConfigBuilderForSingleHost(cfgFile, idFile, jksKeyStoreFile);
builder.tlsForQuorumCommunication(TlsForQuorumCommunication.TLS_WITH_PORT_UNIFICATION);
builder.tlsForClientServerCommunication(TlsForClientServerCommunication.TLS_WITH_PORT_UNIFICATION);
@@ -97,7 +98,7 @@ public class ConfiguratorTest {
}
@Test
- public void config_is_written_correctly_with_tls_for_quorum_communication_tls_only() throws IOException {
+ public void config_is_written_correctly_with_tls_for_quorum_communication_tls_only() {
ZookeeperServerConfig.Builder builder = createConfigBuilderForSingleHost(cfgFile, idFile, jksKeyStoreFile);
builder.tlsForQuorumCommunication(TlsForQuorumCommunication.TLS_ONLY);
builder.tlsForClientServerCommunication(TlsForClientServerCommunication.TLS_ONLY);
@@ -107,28 +108,18 @@ public class ConfiguratorTest {
validateThatJksKeyStoreFileExists(jksKeyStoreFile);
}
- private ZookeeperServerConfig.Builder createConfigBuilderForSingleHost(File cfgFile, File idFile, File jksKeyStoreFile) {
- ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
- builder.zooKeeperConfigFile(cfgFile.getAbsolutePath());
- builder.myidFile(idFile.getAbsolutePath());
- builder.server(newServer(0, "foo", 123, 321));
- builder.myid(0);
- builder.jksKeyStoreFile(jksKeyStoreFile.getAbsolutePath());
- return builder;
- }
-
@Test(expected = RuntimeException.class)
public void require_that_this_id_must_be_present_amongst_servers() {
ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
builder.zooKeeperConfigFile(cfgFile.getAbsolutePath());
- builder.server(newServer(1, "bar", 234, 432));
- builder.server(newServer(2, "baz", 345, 543));
+ builder.server(newServer(1, "bar", 234, 432, false));
+ builder.server(newServer(2, "baz", 345, 543, false));
builder.myid(0);
new Configurator(builder.build()).writeConfigToDisk(Optional.empty());
}
@Test
- public void juteMaxBufferCanBeSet() throws IOException {
+ public void jute_max_buffer_can_be_set() throws IOException {
ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
builder.myid(0);
File idFile = folder.newFile();
@@ -147,17 +138,28 @@ public class ConfiguratorTest {
assertEquals("" + max_buffer, System.getProperty(ZOOKEEPER_JUTE_MAX_BUFFER));
}
- private ZookeeperServerConfig.Server.Builder newServer(int id, String hostName, int electionPort, int quorumPort) {
+ private ZookeeperServerConfig.Builder createConfigBuilderForSingleHost(File cfgFile, File idFile, File jksKeyStoreFile) {
+ ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
+ builder.zooKeeperConfigFile(cfgFile.getAbsolutePath());
+ builder.myidFile(idFile.getAbsolutePath());
+ builder.server(newServer(0, "foo", 123, 321, false));
+ builder.myid(0);
+ builder.jksKeyStoreFile(jksKeyStoreFile.getAbsolutePath());
+ return builder;
+ }
+
+ private ZookeeperServerConfig.Server.Builder newServer(int id, String hostName, int electionPort, int quorumPort, boolean joining) {
ZookeeperServerConfig.Server.Builder builder = new ZookeeperServerConfig.Server.Builder();
builder.id(id);
builder.hostname(hostName);
builder.electionPort(electionPort);
builder.quorumPort(quorumPort);
+ builder.joining(joining);
return builder;
}
- private void validateIdFile(File idFile, String expected) throws IOException {
- String actual = IOUtils.readFile(idFile);
+ private void validateIdFile(File idFile, String expected) {
+ String actual = Exceptions.uncheck(() -> Files.readString(idFile.toPath()));
assertEquals(expected, actual);
}
@@ -168,7 +170,6 @@ public class ConfiguratorTest {
"maxClientCnxns=0\n" +
"snapCount=50000\n" +
"dataDir=" + getDefaults().underVespaHome("var/zookeeper") + "\n" +
- "clientPort=2181\n" +
"secureClientPort=2184\n" +
"autopurge.purgeInterval=1\n" +
"autopurge.snapRetainCount=15\n" +
@@ -177,7 +178,9 @@ public class ConfiguratorTest {
"serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory\n" +
"quorumListenOnAllIPs=true\n" +
"standaloneEnabled=false\n" +
- "reconfigEnabled=true\n";
+ "reconfigEnabled=true\n" +
+ "skipACL=yes\n" +
+ "metricsProvider.className=org.apache.zookeeper.metrics.impl.NullMetricsProvider\n";
}
private String quorumKeyStoreAndTrustStoreConfig(File jksKeyStoreFilePath, File caCertificatesFilePath) {
@@ -200,10 +203,10 @@ public class ConfiguratorTest {
return sb.toString();
}
- private void validateConfigFileSingleHost(File cfgFile) throws IOException {
+ private void validateConfigFileSingleHost(File cfgFile) {
String expected =
commonConfig() +
- "server.0=foo:321:123\n" +
+ "server.0=foo:321:123;2181\n" +
commonTlsQuorumConfig() +
"sslQuorum=false\n" +
"portUnification=false\n" +
@@ -228,12 +231,12 @@ public class ConfiguratorTest {
"ssl.protocol=TLS\n";
}
- private void validateConfigFileMultipleHosts(File cfgFile) throws IOException {
+ private void validateConfigFileMultipleHosts(File cfgFile) {
String expected =
commonConfig() +
- "server.0=foo:321:123\n" +
- "server.1=bar:432:234\n" +
- "server.2=baz:543:345\n" +
+ "server.0=foo:321:123;2181\n" +
+ "server.1=bar:432:234;2181\n" +
+ "server.2=baz:543:345:observer;2181\n" +
commonTlsQuorumConfig() +
"sslQuorum=false\n" +
"portUnification=false\n" +
@@ -242,10 +245,10 @@ public class ConfiguratorTest {
validateConfigFile(cfgFile, expected);
}
- private void validateConfigFilePortUnification(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) throws IOException {
+ private void validateConfigFilePortUnification(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) {
String expected =
commonConfig() +
- "server.0=foo:321:123\n" +
+ "server.0=foo:321:123;2181\n" +
commonTlsQuorumConfig() +
"sslQuorum=false\n" +
"portUnification=true\n" +
@@ -256,10 +259,10 @@ public class ConfiguratorTest {
validateConfigFile(cfgFile, expected);
}
- private void validateConfigFileTlsWithPortUnification(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) throws IOException {
+ private void validateConfigFileTlsWithPortUnification(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) {
String expected =
commonConfig() +
- "server.0=foo:321:123\n" +
+ "server.0=foo:321:123;2181\n" +
commonTlsQuorumConfig() +
"sslQuorum=true\n" +
"portUnification=true\n" +
@@ -270,10 +273,10 @@ public class ConfiguratorTest {
validateConfigFile(cfgFile, expected);
}
- private void validateConfigFileTlsOnly(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) throws IOException {
+ private void validateConfigFileTlsOnly(File cfgFile, File jksKeyStoreFile, File caCertificatesFile) {
String expected =
commonConfig() +
- "server.0=foo:321:123\n" +
+ "server.0=foo:321:123;2181\n" +
commonTlsQuorumConfig() +
"sslQuorum=true\n" +
"portUnification=false\n" +
@@ -284,8 +287,8 @@ public class ConfiguratorTest {
validateConfigFile(cfgFile, expected);
}
- private void validateConfigFile(File cfgFile, String expected) throws IOException {
- String actual = IOUtils.readFile(cfgFile);
+ private void validateConfigFile(File cfgFile, String expected) {
+ String actual = Exceptions.uncheck(() -> Files.readString(cfgFile.toPath()));
assertEquals(expected, actual);
}
@@ -293,25 +296,29 @@ public class ConfiguratorTest {
assertTrue(cfgFile.exists() && cfgFile.canRead());
}
- private Optional<TransportSecurityOptions> createTransportSecurityOptions() throws IOException {
- KeyPair keyPair = KeyUtils.generateKeypair(EC);
- Path privateKeyFile = folder.newFile().toPath();
- Files.writeString(privateKeyFile, KeyUtils.toPem(keyPair.getPrivate()));
-
- X509Certificate certificate = X509CertificateBuilder
- .fromKeypair(keyPair, new X500Principal("CN=dummy"), EPOCH, EPOCH.plus(1, DAYS), SHA256_WITH_ECDSA, BigInteger.ONE)
- .build();
- Path certificateChainFile = folder.newFile().toPath();
- String certificatePem = X509CertificateUtils.toPem(certificate);
- Files.writeString(certificateChainFile, certificatePem);
-
- Path caCertificatesFile = folder.newFile().toPath();
- Files.writeString(caCertificatesFile, certificatePem);
-
- return Optional.of(new TransportSecurityOptions.Builder()
- .withCertificates(certificateChainFile, privateKeyFile)
- .withCaCertificates(caCertificatesFile)
- .build());
+ private Optional<TransportSecurityOptions> createTransportSecurityOptions() {
+ try {
+ KeyPair keyPair = KeyUtils.generateKeypair(EC);
+ Path privateKeyFile = folder.newFile().toPath();
+ Files.writeString(privateKeyFile, KeyUtils.toPem(keyPair.getPrivate()));
+
+ X509Certificate certificate = X509CertificateBuilder
+ .fromKeypair(keyPair, new X500Principal("CN=dummy"), EPOCH, EPOCH.plus(1, DAYS), SHA256_WITH_ECDSA, BigInteger.ONE)
+ .build();
+ Path certificateChainFile = folder.newFile().toPath();
+ String certificatePem = X509CertificateUtils.toPem(certificate);
+ Files.writeString(certificateChainFile, certificatePem);
+
+ Path caCertificatesFile = folder.newFile().toPath();
+ Files.writeString(caCertificatesFile, certificatePem);
+
+ return Optional.of(new TransportSecurityOptions.Builder()
+ .withCertificates(certificateChainFile, privateKeyFile)
+ .withCaCertificates(caCertificatesFile)
+ .build());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
}
diff --git a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ExponentialBackoffTest.java b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ExponentialBackoffTest.java
new file mode 100644
index 00000000000..65e367f8ae8
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ExponentialBackoffTest.java
@@ -0,0 +1,32 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import org.junit.Test;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author mpolden
+ */
+public class ExponentialBackoffTest {
+
+ @Test
+ public void delay() {
+ ExponentialBackoff b = new ExponentialBackoff(Duration.ofSeconds(1), Duration.ofSeconds(10), new Random(1000));
+ assertEquals(List.of(Duration.ofMillis(1210),
+ Duration.ofMillis(2150),
+ Duration.ofMillis(4340),
+ Duration.ofMillis(2157),
+ Duration.ofMillis(4932)),
+ IntStream.rangeClosed(1, 5)
+ .mapToObj(b::delay)
+ .collect(Collectors.toList()));
+ }
+
+}
diff --git a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ReconfigurerTest.java b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ReconfigurerTest.java
new file mode 100644
index 00000000000..a1b98a23bd0
--- /dev/null
+++ b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ReconfigurerTest.java
@@ -0,0 +1,203 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.zookeeper;
+
+import com.yahoo.cloud.config.ZookeeperServerConfig;
+import com.yahoo.net.HostName;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.stream.IntStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests dynamic reconfiguration of zookeeper cluster.
+ *
+ * @author hmusum
+ */
+public class ReconfigurerTest {
+
+ private File cfgFile;
+ private File idFile;
+ private TestableReconfigurer reconfigurer;
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ @Before
+ public void setup() throws IOException {
+ cfgFile = folder.newFile();
+ idFile = folder.newFile("myid");
+ reconfigurer = new TestableReconfigurer(new TestableVespaZooKeeperAdmin());
+ }
+
+ @Test
+ public void testReconfigure() {
+ ZookeeperServerConfig initialConfig = createConfig(3, true);
+ reconfigurer.startOrReconfigure(initialConfig);
+ assertSame(initialConfig, reconfigurer.activeConfig());
+
+ // Cluster grows
+ ZookeeperServerConfig nextConfig = createConfig(5, true);
+ reconfigurer.startOrReconfigure(nextConfig);
+ assertEquals("node1:2181", reconfigurer.connectionSpec());
+ assertEquals("3=node3:2182:2183;2181,4=node4:2182:2183;2181", reconfigurer.joiningServers());
+ assertNull("No servers are leaving", reconfigurer.leavingServers());
+ assertEquals(1, reconfigurer.reconfigurations());
+ assertSame(nextConfig, reconfigurer.activeConfig());
+
+ // No reconfiguration happens with same config
+ reconfigurer.startOrReconfigure(nextConfig);
+ assertEquals(1, reconfigurer.reconfigurations());
+ assertSame(nextConfig, reconfigurer.activeConfig());
+
+ // Cluster shrinks
+ nextConfig = createConfig(3, true);
+ reconfigurer.startOrReconfigure(nextConfig);
+ assertEquals(2, reconfigurer.reconfigurations());
+ assertEquals("node1:2181", reconfigurer.connectionSpec());
+ assertNull("No servers are joining", reconfigurer.joiningServers());
+ assertEquals("3,4", reconfigurer.leavingServers());
+ assertSame(nextConfig, reconfigurer.activeConfig());
+ }
+
+ @Test
+ public void testReconfigureFailsWithReconfigInProgressThenSucceeds() {
+ TestableReconfigurer reconfigurer = new TestableReconfigurer(new TestableVespaZooKeeperAdmin().failures(3));
+ try {
+ ZookeeperServerConfig initialConfig = createConfig(3, true);
+ reconfigurer.startOrReconfigure(initialConfig);
+ assertSame(initialConfig, reconfigurer.activeConfig());
+
+ ZookeeperServerConfig nextConfig = createConfig(5, true);
+ reconfigurer.startOrReconfigure(nextConfig);
+ assertEquals("node1:2181", reconfigurer.connectionSpec());
+ assertEquals("3=node3:2182:2183;2181,4=node4:2182:2183;2181", reconfigurer.joiningServers());
+ assertNull("No servers are leaving", reconfigurer.leavingServers());
+ assertEquals(1, reconfigurer.reconfigurations());
+ assertSame(nextConfig, reconfigurer.activeConfig());
+ } finally {
+ reconfigurer.shutdown();
+ }
+ }
+
+ @Test
+ public void testDynamicReconfigurationDisabled() {
+ ZookeeperServerConfig initialConfig = createConfig(3, false);
+ reconfigurer.startOrReconfigure(initialConfig);
+ assertSame(initialConfig, reconfigurer.activeConfig());
+
+ ZookeeperServerConfig nextConfig = createConfig(5, false);
+ reconfigurer.startOrReconfigure(nextConfig);
+ assertSame(initialConfig, reconfigurer.activeConfig());
+ assertEquals(0, reconfigurer.reconfigurations());
+ }
+
+ @After
+ public void stopReconfigurer() {
+ reconfigurer.shutdown();
+ }
+
+ private ZookeeperServerConfig createConfig(int numberOfServers, boolean dynamicReconfiguration) {
+ ZookeeperServerConfig.Builder builder = new ZookeeperServerConfig.Builder();
+ builder.zooKeeperConfigFile(cfgFile.getAbsolutePath());
+ builder.myidFile(idFile.getAbsolutePath());
+ IntStream.range(0, numberOfServers).forEach(i -> builder.server(newServer(i, "node" + i)));
+ builder.myid(0);
+ builder.dynamicReconfiguration(dynamicReconfiguration);
+ return builder.build();
+ }
+
+ private ZookeeperServerConfig.Server.Builder newServer(int id, String hostName) {
+ ZookeeperServerConfig.Server.Builder builder = new ZookeeperServerConfig.Server.Builder();
+ builder.id(id);
+ builder.hostname(hostName);
+ return builder;
+ }
+
+ private static class TestableReconfigurer extends Reconfigurer implements VespaZooKeeperServer {
+
+ private final TestableVespaZooKeeperAdmin zooKeeperAdmin;
+
+ TestableReconfigurer(TestableVespaZooKeeperAdmin zooKeeperAdmin) {
+ super(zooKeeperAdmin, new Sleeper() {
+ @Override
+ public void sleep(Duration duration) {
+ // Do nothing
+ }
+ });
+ this.zooKeeperAdmin = zooKeeperAdmin;
+ HostName.setHostNameForTestingOnly("node1");
+ }
+
+ void startOrReconfigure(ZookeeperServerConfig newConfig) {
+ startOrReconfigure(newConfig, this);
+ }
+
+ String connectionSpec() {
+ return zooKeeperAdmin.connectionSpec;
+ }
+
+ String joiningServers() {
+ return zooKeeperAdmin.joiningServers;
+ }
+
+ String leavingServers() {
+ return zooKeeperAdmin.leavingServers;
+ }
+
+ int reconfigurations() {
+ return zooKeeperAdmin.reconfigurations;
+ }
+
+ @Override
+ public void shutdown() {}
+
+ @Override
+ public void start(Path configFilePath) { }
+
+ @Override
+ public boolean reconfigurable() {
+ return true;
+ }
+
+ }
+
+ private static class TestableVespaZooKeeperAdmin implements VespaZooKeeperAdmin {
+
+ String connectionSpec;
+ String joiningServers;
+ String leavingServers;
+ int reconfigurations = 0;
+
+ private int failures = 0;
+ private int attempts = 0;
+
+ public TestableVespaZooKeeperAdmin failures(int failures) {
+ this.failures = failures;
+ return this;
+ }
+
+ @Override
+ public void reconfigure(String connectionSpec, String joiningServers, String leavingServers) throws ReconfigException {
+ if (++attempts < failures)
+ throw new ReconfigException("Reconfig failed");
+ this.connectionSpec = connectionSpec;
+ this.joiningServers = joiningServers;
+ this.leavingServers = leavingServers;
+ this.reconfigurations++;
+ }
+
+ }
+
+
+}