summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/abi-spec.json20
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java18
-rw-r--r--config-model/src/main/java/com/yahoo/schema/processing/MakeDefaultSummaryTheSuperSet.java1
-rw-r--r--config-model/src/test/java/com/yahoo/schema/derived/SummaryTestCase.java1
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java6
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeType.java10
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java26
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/FileDistributionMaintainer.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainer.java5
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/TenantsMaintainerTest.java3
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java4
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PurchaseOrder.java21
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TaxId.java21
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantBilling.java51
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java1
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BcpGroupUpdater.java18
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java57
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java11
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java36
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java15
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java167
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/json/DimensionHelper.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java20
-rw-r--r--storage/src/tests/persistence/common/filestortestfixture.cpp4
-rw-r--r--storage/src/tests/persistence/filestorage/filestormanagertest.cpp100
-rw-r--r--storage/src/tests/visiting/visitormanagertest.cpp44
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp8
-rw-r--r--storage/src/vespa/storage/storageserver/bouncer.cpp5
-rw-r--r--storage/src/vespa/storage/storageserver/bouncer.h16
-rw-r--r--storage/src/vespa/storageapi/messageapi/storagemessage.cpp4
-rwxr-xr-xvespa-feed-client/src/main/sh/vespa-version-generator.sh4
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