summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
authorHarald Musum <musum@verizonmedia.com>2021-01-20 08:15:21 +0100
committerHarald Musum <musum@verizonmedia.com>2021-01-20 08:15:21 +0100
commit64e28d6625c0b517d75a2a9eb4295048717a1ca9 (patch)
tree287d0f9dab51d77f07c0f0475ca428b4b5639a24 /configserver
parentb335c179019de4c2a90317ed5bb8f1f29a940be2 (diff)
parent4cb56fdd14fa24a14d07ed20de011965c738c8cb (diff)
Merge branch 'master' into hmusum/reduce-use-of-global-component-registry
Diffstat (limited to 'configserver')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java14
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabase.java11
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationReindexing.java136
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/host/HostRegistry.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java111
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainer.java34
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java1
-rw-r--r--configserver/src/test/apps/app-with-multiple-clusters/hosts.xml7
-rw-r--r--configserver/src/test/apps/app-with-multiple-clusters/schemas/bar.sd14
-rw-r--r--configserver/src/test/apps/app-with-multiple-clusters/schemas/bax.sd10
-rw-r--r--configserver/src/test/apps/app-with-multiple-clusters/schemas/baz.sd10
-rw-r--r--configserver/src/test/apps/app-with-multiple-clusters/services.xml33
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java6
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabaseTest.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationReindexingTest.java46
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java6
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java97
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java42
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java6
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java6
23 files changed, 361 insertions, 250 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 1ffefd1a6b7..a341063ddd7 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -915,12 +915,20 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
}
public ApplicationReindexing getReindexing(ApplicationId id) {
- return getTenant(id).getApplicationRepo().database().readReindexingStatus(id)
- .orElse(ApplicationReindexing.ready(clock.instant()));
+ Tenant tenant = getTenant(id);
+ if (tenant == null)
+ throw new NotFoundException("Tenant '" + id.tenant().value() + "' not found");
+
+ return tenant.getApplicationRepo().database().readReindexingStatus(id)
+ .orElseThrow(() -> new NotFoundException("Reindexing status not found for " + id));
}
public void modifyReindexing(ApplicationId id, UnaryOperator<ApplicationReindexing> modifications) {
- getTenant(id).getApplicationRepo().database().modifyReindexing(id, ApplicationReindexing.ready(clock.instant()), modifications);
+ Tenant tenant = getTenant(id);
+ if (tenant == null)
+ throw new NotFoundException("Tenant '" + id.tenant().value() + "' not found");
+
+ tenant.getApplicationRepo().database().modifyReindexing(id, ApplicationReindexing.empty(), modifications);
}
public ConfigserverConfig configserverConfig() {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
index e77592dc011..57eac2a1a7b 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
@@ -135,12 +135,7 @@ public class Application implements ModelResult {
boolean applyOnRestart = false;
try {
builder = model.getConfigInstance(configKey, def);
- if (builder == null) { // TODO: Remove this condition after December 2020
- payload = model.getConfig(configKey, def);
- if (def.getCNode() != null)
- payload.applyDefaultsFromDef(def.getCNode());
- }
- else if (builder instanceof GenericConfig.GenericConfigBuilder) {
+ if (builder instanceof GenericConfig.GenericConfigBuilder) {
payload = ((GenericConfig.GenericConfigBuilder) builder).getPayload();
applyOnRestart = builder.getApplyOnRestart();
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabase.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabase.java
index f98d58d9fb4..099de9bc2bf 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabase.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabase.java
@@ -73,12 +73,12 @@ public class ApplicationCuratorDatabase {
/**
* Creates a node for the given application, marking its existence.
*/
- public void createApplication(ApplicationId id, Instant now) {
+ public void createApplication(ApplicationId id) {
if ( ! id.tenant().equals(tenant))
throw new IllegalArgumentException("Cannot write application id '" + id + "' for tenant '" + tenant + "'");
try (Lock lock = lock(id)) {
curator.create(applicationPath(id));
- modifyReindexing(id, ApplicationReindexing.ready(now), UnaryOperator.identity());
+ modifyReindexing(id, ApplicationReindexing.empty(), UnaryOperator.identity());
}
}
@@ -158,7 +158,6 @@ public class ApplicationCuratorDatabase {
private static class ReindexingStatusSerializer {
- private static final String COMMON = "common";
private static final String ENABLED = "enabled";
private static final String CLUSTERS = "clusters";
private static final String PENDING = "pending";
@@ -171,13 +170,11 @@ public class ApplicationCuratorDatabase {
private static byte[] toBytes(ApplicationReindexing reindexing) {
Cursor root = new Slime().setObject();
root.setBool(ENABLED, reindexing.enabled());
- setStatus(root.setObject(COMMON), reindexing.common());
Cursor clustersArray = root.setArray(CLUSTERS);
reindexing.clusters().forEach((name, cluster) -> {
Cursor clusterObject = clustersArray.addObject();
clusterObject.setString(NAME, name);
- setStatus(clusterObject.setObject(COMMON), cluster.common());
Cursor pendingArray = clusterObject.setArray(PENDING);
cluster.pending().forEach((type, generation) -> {
@@ -203,15 +200,13 @@ public class ApplicationCuratorDatabase {
private static ApplicationReindexing fromBytes(byte[] data) {
Cursor root = SlimeUtils.jsonToSlimeOrThrow(data).get();
return new ApplicationReindexing(root.field(ENABLED).valid() ? root.field(ENABLED).asBool() : true,
- getStatus(root.field(COMMON)),
SlimeUtils.entriesStream(root.field(CLUSTERS))
.collect(toUnmodifiableMap(object -> object.field(NAME).asString(),
object -> getCluster(object))));
}
private static Cluster getCluster(Inspector object) {
- return new Cluster(getStatus(object.field(COMMON)),
- SlimeUtils.entriesStream(object.field(PENDING))
+ return new Cluster(SlimeUtils.entriesStream(object.field(PENDING))
.collect(toUnmodifiableMap(entry -> entry.field(TYPE).asString(),
entry -> entry.field(GENERATION).asLong())),
SlimeUtils.entriesStream(object.field(READY))
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationReindexing.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationReindexing.java
index cb81bed155e..63aca62768d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationReindexing.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationReindexing.java
@@ -2,22 +2,33 @@
package com.yahoo.vespa.config.server.application;
import com.yahoo.config.model.api.Reindexing;
+import com.yahoo.searchdefinition.Search;
+import com.yahoo.searchdefinition.document.SDField;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.content.cluster.ContentCluster;
+import com.yahoo.vespa.model.search.AbstractSearchCluster;
+import com.yahoo.vespa.model.search.DocumentDatabase;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
import static java.util.stream.Collectors.toUnmodifiableMap;
+import static java.util.stream.Collectors.toUnmodifiableSet;
/**
- * Pending and ready reindexing per document type. Each document type can have either a pending or a ready reindexing.
- * Each cluster may also have a global status, which is merged with its document type-specific status, by selecting
- * whichever status is ready the latest. The application may also have a global status, which is merged likewise.
+ * Pending reindexing: convergence to the stored config generation allows reindexing to start.
+ * Ready reindexing: reindexing may start after this timestamp.
* This is immutable.
*
* @author jonmv
@@ -25,69 +36,64 @@ import static java.util.stream.Collectors.toUnmodifiableMap;
public class ApplicationReindexing implements Reindexing {
private final boolean enabled;
- private final Status common;
private final Map<String, Cluster> clusters;
- ApplicationReindexing(boolean enabled, Status common, Map<String, Cluster> clusters) {
+ ApplicationReindexing(boolean enabled, Map<String, Cluster> clusters) {
this.enabled = enabled;
- this.common = requireNonNull(common);
this.clusters = Map.copyOf(clusters);
}
/** Reindexing for the whole application ready now. */
- public static ApplicationReindexing ready(Instant now) {
- return new ApplicationReindexing(true, new Status(now), Map.of());
- }
-
- /** Returns a copy of this with reindexing for the whole application ready at the given instant. */
- public ApplicationReindexing withReady(Instant readyAt) {
- return new ApplicationReindexing(enabled,
- new Status(readyAt),
- clusters.entrySet().stream()
- .filter(cluster -> ! cluster.getValue().pending.isEmpty())
- .collect(toUnmodifiableMap(cluster -> cluster.getKey(),
- cluster -> new Cluster(new Status(readyAt),
- cluster.getValue().pending,
- Map.of()))));
- }
-
- /** Returns a copy of this with reindexing for the given cluster ready at the given instant. */
- public ApplicationReindexing withReady(String cluster, Instant readyAt) {
- Cluster current = clusters.getOrDefault(cluster, Cluster.ready(common));
- Cluster modified = new Cluster(new Status(readyAt), current.pending, Map.of());
- return new ApplicationReindexing(enabled, common, with(cluster, modified, clusters));
+ public static ApplicationReindexing empty() {
+ return new ApplicationReindexing(true, Map.of());
}
/** Returns a copy of this with reindexing for the given document type in the given cluster ready at the given instant. */
public ApplicationReindexing withReady(String cluster, String documentType, Instant readyAt) {
- Cluster current = clusters.getOrDefault(cluster, Cluster.ready(common));
- Cluster modified = new Cluster(current.common,
- current.pending,
+ Cluster current = clusters.getOrDefault(cluster, Cluster.empty());
+ Cluster modified = new Cluster(current.pending,
with(documentType, new Status(readyAt), current.ready));
- return new ApplicationReindexing(enabled, common, with(cluster, modified, clusters));
+ return new ApplicationReindexing(enabled, with(cluster, modified, clusters));
}
/** Returns a copy of this with a pending reindexing at the given generation, for the given document type. */
public ApplicationReindexing withPending(String cluster, String documentType, long requiredGeneration) {
- Cluster current = clusters.getOrDefault(cluster, Cluster.ready(common));
- Cluster modified = new Cluster(current.common,
- with(documentType, requirePositive(requiredGeneration), current.pending),
+ Cluster current = clusters.getOrDefault(cluster, Cluster.empty());
+ Cluster modified = new Cluster(with(documentType, requirePositive(requiredGeneration), current.pending),
current.ready);
- return new ApplicationReindexing(enabled, common, with(cluster, modified, clusters));
+ return new ApplicationReindexing(enabled, with(cluster, modified, clusters));
}
/** Returns a copy of this with no pending reindexing for the given document type. */
public ApplicationReindexing withoutPending(String cluster, String documentType) {
- Cluster current = clusters.getOrDefault(cluster, Cluster.ready(common));
- Cluster modified = new Cluster(current.common,
- without(documentType, current.pending),
+ Cluster current = clusters.getOrDefault(cluster, Cluster.empty());
+ if (current == null)
+ return this;
+
+ Cluster modified = new Cluster(without(documentType, current.pending),
current.ready);
- return new ApplicationReindexing(enabled, common, with(cluster, modified, clusters));
+ return new ApplicationReindexing(enabled, with(cluster, modified, clusters));
+ }
+
+ /** Returns a copy of this without the given cluster. */
+ public ApplicationReindexing without(String cluster) {
+ return new ApplicationReindexing(enabled, without(cluster, clusters));
+ }
+
+ /** Returns a copy of this without the given document type in the given cluster. */
+ public ApplicationReindexing without(String cluster, String documentType) {
+ Cluster current = clusters.get(cluster);
+ if (current == null)
+ return this;
+
+ Cluster modified = new Cluster(current.pending,
+ without(documentType, current.ready));
+ return new ApplicationReindexing(enabled, with(cluster, modified, clusters));
}
/** Returns a copy of this with the enabled-state set to the given value. */
public ApplicationReindexing enabled(boolean enabled) {
- return new ApplicationReindexing(enabled, common, clusters);
+ return new ApplicationReindexing(enabled, clusters);
}
@Override
@@ -95,21 +101,12 @@ public class ApplicationReindexing implements Reindexing {
return enabled;
}
- /** The common reindexing status for the whole application. */
- public Status common() {
- return common;
- }
-
/** The reindexing status of each of the clusters of this application. */
public Map<String, Cluster> clusters() { return clusters; }
@Override
- public Optional<Reindexing.Status> status(String cluster, String documentType) {
- return ! clusters.containsKey(cluster)
- ? Optional.of(common())
- : ! clusters.get(cluster).ready().containsKey(documentType)
- ? Optional.of(clusters.get(cluster).common())
- : Optional.of(clusters.get(cluster).ready().get(documentType));
+ public Optional<Reindexing.Status> status(String clusterName, String documentType) {
+ return Optional.ofNullable(clusters.get(clusterName)).map(cluster -> cluster.ready().get(documentType));
}
@Override
@@ -118,20 +115,18 @@ public class ApplicationReindexing implements Reindexing {
if (o == null || getClass() != o.getClass()) return false;
ApplicationReindexing that = (ApplicationReindexing) o;
return enabled == that.enabled &&
- common.equals(that.common) &&
clusters.equals(that.clusters);
}
@Override
public int hashCode() {
- return Objects.hash(enabled, common, clusters);
+ return Objects.hash(enabled, clusters);
}
@Override
public String toString() {
return "ApplicationReindexing{" +
"enabled=" + enabled +
- ", common=" + common +
", clusters=" + clusters +
'}';
}
@@ -139,23 +134,16 @@ public class ApplicationReindexing implements Reindexing {
/** Reindexing status for a single content cluster in an application. */
public static class Cluster {
- private static Cluster ready(Status common) { return new Cluster(common, Map.of(), Map.of()); }
+ private static Cluster empty() { return new Cluster(Map.of(), Map.of()); }
- private final Status common;
private final Map<String, Long> pending;
private final Map<String, Status> ready;
- Cluster(Status common, Map<String, Long> pending, Map<String, Status> ready) {
- this.common = requireNonNull(common);
+ Cluster(Map<String, Long> pending, Map<String, Status> ready) {
this.pending = Map.copyOf(pending);
this.ready = Map.copyOf(ready);
}
- /** The common reindexing status for all document types in this cluster. */
- public Status common() {
- return common;
- }
-
/** The config generation at which the application must have converged for the latest reindexing to begin, per document type. */
public Map<String, Long> pending() {
return pending;
@@ -171,21 +159,19 @@ public class ApplicationReindexing implements Reindexing {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cluster cluster = (Cluster) o;
- return common.equals(cluster.common) &&
- pending.equals(cluster.pending) &&
+ return pending.equals(cluster.pending) &&
ready.equals(cluster.ready);
}
@Override
public int hashCode() {
- return Objects.hash(common, pending, ready);
+ return Objects.hash(pending, ready);
}
@Override
public String toString() {
return "Cluster{" +
- "common=" + common +
- ", pending=" + pending +
+ "pending=" + pending +
", ready=" + ready +
'}';
}
@@ -234,17 +220,15 @@ public class ApplicationReindexing implements Reindexing {
}
private static <T> Map<String, T> without(String removed, Map<String, T> map) {
- return map.keySet().stream()
- .filter(key -> ! removed.equals(key))
- .collect(toUnmodifiableMap(key -> key,
- key -> map.get(key)));
+ Map<String, T> modified = new HashMap<>(map);
+ modified.remove(removed);
+ return Map.copyOf(modified);
}
private static <T> Map<String, T> with(String added, T value, Map<String, T> map) {
- return Stream.concat(Stream.of(added), map.keySet().stream()).distinct()
- .collect(toUnmodifiableMap(key -> key,
- key -> added.equals(key) ? value
- : map.get(key)));
+ Map<String, T> modified = new HashMap<>(map);
+ modified.put(added, value);
+ return Map.copyOf(modified);
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
index 34e199e388b..3d979ebd3b8 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
@@ -146,7 +146,7 @@ public class TenantApplications implements RequestHandler, HostValidator<Applica
* Creates a node for the given application, marking its existence.
*/
public void createApplication(ApplicationId id) {
- database().createApplication(id, clock.instant());
+ database().createApplication(id);
}
/**
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/host/HostRegistry.java b/configserver/src/main/java/com/yahoo/vespa/config/server/host/HostRegistry.java
index d45764295dd..696c94fcdbd 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/host/HostRegistry.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/host/HostRegistry.java
@@ -34,9 +34,9 @@ public class HostRegistry implements HostValidator<ApplicationId> {
public synchronized void update(ApplicationId key, Collection<String> newHosts) {
verifyHosts(key, newHosts);
Collection<String> currentHosts = getHostsForKey(key);
- log.log(Level.INFO, () -> "Setting hosts for key '" + key + "', " +
- "newHosts: " + newHosts + ", " +
- "currentHosts: " + currentHosts);
+ log.log(Level.FINE, () -> "Setting hosts for key '" + key + "', " +
+ "newHosts: " + newHosts + ", " +
+ "currentHosts: " + currentHosts);
Collection<String> removedHosts = getRemovedHosts(newHosts, currentHosts);
removeHosts(removedHosts);
addHosts(key, newHosts);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
index 7ea53a66697..08ba028396f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.config.server.http.v2;
import com.google.inject.Inject;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.ApplicationFile;
+import com.yahoo.config.model.api.Model;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.HostFilter;
@@ -38,6 +39,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.StringJoiner;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -226,30 +230,52 @@ public class ApplicationHandler extends HttpHandler {
throw new NotFoundException("Illegal POST request '" + request.getUri() + "'");
}
+ private Model getActiveModelOrThrow(ApplicationId id) {
+ return applicationRepository.getActiveApplicationSet(id)
+ .orElseThrow(() -> new NotFoundException("Application '" + id + "' not found"))
+ .getForVersionOrLatest(Optional.empty(), applicationRepository.clock().instant())
+ .getModel();
+ }
+
private HttpResponse triggerReindexing(HttpRequest request, ApplicationId applicationId) {
+ Model model = getActiveModelOrThrow(applicationId);
+ Map<String, Set<String>> documentTypes = model.documentTypesByCluster();
+ Map<String, Set<String>> indexedDocumentTypes = model.indexedDocumentTypesByCluster();
+
+ boolean indexedOnly = request.getBooleanProperty("indexedOnly");
Set<String> clusters = StringUtilities.split(request.getProperty("clusterId"));
Set<String> types = StringUtilities.split(request.getProperty("documentType"));
+
+ Map<String, Set<String>> reindexed = new TreeMap<>();
Instant now = applicationRepository.clock().instant();
applicationRepository.modifyReindexing(applicationId, reindexing -> {
- if (clusters.isEmpty())
- reindexing = reindexing.withReady(now);
- else
- for (String cluster : clusters)
- if (types.isEmpty())
- reindexing = reindexing.withReady(cluster, now);
- else
- for (String type : types)
- reindexing = reindexing.withReady(cluster, type, now);
+ for (String cluster : clusters.isEmpty() ? documentTypes.keySet() : clusters) {
+ if ( ! documentTypes.containsKey(cluster))
+ throw new IllegalArgumentException("No content cluster '" + cluster + "' in application — only: " +
+ String.join(", ", documentTypes.keySet()));
+
+ for (String type : types.isEmpty() ? documentTypes.get(cluster) : types) {
+ if ( ! documentTypes.get(cluster).contains(type))
+ throw new IllegalArgumentException("No document type '" + type + "' in cluster '" + cluster + "' — only: " +
+ String.join(", ", documentTypes.get(cluster)));
+
+ if ( ! indexedOnly || indexedDocumentTypes.get(cluster).contains(type)) {
+ reindexing = reindexing.withReady(cluster, type, now);
+ reindexed.computeIfAbsent(cluster, __ -> new TreeSet<>()).add(type);
+ }
+ }
+ }
return reindexing;
});
- String message = "Reindexing " +
- (clusters.isEmpty() ? ""
- : (types.isEmpty() ? ""
- : "document types " + String.join(", ", types) + " in ") +
- "clusters " + String.join(", ", clusters) + " of ") +
- "application " + applicationId;
- return createMessageResponse(message);
+ return createMessageResponse(reindexed.entrySet().stream()
+ .filter(cluster -> ! cluster.getValue().isEmpty())
+ .map(cluster -> "[" + String.join(", ", cluster.getValue()) + "] in '" + cluster.getKey() + "'")
+ .reduce(new StringJoiner(", ", "Reindexing document types ", " of application " + applicationId)
+ .setEmptyValue("Not reindexing any document types of application " + applicationId),
+ StringJoiner::add,
+ StringJoiner::merge)
+ .toString());
}
private HttpResponse getReindexingStatus(ApplicationId applicationId) {
@@ -257,9 +283,8 @@ public class ApplicationHandler extends HttpHandler {
if (tenant == null)
throw new NotFoundException("Tenant '" + applicationId.tenant().value() + "' not found");
- return new ReindexingResponse(tenant.getApplicationRepo().database()
- .readReindexingStatus(applicationId)
- .orElseThrow(() -> new NotFoundException("Reindexing status not found for " + applicationId)),
+ return new ReindexingResponse(getActiveModelOrThrow(applicationId).documentTypesByCluster(),
+ applicationRepository.getReindexing(applicationId),
applicationRepository.getClusterReindexingStatus(applicationId));
}
@@ -449,37 +474,33 @@ public class ApplicationHandler extends HttpHandler {
}
static class ReindexingResponse extends JSONResponse {
- ReindexingResponse(ApplicationReindexing reindexing, Map<String, ClusterReindexing> clusters) {
+ ReindexingResponse(Map<String, Set<String>> documentTypes, ApplicationReindexing reindexing,
+ Map<String, ClusterReindexing> clusters) {
super(Response.Status.OK);
object.setBool("enabled", reindexing.enabled());
- setStatus(object.setObject("status"), reindexing.common());
-
Cursor clustersObject = object.setObject("clusters");
- Stream<String> clusterNames = Stream.concat(clusters.keySet().stream(), reindexing.clusters().keySet().stream());
- clusterNames.sorted()
- .forEach(clusterName -> {
- Cursor clusterObject = clustersObject.setObject(clusterName);
- Cursor pendingObject = clusterObject.setObject("pending");
- Cursor readyObject = clusterObject.setObject("ready");
-
- Map<String, Cursor> statuses = new HashMap<>();
- if (reindexing.clusters().containsKey(clusterName)) {
- setStatus(clusterObject.setObject("status"), reindexing.clusters().get(clusterName).common());
-
- reindexing.clusters().get(clusterName).pending().entrySet().stream().sorted(comparingByKey())
- .forEach(pending -> pendingObject.setLong(pending.getKey(), pending.getValue()));
-
- reindexing.clusters().get(clusterName).ready().entrySet().stream().sorted(comparingByKey())
- .forEach(ready -> setStatus(statuses.computeIfAbsent(ready.getKey(), readyObject::setObject), ready.getValue()));
- }
- if (clusters.containsKey(clusterName))
- clusters.get(clusterName).documentTypeStatus().entrySet().stream().sorted(comparingByKey())
- .forEach(status -> setStatus(statuses.computeIfAbsent(status.getKey(), readyObject::setObject), status.getValue()));
-
- });
+ documentTypes.forEach((cluster, types) -> {
+ Cursor clusterObject = clustersObject.setObject(cluster);
+ Cursor pendingObject = clusterObject.setObject("pending");
+ Cursor readyObject = clusterObject.setObject("ready");
+
+ for (String type : types) {
+ Cursor statusObject = readyObject.setObject(type);
+ if (reindexing.clusters().containsKey(cluster)) {
+ if (reindexing.clusters().get(cluster).pending().containsKey(type))
+ pendingObject.setLong(type, reindexing.clusters().get(cluster).pending().get(type));
+
+ if (reindexing.clusters().get(cluster).ready().containsKey(type))
+ setStatus(statusObject, reindexing.clusters().get(cluster).ready().get(type));
+ }
+ if (clusters.containsKey(cluster))
+ if (clusters.get(cluster).documentTypeStatus().containsKey(type))
+ setStatus(statusObject, clusters.get(cluster).documentTypeStatus().get(type));
+ }
+ });
}
- private static void setStatus(Cursor object, ApplicationReindexing.Status readyStatus) {
+ private static void setStatus(Cursor object, ApplicationReindexing.Status readyStatus) {
object.setLong("readyMillis", readyStatus.ready().toEpochMilli());
}
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 22eb95261bd..971c2c20ae9 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
@@ -6,16 +6,20 @@ import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.application.ApplicationCuratorDatabase;
import com.yahoo.vespa.config.server.application.ApplicationReindexing;
+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.vespa.model.VespaModel;
import com.yahoo.yolean.Exceptions;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
+import java.util.Collection;
import java.util.Comparator;
+import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
@@ -25,6 +29,7 @@ import java.util.logging.Logger;
/**
* Watches pending reindexing, and sets these to ready when config convergence is observed.
+ * Also removes data for clusters or document types which no longer exist.
*
* @author jonmv
*/
@@ -55,8 +60,11 @@ public class ReindexingMaintainer extends ConfigServerMaintainer {
.map(application -> application.getForVersionOrLatest(Optional.empty(), clock.instant()))
.ifPresent(application -> {
try {
- applicationRepository.modifyReindexing(id, reindexing ->
- withNewReady(reindexing, lazyGeneration(application), clock.instant()));
+ applicationRepository.modifyReindexing(id, reindexing -> {
+ reindexing = withNewReady(reindexing, lazyGeneration(application), clock.instant());
+ reindexing = withOnlyCurrentData(reindexing, application);
+ return reindexing;
+ });
}
catch (RuntimeException e) {
log.log(Level.INFO, "Failed to update reindexing status for " + id + ": " + Exceptions.toMessageString(e));
@@ -90,4 +98,26 @@ public class ReindexingMaintainer extends ConfigServerMaintainer {
return reindexing;
}
+ static ApplicationReindexing withOnlyCurrentData(ApplicationReindexing reindexing, Application application) {
+ return withOnlyCurrentData(reindexing, application.getModel().documentTypesByCluster());
+ }
+
+ static ApplicationReindexing withOnlyCurrentData(ApplicationReindexing reindexing, Map<String, ? extends Collection<String>> clusterDocumentTypes) {
+ for (String clusterId : reindexing.clusters().keySet()) {
+ if ( ! clusterDocumentTypes.containsKey(clusterId))
+ reindexing = reindexing.without(clusterId);
+ else {
+ Cluster cluster = reindexing.clusters().get(clusterId);
+ Collection<String> documentTypes = clusterDocumentTypes.get(clusterId);
+ for (String pending : cluster.pending().keySet())
+ if ( ! documentTypes.contains(pending))
+ reindexing = reindexing.withoutPending(clusterId, pending);
+ for (String ready : cluster.ready().keySet())
+ if ( ! documentTypes.contains(ready))
+ reindexing = reindexing.without(clusterId, ready);
+ }
+ }
+ return reindexing;
+ }
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
index 8e693d59a40..76fb7d29a43 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
@@ -475,6 +475,7 @@ public class TenantRepository {
return tenants.containsKey(tenant);
}
+ /** Returns the tenant with the given name, or {@code null} if this does not exist. */
public Tenant getTenant(TenantName tenantName) {
return tenants.get(tenantName);
}
diff --git a/configserver/src/test/apps/app-with-multiple-clusters/hosts.xml b/configserver/src/test/apps/app-with-multiple-clusters/hosts.xml
new file mode 100644
index 00000000000..f4256c9fc81
--- /dev/null
+++ b/configserver/src/test/apps/app-with-multiple-clusters/hosts.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<hosts>
+ <host name="mytesthost">
+ <alias>node1</alias>
+ </host>
+</hosts>
diff --git a/configserver/src/test/apps/app-with-multiple-clusters/schemas/bar.sd b/configserver/src/test/apps/app-with-multiple-clusters/schemas/bar.sd
new file mode 100644
index 00000000000..b66695b17df
--- /dev/null
+++ b/configserver/src/test/apps/app-with-multiple-clusters/schemas/bar.sd
@@ -0,0 +1,14 @@
+# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+search bar {
+
+ field zoo type string {
+ indexing: input moo | index | summary
+ }
+
+ document bar {
+ field moo type string {
+ indexing: summary | attribute
+ }
+ }
+
+} \ No newline at end of file
diff --git a/configserver/src/test/apps/app-with-multiple-clusters/schemas/bax.sd b/configserver/src/test/apps/app-with-multiple-clusters/schemas/bax.sd
new file mode 100644
index 00000000000..f9f6aba766e
--- /dev/null
+++ b/configserver/src/test/apps/app-with-multiple-clusters/schemas/bax.sd
@@ -0,0 +1,10 @@
+# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+search bax {
+
+ document bax {
+ field moo type string {
+ indexing: summary | attribute
+ }
+ }
+
+} \ No newline at end of file
diff --git a/configserver/src/test/apps/app-with-multiple-clusters/schemas/baz.sd b/configserver/src/test/apps/app-with-multiple-clusters/schemas/baz.sd
new file mode 100644
index 00000000000..58f0aa16fd0
--- /dev/null
+++ b/configserver/src/test/apps/app-with-multiple-clusters/schemas/baz.sd
@@ -0,0 +1,10 @@
+# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+search baz {
+
+ document baz {
+ field moo type string {
+ indexing: summary | attribute
+ }
+ }
+
+} \ No newline at end of file
diff --git a/configserver/src/test/apps/app-with-multiple-clusters/services.xml b/configserver/src/test/apps/app-with-multiple-clusters/services.xml
new file mode 100644
index 00000000000..735bd04b2f9
--- /dev/null
+++ b/configserver/src/test/apps/app-with-multiple-clusters/services.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright 2020 Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<services version="1.0">
+
+ <content id="foo" version="1.0">
+ <redundancy>2</redundancy>
+ <documents>
+ <document type="bar" mode="index"/>
+ <document type="baz" mode="streaming"/>
+ <document type="bax" mode="index"/>
+ </documents>
+ <nodes>
+ <node hostalias="node1" distribution-key="0"/>
+ </nodes>
+ </content>
+
+ <content id="boo" version="1.0">
+ <redundancy>2</redundancy>
+ <documents>
+ <document type="bar" mode="store-only"/>
+ </documents>
+ <nodes>
+ <node hostalias="node1" distribution-key="1"/>
+ </nodes>
+ </content>
+
+ <container version="1.0">
+ <nodes>
+ <node hostalias="node1" />
+ </nodes>
+ </container>
+
+</services>
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java
index 88f7d352ad7..ed12f4dbbe1 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java
@@ -21,12 +21,6 @@ import java.util.Set;
public class ModelStub implements Model {
@Override
- @SuppressWarnings("deprecation")
- public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
- return null;
- }
-
- @Override
public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabaseTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabaseTest.java
index 0c4472398c1..13803f29794 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabaseTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationCuratorDatabaseTest.java
@@ -22,12 +22,10 @@ public class ApplicationCuratorDatabaseTest {
assertEquals(Optional.empty(), db.readReindexingStatus(id));
- ApplicationReindexing reindexing = ApplicationReindexing.ready(Instant.EPOCH)
- .withReady(Instant.ofEpochMilli(1 << 20))
+ ApplicationReindexing reindexing = ApplicationReindexing.empty()
.withPending("one", "a", 10)
.withReady("two", "b", Instant.ofEpochMilli(2))
.withPending("two", "b", 20)
- .withReady("two", Instant.ofEpochMilli(2 << 10))
.withReady("one", "a", Instant.ofEpochMilli(1))
.withReady("two", "c", Instant.ofEpochMilli(3))
.enabled(false);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationReindexingTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationReindexingTest.java
index 128ba9c0c9d..e8b71dc5433 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationReindexingTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationReindexingTest.java
@@ -20,55 +20,45 @@ public class ApplicationReindexingTest {
@Test
public void test() {
- ApplicationReindexing reindexing = ApplicationReindexing.ready(Instant.EPOCH)
- .withReady(Instant.ofEpochMilli(1 << 20))
+ ApplicationReindexing reindexing = ApplicationReindexing.empty()
.withPending("one", "a", 10)
.withReady("two", "b", Instant.ofEpochMilli(2))
.withPending("two", "b", 20)
- .withReady("two", Instant.ofEpochMilli(2 << 10))
.withReady("one", "a", Instant.ofEpochMilli(1))
- .withReady("two", "c", Instant.ofEpochMilli(3))
+ .withReady("two", "a", Instant.ofEpochMilli(3))
.withoutPending("one", "a");
- // Document is most specific, and is used.
assertEquals(Instant.ofEpochMilli(1),
reindexing.status("one", "a").orElseThrow().ready());
+ assertEquals(Optional.empty(),
+ reindexing.status("one", "b"));
- // Cluster is most specific, and inherits application's common status.
- assertEquals(Instant.ofEpochMilli(1 << 20),
- reindexing.status("one", "d").orElseThrow().ready());
-
- // Cluster is most specific, and has its own status set.
- assertEquals(Instant.ofEpochMilli(2 << 10),
- reindexing.status("two", "d").orElseThrow().ready());
-
- // Application is most specific, as cluster and documeent are unknown.
- assertEquals(Instant.ofEpochMilli(1 << 20),
- reindexing.status("three", "a").orElseThrow().ready());
-
- // Cluster is most specific, and is used, also when pending reindexing exists for document.
- assertEquals(Instant.ofEpochMilli(2 << 10),
+ assertEquals(Instant.ofEpochMilli(2),
reindexing.status("two", "b").orElseThrow().ready());
+ assertEquals(Instant.ofEpochMilli(3),
+ reindexing.status("two", "a").orElseThrow().ready());
- assertEquals(new Status(Instant.ofEpochMilli(1 << 20)),
- reindexing.common());
+ assertEquals(Optional.empty(),
+ reindexing.status("three", "a"));
+ // Remove "a" in "one", and "one" entirely.
+ assertEquals(Optional.empty(),
+ reindexing.without("one", "a").status("one", "a"));
+ assertEquals(Optional.empty(),
+ reindexing.without("one").status("one", "a"));
+
+ // Verify content of "reindexing".
assertEquals(Set.of("one", "two"),
reindexing.clusters().keySet());
- assertEquals(new Status(Instant.ofEpochMilli(1 << 20)),
- reindexing.clusters().get("one").common());
-
assertEquals(Map.of("a", new Status(Instant.ofEpochMilli(1))),
reindexing.clusters().get("one").ready());
assertEquals(Map.of(),
reindexing.clusters().get("one").pending());
- assertEquals(new Status(Instant.ofEpochMilli(2 << 10)),
- reindexing.clusters().get("two").common());
-
- assertEquals(Map.of("c", new Status(Instant.ofEpochMilli(3))),
+ assertEquals(Map.of("a", new Status(Instant.ofEpochMilli(3)),
+ "b", new Status(Instant.ofEpochMilli(2))),
reindexing.clusters().get("two").ready());
assertEquals(Map.of("b", 20L),
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java
index 0288a551cd3..7e57eea74d6 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java
@@ -74,12 +74,6 @@ public class MockModel implements Model {
}
@Override
- @SuppressWarnings("deprecation")
- public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
index 341fa7109da..bb6c85961a5 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
@@ -411,7 +411,7 @@ public class HostedDeployTest {
assertEquals(4, tester.getAllocatedHostsOf(tester.applicationId()).getHosts().size());
assertTrue(prepareResult.configChangeActions().getRestartActions().isEmpty()); // Handled by deployment.
- assertEquals(Optional.of(ApplicationReindexing.ready(clock.instant())
+ assertEquals(Optional.of(ApplicationReindexing.empty()
.withPending("cluster", "music", prepareResult.sessionId())),
tester.tenant().getApplicationRepo().database().readReindexingStatus(tester.applicationId()));
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
index 007cc61aaf7..05b09fb4204 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
@@ -54,6 +54,9 @@ import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.stream.Stream;
import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
@@ -78,6 +81,7 @@ import static org.mockito.Mockito.when;
public class ApplicationHandlerTest {
private static final File testApp = new File("src/test/apps/app");
+ private static final File testAppMultipleClusters = new File("src/test/apps/app-with-multiple-clusters");
private static final File testAppJdiscOnly = new File("src/test/apps/app-jdisc-only");
private final static TenantName mytenantName = TenantName.from("mytenant");
@@ -217,44 +221,57 @@ public class ApplicationHandlerTest {
@Test
public void testReindex() throws Exception {
ApplicationCuratorDatabase database = applicationRepository.getTenant(applicationId).getApplicationRepo().database();
- reindexing(applicationId, GET, "{\"error-code\": \"NOT_FOUND\", \"message\": \"Reindexing status not found for default.default\"}", 404);
+ reindexing(applicationId, GET, "{\"error-code\": \"NOT_FOUND\", \"message\": \"Application 'default.default' not found\"}", 404);
- applicationRepository.deploy(testApp, prepareParams(applicationId));
- ApplicationReindexing expected = ApplicationReindexing.ready(clock.instant());
+ applicationRepository.deploy(testAppMultipleClusters, prepareParams(applicationId));
+ ApplicationReindexing expected = ApplicationReindexing.empty();
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "", "{\"message\":\"Reindexing application default.default\"}");
- expected = expected.withReady(clock.instant());
+ reindex(applicationId, "", "{\"message\":\"Reindexing document types [bar] in 'boo', [bar, bax, baz] in 'foo' of application default.default\"}");
+ expected = expected.withReady("boo", "bar", clock.instant())
+ .withReady("foo", "bar", clock.instant())
+ .withReady("foo", "baz", clock.instant())
+ .withReady("foo", "bax", clock.instant());
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- expected = expected.withReady(clock.instant());
- reindex(applicationId, "?clusterId=", "{\"message\":\"Reindexing application default.default\"}");
+ reindex(applicationId, "?indexedOnly=true", "{\"message\":\"Reindexing document types [bar] in 'foo' of application default.default\"}");
+ expected = expected.withReady("foo", "bar", clock.instant());
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- expected = expected.withReady(clock.instant());
- reindex(applicationId, "?documentType=moo", "{\"message\":\"Reindexing application default.default\"}");
+ expected = expected.withReady("boo", "bar", clock.instant())
+ .withReady("foo", "bar", clock.instant())
+ .withReady("foo", "baz", clock.instant())
+ .withReady("foo", "bax", clock.instant());
+ reindex(applicationId, "?clusterId=", "{\"message\":\"Reindexing document types [bar] in 'boo', [bar, bax, baz] in 'foo' of application default.default\"}");
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "?clusterId=foo,boo", "{\"message\":\"Reindexing clusters foo, boo of application default.default\"}");
- expected = expected.withReady("foo", clock.instant())
- .withReady("boo", clock.instant());
+ expected = expected.withReady("boo", "bar", clock.instant())
+ .withReady("foo", "bar", clock.instant());
+ reindex(applicationId, "?documentType=bar", "{\"message\":\"Reindexing document types [bar] in 'boo', [bar] in 'foo' of application default.default\"}");
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
clock.advance(Duration.ofSeconds(1));
- reindex(applicationId, "?clusterId=foo,boo&documentType=bar,baz", "{\"message\":\"Reindexing document types bar, baz in clusters foo, boo of application default.default\"}");
- expected = expected.withReady("foo", "bar", clock.instant())
+ reindex(applicationId, "?clusterId=foo,boo", "{\"message\":\"Reindexing document types [bar] in 'boo', [bar, bax, baz] in 'foo' of application default.default\"}");
+ expected = expected.withReady("boo", "bar", clock.instant())
+ .withReady("foo", "bar", clock.instant())
.withReady("foo", "baz", clock.instant())
- .withReady("boo", "bar", clock.instant())
- .withReady("boo", "baz", clock.instant());
+ .withReady("foo", "bax", clock.instant());
+ assertEquals(expected,
+ database.readReindexingStatus(applicationId).orElseThrow());
+
+ clock.advance(Duration.ofSeconds(1));
+ reindex(applicationId, "?clusterId=foo&documentType=bar,baz", "{\"message\":\"Reindexing document types [bar, baz] in 'foo' of application default.default\"}");
+ expected = expected.withReady("foo", "bar", clock.instant())
+ .withReady("foo", "baz", clock.instant());
assertEquals(expected,
database.readReindexingStatus(applicationId).orElseThrow());
@@ -273,35 +290,26 @@ public class ApplicationHandlerTest {
long now = clock.instant().toEpochMilli();
reindexing(applicationId, GET, "{" +
" \"enabled\": true," +
- " \"status\": {" +
- " \"readyMillis\": " + (now - 2000) +
- " }," +
" \"clusters\": {" +
" \"boo\": {" +
- " \"status\": {" +
- " \"readyMillis\": " + (now - 1000) +
- " }," +
" \"pending\": {" +
" \"bar\": 123" +
" }," +
" \"ready\": {" +
" \"bar\": {" +
- " \"readyMillis\": " + now +
+ " \"readyMillis\": " + (now - 1000) +
" }," +
- " \"baz\": {" +
- " \"readyMillis\": " + now +
- " }" +
" }" +
" }," +
" \"foo\": {" +
- " \"status\": {" +
- " \"readyMillis\": " + (now - 1000) +
- " }," +
" \"pending\": {}," +
" \"ready\": {" +
" \"bar\": {" +
" \"readyMillis\": " + now +
" }," +
+ " \"bax\": {" +
+ " \"readyMillis\": " + (now - 1000) +
+ " }," +
" \"baz\": {" +
" \"readyMillis\": " + now +
" }" +
@@ -452,9 +460,8 @@ public class ApplicationHandlerTest {
@Test
public void testReindexingSerialization() throws IOException {
Instant now = Instant.ofEpochMilli(123456);
- ApplicationReindexing applicationReindexing = ApplicationReindexing.ready(now.minusSeconds(10))
+ ApplicationReindexing applicationReindexing = ApplicationReindexing.empty()
.withPending("foo", "bar", 123L)
- .withReady("moo", now.minusSeconds(1))
.withReady("moo", "baz", now);
ClusterReindexing clusterReindexing = new ClusterReindexing(Map.of("bax", new Status(now, null, null, null, null),
"baz", new Status(now.plusSeconds(1),
@@ -462,18 +469,21 @@ public class ApplicationHandlerTest {
ClusterReindexing.State.FAILED,
"message",
0.1)));
- assertJsonEquals(getRenderedString(new ReindexingResponse(applicationReindexing,
+ Map<String, Set<String>> documentTypes = new TreeMap<>(Map.of("boo", new TreeSet<>(Set.of("bar", "baz", "bax")),
+ "foo", new TreeSet<>(Set.of("bar", "hax")),
+ "moo", new TreeSet<>(Set.of("baz", "bax"))));
+
+ assertJsonEquals(getRenderedString(new ReindexingResponse(documentTypes,
+ applicationReindexing,
Map.of("boo", clusterReindexing,
"moo", clusterReindexing))),
"{\n" +
" \"enabled\": true,\n" +
- " \"status\": {\n" +
- " \"readyMillis\": 113456\n" +
- " },\n" +
" \"clusters\": {\n" +
" \"boo\": {\n" +
" \"pending\": {},\n" +
" \"ready\": {\n" +
+ " \"bar\": {},\n" +
" \"bax\": {\n" +
" \"startedMillis\": 123456\n" +
" },\n" +
@@ -490,14 +500,17 @@ public class ApplicationHandlerTest {
" \"pending\": {\n" +
" \"bar\": 123\n" +
" },\n" +
- " \"ready\": {},\n" +
- " \"status\": {\n" +
- " \"readyMillis\": 113456\n" +
- " }\n" +
+ " \"ready\": {\n" +
+ " \"bar\": {},\n" +
+ " \"hax\": {}\n" +
+ " },\n" +
" },\n" +
" \"moo\": {\n" +
" \"pending\": {},\n" +
" \"ready\": {\n" +
+ " \"bax\": {\n" +
+ " \"startedMillis\": 123456\n" +
+ " },\n" +
" \"baz\": {\n" +
" \"readyMillis\": 123456,\n" +
" \"startedMillis\": 124456,\n" +
@@ -505,13 +518,7 @@ public class ApplicationHandlerTest {
" \"state\": \"failed\",\n" +
" \"message\": \"message\",\n" +
" \"progress\": 0.1\n" +
- " },\n" +
- " \"bax\": {\n" +
- " \"startedMillis\": 123456\n" +
" }\n" +
- " },\n" +
- " \"status\": {\n" +
- " \"readyMillis\": 122456\n" +
" }\n" +
" }\n" +
" }\n" +
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
index d75b91f45e3..dc4932c8c04 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/maintenance/ReindexingMaintainerTest.java
@@ -5,8 +5,11 @@ import com.yahoo.vespa.config.server.application.ApplicationReindexing;
import org.junit.Test;
import java.time.Instant;
+import java.util.List;
+import java.util.Map;
import static com.yahoo.vespa.config.server.maintenance.ReindexingMaintainer.withNewReady;
+import static com.yahoo.vespa.config.server.maintenance.ReindexingMaintainer.withOnlyCurrentData;
import static org.junit.Assert.assertEquals;
/**
@@ -16,12 +19,10 @@ public class ReindexingMaintainerTest {
@Test
public void testReadyComputation() {
- ApplicationReindexing reindexing = ApplicationReindexing.ready(Instant.EPOCH)
+ ApplicationReindexing reindexing = ApplicationReindexing.empty()
.withPending("one", "a", 10)
.withPending("two", "b", 20)
- .withReady("one", Instant.ofEpochMilli(2))
.withReady("one", "a", Instant.ofEpochMilli(3))
- .withReady("two", Instant.ofEpochMilli(2 << 10))
.withReady("two", "b", Instant.ofEpochMilli(2))
.withReady("two", "c", Instant.ofEpochMilli(3));
@@ -36,9 +37,10 @@ public class ReindexingMaintainerTest {
withNewReady(reindexing, () -> 19L, later));
assertEquals(reindexing.withoutPending("one", "a") // Converged, no longer pending.
+ .withReady("one", "a", later)
.withoutPending("two", "b") // Converged, no Longer pending.
- .withReady(later), // Outsider calls withReady(later), overriding more specific status.
- withNewReady(reindexing, () -> 20L, later).withReady(later));
+ .withReady("two", "b", later),
+ withNewReady(reindexing, () -> 20L, later));
// Verify generation supplier isn't called when no pending document types.
withNewReady(reindexing.withoutPending("one", "a").withoutPending("two", "b"),
@@ -46,4 +48,34 @@ public class ReindexingMaintainerTest {
later);
}
+ @Test
+ public void testGarbageRemoval() {
+ ApplicationReindexing reindexing = ApplicationReindexing.empty()
+ .withPending("one", "a", 10)
+ .withPending("two", "b", 20)
+ .withReady("one", "a", Instant.ofEpochMilli(3))
+ .withReady("two", "b", Instant.ofEpochMilli(2))
+ .withReady("two", "c", Instant.ofEpochMilli(3));
+
+ assertEquals(reindexing,
+ withOnlyCurrentData(reindexing, Map.of("one", List.of("a", "b", "c", "d"),
+ "two", List.of("b", "c"),
+ "three", List.of("a", "b"))));
+
+ assertEquals(reindexing,
+ withOnlyCurrentData(reindexing, Map.of("one", List.of("a"),
+ "two", List.of("b", "c"))));
+
+ assertEquals(ApplicationReindexing.empty()
+ .withPending("two", "b", 20)
+ .withReady("two", "b", Instant.ofEpochMilli(2)),
+ withOnlyCurrentData(reindexing, Map.of("two", List.of("a", "b"))));
+
+ assertEquals(ApplicationReindexing.empty()
+ .withReady("one", "a", Instant.EPOCH).without("one", "a")
+ .withReady("two", "c", Instant.ofEpochMilli(3)),
+ withOnlyCurrentData(reindexing, Map.of("one", List.of("c"),
+ "two", List.of("c"))));
+ }
+
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
index b5cdfa8eda2..865d3b71b6e 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java
@@ -84,12 +84,6 @@ public class DeploymentMetricsRetrieverTest {
}
@Override
- @SuppressWarnings("deprecation")
- public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
index 7fab01faf3d..5aada44b573 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java
@@ -77,12 +77,6 @@ public class ProtonMetricsRetrieverTest {
}
@Override
- @SuppressWarnings("deprecation")
- public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public ConfigInstance.Builder getConfigInstance(ConfigKey<?> configKey, ConfigDefinition targetDef) {
throw new UnsupportedOperationException();
}