diff options
author | Harald Musum <musum@verizonmedia.com> | 2021-01-20 08:15:21 +0100 |
---|---|---|
committer | Harald Musum <musum@verizonmedia.com> | 2021-01-20 08:15:21 +0100 |
commit | 64e28d6625c0b517d75a2a9eb4295048717a1ca9 (patch) | |
tree | 287d0f9dab51d77f07c0f0475ca428b4b5639a24 /configserver | |
parent | b335c179019de4c2a90317ed5bb8f1f29a940be2 (diff) | |
parent | 4cb56fdd14fa24a14d07ed20de011965c738c8cb (diff) |
Merge branch 'master' into hmusum/reduce-use-of-global-component-registry
Diffstat (limited to 'configserver')
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(); } |