3 row
4 room
+mirror(4)
take(root)
choose(2, room)
take_vert
choose(1, disk)
+=> 0
+takeb root
+choose_r 0 room -> w[2]
+takew 2
+choose_r 0 cab -> w[1]
+takew 1
+choose_r 0 disk -> 0
+
+=> 1
+takeb root
+choose_r 0 room -> w[2]
+takew 2
+choose_r 1 cab -> w[1]
+takew 1
+choose_r 0 disk -> 0
+
+=> 2
+takeb root
+choose_r 1 room -> w[2]
+takew 2
+choose_r 0 cab -> w[1]
+takew 1
+choose_r 0 disk -> 0
+
+=> 3
+takeb root
+choose_r 1 room -> w[2]
+takew 2
+choose_r 1 cab -> w[1]
+takew 1
+choose_r 0 disk -> 0
+
+
+mirror(3)
+choose(1, room, root)
+choose(3, cab, _)
+vert(_)
+choose(1, disk, _)
+
+=> 0
+takeb root
+choose_r 0/3 cab
+choose_r 0/1 disk
+
+=> 1
+takeb root
+choose_r 1/3 cab
+choose_r 0/1 disk
+
+=> 2
+takeb root
+choose_r 2/3 cab
+choose_r 0/1 disk
+
+
+
+
mirror(2):
choose(1, room, root) -> [ room1 ]
choose(2, cabinet, _) -> [ cab3 cab2 ]
float get_weight() const { return weight; }
virtual int get_size() const = 0;
- void set_weight(float w) { weight = w; }
+ void set_weight(float w) { weight = w; }
virtual bool is_uniform() const = 0;
virtual int choose_r(int x, int r, Hash& h) const = 0;
}
int choose_r(int x, int r, Hash& h) const {
+ //cout << "uniformbucket.choose_r(" << x << ", " << r << ")" << endl;
//if (r >= get_size()) cout << "warning: r " << r << " >= " << get_size() << " uniformbucket.size" << endl;
int v = (h(x, get_id(), 1) % get_size()) * get_size();
}
int choose_r(int x, int r, Hash& h) const {
+ //cout << "mixedbucket.choose_r(" << x << ", " << r << ")" << endl;
int n = tree.root();
while (!tree.terminal(n)) {
// pick a point in [0,w)
// *** RULES ***
- // rule commands
- const int CRUSH_RULE_TAKE = 0;
- const int CRUSH_RULE_CHOOSE = 1;
- const int CRUSH_RULE_VERT = 2;
-
class RuleStep {
public:
int cmd;
args.push_back(a);
args.push_back(b);
}
+ RuleStep(int o, int a, int b, int c) : cmd(o) {
+ args.push_back(a);
+ args.push_back(b);
+ args.push_back(c);
+ }
};
+
+ // Rule
+ const int CRUSH_RULE_TAKE = 0;
+ const int CRUSH_RULE_CHOOSE = 1;
+ const int CRUSH_RULE_VERT = 2;
+
class Rule {
public:
vector< RuleStep > steps;
};
+ // CRule
+ const int CRULE_TAKEB = 1;
+ const int CRULE_CHOOSER = 2;
+
+ class CRule {
+ public:
+ vector< vector<RuleStep> > steps;
+ int nchoose;
+ int nrep;
+
+ CRule() {}
+ CRule(int nr) : steps(nr), nrep(nr) {}
+ };
// *** CRUSH ***
protected:
map<int, Bucket*> buckets;
map<int, Rule> rules;
+ map<int, CRule> crules;
Hash h;
+ set<int> failed;
+
public:
Crush(int seed=123) : h(seed) {}
void add_rule( int id, Rule& r ) {
rules[id] = r;
}
+ void add_crule( int id, CRule& r ) {
+ crules[id] = r;
+ }
+
+ void crule_choose(int ruleno, int x, vector<int>& result) {
+ CRule& rule = crules[ruleno];
+
+ // input
+ Bucket *in = 0;
+ int out = -1;
+
+ // for replicas
+ for (int rep=0; rep<rule.nrep; rep++) {
+ // initially zero
+ vector<int> add_r(rule.nchoose);
+
+ for (int attempt=0; ; attempt++) {
+
+ // steps
+ int nchoose = 0;
+ for (int pc=0; pc<rule.steps[rep].size(); pc++) {
+ switch (rule.steps[rep][pc].cmd) {
+ case CRULE_TAKEB:
+ {
+ const int arg = rule.steps[rep][pc].args[0];
+ assert(buckets.count(arg));
+ in = buckets[arg];
+ }
+ break;
+
+ case CRULE_CHOOSER:
+ {
+ int r = rule.steps[rep][pc].args[0];
+ const int rperiod = rule.steps[rep][pc].args[1];
+ const int type = rule.steps[rep][pc].args[2];
+
+ // adjust to skip unusable
+ r += rperiod * add_r[nchoose];
+ nchoose++;
+
+ //cout << "choose_r " << r << " type " << type << endl;
+
+ // choose through any intervening buckets
+ while (1) {
+ // choose in this bucket
+ out = in->choose_r(x, r, h);
+
+ if (in->is_uniform() &&
+ ((UniformBucket*)in)->get_item_type() == type)
+ break;
+
+ int itemtype = 0; // 0 is a terminal type
+ if (buckets.count(out)) {
+ in = buckets[out];
+ itemtype = in->get_type();
+ }
+ if (itemtype == type) break; // this is what we want!
+ }
+
+ if (type != 0) { // translate back into a bucket
+ assert(buckets.count(out));
+ in = buckets[out];
+ }
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ // disk failed?
+ bool bad = false;
+ if (failed.count(out))
+ bad = true;
+
+ for (int prep=0; prep<rep; prep++) {
+ if (result[prep] == out)
+ bad = true;
+ }
+
+ if (bad) {
+ // bump an 'r'
+ //cout << "failed|repeat " << attempt << endl;
+ add_r[ rule.nchoose - 1 - ((attempt/2)%rule.nchoose) ]++;
+ continue;
+ }
+
+ break; // disk is fine.
+ }
+
+ // ok!
+ result[rep] = out;
+ }
+ }
+
void choose(int rno, int x, vector<int>& result) {
assert(rules.count(rno));
int main()
{
Hash h(73);
- int numrep = 3;
+ int numrep = 5;
// buckets
ub2.make_primes(h);
cout << "ub2 primes are " << ub2.primes << endl;
- make_disks(21, ndisks, disks);
+ make_disks(4, ndisks, disks);
UniformBucket ub3(3, 1, 0, 30, disks);
ub3.make_primes(h);
cout << "ub3 primes are " << ub3.primes << endl;
// rule
Rule rule;
rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, 100));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, 3, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ CRule crule(numrep);
+ crule.nchoose = 2;
+ for (int j=0; j<numrep; j++) {
+ crule.steps[j].push_back(RuleStep(CRULE_TAKEB, 100));
+ crule.steps[j].push_back(RuleStep(CRULE_CHOOSER, j, numrep, 1));
+ crule.steps[j].push_back(RuleStep(CRULE_CHOOSER, j, numrep, 0));
+ }
// crush
Crush c;
c.add_bucket(&ub3);
c.add_bucket(&b);
c.add_rule(numrep, rule);
+ c.add_crule(numrep, crule);
cout << "placing " << numo << " logical, " << numo*numrep << " total" << endl;
for (int x=1; x<numo; x++) {
//cout << H(x) << "\t" << h(x) << endl;
- v.clear();
- c.choose(numrep, x, v);
+ c.crule_choose(numrep, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+ bool bad = false;
for (int i=0; i<numrep; i++) {
//int d = b.choose_r(x, i, h);
//v[i] = d;
ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
}
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
//cout << v << "\t" << ocount << endl;
}