aboutsummaryrefslogtreecommitdiffstats
path: root/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java
diff options
context:
space:
mode:
Diffstat (limited to 'documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java')
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java93
1 files changed, 93 insertions, 0 deletions
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java
new file mode 100644
index 00000000000..54e18302ef6
--- /dev/null
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/LegacyLoadBalancer.java
@@ -0,0 +1,93 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.documentapi.messagebus.protocol;
+
+import com.yahoo.jrt.slobrok.api.Mirror;
+
+import java.util.List;
+
+/**
+ * Load balances over a set of nodes based on statistics gathered from those nodes.
+ *
+ * @author thomasg
+ */
+class LegacyLoadBalancer extends LoadBalancer {
+
+ static class LegacyNodeMetrics extends NodeMetrics {
+ double weight = 1.0;
+ }
+
+ private double position = 0.0;
+
+ public LegacyLoadBalancer(String cluster) {
+ super(cluster);
+ }
+
+ /**
+ * The load balancing operation: Returns a node choice from the given choices,
+ * based on previously gathered statistics on the nodes, and a running "position"
+ * which is increased by 1 on each call to this.
+ *
+ * @param choices the node choices, represented as Slobrok entries
+ * @return the chosen node, or null only if the given choices were zero
+ */
+ public Node getRecipient(List<Mirror.Entry> choices) {
+ if (choices.isEmpty()) return null;
+
+ double weightSum = 0.0;
+ Node selectedNode = null;
+ synchronized (this) {
+ for (Mirror.Entry entry : choices) {
+ LegacyNodeMetrics nodeMetrics = (LegacyNodeMetrics)getNodeMetrics(entry);
+
+ weightSum += nodeMetrics.weight;
+
+ if (weightSum > position) {
+ selectedNode = new Node(entry, nodeMetrics);
+ break;
+ }
+ }
+ if (selectedNode == null) { // Position>sum of all weights: Wrap around (but keep the remainder for some reason)
+ position -= weightSum;
+ selectedNode = new Node(choices.get(0), getNodeMetrics(choices.get(0)));
+ }
+ position += 1.0;
+ selectedNode.metrics.incSend();
+ }
+ return selectedNode;
+ }
+
+ protected NodeMetrics createNodeMetrics() {
+ return new LegacyNodeMetrics();
+ }
+
+ /** Scale weights such that ratios are preserved */
+ private void increaseWeights() {
+ for (NodeMetrics nodeMetrics : getNodeWeights()) {
+ LegacyNodeMetrics n = (LegacyNodeMetrics) nodeMetrics;
+ if (n == null) continue;
+ double want = n.weight * 1.01010101010101010101;
+ if (want >= 1.0) {
+ n.weight = want;
+ } else {
+ n.weight = 1.0;
+ }
+ }
+ }
+
+ public void received(Node node, boolean busy) {
+ if (busy) {
+ synchronized (this) {
+ LegacyNodeMetrics n = (LegacyNodeMetrics) node.metrics;
+ double wantWeight = n.weight - 0.01;
+ if (wantWeight < 1.0) {
+ increaseWeights();
+ n.weight = 1.0;
+ } else {
+ n.weight = wantWeight;
+ }
+ node.metrics.incBusy();
+ }
+ }
+ }
+
+}