From d6be7f2e2696d2cc00518cd1593d8381692439c2 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Fri, 4 Oct 2019 12:48:01 +0200 Subject: Extract NodeVersionSerializer --- .../persistence/NodeVersionSerializer.java | 61 ++++++++++++++++++++++ .../persistence/VersionStatusSerializer.java | 24 +++------ 2 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NodeVersionSerializer.java diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NodeVersionSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NodeVersionSerializer.java new file mode 100644 index 00000000000..088808f5942 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/NodeVersionSerializer.java @@ -0,0 +1,61 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.persistence; + +import com.yahoo.component.Version; +import com.yahoo.config.provision.HostName; +import com.yahoo.slime.ArrayTraverser; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.vespa.hosted.controller.versions.NodeVersion; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * Serializer for {@link com.yahoo.vespa.hosted.controller.versions.NodeVersion}. + * + * @author mpolden + */ +public class NodeVersionSerializer { + + // WARNING: Since there are multiple servers in a ZooKeeper cluster and they upgrade one by one + // (and rewrite all nodes on startup), changes to the serialized format must be made + // such that what is serialized on version N+1 can be read by version N: + // - ADDING FIELDS: Always ok + // - REMOVING FIELDS: Stop reading the field first. Stop writing it on a later version. + // - CHANGING THE FORMAT OF A FIELD: Don't do it bro. + + private static final String hostnameField = "hostname"; + private static final String currentVersionField = "currentVersion"; + private static final String wantedVersionField = "wantedVersion"; + private static final String changedAtField = "changedAt"; + + public void nodeVersionsToSlime(Collection nodeVersions, Cursor array, boolean writeCurrentVersion) { + for (var nodeVersion : nodeVersions) { + var nodeVersionObject = array.addObject(); + nodeVersionObject.setString(hostnameField, nodeVersion.hostname().value()); + if (writeCurrentVersion) { + nodeVersionObject.setString(currentVersionField, nodeVersion.currentVersion().toFullString()); + } + nodeVersionObject.setString(wantedVersionField, nodeVersion.wantedVersion().toFullString()); + nodeVersionObject.setLong(changedAtField, nodeVersion.changedAt().toEpochMilli()); + } + } + + public List nodeVersionsFromSlime(Inspector object, Optional version) { + var nodeVersions = new ArrayList(); + object.traverse((ArrayTraverser) (i, entry) -> { + var hostname = HostName.from(entry.field(hostnameField).asString()); + var currentVersion = version.orElseGet(() -> Version.fromString(entry.field(currentVersionField).asString())); + var wantedVersion = Version.fromString(entry.field(wantedVersionField).asString()); + var changedAt = Instant.ofEpochMilli(entry.field(changedAtField).asLong()); + nodeVersions.add(new NodeVersion(hostname, currentVersion, wantedVersion, changedAt)); + }); + return Collections.unmodifiableList(nodeVersions); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java index 5061f32da68..62fca7a419b 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/VersionStatusSerializer.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; /** @@ -53,17 +54,14 @@ public class VersionStatusSerializer { // NodeVersions fields private static final String nodeVersionsField = "nodeVersions"; - // NodeVersion fields - private static final String hostnameField = "hostname"; - private static final String wantedVersionField = "wantedVersion"; - private static final String changedAtField = "changedAt"; - // DeploymentStatistics fields private static final String versionField = "version"; private static final String failingField = "failing"; private static final String productionField = "production"; private static final String deployingField = "deploying"; + private final NodeVersionSerializer nodeVersionSerializer = new NodeVersionSerializer(); + public Slime toSlime(VersionStatus status) { Slime slime = new Slime(); Cursor root = slime.setObject(); @@ -93,12 +91,7 @@ public class VersionStatusSerializer { } private void nodeVersionsToSlime(NodeVersions nodeVersions, Cursor array) { - for (NodeVersion nodeVersion : nodeVersions.asMap().values()) { - var nodeVersionObject = array.addObject(); - nodeVersionObject.setString(hostnameField, nodeVersion.hostname().value()); - nodeVersionObject.setString(wantedVersionField, nodeVersion.wantedVersion().toFullString()); - nodeVersionObject.setLong(changedAtField, nodeVersion.changedAt().toEpochMilli()); - } + nodeVersionSerializer.nodeVersionsToSlime(nodeVersions.asMap().values(), array, false); } // TODO(mpolden): Remove after October 2019 @@ -140,12 +133,9 @@ public class VersionStatusSerializer { var nodeVersions = ImmutableMap.builder(); var nodeVersionsRoot = root.field(nodeVersionsField); if (nodeVersionsRoot.valid()) { - nodeVersionsRoot.traverse((ArrayTraverser) (i, entry) -> { - var hostname = HostName.from(entry.field(hostnameField).asString()); - var wantedVersion = Version.fromString(entry.field(wantedVersionField).asString()); - var changedAt = Instant.ofEpochMilli(entry.field(changedAtField).asLong()); - nodeVersions.put(hostname, new NodeVersion(hostname, version, wantedVersion, changedAt)); - }); + for (var nodeVersion : nodeVersionSerializer.nodeVersionsFromSlime(nodeVersionsRoot, Optional.of(version))) { + nodeVersions.put(nodeVersion.hostname(), nodeVersion); + } } else { // TODO(mpolden): Remove after October 2019 var configServerHostnames = configServersFromSlime(root.field(configServersField)); -- cgit v1.2.3