diff --git a/lp/lp-optimizer.js b/lp/lp-optimizer.js index 6aa9e863..9fdd4c9b 100644 --- a/lp/lp-optimizer.js +++ b/lp/lp-optimizer.js @@ -376,6 +376,40 @@ function put_aligned_pgs(aligned_pgs, int_pgs, prev_int_pgs, keygen) } } +// Convert multi-level osd_tree = { level: number, id?: string, size?: number, children?: osd_tree }[] +// to a two-level osd_tree suitable for all_combinations() +function flatten_tree(osd_tree, failure_domain_level, osd_level, domains = {}, i = { i: 1 }) +{ + for (const node of osd_tree) + { + if (node.level < failure_domain_level) + { + flatten_tree(node.children||[], failure_domain_level, osd_level, domains, i); + } + else + { + domains['dom'+(i.i++)] = extract_osds([ node ], osd_level); + } + } + return domains; +} + +function extract_osds(osd_tree, osd_level, osds = {}) +{ + for (const node of osd_tree) + { + if (node.level >= osd_level) + { + osds[node.id] = node.size; + } + else + { + extract_osds(node.children||[], osd_level, osds); + } + } + return osds; +} + function all_combinations(osd_tree, count, ordered) { const hosts = Object.keys(osd_tree).sort(); @@ -485,6 +519,7 @@ module.exports = { pg_weights_space_efficiency, pg_list_space_efficiency, pg_per_osd_space_efficiency, + flatten_tree, lp_solve, make_single, diff --git a/lp/test-optimize.js b/lp/test-optimize.js index 4c8e9046..fce5049d 100644 --- a/lp/test-optimize.js +++ b/lp/test-optimize.js @@ -40,20 +40,55 @@ const osd_tree = { },*/ }; +const crush_tree = [ + { level: 1, children: [ + { level: 2, children: [ + { level: 3, id: 1, size: 3 }, + { level: 3, id: 2, size: 2 }, + ] }, + { level: 2, children: [ + { level: 3, id: 3, size: 4 }, + { level: 3, id: 4, size: 4 }, + ] }, + ] }, + { level: 1, children: [ + { level: 2, children: [ + { level: 3, id: 5, size: 4 }, + { level: 3, id: 6, size: 1 }, + ] }, + { level: 2, children: [ + { level: 3, id: 7, size: 3 }, + { level: 3, id: 8, size: 5 }, + ] }, + ] }, + { level: 1, children: [ + { level: 2, children: [ + { level: 3, id: 9, size: 5 }, + { level: 3, id: 10, size: 2 }, + ] }, + { level: 2, children: [ + { level: 3, id: 11, size: 3 }, + { level: 3, id: 12, size: 3 }, + ] }, + ] }, +]; + async function run() { // Test: add 1 OSD of almost the same size. Ideal data movement could be 1/12 = 8.33%. Actual is ~13% // Space efficiency is ~99.5% in both cases. - let prev = await LPOptimizer.optimize_initial(osd_tree, 256); - LPOptimizer.print_change_stats(prev, false); + let res = await LPOptimizer.optimize_initial(osd_tree, 256); + LPOptimizer.print_change_stats(res, false); console.log('adding osd.8'); osd_tree[500][8] = 3.58589; - let next = await LPOptimizer.optimize_change(prev.int_pgs, osd_tree); - LPOptimizer.print_change_stats(next, false); + res = await LPOptimizer.optimize_change(res.int_pgs, osd_tree); + LPOptimizer.print_change_stats(res, false); console.log('removing osd.8'); delete osd_tree[500][8]; - next = await LPOptimizer.optimize_change(next.int_pgs, osd_tree); - LPOptimizer.print_change_stats(next, false); + res = await LPOptimizer.optimize_change(res.int_pgs, osd_tree); + LPOptimizer.print_change_stats(res, false); + res = await LPOptimizer.optimize_initial(LPOptimizer.flatten_tree(crush_tree, 1, 3), 256); + LPOptimizer.print_change_stats(res, false); } run().catch(console.error);