Add asserts for lp-optimizer tests, pass `ordered` from the monitor
parent
9c6168bf17
commit
68b6763ebe
|
@ -50,7 +50,7 @@ async function lp_solve(text)
|
||||||
return { score, vars };
|
return { score, vars };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function optimize_initial({ osd_tree, pg_count, pg_size = 3, pg_minsize = 2, max_combinations = 10000, parity_space = 1, round_robin = false })
|
async function optimize_initial({ osd_tree, pg_count, pg_size = 3, pg_minsize = 2, max_combinations = 10000, parity_space = 1, ordered = false })
|
||||||
{
|
{
|
||||||
if (!pg_count || !osd_tree)
|
if (!pg_count || !osd_tree)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ async function optimize_initial({ osd_tree, pg_count, pg_size = 3, pg_minsize =
|
||||||
console.log(lp);
|
console.log(lp);
|
||||||
throw new Error('Problem is infeasible or unbounded - is it a bug?');
|
throw new Error('Problem is infeasible or unbounded - is it a bug?');
|
||||||
}
|
}
|
||||||
const int_pgs = make_int_pgs(lp_result.vars, pg_count, round_robin);
|
const int_pgs = make_int_pgs(lp_result.vars, pg_count, ordered);
|
||||||
const eff = pg_list_space_efficiency(int_pgs, all_weights, pg_minsize, parity_space);
|
const eff = pg_list_space_efficiency(int_pgs, all_weights, pg_minsize, parity_space);
|
||||||
const res = {
|
const res = {
|
||||||
score: lp_result.score,
|
score: lp_result.score,
|
||||||
|
@ -382,11 +382,35 @@ async function optimize_change({ prev_pgs: prev_int_pgs, osd_tree, pg_size = 3,
|
||||||
{
|
{
|
||||||
differs++;
|
differs++;
|
||||||
}
|
}
|
||||||
for (let j = 0; j < pg_size; j++)
|
}
|
||||||
|
if (ordered)
|
||||||
|
{
|
||||||
|
for (let i = 0; i < pg_count; i++)
|
||||||
{
|
{
|
||||||
if (new_pgs[i][j] != prev_int_pgs[i][j])
|
for (let j = 0; j < pg_size; j++)
|
||||||
{
|
{
|
||||||
osd_differs++;
|
if (new_pgs[i][j] != prev_int_pgs[i][j])
|
||||||
|
{
|
||||||
|
osd_differs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (let i = 0; i < pg_count; i++)
|
||||||
|
{
|
||||||
|
const old_map = prev_int_pgs[i].reduce((a, c) => { a[c] = (a[c]|0) + 1; return a; }, {});
|
||||||
|
for (let j = 0; j < pg_size; j++)
|
||||||
|
{
|
||||||
|
if ((0|old_map[new_pgs[i][j]]) > 0)
|
||||||
|
{
|
||||||
|
old_map[new_pgs[i][j]]--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osd_differs++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1098,7 +1098,7 @@ class Mon
|
||||||
pg_size: pool_cfg.pg_size,
|
pg_size: pool_cfg.pg_size,
|
||||||
pg_minsize: pool_cfg.pg_minsize,
|
pg_minsize: pool_cfg.pg_minsize,
|
||||||
max_combinations: pool_cfg.max_osd_combinations,
|
max_combinations: pool_cfg.max_osd_combinations,
|
||||||
round_robin: pool_cfg.scheme != 'replicated',
|
ordered: pool_cfg.scheme != 'replicated',
|
||||||
};
|
};
|
||||||
let optimize_result;
|
let optimize_result;
|
||||||
if (old_pg_count > 0)
|
if (old_pg_count > 0)
|
||||||
|
@ -1121,10 +1121,6 @@ class Mon
|
||||||
{
|
{
|
||||||
pg.push(0);
|
pg.push(0);
|
||||||
}
|
}
|
||||||
while (pg.length > pool_cfg.pg_size)
|
|
||||||
{
|
|
||||||
pg.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!this.state.config.pgs.hash)
|
if (!this.state.config.pgs.hash)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
|
||||||
|
|
||||||
const LPOptimizer = require('./lp-optimizer.js');
|
|
||||||
|
|
||||||
const osd_tree = {
|
|
||||||
100: { 1: 1 },
|
|
||||||
200: { 2: 1 },
|
|
||||||
300: { 3: 1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
async function run()
|
|
||||||
{
|
|
||||||
let res;
|
|
||||||
console.log('16 PGs, size=3');
|
|
||||||
res = await LPOptimizer.optimize_initial({ osd_tree, pg_size: 3, pg_count: 16 });
|
|
||||||
LPOptimizer.print_change_stats(res, false);
|
|
||||||
console.log('\nChanging size to 2');
|
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree, pg_size: 2 });
|
|
||||||
LPOptimizer.print_change_stats(res, false);
|
|
||||||
if (res.space < 3*14/16)
|
|
||||||
{
|
|
||||||
throw new Error('Redistribution failed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run().catch(console.error);
|
|
|
@ -5,21 +5,45 @@ const LPOptimizer = require('./lp-optimizer.js');
|
||||||
|
|
||||||
async function run()
|
async function run()
|
||||||
{
|
{
|
||||||
const osd_tree = { a: { 1: 1 }, b: { 2: 1 }, c: { 3: 1 } };
|
const osd_tree = {
|
||||||
|
100: { 1: 1 },
|
||||||
|
200: { 2: 1 },
|
||||||
|
300: { 3: 1 },
|
||||||
|
};
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
|
||||||
console.log('16 PGs, size=3');
|
console.log('16 PGs, size=3');
|
||||||
res = await LPOptimizer.optimize_initial({ osd_tree, pg_size: 3, pg_count: 16 });
|
res = await LPOptimizer.optimize_initial({ osd_tree, pg_size: 3, pg_count: 16, ordered: false });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 3, 'Initial distribution');
|
||||||
console.log('\nReduce PG size to 2');
|
console.log('\nChange size to 2');
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs.map(pg => pg.slice(0, 2)), osd_tree, pg_size: 2 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree, pg_size: 2, ordered: false });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space >= 3*14/16 && res.osd_differs == 0, 'Redistribution');
|
||||||
console.log('\nRemove OSD 3');
|
console.log('\nRemove OSD 3');
|
||||||
delete osd_tree['c'];
|
const no3_tree = { ...osd_tree };
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree, pg_size: 2 });
|
delete no3_tree['300'];
|
||||||
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: no3_tree, pg_size: 2, ordered: false });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 2, 'Redistribution after OSD removal');
|
||||||
|
|
||||||
|
console.log('\n16 PGs, size=3, ordered');
|
||||||
|
res = await LPOptimizer.optimize_initial({ osd_tree, pg_size: 3, pg_count: 16, ordered: true });
|
||||||
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 3, 'Initial distribution');
|
||||||
|
console.log('\nChange size to 2, ordered');
|
||||||
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree, pg_size: 2, ordered: true });
|
||||||
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space >= 3*14/16 && res.osd_differs < 8, 'Redistribution');
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert(cond, txt)
|
||||||
|
{
|
||||||
|
if (!cond)
|
||||||
|
{
|
||||||
|
throw new Error((txt||'test')+' failed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run().catch(console.error);
|
run().catch(console.error);
|
||||||
|
|
|
@ -45,30 +45,45 @@ async function run()
|
||||||
console.log('Empty tree:');
|
console.log('Empty tree:');
|
||||||
let res = await LPOptimizer.optimize_initial({ osd_tree: cur_tree, pg_size: 3, pg_count: 256 });
|
let res = await LPOptimizer.optimize_initial({ osd_tree: cur_tree, pg_size: 3, pg_count: 256 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 0);
|
||||||
console.log('\nAdding 1st failure domain:');
|
console.log('\nAdding 1st failure domain:');
|
||||||
cur_tree['dom1'] = osd_tree['dom1'];
|
cur_tree['dom1'] = osd_tree['dom1'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 12 && res.total_space == 12);
|
||||||
console.log('\nAdding 2nd failure domain:');
|
console.log('\nAdding 2nd failure domain:');
|
||||||
cur_tree['dom2'] = osd_tree['dom2'];
|
cur_tree['dom2'] = osd_tree['dom2'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 24 && res.total_space == 24);
|
||||||
console.log('\nAdding 3rd failure domain:');
|
console.log('\nAdding 3rd failure domain:');
|
||||||
cur_tree['dom3'] = osd_tree['dom3'];
|
cur_tree['dom3'] = osd_tree['dom3'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 36 && res.total_space == 36);
|
||||||
console.log('\nRemoving 3rd failure domain:');
|
console.log('\nRemoving 3rd failure domain:');
|
||||||
delete cur_tree['dom3'];
|
delete cur_tree['dom3'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 24 && res.total_space == 24);
|
||||||
console.log('\nRemoving 2nd failure domain:');
|
console.log('\nRemoving 2nd failure domain:');
|
||||||
delete cur_tree['dom2'];
|
delete cur_tree['dom2'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 12 && res.total_space == 12);
|
||||||
console.log('\nRemoving 1st failure domain:');
|
console.log('\nRemoving 1st failure domain:');
|
||||||
delete cur_tree['dom1'];
|
delete cur_tree['dom1'];
|
||||||
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
res = await LPOptimizer.optimize_change({ prev_pgs: res.int_pgs, osd_tree: cur_tree, pg_size: 3 });
|
||||||
LPOptimizer.print_change_stats(res, false);
|
LPOptimizer.print_change_stats(res, false);
|
||||||
|
assert(res.space == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert(cond, txt)
|
||||||
|
{
|
||||||
|
if (!cond)
|
||||||
|
{
|
||||||
|
throw new Error((txt||'test')+' failed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run().catch(console.error);
|
run().catch(console.error);
|
||||||
|
|
Loading…
Reference in New Issue