Skip to content

Commit 1037fec

Browse files
committed
poolmanager,pool: Fix precision underflow in WASS
Fixes a problem in which a large number of writers on a pool (such as what you would see on a tape read pool) would cause the scale of a double to underflow, causing the weigthed acailable space to become zero. If all pools have such high load, no pool would be availble for selection and pool manager would report that no pool is available for staging. The fix uses the fact that only the relative weighted available space is relevant. Since the weighted space is calculated by dividing unweighted space with two to the power of the load, we can subtract a constant from the load of all pools and maintain the relative available space of each pool. The patch first finds the lowest load of all non-full pools in the selection and subtracts that from the load of all pools, thus normalizing the calculation. Other pools may have even high load, still causing the precision of a double to be insufficient, however the likelihood of selection such a pool is virtuallt zero anyway, so this barely affects the write distribution. The normalization does however ensure that at least one pool does not underflow (assuming non-full pools exist at all) and thus that a pool can be selected. Target: 2.6 Ticket: http://rt.dcache.org/Ticket/Display.html?id=7993 Require-notes: yes Require-book: no
1 parent 9fa01a1 commit 1037fec

File tree

1 file changed

+41
-15
lines changed

1 file changed

+41
-15
lines changed

modules/dcache/src/main/java/org/dcache/poolmanager/WassPartition.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -249,39 +249,65 @@ protected double getAvailable(PoolSpaceInfo space, long filesize)
249249
* become random. This it the same behaviour as with the classic
250250
* partition.
251251
*/
252-
protected double getWeightedAvailable(PoolCostInfo info, long filesize)
252+
protected double getWeightedAvailable(PoolCostInfo info, double available, double load)
253253
{
254-
double available = getAvailable(info.getSpaceInfo(), filesize);
255-
double load = _performanceCostFactor *
256-
info.getMoverCostFactor() * info.getWriters();
257-
return Math.pow(available, _spaceCostFactor) / Math.pow(2.0, load);
254+
return (available == 0) ? 0 : (Math.pow(available, _spaceCostFactor) / Math.pow(2.0, load));
255+
}
256+
257+
private double getLoad(PoolCostInfo info)
258+
{
259+
return _performanceCostFactor * info.getMoverCostFactor() * info.getWriters();
258260
}
259261

260262
/**
261263
* Selects a pool from a list using the WASS algorithm.
262-
*
264+
* <p/>
263265
* Returns null if all pools are full.
264266
*/
265-
protected PoolInfo
266-
selectByAvailableSpace(List<PoolInfo> pools, long size)
267+
public PoolInfo selectByAvailableSpace(List<PoolInfo> pools, long filesize)
267268
{
268-
double[] available = new double[pools.size()];
269-
double sum = 0.0;
269+
int length = pools.size();
270+
double[] available = new double[length];
270271

271-
for (int i = 0; i < available.length; i++) {
272-
sum += getWeightedAvailable(pools.get(i).getCostInfo(), size);
272+
/* Calculate available space adjusted by space cost factor. Determine the smallest
273+
* load of all pools able to hold the file.
274+
*/
275+
double minLoad = Double.POSITIVE_INFINITY;
276+
for (int i = 0; i < length; i++) {
277+
PoolCostInfo info = pools.get(i).getCostInfo();
278+
double free = getAvailable(info.getSpaceInfo(), filesize);
279+
if (free > 0) {
280+
available[i] = free;
281+
minLoad = Math.min(minLoad, getLoad(info));
282+
}
283+
}
284+
285+
if (minLoad == Double.POSITIVE_INFINITY) {
286+
return null;
287+
}
288+
289+
/* Weight available space by normalized load. Load is normalized to ensure that at least
290+
* for one pool we maintain enough precision to not reduce available space to zero.
291+
*/
292+
double sum = 0.0;
293+
for (int i = 0; i < length; i++) {
294+
PoolCostInfo info = pools.get(i).getCostInfo();
295+
double normalizedLoad = getLoad(info) - minLoad;
296+
double weightedAvailable = getWeightedAvailable(info, available[i], normalizedLoad);
297+
sum += weightedAvailable;
273298
available[i] = sum;
274299
}
275300

301+
/* Randomly choose one of the pools.
302+
*/
276303
double threshold = random() * sum;
277-
278-
for (int i = 0; i < available.length; i++) {
304+
for (int i = 0; i < length; i++) {
279305
if (threshold < available[i]) {
280306
return pools.get(i);
281307
}
282308
}
283309

284-
return null;
310+
throw new RuntimeException("Unreachable statement");
285311
}
286312

287313
@Override

0 commit comments

Comments
 (0)