diff options
38 files changed, 564 insertions, 199 deletions
diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 1fc39b8fa1d..5d9ae6bc26e 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1460,6 +1460,25 @@ ], "fields" : [ ] }, + "com.yahoo.config.model.api.OnnxModelCost$DisabledOnnxModelCost" : { + "superClass" : "java.lang.Object", + "interfaces" : [ + "com.yahoo.config.model.api.OnnxModelCost", + "com.yahoo.config.model.api.OnnxModelCost$Calculator" + ], + "attributes" : [ + "public" + ], + "methods" : [ + "public void <init>()", + "public com.yahoo.config.model.api.OnnxModelCost$Calculator newCalculator(com.yahoo.config.application.api.ApplicationPackage, com.yahoo.config.application.api.DeployLogger)", + "public com.yahoo.config.model.api.OnnxModelCost$Calculator newCalculator(com.yahoo.config.application.api.ApplicationPackage, com.yahoo.config.provision.ApplicationId)", + "public long aggregatedModelCostInBytes()", + "public void registerModel(com.yahoo.config.application.api.ApplicationFile)", + "public void registerModel(java.net.URI)" + ], + "fields" : [ ] + }, "com.yahoo.config.model.api.OnnxModelCost" : { "superClass" : "java.lang.Object", "interfaces" : [ ], @@ -1470,6 +1489,7 @@ ], "methods" : [ "public abstract com.yahoo.config.model.api.OnnxModelCost$Calculator newCalculator(com.yahoo.config.application.api.ApplicationPackage, com.yahoo.config.application.api.DeployLogger)", + "public abstract com.yahoo.config.model.api.OnnxModelCost$Calculator newCalculator(com.yahoo.config.application.api.ApplicationPackage, com.yahoo.config.provision.ApplicationId)", "public static com.yahoo.config.model.api.OnnxModelCost disabled()" ], "fields" : [ ] diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java b/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java index 6ce46e4f2af..02a32852e08 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java @@ -5,6 +5,7 @@ package com.yahoo.config.model.api; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.config.application.api.ApplicationPackage; import com.yahoo.config.application.api.DeployLogger; +import com.yahoo.config.provision.ApplicationId; import java.net.URI; @@ -13,7 +14,8 @@ import java.net.URI; */ public interface OnnxModelCost { - Calculator newCalculator(ApplicationPackage appPkg, DeployLogger logger); + Calculator newCalculator(ApplicationPackage appPkg, DeployLogger deployLogger); // TODO: Remove when 8.249 is oldest model in use + Calculator newCalculator(ApplicationPackage appPkg, ApplicationId applicationId); interface Calculator { long aggregatedModelCostInBytes(); @@ -21,12 +23,14 @@ public interface OnnxModelCost { void registerModel(URI uri); } - static OnnxModelCost disabled() { - return (__, ___) -> new Calculator() { - @Override public long aggregatedModelCostInBytes() { return 0; } - @Override public void registerModel(ApplicationFile path) {} - @Override public void registerModel(URI uri) {} - }; + static OnnxModelCost disabled() { return new DisabledOnnxModelCost(); } + + class DisabledOnnxModelCost implements OnnxModelCost, Calculator { + @Override public Calculator newCalculator(ApplicationPackage appPkg, DeployLogger deployLogger) { return this; } + @Override public Calculator newCalculator(ApplicationPackage appPkg, ApplicationId applicationId) { return this; } + @Override public long aggregatedModelCostInBytes() {return 0;} + @Override public void registerModel(ApplicationFile path) {} + @Override public void registerModel(URI uri) {} } } diff --git a/config-model/src/main/java/com/yahoo/schema/processing/MakeDefaultSummaryTheSuperSet.java b/config-model/src/main/java/com/yahoo/schema/processing/MakeDefaultSummaryTheSuperSet.java index 610021c510d..420df3ee575 100644 --- a/config-model/src/main/java/com/yahoo/schema/processing/MakeDefaultSummaryTheSuperSet.java +++ b/config-model/src/main/java/com/yahoo/schema/processing/MakeDefaultSummaryTheSuperSet.java @@ -41,6 +41,7 @@ public class MakeDefaultSummaryTheSuperSet extends Processor { if (summaryField.getTransform() == SummaryTransform.ATTRIBUTE) continue; if (summaryField.getTransform() == SummaryTransform.ATTRIBUTECOMBINER) continue; if (summaryField.getTransform() == SummaryTransform.MATCHED_ATTRIBUTE_ELEMENTS_FILTER) continue; + if (summaryField.getTransform() == SummaryTransform.TOKENS) continue; defaultSummary.add(summaryField.clone()); } diff --git a/config-model/src/test/java/com/yahoo/schema/derived/SummaryTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/SummaryTestCase.java index 1c03c66d17b..5019ed0dd60 100644 --- a/config-model/src/test/java/com/yahoo/schema/derived/SummaryTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/derived/SummaryTestCase.java @@ -237,6 +237,7 @@ public class SummaryTestCase extends AbstractSchemaTestCase { " from-disk", "}")); assertOverride(schema, "baz", SummaryTransform.TOKENS.getName(), "foo", "bar"); + assert(!schema.getSummary("default").getSummaryFields().containsKey("baz")); } @Test diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java index 9d4b8837d34..fd8e93d73ed 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java @@ -13,6 +13,7 @@ import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.model.test.MockApplicationPackage; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.NodeResources; import com.yahoo.text.Text; import com.yahoo.vespa.model.VespaModel; @@ -119,7 +120,10 @@ class JvmHeapSizeValidatorTest { ModelCostDummy(long modelCost) { this.modelCost = modelCost; } - @Override public Calculator newCalculator(ApplicationPackage appPkg, DeployLogger logger) { return this; } + @Override + public Calculator newCalculator(ApplicationPackage appPkg, DeployLogger deployLogger) { return this; } + + @Override public Calculator newCalculator(ApplicationPackage appPkg, ApplicationId applicationId) { return this; } @Override public long aggregatedModelCostInBytes() { return totalCost.get(); } @Override public void registerModel(ApplicationFile path) {} diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java index 266ede04800..0eac568ec45 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java @@ -88,6 +88,14 @@ public enum NodeType { return childNodeTypes.contains(type); } + /** Returns the parent host type. */ + public NodeType parentNodeType() { + for (var type : values()) { + if (type.childNodeTypes.contains(this)) return type; + } + throw new IllegalStateException(this + " has no parent"); + } + /** Returns the host type of this */ public NodeType hostType() { if (isHost()) return this; @@ -97,7 +105,7 @@ public enum NodeType { return nodeType; } } - throw new IllegalArgumentException("No host of " + this + " exists"); + throw new IllegalStateException("No host of " + this + " exists"); } } 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 82732a00dc4..dcc5d7caa0d 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 @@ -16,7 +16,7 @@ import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.filedistribution.FileDistributionConnectionPool; import com.yahoo.vespa.filedistribution.FileDownloader; import com.yahoo.vespa.filedistribution.FileReferenceDownload; -import com.yahoo.vespa.flags.FlagSource; + import java.io.File; import java.time.Duration; import java.util.List; @@ -24,6 +24,7 @@ import java.util.Optional; import java.util.logging.Logger; import static com.yahoo.vespa.config.server.filedistribution.FileDistributionUtil.fileReferenceExistsOnDisk; +import static com.yahoo.vespa.config.server.filedistribution.FileDistributionUtil.getOtherConfigServersInCluster; /** * Verifies that all active sessions has an application package on local disk. @@ -37,20 +38,14 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer { private static final Logger log = Logger.getLogger(ApplicationPackageMaintainer.class.getName()); - private final ApplicationRepository applicationRepository; private final File downloadDirectory; private final Supervisor supervisor = new Supervisor(new Transport("filedistribution-pool")).setDropEmptyBuffers(true); private final FileDownloader fileDownloader; - ApplicationPackageMaintainer(ApplicationRepository applicationRepository, - Curator curator, - Duration interval, - FlagSource flagSource, - List<String> otherConfigServersInCluster) { - super(applicationRepository, curator, flagSource, applicationRepository.clock(), interval, false); - this.applicationRepository = applicationRepository; + ApplicationPackageMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval) { + super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), interval, false); this.downloadDirectory = new File(Defaults.getDefaults().underVespaHome(applicationRepository.configserverConfig().fileReferencesDir())); - this.fileDownloader = createFileDownloader(otherConfigServersInCluster, downloadDirectory, supervisor); + this.fileDownloader = createFileDownloader(applicationRepository, downloadDirectory, supervisor); } @Override @@ -91,9 +86,10 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer { return asSuccessFactorDeviation(attempts, failures); } - private static FileDownloader createFileDownloader(List<String> otherConfigServersInCluster, + private static FileDownloader createFileDownloader(ApplicationRepository applicationRepository, File downloadDirectory, Supervisor supervisor) { + List<String> otherConfigServersInCluster = getOtherConfigServersInCluster(applicationRepository.configserverConfig()); ConfigSourceSet configSourceSet = new ConfigSourceSet(otherConfigServersInCluster); ConnectionPool connectionPool = new FileDistributionConnectionPool(configSourceSet, supervisor); return new FileDownloader(connectionPool, supervisor, downloadDirectory, Duration.ofSeconds(300)); 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 a3e774feec4..dbd30f72c24 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 @@ -6,7 +6,7 @@ import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker; import com.yahoo.vespa.config.server.filedistribution.FileDirectory; import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.flags.FlagSource; + import java.time.Clock; import java.time.Duration; import java.util.List; @@ -26,7 +26,6 @@ public class ConfigServerMaintenance { private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>(); private final ApplicationRepository applicationRepository; private final Curator curator; - private final FlagSource flagSource; private final ConfigConvergenceChecker convergenceChecker; private final FileDirectory fileDirectory; private final Duration interval; @@ -34,28 +33,21 @@ public class ConfigServerMaintenance { public ConfigServerMaintenance(ApplicationRepository applicationRepository, FileDirectory fileDirectory) { this.applicationRepository = applicationRepository; this.curator = applicationRepository.tenantRepository().getCurator(); - this.flagSource = applicationRepository.flagSource(); this.convergenceChecker = applicationRepository.configConvergenceChecker(); this.fileDirectory = fileDirectory; this.interval = Duration.ofMinutes(applicationRepository.configserverConfig().maintainerIntervalMinutes()); } public void startBeforeBootstrap() { - List<String> otherConfigServersInCluster = getOtherConfigServersInCluster(applicationRepository.configserverConfig()); - if ( ! otherConfigServersInCluster.isEmpty()) - maintainers.add(new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(30), - flagSource, otherConfigServersInCluster)); - maintainers.add(new TenantsMaintainer(applicationRepository, curator, flagSource, interval, Clock.systemUTC())); + if (moreThanOneConfigServer()) + maintainers.add(new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(15))); + maintainers.add(new TenantsMaintainer(applicationRepository, curator, interval, Clock.systemUTC())); } public void startAfterBootstrap() { - maintainers.add(new FileDistributionMaintainer(applicationRepository, - curator, - interval, - flagSource, - fileDirectory)); - maintainers.add(new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource)); - maintainers.add(new ReindexingMaintainer(applicationRepository, curator, flagSource, + maintainers.add(new FileDistributionMaintainer(applicationRepository, curator, interval, fileDirectory)); + maintainers.add(new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30))); + maintainers.add(new ReindexingMaintainer(applicationRepository, curator, Duration.ofMinutes(3), convergenceChecker, Clock.systemUTC())); } @@ -66,4 +58,8 @@ public class ConfigServerMaintenance { public List<Maintainer> maintainers() { return List.copyOf(maintainers); } + private boolean moreThanOneConfigServer() { + return ! getOtherConfigServersInCluster(applicationRepository.configserverConfig()).isEmpty(); + } + } 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 91721bbf409..4a0221fdc2c 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 @@ -5,7 +5,7 @@ import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.filedistribution.FileDirectory; import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.flags.FlagSource; + import java.time.Duration; /** @@ -24,9 +24,8 @@ public class FileDistributionMaintainer extends ConfigServerMaintainer { FileDistributionMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, - FlagSource flagSource, FileDirectory fileDirectory) { - super(applicationRepository, curator, flagSource, applicationRepository.clock(), interval, false); + super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), interval, false); ConfigserverConfig configserverConfig = applicationRepository.configserverConfig(); this.maxUnusedFileReferenceAge = Duration.ofMinutes(configserverConfig.keepUnusedFileReferencesMinutes()); this.fileDirectory = fileDirectory; 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 decf658f6ee..8171d63ae37 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 @@ -10,7 +10,6 @@ import com.yahoo.vespa.config.server.application.ApplicationReindexing.Cluster; import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker; import com.yahoo.vespa.config.server.tenant.Tenant; import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.flags.FlagSource; import com.yahoo.yolean.Exceptions; import java.time.Clock; @@ -46,9 +45,9 @@ public class ReindexingMaintainer extends ConfigServerMaintainer { private final ConfigConvergenceChecker convergence; private final Clock clock; - public ReindexingMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource, + public ReindexingMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, ConfigConvergenceChecker convergence, Clock clock) { - super(applicationRepository, curator, flagSource, clock, interval, true); + super(applicationRepository, curator, applicationRepository.flagSource(), clock, interval, true); this.convergence = convergence; this.clock = clock; } 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 4c27913251a..844b667fd85 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 @@ -3,7 +3,6 @@ package com.yahoo.vespa.config.server.maintenance; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.flags.FlagSource; import java.time.Duration; import java.util.logging.Level; @@ -17,8 +16,8 @@ import java.util.logging.Level; */ public class SessionsMaintainer extends ConfigServerMaintainer { - SessionsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, FlagSource flagSource) { - super(applicationRepository, curator, flagSource, applicationRepository.clock(), interval, true); + SessionsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval) { + super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), interval, true); } @Override 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 4ce0546fa2d..3fcdc8878d2 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 @@ -23,9 +23,8 @@ public class TenantsMaintainer extends ConfigServerMaintainer { private final Duration ttlForUnusedTenant; private final Clock clock; - TenantsMaintainer(ApplicationRepository applicationRepository, Curator curator, FlagSource flagSource, - Duration interval, Clock clock) { - super(applicationRepository, curator, flagSource, applicationRepository.clock(), interval, true); + TenantsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, Clock clock) { + super(applicationRepository, curator, applicationRepository.flagSource(), applicationRepository.clock(), interval, true); this.ttlForUnusedTenant = defaultTtlForUnusedTenant; this.clock = clock; } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainerTest.java index 5fd23a95eed..42c22977f79 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainerTest.java @@ -9,7 +9,6 @@ import com.yahoo.test.ManualClock; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.session.PrepareParams; import com.yahoo.vespa.config.server.tenant.TenantRepository; -import com.yahoo.vespa.flags.InMemoryFlagSource; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -46,7 +45,7 @@ public class TenantsMaintainerTest { assertNotNull(tenantRepository.getTenant(shouldNotBeDeleted)); clock.advance(TenantsMaintainer.defaultTtlForUnusedTenant.plus(Duration.ofDays(1))); - new TenantsMaintainer(applicationRepository, tester.curator(), new InMemoryFlagSource(), Duration.ofDays(1), clock).run(); + new TenantsMaintainer(applicationRepository, tester.curator(), Duration.ofDays(1), clock).run(); // One tenant should now have been deleted assertNull(tenantRepository.getTenant(shouldBeDeleted)); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java index 872cbd67780..82cddb46d9a 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java @@ -38,6 +38,8 @@ public class ConsoleUrls { return "%s/tenant/%s/account/notifications".formatted(root, tenantName.value()); } + public String tenantBilling(TenantName t) { return "%s/tenant/%s/account/billing".formatted(root, t.value()); } + public String prodApplicationOverview(TenantName tenantName, ApplicationName applicationName) { return "%s/tenant/%s/application/%s/prod/instance".formatted(root, tenantName.value(), applicationName.value()); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java index c1c8a780df1..702a183e7af 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java @@ -36,6 +36,10 @@ public class Email { return new Email(emailAddress, isVerified); } + public boolean isBlank() { + return emailAddress.isBlank(); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PurchaseOrder.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PurchaseOrder.java new file mode 100644 index 00000000000..d222864a388 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PurchaseOrder.java @@ -0,0 +1,21 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.tenant; + +import ai.vespa.validation.StringWrapper; + +import static ai.vespa.validation.Validation.requireLength; + +/** + * @author olaa + */ +public class PurchaseOrder extends StringWrapper<PurchaseOrder> { + + public PurchaseOrder(String value) { + super(value); + requireLength(value, "purchase order length", 0, 64); + } + + public static PurchaseOrder empty() { + return new PurchaseOrder(""); + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TaxId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TaxId.java new file mode 100644 index 00000000000..bd7a9402033 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TaxId.java @@ -0,0 +1,21 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.tenant; + +import ai.vespa.validation.StringWrapper; + +import static ai.vespa.validation.Validation.requireLength; + +/** + * @author olaa + */ +public class TaxId extends StringWrapper<TaxId> { + + public TaxId(String value) { + super(value); + requireLength(value, "tax code length", 0, 64); + } + + public static TaxId empty() { + return new TaxId(""); + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java index 5377b820e18..6e3b26661e5 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java @@ -10,14 +10,20 @@ public class TenantBilling { private final TenantContact contact; private final TenantAddress address; + private final TaxId taxId; + private final PurchaseOrder purchaseOrder; + private final Email invoiceEmail; - public TenantBilling(TenantContact contact, TenantAddress address) { + public TenantBilling(TenantContact contact, TenantAddress address, TaxId taxId, PurchaseOrder purchaseOrder, Email invoiceEmail) { this.contact = Objects.requireNonNull(contact); this.address = Objects.requireNonNull(address); + this.taxId = Objects.requireNonNull(taxId); + this.purchaseOrder = Objects.requireNonNull(purchaseOrder); + this.invoiceEmail = Objects.requireNonNull(invoiceEmail); } public static TenantBilling empty() { - return new TenantBilling(TenantContact.empty(), TenantAddress.empty()); + return new TenantBilling(TenantContact.empty(), TenantAddress.empty(), TaxId.empty(), PurchaseOrder.empty(), Email.empty()); } public TenantContact contact() { @@ -28,12 +34,36 @@ public class TenantBilling { return address; } + public TaxId getTaxId() { + return taxId; + } + + public PurchaseOrder getPurchaseOrder() { + return purchaseOrder; + } + + public Email getInvoiceEmail() { + return invoiceEmail; + } + public TenantBilling withContact(TenantContact updatedContact) { - return new TenantBilling(updatedContact, this.address); + return new TenantBilling(updatedContact, this.address, this.taxId, this.purchaseOrder, this.invoiceEmail); } public TenantBilling withAddress(TenantAddress updatedAddress) { - return new TenantBilling(this.contact, updatedAddress); + return new TenantBilling(this.contact, updatedAddress, this.taxId, this.purchaseOrder, this.invoiceEmail); + } + + public TenantBilling withTaxId(TaxId updatedTaxId) { + return new TenantBilling(this.contact, this.address, updatedTaxId, this.purchaseOrder, this.invoiceEmail); + } + + public TenantBilling withPurchaseOrder(PurchaseOrder updatedPurchaseOrder) { + return new TenantBilling(this.contact, this.address, this.taxId, updatedPurchaseOrder, this.invoiceEmail); + } + + public TenantBilling withInvoiceEmail(Email updatedInvoiceEmail) { + return new TenantBilling(this.contact, this.address, this.taxId, this.purchaseOrder, updatedInvoiceEmail); } public boolean isEmpty() { @@ -45,19 +75,26 @@ public class TenantBilling { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TenantBilling that = (TenantBilling) o; - return Objects.equals(contact, that.contact) && Objects.equals(address, that.address); + return Objects.equals(contact, that.contact) && + Objects.equals(address, that.address) && + Objects.equals(taxId, that.taxId) && + Objects.equals(purchaseOrder, that.purchaseOrder) && + Objects.equals(invoiceEmail, that.invoiceEmail); } @Override public int hashCode() { - return Objects.hash(contact, address); + return Objects.hash(contact, address, taxId, purchaseOrder, invoiceEmail); } @Override public String toString() { - return "TenantInfoBillingContact{" + + return "TenantBilling{" + "contact=" + contact + ", address=" + address + + ", taxId='" + taxId + '\'' + + ", purchaseOrder='" + purchaseOrder + '\'' + + ", invoiceEmail=" + invoiceEmail + '}'; } } diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java index 62e79c3be50..259a279671b 100644 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java @@ -31,6 +31,7 @@ class ConsoleUrlsTest { assertEquals("https://console.tld", urls.root()); assertEquals("https://console.tld/tenant/t1", urls.tenantOverview(app.tenant())); assertEquals("https://console.tld/tenant/t1/account/notifications", urls.tenantNotifications(app.tenant())); + assertEquals("https://console.tld/tenant/t1/account/billing", urls.tenantBilling(app.tenant())); assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance", urls.prodApplicationOverview(app.tenant(), app.application())); assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance/i1", urls.instanceOverview(app, Environment.test)); assertEquals("https://console.tld/tenant/t1/application/a1/dev/instance/i1?i1.dev.eu-west-2=clusters%2Cc1", urls.clusterOverview(app, dev, cluster)); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BcpGroupUpdater.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BcpGroupUpdater.java index 1ad4feb1897..36aeb598890 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BcpGroupUpdater.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BcpGroupUpdater.java @@ -71,6 +71,24 @@ public class BcpGroupUpdater extends ControllerMaintainer { var patch = new ApplicationPatch(); addTrafficShare(deployment, bcpGroups, patch); addBcpGroupInfo(deployment.zone().region(), metrics.get(instance.id()), bcpGroups, patch); + + StringBuilder patchAsStringBuilder = new StringBuilder("Patch of instance ").append(instance.id().serializedForm()).append(": ") + .append("\n\tcurrentReadShare: ") + .append(patch.currentReadShare) + .append("\n\tmaxReadShare: ") + .append(patch.maxReadShare); + for (Map.Entry<String, ApplicationPatch.ClusterPatch> entry : patch.clusters.entrySet()) { + String key = entry.getKey(); + ApplicationPatch.ClusterPatch value = entry.getValue(); + patchAsStringBuilder.append("\n\tbcpGroupInfo for ").append(key).append(": ") + .append("\n\t\tcpuCostPerQuery: ") + .append(value.bcpGroupInfo.cpuCostPerQuery) + .append("\n\t\tqueryRate: ") + .append(value.bcpGroupInfo.queryRate) + .append("\n\t\tgrowthRateHeadroom: ") + .append(value.bcpGroupInfo.growthRateHeadroom); + } + log.log(Level.FINER, patchAsStringBuilder.toString()); nodeRepository.patchApplication(deployment.zone(), instance.id(), patch); } catch (Exception e) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java index 9121c139b00..55428e80493 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java @@ -121,32 +121,22 @@ public class CloudTrialExpirer extends ControllerMaintainer { // Ignore tenants that are on a paid plan and skip from inclusion in updated data structure } else if (status == null && "trial".equals(plan) && ageInDays <= 1) { updatedStatus.add(updatedStatus(tenant, now, SIGNED_UP)); - queueNotification(tenant, "Welcome to Vespa Cloud", "Welcome to Vespa Cloud", - "Welcome to Vespa Cloud! We hope you will enjoy your trial. " + - "Please reach out to us if you have any questions or feedback."); + notifySignup(tenant); } else if ("none".equals(plan) && !List.of(EXPIRED).contains(state)) { updatedStatus.add(updatedStatus(tenant, now, EXPIRED)); - queueNotification(tenant, "Your Vespa Cloud trial has expired", "Your Vespa Cloud trial has expired", - "Your Vespa Cloud trial has expired. " + - "Please reach out to us if you have any questions or feedback."); + notifyExpired(tenant); } else if ("trial".equals(plan) && ageInDays >= 13 && !List.of(EXPIRES_IMMEDIATELY, EXPIRED).contains(state)) { updatedStatus.add(updatedStatus(tenant, now, EXPIRES_IMMEDIATELY)); - queueNotification(tenant, "Your Vespa Cloud trial expires tomorrow", "Your Vespa Cloud trial expires tomorrow", - "Your Vespa Cloud trial expires tomorrow. " + - "Please reach out to us if you have any questions or feedback."); + notifyExpiresImmediately(tenant); } else if ("trial".equals(plan) && ageInDays >= 12 && !List.of(EXPIRES_SOON, EXPIRES_IMMEDIATELY, EXPIRED).contains(state)) { updatedStatus.add(updatedStatus(tenant, now, EXPIRES_SOON)); - queueNotification(tenant, "Your Vespa Cloud trial expires in 2 days", "Your Vespa Cloud trial expires in 2 days", - "Your Vespa Cloud trial expires in 2 days. " + - "Please reach out to us if you have any questions or feedback."); + notifyExpiresSoon(tenant); } else if ("trial".equals(plan) && ageInDays >= 7 && !List.of(MID_CHECK_IN, EXPIRES_SOON, EXPIRES_IMMEDIATELY, EXPIRED).contains(state)) { updatedStatus.add(updatedStatus(tenant, now, MID_CHECK_IN)); - queueNotification(tenant, "How is your Vespa Cloud trial going?", "How is your Vespa Cloud trial going?", - "How is your Vespa Cloud trial going? " + - "Please reach out to us if you have any questions or feedback."); + notifyMidCheckIn(tenant); } else { updatedStatus.add(status); } @@ -160,6 +150,41 @@ public class CloudTrialExpirer extends ControllerMaintainer { } } + private void notifySignup(Tenant tenant) { + var consoleMsg = "Welcome to Vespa Cloud trial! [Manage plan](%s)".formatted(billingUrl(tenant)); + queueNotification(tenant, consoleMsg, "Welcome to Vespa Cloud", + "Welcome to Vespa Cloud! We hope you will enjoy your trial. " + + "Please reach out to us if you have any questions or feedback."); + } + + private void notifyMidCheckIn(Tenant tenant) { + var consoleMsg = "You're halfway through the **14 day** trial period. [Manage plan](%s)".formatted(billingUrl(tenant)); + queueNotification(tenant, consoleMsg, "How is your Vespa Cloud trial going?", + "How is your Vespa Cloud trial going? " + + "Please reach out to us if you have any questions or feedback."); + } + + private void notifyExpiresSoon(Tenant tenant) { + var consoleMsg = "Your Vespa Cloud trial expires in **2** days. [Manage plan](%s)".formatted(billingUrl(tenant)); + queueNotification(tenant, consoleMsg, "Your Vespa Cloud trial expires in 2 days", + "Your Vespa Cloud trial expires in 2 days. " + + "Please reach out to us if you have any questions or feedback."); + } + + private void notifyExpiresImmediately(Tenant tenant) { + var consoleMsg = "Your Vespa Cloud trial expires **tomorrow**. [Manage plan](%s)".formatted(billingUrl(tenant)); + queueNotification(tenant, consoleMsg, "Your Vespa Cloud trial expires tomorrow", + "Your Vespa Cloud trial expires tomorrow. " + + "Please reach out to us if you have any questions or feedback."); + } + + private void notifyExpired(Tenant tenant) { + var consoleMsg = "Your Vespa Cloud trial has expired. [Upgrade plan](%s)".formatted(billingUrl(tenant)); + queueNotification(tenant, consoleMsg, "Your Vespa Cloud trial has expired", + "Your Vespa Cloud trial has expired. " + + "Please reach out to us if you have any questions or feedback."); + } + private void queueNotification(Tenant tenant, String consoleMsg, String emailSubject, String emailMsg) { var mail = Optional.of(Notification.MailContent.fromTemplate(MailTemplating.Template.DEFAULT_MAIL_CONTENT) .subject(emailSubject) @@ -175,6 +200,8 @@ public class CloudTrialExpirer extends ControllerMaintainer { source, Notification.Type.account, Notification.Level.info, consoleMsg, List.of(), mail); } + private String billingUrl(Tenant t) { return controller().serviceRegistry().consoleUrls().tenantBilling(t.name()); } + private static TrialNotifications.Status updatedStatus(Tenant t, Instant i, TrialNotifications.State s) { return new TrialNotifications.Status(t.name(), s, i); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java index b0b43866fae..f27e69c4636 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java @@ -101,10 +101,13 @@ public class Notifier { log.fine(() -> "Sending notification " + notification + " to " + contacts.stream().map(c -> c.email().getEmailAddress()).toList()); var content = formatter.format(notification); - mailer.send(mailOf(content, contacts.stream() - .filter(c -> c.email().isVerified()) - .map(c -> c.email().getEmailAddress()) - .toList())); + var verifiedContacts = contacts.stream() + .filter(c -> c.email().isVerified()).map(c -> c.email().getEmailAddress()).toList(); + if (verifiedContacts.isEmpty()) { + log.fine(() -> "None of the %d contact(s) are verified - skipping delivery of %s".formatted(contacts.size(), notification)); + return; + } + mailer.send(mailOf(content, verifiedContacts)); } catch (MailerException e) { log.log(Level.SEVERE, "Failed sending email", e); } catch (MissingOptionalException e) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java index d5bb47c94b0..eae8f86f289 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java @@ -28,6 +28,8 @@ import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.Email; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; +import com.yahoo.vespa.hosted.controller.tenant.PurchaseOrder; +import com.yahoo.vespa.hosted.controller.tenant.TaxId; import com.yahoo.vespa.hosted.controller.tenant.Tenant; import com.yahoo.vespa.hosted.controller.tenant.TenantAddress; import com.yahoo.vespa.hosted.controller.tenant.TenantBilling; @@ -93,6 +95,9 @@ public class TenantSerializer { private static final String cloudAccountsField = "cloudAccounts"; private static final String accountField = "account"; private static final String templateVersionField = "templateVersion"; + private static final String taxIdField = "taxId"; + private static final String purchaseOrderField = "purchaseOrder"; + private static final String invoiceEmailField = "invoiceEmail"; private static final String awsIdField = "awsId"; private static final String roleField = "role"; @@ -282,12 +287,19 @@ public class TenantSerializer { } private TenantBilling tenantInfoBillingContactFromSlime(Inspector billingObject) { + var taxId = new TaxId(billingObject.field(taxIdField).asString()); + var purchaseOrder = new PurchaseOrder(billingObject.field(purchaseOrderField).asString()); + var invoiceEmail = new Email(billingObject.field(invoiceEmailField).asString(), false); + return TenantBilling.empty() .withContact(TenantContact.from( billingObject.field("name").asString(), new Email(billingObject.field("email").asString(), billingObject.field("emailVerified").asBool()), billingObject.field("phone").asString())) - .withAddress(tenantInfoAddressFromSlime(billingObject.field("address"))); + .withAddress(tenantInfoAddressFromSlime(billingObject.field("address"))) + .withTaxId(taxId) + .withPurchaseOrder(purchaseOrder) + .withInvoiceEmail(invoiceEmail); } private List<TenantSecretStore> secretStoresFromSlime(Inspector secretStoresObject) { @@ -349,6 +361,9 @@ public class TenantSerializer { billingCursor.setString("email", billingContact.contact().email().getEmailAddress()); billingCursor.setBool("emailVerified", billingContact.contact().email().isVerified()); billingCursor.setString("phone", billingContact.contact().phone()); + billingCursor.setString(taxIdField, billingContact.getTaxId().value()); + billingCursor.setString(purchaseOrderField, billingContact.getPurchaseOrder().value()); + billingCursor.setString(invoiceEmailField, billingContact.getInvoiceEmail().getEmailAddress()); toSlime(billingContact.address(), billingCursor); } 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 6a6c8a51d72..5548928b9d0 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 @@ -127,6 +127,8 @@ import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.Email; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; import com.yahoo.vespa.hosted.controller.tenant.PendingMailVerification; +import com.yahoo.vespa.hosted.controller.tenant.PurchaseOrder; +import com.yahoo.vespa.hosted.controller.tenant.TaxId; import com.yahoo.vespa.hosted.controller.tenant.Tenant; import com.yahoo.vespa.hosted.controller.tenant.TenantAddress; import com.yahoo.vespa.hosted.controller.tenant.TenantBilling; @@ -694,6 +696,9 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { contact.setString("email", billingContact.contact().email().getEmailAddress()); contact.setBool("emailVerified", billingContact.contact().email().isVerified()); contact.setString("phone", billingContact.contact().phone()); + root.setString("taxId", billingContact.getTaxId().value()); + root.setString("purchaseOrder", billingContact.getPurchaseOrder().value()); + root.setString("invoiceEmail", billingContact.getInvoiceEmail().getEmailAddress()); toSlime(billingContact.address(), root); // will create "address" on the parent } @@ -703,15 +708,22 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { private SlimeJsonResponse putTenantInfoBilling(CloudTenant cloudTenant, Inspector inspector) { var info = cloudTenant.info(); - var contact = info.billingContact().contact(); - var address = info.billingContact().address(); + var billing = info.billingContact(); + var contact = billing.contact(); + var address = billing.address(); var mergedContact = updateBillingContact(inspector.field("contact"), cloudTenant.name(), contact); - var mergedAddress = updateTenantInfoAddress(inspector.field("address"), info.billingContact().address()); + var mergedAddress = updateTenantInfoAddress(inspector.field("address"), billing.address()); + var mergedTaxId = optional("taxId", inspector).map(TaxId::new).orElse(billing.getTaxId()); + var mergedPurchaseOrder = optional("purchaseOrder", inspector).map(PurchaseOrder::new).orElse(billing.getPurchaseOrder()); + var mergedInvoiceEmail = optional("invoiceEmail", inspector).map(mail -> new Email(mail, false)).orElse(billing.getInvoiceEmail()); var mergedBilling = info.billingContact() .withContact(mergedContact) - .withAddress(mergedAddress); + .withAddress(mergedAddress) + .withTaxId(mergedTaxId) + .withPurchaseOrder(mergedPurchaseOrder) + .withInvoiceEmail(mergedInvoiceEmail); var mergedInfo = info.withBilling(mergedBilling); @@ -764,6 +776,11 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { throw new IllegalArgumentException("'website' needs to be a valid address"); } } + if (! mergedInfo.billingContact().getInvoiceEmail().isBlank()) { + // TODO: Validate invoice email is set if collection method is INVOICE + if (! mergedInfo.billingContact().getInvoiceEmail().getEmailAddress().contains("@")) + throw new IllegalArgumentException("'Invoice email' needs to be an email address"); + } } private void toSlime(TenantAddress address, Cursor parentCursor) { @@ -785,6 +802,9 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { billingCursor.setString("email", billingContact.contact().email().getEmailAddress()); billingCursor.setBool("emailVerified", billingContact.contact().email().isVerified()); billingCursor.setString("phone", billingContact.contact().phone()); + billingCursor.setString("taxId", billingContact.getTaxId().value()); + billingCursor.setString("purchaseOrder", billingContact.getPurchaseOrder().value()); + billingCursor.setString("invoiceEmail", billingContact.getInvoiceEmail().getEmailAddress()); toSlime(billingContact.address(), billingCursor); } @@ -914,9 +934,15 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { private TenantBilling updateTenantInfoBillingContact(Inspector insp, TenantName tenantName, TenantBilling oldContact) { if (!insp.valid()) return oldContact; + var taxId = optional("taxId", insp).map(TaxId::new).orElse(oldContact.getTaxId()); + var purchaseOrder = optional("purchaseOrder", insp).map(PurchaseOrder::new).orElse(oldContact.getPurchaseOrder()); + var invoiceEmail = optional("invoiceEmail", insp).map(mail -> new Email(mail, false)).orElse(oldContact.getInvoiceEmail()); return TenantBilling.empty() .withContact(updateBillingContact(insp, tenantName, oldContact.contact())) - .withAddress(updateTenantInfoAddress(insp.field("address"), oldContact.address())); + .withAddress(updateTenantInfoAddress(insp.field("address"), oldContact.address())) + .withTaxId(taxId) + .withPurchaseOrder(purchaseOrder) + .withInvoiceEmail(invoiceEmail); } private TenantContacts updateTenantInfoContacts(Inspector insp, TenantName tenantName, TenantContacts oldContacts) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java index 07ce2e415a7..4056459c532 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java @@ -110,27 +110,32 @@ public class CloudTrialExpirerTest { .withBooleanFlag(Flags.CLOUD_TRIAL_NOTIFICATIONS.id(), true); registerTenant(tenant.value(), "trial", Duration.ZERO); assertEquals(0.0, expirer.maintain()); - assertEquals("Welcome to Vespa Cloud", lastAccountLevelNotificationTitle(tenant)); + var expected = "Welcome to Vespa Cloud trial! [Manage plan](https://console.tld/tenant/trial-tenant/account/billing)"; + assertEquals(expected, lastAccountLevelNotificationTitle(tenant)); assertLastEmailEquals(mailer, "welcome.html"); + expected = "You're halfway through the **14 day** trial period. [Manage plan](https://console.tld/tenant/trial-tenant/account/billing)"; clock.advance(Duration.ofDays(7)); assertEquals(0.0, expirer.maintain()); - assertEquals("How is your Vespa Cloud trial going?", lastAccountLevelNotificationTitle(tenant)); + assertEquals(expected, lastAccountLevelNotificationTitle(tenant)); assertLastEmailEquals(mailer, "trial-reminder.html"); + expected = "Your Vespa Cloud trial expires in **2** days. [Manage plan](https://console.tld/tenant/trial-tenant/account/billing)"; clock.advance(Duration.ofDays(5)); assertEquals(0.0, expirer.maintain()); - assertEquals("Your Vespa Cloud trial expires in 2 days", lastAccountLevelNotificationTitle(tenant)); + assertEquals(expected, lastAccountLevelNotificationTitle(tenant)); assertLastEmailEquals(mailer, "trial-expiring-soon.html"); + expected = "Your Vespa Cloud trial expires **tomorrow**. [Manage plan](https://console.tld/tenant/trial-tenant/account/billing)"; clock.advance(Duration.ofDays(1)); assertEquals(0.0, expirer.maintain()); - assertEquals("Your Vespa Cloud trial expires tomorrow", lastAccountLevelNotificationTitle(tenant)); + assertEquals(expected, lastAccountLevelNotificationTitle(tenant)); assertLastEmailEquals(mailer, "trial-expiring-immediately.html"); + expected = "Your Vespa Cloud trial has expired. [Upgrade plan](https://console.tld/tenant/trial-tenant/account/billing)"; clock.advance(Duration.ofDays(2)); assertEquals(0.0, expirer.maintain()); - assertEquals("Your Vespa Cloud trial has expired", lastAccountLevelNotificationTitle(tenant)); + assertEquals(expected, lastAccountLevelNotificationTitle(tenant)); assertLastEmailEquals(mailer, "trial-expired.html"); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java index 9de856971c9..4912c9ae407 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java @@ -24,6 +24,8 @@ import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.Email; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; +import com.yahoo.vespa.hosted.controller.tenant.PurchaseOrder; +import com.yahoo.vespa.hosted.controller.tenant.TaxId; import com.yahoo.vespa.hosted.controller.tenant.TenantAddress; import com.yahoo.vespa.hosted.controller.tenant.TenantBilling; import com.yahoo.vespa.hosted.controller.tenant.TenantContact; @@ -234,7 +236,11 @@ public class TenantSerializerTest { .withCity("Suddery") .withCountry("Sodor") .withAddress("Central Station") - .withRegion("Irish Sea"))); + .withRegion("Irish Sea")) + .withPurchaseOrder(new PurchaseOrder("PO42")) + .withTaxId(new TaxId("1234L")) + .withInvoiceEmail(new Email("billing@mycomp.any", false)) + ); Slime slime = new Slime(); Cursor parentCursor = slime.setObject(); 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 2b01d87c903..32f0247b3bc 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 @@ -98,19 +98,68 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { @Test void tenant_info_billing() { + var expectedResponse = """ + { + "contact": { + "name":"", + "email":"", + "emailVerified":false, + "phone":"" + }, + "taxId":"", + "purchaseOrder":"", + "invoiceEmail":"" + } + """; var request = request("/application/v4/tenant/scoober/info/billing", GET) .roles(Set.of(Role.reader(tenantName))); - tester.assertResponse(request, "{\"contact\":{\"name\":\"\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"\"}}", 200); - - var fullAddress = "{\"addressLines\":\"addressLines\",\"postalCodeOrZip\":\"postalCodeOrZip\",\"city\":\"city\",\"stateRegionProvince\":\"stateRegionProvince\",\"country\":\"country\"}"; - var fullBillingContact = "{\"contact\":{\"name\":\"name\",\"email\":\"foo@example\",\"phone\":\"phone\"},\"address\":" + fullAddress + "}"; - + tester.assertJsonResponse(request, expectedResponse, 200); + + var fullBillingContact = """ + { + "contact": { + "name":"name", + "email":"foo@example", + "phone":"phone" + }, + "taxId":"1234L", + "purchaseOrder":"PO9001", + "invoiceEmail":"billing@mycomp.any", + "address": { + "addressLines":"addressLines", + "postalCodeOrZip":"postalCodeOrZip", + "city":"city", + "stateRegionProvince":"stateRegionProvince", + "country":"country" + } + } + """; var updateRequest = request("/application/v4/tenant/scoober/info/billing", PUT) .data(fullBillingContact) .roles(Set.of(Role.administrator(tenantName))); tester.assertResponse(updateRequest, "{\"message\":\"Tenant info updated\"}", 200); - tester.assertResponse(request, "{\"contact\":{\"name\":\"name\",\"email\":\"foo@example\",\"emailVerified\":false,\"phone\":\"phone\"},\"address\":{\"addressLines\":\"addressLines\",\"postalCodeOrZip\":\"postalCodeOrZip\",\"city\":\"city\",\"stateRegionProvince\":\"stateRegionProvince\",\"country\":\"country\"}}", 200); + expectedResponse = """ + { + "contact": { + "name":"name", + "email":"foo@example", + "emailVerified": false, + "phone":"phone" + }, + "taxId":"1234L", + "purchaseOrder":"PO9001", + "invoiceEmail":"billing@mycomp.any", + "address": { + "addressLines":"addressLines", + "postalCodeOrZip":"postalCodeOrZip", + "city":"city", + "stateRegionProvince":"stateRegionProvince", + "country":"country" + } + } + """; + tester.assertJsonResponse(request, expectedResponse, 200); } @Test @@ -120,12 +169,32 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { tester.assertResponse(request, "{\"contacts\":[{\"audiences\":[\"tenant\",\"notifications\"],\"email\":\"developer@scoober\",\"emailVerified\":true}]}", 200); - var fullContacts = "{\"contacts\":[{\"audiences\":[\"tenant\"],\"email\":\"contact1@example.com\",\"emailVerified\":false},{\"audiences\":[\"notifications\"],\"email\":\"contact2@example.com\",\"emailVerified\":false},{\"audiences\":[\"tenant\",\"notifications\"],\"email\":\"contact3@example.com\",\"emailVerified\":false}]}"; + var fullContacts = """ + { + "contacts":[ + { + "audiences":["tenant"] + ,"email":"contact1@example.com", + "emailVerified":false + }, + { + "audiences":["notifications"], + "email":"contact2@example.com", + "emailVerified":false + }, + { + "audiences":["tenant","notifications"], + "email":"contact3@example.com", + "emailVerified":false + } + ] + } + """; var updateRequest = request("/application/v4/tenant/scoober/info/contacts", PUT) .data(fullContacts) .roles(Set.of(Role.administrator(tenantName))); tester.assertResponse(updateRequest, "{\"message\":\"Tenant info updated\"}", 200); - tester.assertResponse(request, fullContacts, 200); + tester.assertJsonResponse(request, fullContacts, 200); } @Test @@ -150,13 +219,79 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { tester.assertResponse(postPartialContacts, "{\"message\":\"Tenant info updated\"}", 200); // Read back the updated info - tester.assertResponse(infoRequest, "{\"name\":\"\",\"email\":\"\",\"website\":\"\",\"contactName\":\"newName\",\"contactEmail\":\"foo@example.com\",\"contactEmailVerified\":false,\"billingContact\":{\"name\":\"billingName\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"\"},\"contacts\":[{\"audiences\":[\"tenant\"],\"email\":\"contact1@example.com\",\"emailVerified\":false}]}", 200); - - String fullAddress = "{\"addressLines\":\"addressLines\",\"postalCodeOrZip\":\"postalCodeOrZip\",\"city\":\"city\",\"stateRegionProvince\":\"stateRegionProvince\",\"country\":\"country\"}"; - String fullBillingContact = "{\"name\":\"name\",\"email\":\"foo@example\",\"emailVerified\":false,\"phone\":\"phone\",\"address\":" + fullAddress + "}"; - String fullContacts = "[{\"audiences\":[\"tenant\"],\"email\":\"contact1@example.com\",\"emailVerified\":false},{\"audiences\":[\"notifications\"],\"email\":\"contact2@example.com\",\"emailVerified\":false},{\"audiences\":[\"tenant\",\"notifications\"],\"email\":\"contact3@example.com\",\"emailVerified\":false}]"; - String fullInfo = "{\"name\":\"name\",\"email\":\"foo@example\",\"website\":\"https://yahoo.com\",\"contactName\":\"contactName\",\"contactEmail\":\"contact@example.com\",\"contactEmailVerified\":false,\"address\":" + fullAddress + ",\"billingContact\":" + fullBillingContact + ",\"contacts\":" + fullContacts + "}"; - + var expectedResponse = """ + { + "name":"", + "email":"", + "website":"", + "contactName":"newName", + "contactEmail":"foo@example.com", + "contactEmailVerified":false, + "billingContact": { + "name":"billingName", + "email":"","emailVerified":false, + "phone":"", + "taxId":"", + "purchaseOrder":"", + "invoiceEmail":"" + }, + "contacts": [ + {"audiences":["tenant"],"email":"contact1@example.com","emailVerified":false} + ] + } + """; + tester.assertJsonResponse(infoRequest, expectedResponse, 200); + + var fullInfo = """ + { + "name":"name", + "email":"foo@example", + "website":"https://yahoo.com", + "contactName":"contactName", + "contactEmail":"contact@example.com", + "contactEmailVerified":false, + "address": { + "addressLines":"addressLines", + "postalCodeOrZip":"postalCodeOrZip", + "city":"city", + "stateRegionProvince":"stateRegionProvince", + "country":"country" + }, + "billingContact": { + "name":"name", + "email":"foo@example", + "emailVerified":false, + "phone":"phone", + "taxId":"", + "purchaseOrder":"", + "invoiceEmail":"", + "address": { + "addressLines":"addressLines", + "postalCodeOrZip":"postalCodeOrZip", + "city":"city", + "stateRegionProvince":"stateRegionProvince", + "country":"country" + } + }, + "contacts": [ + { + "audiences":["tenant"], + "email":"contact1@example.com", + "emailVerified":false + }, + { + "audiences":["notifications"], + "email":"contact2@example.com", + "emailVerified":false + }, + { + "audiences":["tenant","notifications"] + ,"email":"contact3@example.com", + "emailVerified":false + } + ] + } + """; // Now set all fields var postFull = request("/application/v4/tenant/scoober/info", PUT) @@ -165,7 +300,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest { tester.assertResponse(postFull, "{\"message\":\"Tenant info updated\"}", 200); // Now compare the updated info with the full info we sent - tester.assertResponse(infoRequest, fullInfo, 200); + tester.assertJsonResponse(infoRequest, fullInfo, 200); var invalidBody = "{\"mail\":\"contact1@example.com\", \"mailType\":\"blurb\"}"; var resendMailRequest = diff --git a/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java b/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java index dea88d1687b..4323af5a4fd 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java @@ -17,6 +17,8 @@ public class DimensionHelper { private static final Map<FetchVector.Dimension, String> serializedDimensions = new HashMap<>(); static { + // WARNING: If you ever change the serialized form of a dimension, ensure the new serialized + // flag data are pushed out everywhere before removing support for old format, see VESPA-27760. serializedDimensions.put(FetchVector.Dimension.APPLICATION_ID, "application"); serializedDimensions.put(FetchVector.Dimension.CLOUD, "cloud"); serializedDimensions.put(FetchVector.Dimension.CLOUD_ACCOUNT, "cloud-account"); 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 10a8460614f..179d88d33ab 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 @@ -628,7 +628,9 @@ public abstract class NodeCandidate implements Nodelike, Comparable<NodeCandidat // this cluster requires exclusivity, but the parent is not exclusive if (exclusiveAllocation && parent.flatMap(Node::exclusiveToApplicationId).isEmpty()) - return makeExclusive ? ExclusivityViolation.PARENT_HOST_NOT_EXCLUSIVE : ExclusivityViolation.YES; + return Preparer.requireParentHostLock(makeExclusive, type(), hostSharing) ? + ExclusivityViolation.PARENT_HOST_NOT_EXCLUSIVE : + ExclusivityViolation.YES; } return ExclusivityViolation.NONE; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java index 9f5775ee8c3..fad42449285 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java @@ -92,10 +92,24 @@ public class Preparer { } } + /** + * Whether the preparation of an application MAY require changes to the parent hosts, and therefore the parent host lock is required. + * See {@link NodeCandidate#withExclusiveParent(boolean)}. + */ + public static boolean requireParentHostLock(boolean makeExclusive, NodeType type, boolean allowHostSharing) { + return makeExclusive && type == NodeType.tenant && !allowHostSharing; + } + + private ApplicationMutex parentLockOrNull(boolean makeExclusive, NodeType type) { + return requireParentHostLock(makeExclusive, type, nodeRepository.zone().cloud().allowHostSharing()) ? + nodeRepository.applications().lock(InfrastructureApplication.withNodeType(type.parentNodeType()).id()) : + null; + } + /// Note that this will write to the node repo. private List<Node> prepareWithLocks(ApplicationId application, ClusterSpec cluster, NodeSpec requested, NodeIndices indices, boolean makeExclusive) { try (Mutex lock = nodeRepository.applications().lock(application); - ApplicationMutex tenantHostLock = makeExclusive ? nodeRepository.applications().lock(InfrastructureApplication.TENANT_HOST.id()) : null; + ApplicationMutex parentLockOrNull = parentLockOrNull(makeExclusive, requested.type()); Mutex allocationLock = nodeRepository.nodes().lockUnallocated()) { LockedNodeList allNodes = nodeRepository.nodes().list(allocationLock); NodeAllocation allocation = prepareAllocation(application, cluster, requested, indices::next, allNodes, makeExclusive); @@ -158,9 +172,9 @@ public class Preparer { allocation.allocationFailureDetails(), true); // Carry out and return allocation - if (tenantHostLock != null) { + if (parentLockOrNull != null) { List<Node> exclusiveParents = allocation.parentsRequiredToBeExclusive(); - nodeRepository.nodes().setExclusiveToApplicationId(exclusiveParents, tenantHostLock); + nodeRepository.nodes().setExclusiveToApplicationId(exclusiveParents, parentLockOrNull); // TODO: also update tags } List<Node> acceptedNodes = allocation.finalNodes(); diff --git a/storage/src/tests/persistence/common/filestortestfixture.cpp b/storage/src/tests/persistence/common/filestortestfixture.cpp index 74d34fb0f50..86015bee4e7 100644 --- a/storage/src/tests/persistence/common/filestortestfixture.cpp +++ b/storage/src/tests/persistence/common/filestortestfixture.cpp @@ -84,11 +84,11 @@ FileStorTestFixture::TestFileStorComponents::TestFileStorComponents( top.open(); } -vespalib::string _Storage("storage"); +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 586863251c9..2b0218bf20c 100644 --- a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp +++ b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp @@ -66,11 +66,11 @@ namespace storage { namespace { -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); +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; @@ -94,7 +94,7 @@ struct FileStorTestBase : Test { const document::DocumentType* _testdoctype1; FileStorTestBase() : _node(), _waitTime(LONG_WAITTIME) {} - ~FileStorTestBase(); + ~FileStorTestBase() override; void SetUp() override; void TearDown() override; @@ -327,7 +327,7 @@ TEST_F(FileStorManagerTest, header_only_put) { // Putting it { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -342,7 +342,7 @@ TEST_F(FileStorManagerTest, header_only_put) { { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 124); cmd->setUpdateTimestamp(105); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -354,7 +354,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -389,7 +389,7 @@ TEST_F(FileStorManagerTest, put) { // Putting it { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -470,7 +470,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(_Storage3); + cmd->setAddress(_storage3); _commands.push_back(cmd); } for (uint32_t i=0; i<msgCount; ++i) { @@ -497,7 +497,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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(i * 15); filestorHandler.schedule(cmd); } @@ -632,7 +632,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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(i * 15); filestorHandler.schedule(cmd); } @@ -708,7 +708,7 @@ TEST_F(FileStorManagerTest, handler_timeout) { // Populate bucket with the given data { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(0); cmd->setTimeout(50ms); filestorHandler.schedule(cmd); @@ -716,7 +716,7 @@ TEST_F(FileStorManagerTest, handler_timeout) { { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), doc, 100); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(200); cmd->setTimeout(10000ms); filestorHandler.schedule(cmd); @@ -776,7 +776,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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(i * 2); filestorHandler.schedule(cmd); } @@ -835,7 +835,7 @@ TEST_F(FileStorManagerTest, split1) { _node->getPersistenceProvider().createBucket(makeSpiBucket(bucket)); auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setSourceIndex(0); filestorHandler.schedule(cmd); @@ -850,7 +850,7 @@ 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(_Storage3); + rcmd->setAddress(_storage3); filestorHandler.schedule(rcmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -878,7 +878,7 @@ TEST_F(FileStorManagerTest, split1) { 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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -910,7 +910,7 @@ TEST_F(FileStorManagerTest, split1) { 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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -956,7 +956,7 @@ TEST_F(FileStorManagerTest, split_single_group) { _node->getPersistenceProvider().createBucket(makeSpiBucket(bucket)); auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bucket), documents[i], 100 + i); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -982,7 +982,7 @@ TEST_F(FileStorManagerTest, split_single_group) { 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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -1010,7 +1010,7 @@ FileStorTestBase::putDoc(DummyStorageLink& top, _node->getPersistenceProvider().createBucket(makeSpiBucket(target)); auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(target), doc, docNum+1); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); cmd->setPriority(120); filestorHandler.schedule(cmd); filestorHandler.flush(true); @@ -1051,7 +1051,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>(*_node->getTypeRepo(), *_testdoctype1, docId); auto putCmd = std::make_shared<api::PutCommand>(makeDocumentBucket(source), doc, 1001); - putCmd->setAddress(_Storage3); + putCmd->setAddress(_storage3); putCmd->setPriority(120); filestorHandler.schedule(splitCmd); @@ -1132,7 +1132,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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -1144,7 +1144,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(_Storage3); + rcmd->setAddress(_storage3); filestorHandler.schedule(rcmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -1173,7 +1173,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); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); filestorHandler.schedule(cmd); filestorHandler.flush(true); ASSERT_EQ(1, top.getNumReplies()); @@ -1345,7 +1345,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1358,7 +1358,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1384,7 +1384,7 @@ TEST_F(FileStorManagerTest, delete_bucket) { // Putting it { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 105); - cmd->setAddress(_Storage2); + cmd->setAddress(_storage2); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1400,7 +1400,7 @@ TEST_F(FileStorManagerTest, delete_bucket) { // Delete bucket { auto cmd = std::make_shared<api::DeleteBucketCommand>(makeDocumentBucket(bid)); - cmd->setAddress(_Storage2); + cmd->setAddress(_storage2); cmd->setBucketInfo(bucketInfo); top.sendDown(cmd); top.waitForMessages(1, _waitTime); @@ -1426,7 +1426,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(_Storage2); + cmd->setAddress(_storage2); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1443,7 +1443,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(_Storage2); + cmd->setAddress(_storage2); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1471,7 +1471,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(_Storage2); + cmd->setAddress(_storage2); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1485,7 +1485,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(_Storage2); + cmd->setAddress(_storage2); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1509,7 +1509,7 @@ TEST_F(FileStorManagerTest, no_timestamps) { // Putting it { auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(bid), doc, 0); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); EXPECT_EQ(api::Timestamp(0), cmd->getTimestamp()); top.sendDown(cmd); top.waitForMessages(1, _waitTime); @@ -1522,7 +1522,7 @@ TEST_F(FileStorManagerTest, no_timestamps) { // Removing it { auto cmd = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bid), doc->getId(), 0); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); EXPECT_EQ(api::Timestamp(0), cmd->getTimestamp()); top.sendDown(cmd); top.waitForMessages(1, _waitTime); @@ -1547,7 +1547,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1564,7 +1564,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1579,7 +1579,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1611,7 +1611,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(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1674,7 +1674,7 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) { { auto cmd = std::make_shared<api::SetBucketStateCommand>(makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1693,7 +1693,7 @@ TEST_F(FileStorManagerTest, set_bucket_active_state) { { auto cmd = std::make_shared<api::SetBucketStateCommand>( makeDocumentBucket(bid), api::SetBucketStateCommand::INACTIVE); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); top.sendDown(cmd); top.waitForMessages(1, _waitTime); ASSERT_EQ(1, top.getNumReplies()); @@ -1720,7 +1720,7 @@ TEST_F(FileStorManagerTest, notify_owner_distributor_on_outdated_set_bucket_stat createBucket(bid); auto cmd = std::make_shared<api::SetBucketStateCommand>(makeDocumentBucket(bid), api::SetBucketStateCommand::ACTIVE); - cmd->setAddress(_Cluster1); + cmd->setAddress(_cluster1); cmd->setSourceIndex(0); top.sendDown(cmd); @@ -1755,7 +1755,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(_Cluster1); + cmd->setAddress(_cluster1); cmd->setSourceIndex(0); top.sendDown(cmd); @@ -1779,7 +1779,7 @@ 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(_Cluster1); + cmd->setAddress(_cluster1); cmd->setSourceIndex(0); top.sendDown(cmd); @@ -1800,7 +1800,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(_Cluster1); + cmd->setAddress(_cluster1); cmd->setSourceIndex(0); top.sendDown(cmd); @@ -1821,7 +1821,7 @@ TEST_F(FileStorManagerTest, create_bucket_sets_active_flag_in_database_and_reply document::BucketId bid(16, 4000); auto cmd = std::make_shared<api::CreateBucketCommand>(makeDocumentBucket(bid)); - cmd->setAddress(_Cluster1); + cmd->setAddress(_cluster1); cmd->setSourceIndex(0); cmd->setActive(true); c.top.sendDown(cmd); @@ -1840,7 +1840,7 @@ 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) { cmd->setApproxByteSize(54321); - cmd->setAddress(_Storage3); + cmd->setAddress(_storage3); c.top.sendDown(cmd); c.top.waitForMessages(1, _waitTime); EXPECT_EQ(static_cast<int64_t>(cmd->getApproxByteSize()), metric.request_size.getLast()); @@ -1897,7 +1897,7 @@ 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(_Storage3); + cmd->setAddress(_storage3); c.top.sendDown(cmd); api::PutReply* reply; diff --git a/storage/src/tests/visiting/visitormanagertest.cpp b/storage/src/tests/visiting/visitormanagertest.cpp index 4fb857f9e67..5fa6d4a77d8 100644 --- a/storage/src/tests/visiting/visitormanagertest.cpp +++ b/storage/src/tests/visiting/visitormanagertest.cpp @@ -37,8 +37,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); +vespalib::string _storage("storage"); +api::StorageMessageAddress _address(&_storage, lib::NodeType::STORAGE, 0); } struct VisitorManagerTest : Test { @@ -156,7 +156,7 @@ VisitorManagerTest::initializeTest(bool defer_manager_thread_start) 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); @@ -171,7 +171,7 @@ VisitorManagerTest::initializeTest(bool defer_manager_thread_start) 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(); @@ -191,7 +191,7 @@ VisitorManagerTest::addSomeRemoves(bool removeAll) document::BucketId bid(16, i % 10); auto cmd = std::make_shared<api::RemoveCommand>(makeDocumentBucket(bid), _documents[i]->getId(), vespalib::count_us(clock.getSystemTime().time_since_epoch()) + docCount + i + 1); - cmd->setAddress(_Address); + cmd->setAddress(_address); _top->sendDown(cmd); _top->waitForMessages(1, 60); const msg_ptr_vector replies = _top->getRepliesOnce(); @@ -345,7 +345,7 @@ TEST_F(VisitorManagerTest, normal_usage) { ASSERT_NO_FATAL_FAILURE(initializeTest()); 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; @@ -365,7 +365,7 @@ TEST_F(VisitorManagerTest, resending) { ASSERT_NO_FATAL_FAILURE(initializeTest()); 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; @@ -412,7 +412,7 @@ TEST_F(VisitorManagerTest, visit_empty_bucket) { 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 @@ -425,7 +425,7 @@ TEST_F(VisitorManagerTest, multi_bucket_visit) { 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; @@ -444,7 +444,7 @@ TEST_F(VisitorManagerTest, no_buckets) { ASSERT_NO_FATAL_FAILURE(initializeTest()); 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 @@ -463,7 +463,7 @@ TEST_F(VisitorManagerTest, visit_puts_and_removes) { ASSERT_NO_FATAL_FAILURE(initializeTest()); addSomeRemoves(); 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)); @@ -491,7 +491,7 @@ TEST_F(VisitorManagerTest, visit_with_timeframe_and_selection) { 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; @@ -520,7 +520,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); @@ -556,7 +556,7 @@ TEST_F(VisitorManagerTest, visitor_callbacks) { 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 @@ -600,7 +600,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); @@ -612,7 +612,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); } @@ -681,7 +681,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); } @@ -711,7 +711,7 @@ TEST_F(VisitorManagerTest, abort_on_failed_visitor_info) { { 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); } @@ -745,7 +745,7 @@ TEST_F(VisitorManagerTest, abort_on_field_path_error) { 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); @@ -759,7 +759,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); // The manager thread isn't running yet so the visitor stays on the queue @@ -785,7 +785,7 @@ TEST_F(VisitorManagerTest, visitor_processing_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(0ms); cmd->setTimeout(100ms); _top->sendDown(cmd); @@ -809,7 +809,7 @@ sendCreateVisitor(vespalib::duration timeout, DummyStorageLink& top, uint8_t pri ost << "testvis" << ++nextVisitor; 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/vespa/storage/persistence/filestorage/filestormanager.cpp b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp index 6c49fcd0878..e6cd8987c0a 100644 --- a/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp +++ b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp @@ -170,7 +170,7 @@ dynamic_throttle_params_from_config(const StorFilestorConfig& config, uint32_t n #define TLS_LINKAGE __attribute__((visibility("hidden"), tls_model("local-exec"))) #endif -thread_local PersistenceHandler * _G_threadLocalHandler TLS_LINKAGE = nullptr; +thread_local PersistenceHandler * _g_threadLocalHandler TLS_LINKAGE = nullptr; size_t computeAllPossibleHandlerThreads(const vespa::config::content::StorFilestorConfig & cfg) { @@ -198,10 +198,10 @@ FileStorManager::createRegisteredHandler(const ServiceLayerComponent & component PersistenceHandler & FileStorManager::getThreadLocalHandler() { - if (_G_threadLocalHandler == nullptr) { - _G_threadLocalHandler = & createRegisteredHandler(_component); + if (_g_threadLocalHandler == nullptr) { + _g_threadLocalHandler = & createRegisteredHandler(_component); } - return *_G_threadLocalHandler; + return *_g_threadLocalHandler; } void diff --git a/storage/src/vespa/storage/storageserver/bouncer.cpp b/storage/src/vespa/storage/storageserver/bouncer.cpp index 7e3b21ef33a..bfc38e0c8ba 100644 --- a/storage/src/vespa/storage/storageserver/bouncer.cpp +++ b/storage/src/vespa/storage/storageserver/bouncer.cpp @@ -47,6 +47,7 @@ Bouncer::print(std::ostream& out, bool verbose, const std::string& indent) const { (void) verbose; (void) indent; + std::lock_guard guard(_lock); out << "Bouncer(" << _baselineNodeState << ")"; } @@ -343,9 +344,9 @@ void Bouncer::handleNewState() noexcept { std::lock_guard lock(_lock); - const auto reportedNodeState = *_component.getStateUpdater().getReportedNodeState(); + const auto reportedNodeState = *_component.getStateUpdater().getReportedNodeState(); const auto clusterStateBundle = _component.getStateUpdater().getClusterStateBundle(); - const auto &clusterState = *clusterStateBundle->getBaselineClusterState(); + const auto& clusterState = *clusterStateBundle->getBaselineClusterState(); _clusterState = &clusterState.getClusterState(); const lib::Node node(_component.getNodeType(), _component.getIndex()); _baselineNodeState = deriveNodeState(reportedNodeState, clusterState.getNodeState(node)); diff --git a/storage/src/vespa/storage/storageserver/bouncer.h b/storage/src/vespa/storage/storageserver/bouncer.h index 44c7a16f3dc..26282625269 100644 --- a/storage/src/vespa/storage/storageserver/bouncer.h +++ b/storage/src/vespa/storage/storageserver/bouncer.h @@ -27,16 +27,16 @@ class Bouncer : public StorageLink, private StateListener { using StorBouncerConfig = vespa::config::content::core::StorBouncerConfig; + using BucketSpaceNodeStateMapping = std::unordered_map<document::BucketSpace, lib::NodeState, document::BucketSpace::hash>; std::unique_ptr<StorBouncerConfig> _config; - StorageComponent _component; - std::mutex _lock; - lib::NodeState _baselineNodeState; - using BucketSpaceNodeStateMapping = std::unordered_map<document::BucketSpace, lib::NodeState, document::BucketSpace::hash>; - BucketSpaceNodeStateMapping _derivedNodeStates; - const lib::State* _clusterState; - std::unique_ptr<BouncerMetrics> _metrics; - bool _closed; + StorageComponent _component; + mutable std::mutex _lock; + lib::NodeState _baselineNodeState; + BucketSpaceNodeStateMapping _derivedNodeStates; + const lib::State* _clusterState; + std::unique_ptr<BouncerMetrics> _metrics; + bool _closed; public: Bouncer(StorageComponentRegister& compReg, const StorBouncerConfig& bootstrap_config); diff --git a/storage/src/vespa/storageapi/messageapi/storagemessage.cpp b/storage/src/vespa/storageapi/messageapi/storagemessage.cpp index 5a836ec1021..f62c6410882 100644 --- a/storage/src/vespa/storageapi/messageapi/storagemessage.cpp +++ b/storage/src/vespa/storageapi/messageapi/storagemessage.cpp @@ -13,7 +13,7 @@ namespace storage::api { namespace { -std::atomic<uint64_t> _G_lastMsgId(1000); +std::atomic<uint64_t> _g_lastMsgId(1000); } @@ -231,7 +231,7 @@ TransportContext::~TransportContext() = default; StorageMessage::Id StorageMessage::generateMsgId() noexcept { - return _G_lastMsgId.fetch_add(1, std::memory_order_relaxed); + return _g_lastMsgId.fetch_add(1, std::memory_order_relaxed); } StorageMessage::StorageMessage(const MessageType& type, Id internal_id, Id originator_id) noexcept diff --git a/vespa-feed-client/src/main/sh/vespa-version-generator.sh b/vespa-feed-client/src/main/sh/vespa-version-generator.sh index ee46a8debed..cd4684eb24d 100755 --- a/vespa-feed-client/src/main/sh/vespa-version-generator.sh +++ b/vespa-feed-client/src/main/sh/vespa-version-generator.sh @@ -18,7 +18,7 @@ versionNumber=$(cat $source | grep V_TAG_COMPONENT | awk '{print $2}' ) cat > $destination <<- END package ai.vespa.feed.client.impl; -class Vespa { - static final String VERSION = "$versionNumber"; +public class Vespa { + public static final String VERSION = "$versionNumber"; } END |