const vector<pair<int,int>>& stack,
const set<int>& overfull,
const vector<int>& underfull,
+ const vector<int>& more_underfull,
const vector<int>& orig,
vector<int>::const_iterator& i,
set<int>& used,
++i;
break;
}
+ if (!replaced) {
+ for (auto item : more_underfull) {
+ ldout(cct, 10) << __func__ << " more underfull pos " << pos
+ << " was " << *i << " considering " << item
+ << dendl;
+ if (used.count(item)) {
+ ldout(cct, 20) << __func__ << " in used " << used << dendl;
+ continue;
+ }
+ if (!subtree_contains(from, item)) {
+ ldout(cct, 20) << __func__ << " not in subtree " << from << dendl;
+ continue;
+ }
+ if (std::find(orig.begin(), orig.end(), item) != orig.end()) {
+ ldout(cct, 20) << __func__ << " in orig " << orig << dendl;
+ continue;
+ }
+ o.push_back(item);
+ used.insert(item);
+ ldout(cct, 10) << __func__ << " pos " << pos << " replace "
+ << *i << " -> " << item << dendl;
+ replaced = true;
+ assert(i != orig.end());
+ ++i;
+ break;
+ }
+ }
}
if (!replaced) {
ldout(cct, 10) << __func__ << " pos " << pos << " keep " << *i
int maxout,
const set<int>& overfull,
const vector<int>& underfull,
+ const vector<int>& more_underfull,
const vector<int>& orig,
vector<int> *out) const
{
ldout(cct, 10) << __func__ << " ruleno " << ruleno
<< " numrep " << maxout << " overfull " << overfull
- << " underfull " << underfull << " orig " << orig
+ << " underfull " << underfull
+ << " more_underfull " << more_underfull
+ << " orig " << orig
<< dendl;
vector<int> w; // working set
out->clear();
type_stack.push_back(make_pair(type, numrep));
if (type > 0)
type_stack.push_back(make_pair(0, 1));
- int r = _choose_type_stack(cct, type_stack, overfull, underfull, orig,
+ int r = _choose_type_stack(cct, type_stack, overfull, underfull, more_underfull, orig,
i, used, &w, root_bucket, ruleno);
if (r < 0)
return r;
case CRUSH_RULE_EMIT:
ldout(cct, 10) << " emit " << w << dendl;
if (!type_stack.empty()) {
- int r = _choose_type_stack(cct, type_stack, overfull, underfull, orig,
+ int r = _choose_type_stack(cct, type_stack, overfull, underfull, more_underfull, orig,
i, used, &w, root_bucket, ruleno);
if (r < 0)
return r;
const vector<pair<int,int>>& stack,
const set<int>& overfull,
const vector<int>& underfull,
+ const vector<int>& more_underfull,
const vector<int>& orig,
vector<int>::const_iterator& i,
set<int>& used,
int maxout,
const set<int>& overfull,
const vector<int>& underfull,
+ const vector<int>& more_underfull,
const vector<int>& orig,
vector<int> *out) const;
pg_t pg, ///< pg to potentially remap
const set<int>& overfull, ///< osds we'd want to evacuate
const vector<int>& underfull, ///< osds to move to, in order of preference
+ const vector<int>& more_underfull, ///< more osds only slightly underfull
vector<int> *orig,
vector<int> *out) ///< resulting alternative mapping
{
rule,
pool->get_size(),
overfull, underfull,
+ more_underfull,
*orig,
out);
if (r < 0)
// build overfull and underfull
set<int> overfull;
vector<int> underfull;
+ vector<int> more_underfull;
for (auto i = deviation_osd.rbegin(); i != deviation_osd.rend(); i++) {
ldout(cct, 30) << " check " << i->first << " <= " << max_deviation << dendl;
if (i->first <= max_deviation)
for (auto i = deviation_osd.begin(); i != deviation_osd.end(); i++) {
ldout(cct, 30) << " check " << i->first << " >= " << -(int)max_deviation << dendl;
- if (i->first >= -(int)max_deviation)
+ if (i->first >= 0)
break;
- ldout(cct, 30) << " add underfull osd." << i->second << dendl;
- underfull.push_back(i->second);
+ if (i->first < -(int)max_deviation) {
+ ldout(cct, 30) << " add underfull osd." << i->second << dendl;
+ underfull.push_back(i->second);
+ } else {
+ more_underfull.push_back(i->second);
+ }
}
- if (underfull.empty()) {
- ldout(cct, 20) << __func__ << " failed to build underfull" << dendl;
+ if (underfull.empty() && more_underfull.empty()) {
+ ldout(cct, 20) << __func__ << " failed to build underfull and more_underfull" << dendl;
break;
}
auto temp_pgs_by_osd = pgs_by_osd;
// always start with fullest, break if we find any changes to make
for (auto p = deviation_osd.rbegin(); p != deviation_osd.rend(); ++p) {
- if (skip_overfull) {
+ if (skip_overfull && !underfull.empty()) {
ldout(cct, 10) << " skipping overfull " << dendl;
break; // fall through to check underfull
}
ldout(cct, 10) << " trying " << pg << dendl;
vector<int> raw, orig, out;
tmp.pg_to_raw_upmap(pg, &raw, &orig); // including existing upmaps too
- if (!try_pg_upmap(cct, pg, overfull, underfull, &orig, &out)) {
+ if (!try_pg_upmap(cct, pg, overfull, underfull, more_underfull, &orig, &out)) {
continue;
}
ldout(cct, 10) << " " << pg << " " << orig << " -> " << out << dendl;
pg_t pg, ///< pg to potentially remap
const set<int>& overfull, ///< osds we'd want to evacuate
const vector<int>& underfull, ///< osds to move to, in order of preference
+ const vector<int>& more_underfull, ///< less full osds to move to, in order of preference
vector<int> *orig,
vector<int> *out); ///< resulting alternative mapping
vector<int> orig = { 0, 3, 9 };
set<int> overfull = { 3 };
vector<int> underfull = { 0, 2, 5, 8, 11 };
+ vector<int> more_underfull = {};
vector<int> out;
int r = c.try_remap_rule(g_ceph_context, rule, 3,
- overfull, underfull,
+ overfull, underfull, more_underfull,
orig, &out);
cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
ASSERT_EQ(r, 0);
orig = {1, 3, 9};
r = c.try_remap_rule(g_ceph_context, rule, 3,
- overfull, underfull,
+ overfull, underfull, more_underfull,
orig, &out);
cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
ASSERT_EQ(r, 0);
ASSERT_EQ(1, out[0]);
ASSERT_EQ(0, out[1]);
ASSERT_EQ(9, out[2]);
+ //
+ // Check that more_underfull is used when underfull runs out
+ orig = { 0, 3, 9 };
+ overfull = { 3, 9 };
+ underfull = { 2 };
+ more_underfull = { 5, 8, 11 };
+ r = c.try_remap_rule(g_ceph_context, rule, 3,
+ overfull, underfull, more_underfull,
+ orig, &out);
+ cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
+ ASSERT_EQ(r, 0);
+ ASSERT_EQ(3u, out.size());
+ ASSERT_EQ(0, out[0]);
+ ASSERT_EQ(2, out[1]);
+ ASSERT_EQ(5, out[2]);
}
// chooseleaf
vector<int> orig = { 0, 3, 9 };
set<int> overfull = { 3 };
vector<int> underfull = { 0, 2, 5, 8, 11 };
+ vector<int> more_underfull = { };
vector<int> out;
int r = c.try_remap_rule(g_ceph_context, rule, 3,
- overfull, underfull,
+ overfull, underfull, more_underfull,
orig, &out);
cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
ASSERT_EQ(r, 0);
vector<int> orig = { 0, 3, 16, 12 };
set<int> overfull = { 3, 12 };
vector<int> underfull = { 6, 7, 9, 3, 0, 1, 15, 16, 13, 2, 5, 8, 11 };
+ vector<int> more_underfull = { };
vector<int> out;
int r = c.try_remap_rule(g_ceph_context, rule, 3,
- overfull, underfull,
+ overfull, underfull, more_underfull,
orig, &out);
cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
ASSERT_EQ(r, 0);
orig.pop_back();
out.clear();
r = c.try_remap_rule(g_ceph_context, rule, 3,
- overfull, underfull,
+ overfull, underfull, more_underfull,
orig, &out);
cout << orig << " -> r = " << (int)r << " out " << out << std::endl;
ASSERT_EQ(r, 0);