Browse Source

Refactor code to simplify calculation logic (#1199)

pull/1206/head
纪卓志 2 years ago committed by GitHub
parent
commit
b996fec203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 93
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/LazyWeightedServiceInstanceList.java

93
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/LazyWeightedServiceInstanceList.java

@ -32,14 +32,14 @@ import org.springframework.cloud.client.ServiceInstance; @@ -32,14 +32,14 @@ import org.springframework.cloud.client.ServiceInstance;
*/
class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> {
private final InterleavedWeightedServiceInstanceSelector selector;
private volatile int position;
/* for testing */ final ServiceInstance[] expanded;
private final Object expandingLock = new Object();
private WeightedServiceInstanceSelector selector;
private volatile int position = 0;
LazyWeightedServiceInstanceList(List<ServiceInstance> instances, int[] weights) {
// Calculate the greatest common divisor (GCD) of weights, and the
// total number of elements after expansion.
@ -49,10 +49,8 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> { @@ -49,10 +49,8 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> {
greatestCommonDivisor = greatestCommonDivisor(greatestCommonDivisor, weight);
total += weight;
}
selector = new InterleavedWeightedServiceInstanceSelector(instances.toArray(new ServiceInstance[0]), weights,
greatestCommonDivisor);
position = 0;
expanded = new ServiceInstance[total / greatestCommonDivisor];
selector = new WeightedServiceInstanceSelector(instances, weights, greatestCommonDivisor);
}
@Override
@ -62,6 +60,9 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> { @@ -62,6 +60,9 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> {
for (; position <= index && position < expanded.length; position++) {
expanded[position] = selector.next();
}
if (position == expanded.length) {
selector = null; // for gc
}
}
}
return expanded[index];
@ -82,77 +83,61 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> { @@ -82,77 +83,61 @@ class LazyWeightedServiceInstanceList extends AbstractList<ServiceInstance> {
return a;
}
static class InterleavedWeightedServiceInstanceSelector {
static final int MODE_LIST = 0;
static final int MODE_QUEUE = 1;
final ServiceInstance[] instances;
final int[] weights;
static class WeightedServiceInstanceSelector {
final int greatestCommonDivisor;
Queue<Entry> active;
final Queue<Entry> queue;
Queue<Entry> expired;
int mode;
int position;
InterleavedWeightedServiceInstanceSelector(ServiceInstance[] instances, int[] weights,
int greatestCommonDivisor) {
this.instances = instances;
this.weights = weights;
this.greatestCommonDivisor = greatestCommonDivisor;
queue = new ArrayDeque<>(instances.length);
mode = MODE_LIST;
position = 0;
WeightedServiceInstanceSelector(List<ServiceInstance> instances, int[] weights, int greatestCommonDivisor) {
active = new ArrayDeque<>(instances.size());
expired = new ArrayDeque<>(instances.size());
// Use iterator for some implementation of the List that not supports
// RandomAccess, but `weights` is supported, so use a local variable `i`
// to get the current position.
int i = 0;
for (ServiceInstance instance : instances) {
active.offer(new Entry(instance, weights[i] / greatestCommonDivisor));
i++;
}
}
ServiceInstance next() {
if (mode == MODE_LIST) {
ServiceInstance instance = instances[position];
int weight = weights[position];
weight = weight - greatestCommonDivisor;
if (weight > 0) {
queue.add(new Entry(instance, weight));
if (active.isEmpty()) {
Queue<Entry> temp = active;
active = expired;
expired = temp;
}
position++;
if (position == instances.length) {
mode = MODE_QUEUE;
position = 0;
Entry entry = active.poll();
if (entry == null) {
// Suppress warnings, never touched!
return null;
}
return instance;
entry.remainder--;
if (entry.remainder == 0) {
entry.remainder = entry.weight;
expired.offer(entry);
}
else {
if (queue.isEmpty()) {
mode = MODE_LIST;
return next();
active.offer(entry);
}
Entry entry = queue.poll();
entry.weight = entry.weight - greatestCommonDivisor;
if (entry.weight > 0) {
queue.add(entry);
}
return entry.instance;
}
}
static class Entry {
final ServiceInstance instance;
int weight;
final int weight;
int remainder;
Entry(ServiceInstance instance, int weight) {
this.instance = instance;
this.weight = weight;
remainder = weight;
}
}

Loading…
Cancel
Save