Refactor code to simplify calculation logic (#1199)

This commit is contained in:
纪卓志
2023-02-02 19:41:55 +08:00
committed by GitHub
parent f990f1c8cf
commit b996fec203

View File

@@ -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> {
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> {
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> {
return a;
}
static class InterleavedWeightedServiceInstanceSelector {
static class WeightedServiceInstanceSelector {
static final int MODE_LIST = 0;
Queue<Entry> active;
static final int MODE_QUEUE = 1;
Queue<Entry> expired;
final ServiceInstance[] instances;
final int[] weights;
final int greatestCommonDivisor;
final Queue<Entry> queue;
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];
if (active.isEmpty()) {
Queue<Entry> temp = active;
active = expired;
expired = temp;
}
weight = weight - greatestCommonDivisor;
if (weight > 0) {
queue.add(new Entry(instance, weight));
}
Entry entry = active.poll();
if (entry == null) {
// Suppress warnings, never touched!
return null;
}
position++;
if (position == instances.length) {
mode = MODE_QUEUE;
position = 0;
}
return instance;
entry.remainder--;
if (entry.remainder == 0) {
entry.remainder = entry.weight;
expired.offer(entry);
}
else {
if (queue.isEmpty()) {
mode = MODE_LIST;
return next();
}
Entry entry = queue.poll();
entry.weight = entry.weight - greatestCommonDivisor;
if (entry.weight > 0) {
queue.add(entry);
}
return entry.instance;
active.offer(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;
}
}