diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java index 3f3bf62bf4d2..a1e213fc1f95 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java @@ -37,6 +37,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.TimeZone; @@ -130,12 +131,9 @@ public FleetController(FleetControllerContext context, this.systemStateBroadcaster = systemStateBroadcaster; this.stateVersionTracker = new StateVersionTracker(options.minMergeCompletionRatio); this.metricUpdater = metricUpdater; - - this.statusPageServer = statusPage; + this.statusPageServer = Objects.requireNonNull(statusPage, "statusPage cannot be null"); this.rpcServer = server; - this.masterElectionHandler = masterElectionHandler; - this.statusRequestRouter.addHandler( "^/node=([a-z]+)\\.(\\d+)$", new LegacyNodePageRequestHandler(timer, eventLog, cluster)); @@ -277,9 +275,7 @@ public void shutdown() throws InterruptedException, java.io.IOException { controllerThreadId = Thread.currentThread().getId(); database.shutdown(databaseContext); - if (statusPageServer != null) { - statusPageServer.shutdown(); - } + statusPageServer.shutdown(); if (rpcServer != null) { rpcServer.shutdown(); } @@ -530,12 +526,10 @@ private void propagateOptions() { } } - if (statusPageServer != null) { - try{ - statusPageServer.setPort(options.httpPort); - } catch (Exception e) { - context.log(logger, Level.WARNING, "Failed to initialize status server socket. This may be natural if cluster has altered the services running on this node: " + e.getMessage()); - } + try { + statusPageServer.setPort(options.httpPort); + } catch (Exception e) { + context.log(logger, Level.WARNING, "Failed to initialize status server socket. This may be natural if cluster has altered the services running on this node: " + e.getMessage()); } long currentTime = timer.getCurrentTimeInMillis(); @@ -679,12 +673,10 @@ private void switchToNewConfig() { } private boolean processAnyPendingStatusPageRequest() { - if (statusPageServer != null) { - StatusPageServer.HttpRequest statusRequest = statusPageServer.getCurrentHttpRequest(); - if (statusRequest != null) { - statusPageServer.answerCurrentStatusRequest(fetchStatusPage(statusRequest)); - return true; - } + StatusPageServer.HttpRequest statusRequest = statusPageServer.getCurrentHttpRequest(); + if (statusRequest != null) { + statusPageServer.answerCurrentStatusRequest(fetchStatusPage(statusRequest)); + return true; } return false; } @@ -1224,8 +1216,6 @@ public void waitForNodesInSlobrok(int distNodeCount, int storNodeCount, Duration public ContentCluster getCluster() { return cluster; } - public List getNodeEvents(Node n) { return eventLog.getNodeEvents(n); } - public EventLog getEventLog() { return eventLog; } diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetControllerOptions.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetControllerOptions.java index 16e0e1c06735..750d44c8fbfb 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetControllerOptions.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetControllerOptions.java @@ -5,18 +5,13 @@ import com.yahoo.vdslib.distribution.ConfiguredNode; import com.yahoo.vdslib.distribution.Distribution; import com.yahoo.vdslib.state.NodeType; - -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.time.Duration; import java.util.Collection; import java.util.Collections; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import java.util.stream.Collectors; /** * This class represents all the options that can be set in the fleetcontroller. @@ -125,7 +120,7 @@ public class FleetControllerOptions implements Cloneable { // TODO: Get rid of this by always getting nodes by distribution.getNodes() public Set nodes; - private Duration maxDeferredTaskVersionWaitTime = Duration.ofSeconds(30); + public Duration maxDeferredTaskVersionWaitTime = Duration.ofSeconds(30); public boolean clusterHasGlobalDocumentTypes = false; @@ -175,82 +170,4 @@ public FleetControllerOptions clone() { } } - public static String splitZooKeeperAddress(String s) { - StringBuilder sb = new StringBuilder(); - while (true) { - int index = s.indexOf(','); - if (index > 0) { - sb.append(s.substring(0, index + 1)).append(' '); - s = s.substring(index+1); - } else { - break; - } - } - sb.append(s); - return sb.toString(); - } - - static DecimalFormat DecimalDot2 = new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.ENGLISH)); - - public void writeHtmlState(StringBuilder sb) { - String slobrokspecs = ""; - for (int i=0; iCurrent config\n") - .append("

Fleet controller config id: ").append(fleetControllerConfigId == null ? null : fleetControllerConfigId.replaceAll("\n", "
\n")).append("

\n") - .append("

Slobrok config id: ").append(slobrokConfigId == null ? null : slobrokConfigId.replaceAll("\n", "
\n")).append("

\n") - .append("\n"); - - sb.append(""); - sb.append(""); - sb.append(""); - - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - String zooKeeperAddress = (zooKeeperServerAddress == null ? "Not using Zookeeper" : splitZooKeeperAddress(zooKeeperServerAddress)); - sb.append(""); - sb.append(""); - - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - - sb.append("
PropertyValue
Cluster name").append(clusterName).append("
Fleet controller index").append(fleetControllerIndex).append("/").append(fleetControllerCount).append("
Number of fleetcontrollers gathering states from nodes").append(stateGatherCount).append("
Slobrok connection spec").append(slobrokspecs).append("
RPC port").append(rpcPort == 0 ? "Pick random available" : rpcPort).append("
HTTP port").append(httpPort == 0 ? "Pick random available" : httpPort).append("
Master cooldown period").append(RealTimer.printDuration(masterZooKeeperCooldownPeriod)).append("
Zookeeper server address").append(zooKeeperAddress).append("
Zookeeper session timeout").append(RealTimer.printDuration(zooKeeperSessionTimeout)).append("
Cycle wait time").append(cycleWaitTime).append(" ms
Minimum time before first clusterstate broadcast as master").append(RealTimer.printDuration(minTimeBeforeFirstSystemStateBroadcast)).append("
Minimum time between official cluster states").append(RealTimer.printDuration(minTimeBetweenNewSystemStates)).append("
Slobrok mirror backoff policy").append(slobrokBackOffPolicy == null ? "default" : "overridden").append("
Node state request timeout").append(RealTimer.printDuration(nodeStateRequestTimeoutMS)).append("
VDS 4.1 node state polling frequency").append(RealTimer.printDuration(statePollingFrequency)).append("
Maximum distributor transition time").append(RealTimer.printDuration(maxTransitionTime.get(NodeType.DISTRIBUTOR))).append("
Maximum storage transition time").append(RealTimer.printDuration(maxTransitionTime.get(NodeType.STORAGE))).append("
Maximum initialize without progress time").append(RealTimer.printDuration(maxInitProgressTime)).append("
Maximum premature crashes").append(maxPrematureCrashes).append("
Stable state time period").append(RealTimer.printDuration(stableStateTimePeriod)).append("
Slobrok disconnect grace period").append(RealTimer.printDuration(maxSlobrokDisconnectGracePeriod)).append("
Number of distributor nodes").append(nodes == null ? "Autodetect" : nodes.size()).append("
Number of storage nodes").append(nodes == null ? "Autodetect" : nodes.size()).append("
Minimum distributor nodes being up for cluster to be up").append(minDistributorNodesUp).append("
Minimum storage nodes being up for cluster to be up").append(minStorageNodesUp).append("
Minimum percentage of distributor nodes being up for cluster to be up").append(DecimalDot2.format(100 * minRatioOfDistributorNodesUp)).append(" %
Minimum percentage of storage nodes being up for cluster to be up").append(DecimalDot2.format(100 * minRatioOfStorageNodesUp)).append(" %
Show local cluster state changes").append(showLocalSystemStatesInEventLog).append("
Maximum event log size").append(eventLogMaxSize).append("
Maximum node event log size").append(eventNodeLogMaxSize).append("
Wanted distribution bits").append(distributionBits).append("
Max deferred task version wait time").append(maxDeferredTaskVersionWaitTime.toMillis()).append("ms
Cluster has global document types configured").append(clusterHasGlobalDocumentTypes).append("
Enable 2-phase cluster state activation protocol").append(enableTwoPhaseClusterStateActivation).append("
Cluster auto feed block on resource exhaustion enabled") - .append(clusterFeedBlockEnabled).append("
Feed block limits") - .append(clusterFeedBlockLimit.entrySet().stream() - .map(kv -> String.format("%s: %.2f%%", kv.getKey(), kv.getValue() * 100.0)) - .collect(Collectors.joining("
"))).append("
"); - } - } diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MasterElectionHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MasterElectionHandler.java index 637aca16ee7c..dfc328346bb3 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MasterElectionHandler.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MasterElectionHandler.java @@ -35,11 +35,9 @@ public MasterElectionHandler(FleetControllerContext context, int index, int tota this.index = index; this.totalCount = totalCount; this.nextInLineCount = Integer.MAX_VALUE; - // Only a given set of nodes can ever become master - if (index > (totalCount - 1) / 2) { + if (cannotBecomeMaster()) context.log(logger, Level.FINE, () -> "We can never become master and will always stay a follower."); - } - // Tag current time as when we have not seen any other master. Make sure we're not taking over at once for master that is on the way down + // Tag current time as when we have not seen any other master. Make sure we're not taking over at once for master that is on the way down masterGoneFromZooKeeperTime = timer.getCurrentTimeInMillis(); } @@ -77,16 +75,15 @@ public boolean inMasterMoratorium() { @Override public Integer getMaster() { - // If too few followers there can be no master - if (2 * followers <= totalCount) { + if (tooFewFollowersToHaveAMaster()) { return null; } - // If all are following master candidate, it is master if it exists. + // If all are following master candidate, it is master if it exists. if (followers == totalCount) { return masterCandidate; } - // If not all are following we only accept master candidate if old master - // disappeared sufficient time ago + // If not all are following we only accept master candidate if old master + // disappeared sufficient time ago if (masterGoneFromZooKeeperTime + masterZooKeeperCooldownPeriod > timer.getCurrentTimeInMillis()) { return null; } @@ -97,8 +94,7 @@ public String getMasterReason() { if (masterCandidate == null) { return "There is currently no master candidate."; } - // If too few followers there can be no master - if (2 * followers <= totalCount) { + if (tooFewFollowersToHaveAMaster()) { return "More than half of the nodes must agree for there to be a master. Only " + followers + " of " + totalCount + " nodes agree on current master candidate (" + masterCandidate + ")."; } @@ -118,6 +114,10 @@ public String getMasterReason() { return followers + " of " + totalCount + " nodes agree " + masterCandidate + " is master."; } + private boolean tooFewFollowersToHaveAMaster() { + return 2 * followers <= totalCount; + } + public boolean isAmongNthFirst(int first) { return (nextInLineCount < first); } public boolean watchMasterElection(DatabaseHandler database, @@ -131,8 +131,8 @@ public boolean watchMasterElection(DatabaseHandler database, } return false; // Nothing have happened since last time. } - // Move next data to temporary, such that we don't need to keep lock, and such that we don't retry - // if we happen to fail processing the data. + // Move next data to temporary, such that we don't need to keep lock, and such that we don't retry + // if we happen to fail processing the data. Map state; context.log(logger, Level.INFO, "Handling new master election, as we have received " + nextMasterData.size() + " entries"); synchronized (monitor) { @@ -184,8 +184,7 @@ public boolean watchMasterElection(DatabaseHandler database, database.setMasterVote(dbContext, first.getKey()); } } - // Only a given set of nodes can ever become master - if (index <= (totalCount - 1) / 2) { + if (canBecomeMaster()) { int ourPosition = 0; for (Map.Entry entry : state.entrySet()) { if (entry.getKey() != index) { @@ -205,6 +204,11 @@ public boolean watchMasterElection(DatabaseHandler database, return true; } + // Only a given set of nodes can ever become master + private boolean canBecomeMaster() {return index <= (totalCount - 1) / 2;} + + private boolean cannotBecomeMaster() {return ! canBecomeMaster();} + private static String toString(Map data) { StringBuilder sb = new StringBuilder(); for (Map.Entry entry : data.entrySet()) { @@ -253,10 +257,10 @@ public void writeHtmlState(StringBuilder sb, int stateGatherCount) { Integer master = getMaster(); if (master != null) { sb.append("

Current cluster controller master is node " + master + "."); - if (master.intValue() == index) sb.append(" (This node)"); + if (master == index) sb.append(" (This node)"); sb.append("

"); } else { - if (2 * followers <= totalCount) { + if (tooFewFollowersToHaveAMaster()) { sb.append("

There is currently no master. Less than half the fleet controllers (") .append(followers).append(") are following master candidate ").append(masterCandidate) .append(".

"); @@ -267,19 +271,19 @@ public void writeHtmlState(StringBuilder sb, int stateGatherCount) { .append(" before electing new master unless all possible master candidates are online.

"); } } - if ((master == null || master.intValue() != index) && nextInLineCount < stateGatherCount) { + if ((master == null || master != index) && nextInLineCount < stateGatherCount) { sb.append("

As we are number ").append(nextInLineCount) .append(" in line for taking over as master, we're gathering state from nodes.

"); sb.append("

As we are not the master, we don't know about nodes current system state" + " or wanted states, so some statistics below may be stale. Look at status page on master " + "for updated data.

"); } - if (index * 2 > totalCount) { + if (cannotBecomeMaster()) { sb.append("

As lowest index fleet controller is prioritized to become master, and more than half " + "of the fleet controllers need to be available to select a master, we can never become master.

"); } - // Debug data + // Debug data sb.append("

Master election handler internal state:") .append("
Index: " + index) .append("
Fleet controller count: " + totalCount) diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/LegacyIndexPageRequestHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/LegacyIndexPageRequestHandler.java index 4f20b3d0cdca..0611d754b698 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/LegacyIndexPageRequestHandler.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/LegacyIndexPageRequestHandler.java @@ -20,16 +20,22 @@ import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageResponse; import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageServer; import com.yahoo.vespa.clustercontroller.core.status.statuspage.VdsClusterHtmlRenderer; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.TimeZone; import java.util.TreeMap; +import java.util.stream.Collectors; /** * @author Haakon Humberset */ public class LegacyIndexPageRequestHandler implements StatusPageServer.RequestHandler { + private static final DecimalFormat DecimalDot2 = new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.ENGLISH)); + private final Timer timer; private final ContentCluster cluster; private final MasterElectionHandler masterElectionHandler; @@ -69,7 +75,6 @@ public StatusPageResponse handle(StatusPageServer.HttpRequest request) { .append(" | Event log") .append(" ]

\n"); content.append(""); - //content.append(""); content.append("
UTC time when creating this page:").append(RealTimer.printDateNoMilliSeconds(currentTime, tz)).append("
Fleetcontroller version:" + Vtag.V_TAG_PKG + "
Cluster controller uptime:" + RealTimer.printDuration(currentTime - startedTime) + "
"); if (masterElectionHandler.isAmongNthFirst(options.stateGatherCount)) { // Table overview of all the nodes @@ -78,12 +83,12 @@ public StatusPageResponse handle(StatusPageServer.HttpRequest request) { writeHtmlState(stateVersionTracker, content); } else { // Overview of current config - options.writeHtmlState(content); + writeHtmlState(content, options); } // State of master election masterElectionHandler.writeHtmlState(content, options.stateGatherCount); // Overview of current config - options.writeHtmlState(content); + writeHtmlState(content, options); // Event log eventLog.writeHtmlState(content, null); response.writeHtmlFooter(content, ""); @@ -200,4 +205,80 @@ private void storeNodeInfo(ContentCluster cluster, int nodeIndex, NodeType nodeT nodeInfoByIndex.put(nodeIndex, nodeInfo); } + public void writeHtmlState(StringBuilder sb, FleetControllerOptions options) { + String slobrokspecs = ""; + for (int i = 0; i < options.slobrokConnectionSpecs.length; ++i) { + if (i != 0) slobrokspecs += "
"; + slobrokspecs += options.slobrokConnectionSpecs[i]; + } + sb.append("

Current config

\n") + .append("

Fleet controller config id: ").append(options.fleetControllerConfigId == null ? null : options.fleetControllerConfigId.replaceAll("\n", "
\n")).append("

\n") + .append("

Slobrok config id: ").append(options.slobrokConfigId == null ? null : options.slobrokConfigId.replaceAll("\n", "
\n")).append("

\n") + .append("\n"); + + sb.append(""); + sb.append(""); + sb.append(""); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + String zooKeeperAddress = (options.zooKeeperServerAddress == null ? "Not using Zookeeper" : splitZooKeeperAddress(options.zooKeeperServerAddress)); + sb.append(""); + sb.append(""); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + + sb.append("
PropertyValue
Cluster name").append(options.clusterName).append("
Fleet controller index").append(options.fleetControllerIndex).append("/").append(options.fleetControllerCount).append("
Number of fleetcontrollers gathering states from nodes").append(options.stateGatherCount).append("
Slobrok connection spec").append(slobrokspecs).append("
RPC port").append(options.rpcPort == 0 ? "Pick random available" : options.rpcPort).append("
HTTP port").append(options.httpPort == 0 ? "Pick random available" : options.httpPort).append("
Master cooldown period").append(RealTimer.printDuration(options.masterZooKeeperCooldownPeriod)).append("
Zookeeper server address").append(zooKeeperAddress).append("
Zookeeper session timeout").append(RealTimer.printDuration(options.zooKeeperSessionTimeout)).append("
Cycle wait time").append(options.cycleWaitTime).append(" ms
Minimum time before first clusterstate broadcast as master").append(RealTimer.printDuration(options.minTimeBeforeFirstSystemStateBroadcast)).append("
Minimum time between official cluster states").append(RealTimer.printDuration(options.minTimeBetweenNewSystemStates)).append("
Slobrok mirror backoff policy").append(options.slobrokBackOffPolicy == null ? "default" : "overridden").append("
Node state request timeout").append(RealTimer.printDuration(options.nodeStateRequestTimeoutMS)).append("
VDS 4.1 node state polling frequency").append(RealTimer.printDuration(options.statePollingFrequency)).append("
Maximum distributor transition time").append(RealTimer.printDuration(options.maxTransitionTime.get(NodeType.DISTRIBUTOR))).append("
Maximum storage transition time").append(RealTimer.printDuration(options.maxTransitionTime.get(NodeType.STORAGE))).append("
Maximum initialize without progress time").append(RealTimer.printDuration(options.maxInitProgressTime)).append("
Maximum premature crashes").append(options.maxPrematureCrashes).append("
Stable state time period").append(RealTimer.printDuration(options.stableStateTimePeriod)).append("
Slobrok disconnect grace period").append(RealTimer.printDuration(options.maxSlobrokDisconnectGracePeriod)).append("
Number of distributor nodes").append(options.nodes == null ? "Autodetect" : options.nodes.size()).append("
Number of storage nodes").append(options.nodes == null ? "Autodetect" : options.nodes.size()).append("
Minimum distributor nodes being up for cluster to be up").append(options.minDistributorNodesUp).append("
Minimum storage nodes being up for cluster to be up").append(options.minStorageNodesUp).append("
Minimum percentage of distributor nodes being up for cluster to be up").append(DecimalDot2.format(100 * options.minRatioOfDistributorNodesUp)).append(" %
Minimum percentage of storage nodes being up for cluster to be up").append(DecimalDot2.format(100 * options.minRatioOfStorageNodesUp)).append(" %
Show local cluster state changes").append(options.showLocalSystemStatesInEventLog).append("
Maximum event log size").append(options.eventLogMaxSize).append("
Maximum node event log size").append(options.eventNodeLogMaxSize).append("
Wanted distribution bits").append(options.distributionBits).append("
Max deferred task version wait time").append(options.maxDeferredTaskVersionWaitTime.toMillis()).append("ms
Cluster has global document types configured").append(options.clusterHasGlobalDocumentTypes).append("
Enable 2-phase cluster state activation protocol").append(options.enableTwoPhaseClusterStateActivation).append("
Cluster auto feed block on resource exhaustion enabled") + .append(options.clusterFeedBlockEnabled).append("
Feed block limits") + .append(options.clusterFeedBlockLimit.entrySet().stream() + .map(kv -> String.format("%s: %.2f%%", kv.getKey(), kv.getValue() * 100.0)) + .collect(Collectors.joining("
"))).append("
"); + } + + private static String splitZooKeeperAddress(String s) { + StringBuilder sb = new StringBuilder(); + while (true) { + int index = s.indexOf(','); + if (index > 0) { + sb.append(s.substring(0, index + 1)).append(' '); + s = s.substring(index+1); + } else { + break; + } + } + sb.append(s); + return sb.toString(); + } + } diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/StatusHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/StatusHandler.java index 69144d23fe53..79e6a91f5612 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/StatusHandler.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/StatusHandler.java @@ -31,7 +31,7 @@ public static class ContainerStatusPageServer implements StatusPageServerInterfa StatusPageServer.HttpRequest request; StatusPageResponse response; - // Ensure only only one use the server at a time + // Ensure only one use the server at a time private final Object queueMonitor = new Object(); // Lock safety with fleetcontroller. Wait until completion private final Object answerMonitor = new Object(); diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFeedBlockTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFeedBlockTest.java index ec6255fd13bf..5a9d28bc3278 100644 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFeedBlockTest.java +++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFeedBlockTest.java @@ -9,6 +9,7 @@ import com.yahoo.vdslib.state.State; import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler; import com.yahoo.vespa.clustercontroller.core.database.ZooKeeperDatabaseFactory; +import com.yahoo.vespa.clustercontroller.core.status.StatusHandler; import com.yahoo.vespa.clustercontroller.utils.util.NoMetricReporter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -58,7 +59,9 @@ private void initialize(FleetControllerOptions options) throws Exception { var stateGenerator = new StateChangeHandler(context, timer, eventLog); var stateBroadcaster = new SystemStateBroadcaster(context, timer, timer); var masterElectionHandler = new MasterElectionHandler(context, options.fleetControllerIndex, options.fleetControllerCount, timer, timer); - ctrl = new FleetController(context, timer, eventLog, cluster, stateGatherer, communicator, null, null, communicator, database, stateGenerator, stateBroadcaster, masterElectionHandler, metricUpdater, options); + var status = new StatusHandler.ContainerStatusPageServer(); + ctrl = new FleetController(context, timer, eventLog, cluster, stateGatherer, communicator, status, null, communicator, database, + stateGenerator, stateBroadcaster, masterElectionHandler, metricUpdater, options); ctrl.tick(); markAllNodesAsUp(options); diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java index 426ac42fe9e6..fd6ff30a08fb 100644 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java +++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java @@ -11,6 +11,7 @@ import com.yahoo.vdslib.state.State; import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler; import com.yahoo.vespa.clustercontroller.core.database.ZooKeeperDatabaseFactory; +import com.yahoo.vespa.clustercontroller.core.status.StatusHandler; import com.yahoo.vespa.clustercontroller.core.testutils.StateWaiter; import com.yahoo.vespa.clustercontroller.utils.util.NoMetricReporter; import org.junit.jupiter.api.BeforeEach; @@ -57,7 +58,9 @@ private void initialize(FleetControllerOptions options) throws Exception { var stateGenerator = new StateChangeHandler(context, timer, eventLog); var stateBroadcaster = new SystemStateBroadcaster(context, timer, timer); var masterElectionHandler = new MasterElectionHandler(context, options.fleetControllerIndex, options.fleetControllerCount, timer, timer); - ctrl = new FleetController(context, timer, eventLog, cluster, stateGatherer, communicator, null, null, communicator, database, stateGenerator, stateBroadcaster, masterElectionHandler, metricUpdater, options); + var status = new StatusHandler.ContainerStatusPageServer(); + ctrl = new FleetController(context, timer, eventLog, cluster, stateGatherer, communicator, status, null, communicator, database, + stateGenerator, stateBroadcaster, masterElectionHandler, metricUpdater, options); ctrl.tick(); if (options.fleetControllerCount == 1) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java index 74017b6b821c..bf5770681ef8 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java @@ -117,20 +117,23 @@ public ContentCluster build(Collection containers, ConfigModelCo RedundancyBuilder redundancyBuilder = new RedundancyBuilder(contentElement); Set globallyDistributedDocuments = new GlobalDistributionBuilder(documentDefinitions).build(documentsElement); - ContentCluster c = new ContentCluster(context.getParentProducer(), getClusterId(contentElement), documentDefinitions, + String clusterId = getClusterId(contentElement); + ContentCluster c = new ContentCluster(context.getParentProducer(), clusterId, documentDefinitions, globallyDistributedDocuments, routingSelection, deployState.zone(), deployState.isHosted()); var resourceLimits = new ClusterResourceLimits.Builder(stateIsHosted(deployState), deployState.featureFlags().resourceLimitDisk(), deployState.featureFlags().resourceLimitMemory()) .build(contentElement); - c.clusterControllerConfig = new ClusterControllerConfig.Builder(getClusterId(contentElement), - contentElement, - resourceLimits.getClusterControllerLimits()).build(deployState, c, contentElement.getXml()); + c.clusterControllerConfig = new ClusterControllerConfig.Builder(clusterId, + contentElement, + resourceLimits.getClusterControllerLimits()) + .build(deployState, c, contentElement.getXml()); c.search = new ContentSearchCluster.Builder(documentDefinitions, - globallyDistributedDocuments, - fractionOfMemoryReserved(getClusterId(contentElement), containers), - resourceLimits.getContentNodeLimits()).build(deployState, c, contentElement.getXml()); + globallyDistributedDocuments, + fractionOfMemoryReserved(clusterId, containers), + resourceLimits.getContentNodeLimits()) + .build(deployState, c, contentElement.getXml()); c.persistenceFactory = new EngineFactoryBuilder().build(contentElement, c); c.storageNodes = new StorageCluster.Builder().build(deployState, c, w3cContentElement); c.distributorNodes = new DistributorCluster.Builder(c).build(deployState, c, w3cContentElement); @@ -173,9 +176,8 @@ private void setupSearchCluster(ContentSearchCluster csc, ModelElement element, if (csc.hasIndexedCluster()) { setupIndexedCluster(csc.getIndexed(), search, element, logger); } - - } + private void setupIndexedCluster(IndexedSearchCluster index, ContentSearch search, ModelElement element, DeployLogger logger) { Double queryTimeout = search.getQueryTimeout(); if (queryTimeout != null) { @@ -267,9 +269,8 @@ private void validateGroupSiblings(String cluster, StorageGroup group) { } private void validateThatGroupSiblingsAreUnique(String cluster, StorageGroup group) { - if (group == null) { - return; // Unit testing case - } + if (group == null) return; // Unit testing case + validateGroupSiblings(cluster, group); for (StorageGroup g : group.getSubgroups()) { validateThatGroupSiblingsAreUnique(cluster, g); @@ -301,7 +302,7 @@ else if (admin.multitenant()) { // system tests: cluster controllers on logserve } clusterControllers = admin.getClusterControllers(); } - else { // self-hosted: Put cluser controller on config servers or use explicit cluster controllers + else { // self-hosted: Put cluster controller on config servers or use explicit cluster controllers if (admin.getClusterControllers() == null) { var hosts = admin.getConfigservers().stream().map(s -> s.getHostResource()).collect(toList()); if (hosts.size() > 1) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java index fb4016f4cf47..ff9051879694 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/FileStorProducer.java @@ -44,11 +44,11 @@ private Integer getThreads(ModelElement clusterElem) { private final Integer numThreads; private final ContentCluster cluster; - private final int reponseNumThreads; + private final int responseNumThreads; private final StorFilestorConfig.Response_sequencer_type.Enum responseSequencerType; private final double persistenceThrottlingWsDecrementFactor; private final double persistenceThrottlingWsBackoff; - private final int persistenceThrottingWindowSize; + private final int persistenceThrottlingWindowSize; private final double persistenceThrottlingWsResizeRate; private final boolean persistenceThrottlingOfMergeFeedOps; private final boolean useAsyncMessageHandlingOnSchedule; @@ -64,11 +64,11 @@ private static StorFilestorConfig.Response_sequencer_type.Enum convertResponseSe public FileStorProducer(ModelContext.FeatureFlags featureFlags, ContentCluster parent, Integer numThreads) { this.numThreads = numThreads; this.cluster = parent; - this.reponseNumThreads = featureFlags.defaultNumResponseThreads(); + this.responseNumThreads = featureFlags.defaultNumResponseThreads(); this.responseSequencerType = convertResponseSequencerType(featureFlags.responseSequencerType()); this.persistenceThrottlingWsDecrementFactor = featureFlags.persistenceThrottlingWsDecrementFactor(); this.persistenceThrottlingWsBackoff = featureFlags.persistenceThrottlingWsBackoff(); - this.persistenceThrottingWindowSize = featureFlags.persistenceThrottlingWindowSize(); + this.persistenceThrottlingWindowSize = featureFlags.persistenceThrottlingWindowSize(); this.persistenceThrottlingWsResizeRate = featureFlags.persistenceThrottlingWsResizeRate(); this.persistenceThrottlingOfMergeFeedOps = featureFlags.persistenceThrottlingOfMergeFeedOps(); this.useAsyncMessageHandlingOnSchedule = featureFlags.useAsyncMessageHandlingOnSchedule(); @@ -80,15 +80,15 @@ public void getConfig(StorFilestorConfig.Builder builder) { builder.num_threads(numThreads); } builder.enable_multibit_split_optimalization(cluster.getPersistence().enableMultiLevelSplitting()); - builder.num_response_threads(reponseNumThreads); + builder.num_response_threads(responseNumThreads); builder.response_sequencer_type(responseSequencerType); builder.use_async_message_handling_on_schedule(useAsyncMessageHandlingOnSchedule); var throttleBuilder = new StorFilestorConfig.Async_operation_throttler.Builder(); throttleBuilder.window_size_decrement_factor(persistenceThrottlingWsDecrementFactor); throttleBuilder.window_size_backoff(persistenceThrottlingWsBackoff); - if (persistenceThrottingWindowSize > 0) { - throttleBuilder.min_window_size(persistenceThrottingWindowSize); - throttleBuilder.max_window_size(persistenceThrottingWindowSize); + if (persistenceThrottlingWindowSize > 0) { + throttleBuilder.min_window_size(persistenceThrottlingWindowSize); + throttleBuilder.max_window_size(persistenceThrottlingWindowSize); } throttleBuilder.resize_rate(persistenceThrottlingWsResizeRate); throttleBuilder.throttle_individual_merge_feed_ops(persistenceThrottlingOfMergeFeedOps); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/IntegrityCheckerProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/IntegrityCheckerProducer.java index 588e7c55ab92..4f81bbf165f0 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/IntegrityCheckerProducer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/IntegrityCheckerProducer.java @@ -16,9 +16,9 @@ protected IntegrityCheckerProducer build(ContentCluster cluster, ModelElement cl } } - private Integer startTime; - private Integer stopTime; - private String weeklyCycle; + private final Integer startTime; + private final Integer stopTime; + private final String weeklyCycle; IntegrityCheckerProducer(Integer startTime, Integer stopTime, String weeklyCycle) { this.startTime = startTime; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java index 2fca964a9955..e66f2c48f267 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorServerProducer.java @@ -3,10 +3,8 @@ import com.yahoo.config.model.api.ModelContext; import com.yahoo.vespa.config.content.core.StorServerConfig; -import com.yahoo.vespa.model.content.cluster.ContentCluster; import com.yahoo.vespa.model.builder.xml.dom.ModelElement; - -import java.util.Optional; +import com.yahoo.vespa.model.content.cluster.ContentCluster; /** * Serves config for stor-server for storage clusters (clusters of storage nodes). @@ -28,11 +26,10 @@ StorServerProducer build(ModelContext.Properties properties, ModelElement elemen } } - private String clusterName; + private final String clusterName; private Integer maxMergesPerNode; private Integer queueSize; - private Integer bucketDBStripeBits; - private StorServerConfig.Merge_throttling_policy.Type.Enum mergeThrottlingPolicyType; + private final StorServerConfig.Merge_throttling_policy.Type.Enum mergeThrottlingPolicyType; private StorServerProducer setMaxMergesPerNode(Integer value) { if (value != null) { @@ -46,10 +43,6 @@ private StorServerProducer setMaxQueueSize(Integer value) { } return this; } - private StorServerProducer setBucketDBStripeBits(Integer value) { - bucketDBStripeBits = value; - return this; - } private static StorServerConfig.Merge_throttling_policy.Type.Enum toThrottlePolicyType(String policyType) { try { @@ -80,9 +73,6 @@ public void getConfig(StorServerConfig.Builder builder) { if (queueSize != null) { builder.max_merge_queue_size(queueSize); } - if (bucketDBStripeBits != null) { - builder.content_node_bucket_db_stripe_bits(bucketDBStripeBits); - } // TODO set throttle policy params based on existing or separate flags builder.merge_throttling_policy(new StorServerConfig.Merge_throttling_policy.Builder().type(mergeThrottlingPolicyType)); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java index a3f32fcb44ba..da82a69842ab 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/storagecluster/StorageCluster.java @@ -30,7 +30,7 @@ public class StorageCluster extends AbstractConfigProducer { public static class Builder extends VespaDomBuilder.DomConfigProducerBuilder { @Override - protected StorageCluster doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element producerSpec) { + protected StorageCluster doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element producerSpec) { final ModelElement clusterElem = new ModelElement(producerSpec); final ContentCluster cluster = (ContentCluster)ancestor; @@ -51,7 +51,7 @@ protected StorageCluster doBuild(DeployState deployState, AbstractConfigProducer private final StorVisitorProducer storVisitorProducer; private final PersistenceProducer persistenceProducer; - StorageCluster(AbstractConfigProducer parent, + StorageCluster(AbstractConfigProducer parent, String clusterName, FileStorProducer fileStorProducer, IntegrityCheckerProducer integrityCheckerProducer,