if (IS_ERR(b)) return PTR_ERR(b);
return b->alg;
}
+ int get_bucket_hash(int id) {
+ crush_bucket *b = get_bucket(id);
+ if (IS_ERR(b)) return PTR_ERR(b);
+ return b->hash;
+ }
int get_bucket_size(int id) {
crush_bucket *b = get_bucket(id);
if (IS_ERR(b)) return PTR_ERR(b);
::encode(crush->buckets[i]->id, bl);
::encode(crush->buckets[i]->type, bl);
+ ::encode(crush->buckets[i]->hash, bl);
::encode(crush->buckets[i]->alg, bl);
::encode(crush->buckets[i]->weight, bl);
::encode(crush->buckets[i]->size, bl);
::decode(crush->buckets[i]->id, blp);
::decode(crush->buckets[i]->type, blp);
+ ::decode(crush->buckets[i]->hash, blp);
::decode(crush->buckets[i]->alg, blp);
::decode(crush->buckets[i]->weight, blp);
::decode(crush->buckets[i]->size, blp);
memset(bucket, 0, sizeof(*bucket));
bucket->h.alg = CRUSH_BUCKET_UNIFORM;
bucket->h.type = type;
+ bucket->h.hash = CRUSH_HASH_RJENKINS1;
bucket->h.size = size;
bucket->h.weight = size * item_weight;
memset(bucket, 0, sizeof(*bucket));
bucket->h.alg = CRUSH_BUCKET_LIST;
bucket->h.type = type;
+ bucket->h.hash = CRUSH_HASH_RJENKINS1;
bucket->h.size = size;
bucket->h.items = malloc(sizeof(__u32)*size);
memset(bucket, 0, sizeof(*bucket));
bucket->h.alg = CRUSH_BUCKET_TREE;
bucket->h.type = type;
+ bucket->h.hash = CRUSH_HASH_RJENKINS1;
bucket->h.size = size;
bucket->h.items = malloc(sizeof(__u32)*size);
memset(bucket, 0, sizeof(*bucket));
bucket->h.alg = CRUSH_BUCKET_STRAW;
bucket->h.type = type;
+ bucket->h.hash = CRUSH_HASH_RJENKINS1;
bucket->h.size = size;
bucket->h.items = malloc(sizeof(__u32)*size);
struct crush_bucket {
__s32 id; /* this'll be negative */
__u16 type; /* non-zero; type=0 is reserved for devices */
- __u16 alg; /* one of CRUSH_BUCKET_* */
+ __u8 alg; /* one of CRUSH_BUCKET_* */
+ __u8 hash; /* which hash function to use, CRUSH_HASH_* */
__u32 weight; /* 16-bit fixed point */
__u32 size; /* num items */
__s32 *items;
struct crush_grammar : public grammar<crush_grammar>
{
- static const int _int = 1;
- static const int _posint = 2;
- static const int _negint = 3;
- static const int _name = 4;
-
- static const int _device = 12;
- static const int _bucket_type = 13;
- static const int _bucket_id = 14;
- static const int _bucket_alg = 15;
- static const int _bucket_item = 16;
- static const int _bucket = 17;
-
- static const int _step_take = 18;
- static const int _step_choose = 19;
- static const int _step_chooseleaf = 20;
- static const int _step_emit = 21;
- static const int _step = 22;
- static const int _crushrule = 23;
-
- static const int _crushmap = 24;
+ enum {
+ _int = 1,
+ _posint,
+ _negint,
+ _name,
+ _device,
+ _bucket_type,
+ _bucket_id,
+ _bucket_alg,
+ _bucket_hash,
+ _bucket_item,
+ _bucket,
+ _step_take,
+ _step_choose,
+ _step_chooseleaf,
+ _step_emit,
+ _step,
+ _crushrule,
+ _crushmap,
+ };
template <typename ScannerT>
struct definition
rule<ScannerT, parser_context<>, parser_tag<_device> > device;
- rule<ScannerT, parser_context<>, parser_tag<_bucket_type> > bucket_type;
+ rule<ScannerT, parser_context<>, parser_tag<_bucket_type> > bucket_type;
rule<ScannerT, parser_context<>, parser_tag<_bucket_id> > bucket_id;
- rule<ScannerT, parser_context<>, parser_tag<_bucket_alg> > bucket_alg;
- rule<ScannerT, parser_context<>, parser_tag<_bucket_item> > bucket_item;
+ rule<ScannerT, parser_context<>, parser_tag<_bucket_alg> > bucket_alg;
+ rule<ScannerT, parser_context<>, parser_tag<_bucket_hash> > bucket_hash;
+ rule<ScannerT, parser_context<>, parser_tag<_bucket_item> > bucket_item;
rule<ScannerT, parser_context<>, parser_tag<_bucket> > bucket;
rule<ScannerT, parser_context<>, parser_tag<_step_take> > step_take;
- rule<ScannerT, parser_context<>, parser_tag<_step_choose> > step_choose;
+ rule<ScannerT, parser_context<>, parser_tag<_step_choose> > step_choose;
rule<ScannerT, parser_context<>, parser_tag<_step_chooseleaf> > step_chooseleaf;
rule<ScannerT, parser_context<>, parser_tag<_step_emit> > step_emit;
rule<ScannerT, parser_context<>, parser_tag<_step> > step;
str_p("list") |
str_p("tree") |
str_p("straw") );
+ bucket_hash = str_p("hash") >> ( integer |
+ str_p("rjenkins1") );
bucket_item = str_p("item") >> name
>> !( str_p("weight") >> real_p )
>> !( str_p("pos") >> posint );
#include <linux/types.h>
+#include "hash.h"
/*
* Robert Jenkins' function for mixing 32-bit values
#define crush_hash_seed 1315423911
-__u32 crush_hash32(__u32 a)
+static __u32 crush_hash32_rjenkins1(__u32 a)
{
__u32 hash = crush_hash_seed ^ a;
__u32 b = a;
return hash;
}
-__u32 crush_hash32_2(__u32 a, __u32 b)
+static __u32 crush_hash32_rjenkins1_2(__u32 a, __u32 b)
{
__u32 hash = crush_hash_seed ^ a ^ b;
__u32 x = 231232;
return hash;
}
-__u32 crush_hash32_3(__u32 a, __u32 b, __u32 c)
+static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c)
{
__u32 hash = crush_hash_seed ^ a ^ b ^ c;
__u32 x = 231232;
return hash;
}
-__u32 crush_hash32_4(__u32 a, __u32 b, __u32 c, __u32 d)
+static __u32 crush_hash32_rjenkins1_4(__u32 a, __u32 b, __u32 c, __u32 d)
{
__u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d;
__u32 x = 231232;
return hash;
}
-__u32 crush_hash32_5(__u32 a, __u32 b, __u32 c, __u32 d, __u32 e)
+static __u32 crush_hash32_rjenkins1_5(__u32 a, __u32 b, __u32 c, __u32 d,
+ __u32 e)
{
__u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
__u32 x = 231232;
crush_hashmix(y, e, hash);
return hash;
}
+
+
+__u32 crush_hash32(int type, __u32 a)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return crush_hash32_rjenkins1(a);
+ default:
+ return 0;
+ }
+}
+
+__u32 crush_hash32_2(int type, __u32 a, __u32 b)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return crush_hash32_rjenkins1_2(a, b);
+ default:
+ return 0;
+ }
+}
+
+__u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return crush_hash32_rjenkins1_3(a, b, c);
+ default:
+ return 0;
+ }
+}
+
+__u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return crush_hash32_rjenkins1_4(a, b, c, d);
+ default:
+ return 0;
+ }
+}
+
+__u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d, __u32 e)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return crush_hash32_rjenkins1_5(a, b, c, d, e);
+ default:
+ return 0;
+ }
+}
+
+const char *crush_hash_name(int type)
+{
+ switch (type) {
+ case CRUSH_HASH_RJENKINS1:
+ return "rjenkins1";
+ default:
+ return "unknown";
+ }
+}
#ifndef _CRUSH_HASH_H
#define _CRUSH_HASH_H
-extern __u32 crush_hash32(__u32 a);
-extern __u32 crush_hash32_2(__u32 a, __u32 b);
-extern __u32 crush_hash32_3(__u32 a, __u32 b, __u32 c);
-extern __u32 crush_hash32_4(__u32 a, __u32 b, __u32 c,
- __u32 d);
-extern __u32 crush_hash32_5(__u32 a, __u32 b, __u32 c,
- __u32 d, __u32 e);
+#define CRUSH_HASH_RJENKINS1 0
+
+extern const char *crush_hash_name(int type);
+
+extern __u32 crush_hash32(int type, __u32 a);
+extern __u32 crush_hash32_2(int type, __u32 a, __u32 b);
+extern __u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c);
+extern __u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d);
+extern __u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d,
+ __u32 e);
#endif
/* optimize common r=0 case */
if (pr == 0) {
- s = crush_hash32_3(x, bucket->id, 0) %
+ s = crush_hash32_3(bucket->hash, x, bucket->id, 0) %
bucket->size;
bucket->perm[0] = s;
bucket->perm_n = 0xffff; /* magic value, see below */
unsigned p = bucket->perm_n;
/* no point in swapping the final entry */
if (p < bucket->size - 1) {
- i = crush_hash32_3(x, bucket->id, p) %
+ i = crush_hash32_3(bucket->hash, x, bucket->id, p) %
(bucket->size - p);
if (i) {
unsigned t = bucket->perm[p + i];
int i;
for (i = bucket->h.size-1; i >= 0; i--) {
- __u64 w = crush_hash32_4(x, bucket->h.items[i], r,
- bucket->h.id);
+ __u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i],
+ r, bucket->h.id);
w &= 0xffff;
dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
"sw %x rand %llx",
while (!terminal(n)) {
/* pick point in [0, w) */
w = bucket->node_weights[n];
- t = (__u64)crush_hash32_4(x, n, r, bucket->h.id) * (__u64)w;
+ t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r,
+ bucket->h.id) * (__u64)w;
t = t >> 32;
/* descend to the left or right? */
__u64 draw;
for (i = 0; i < bucket->h.size; i++) {
- draw = crush_hash32_3(x, bucket->h.items[i], r);
+ draw = crush_hash32_3(bucket->h.hash, x, bucket->h.items[i], r);
draw &= 0xffff;
draw *= bucket->straws[i];
if (i == 0 || draw > high_draw) {
return 0;
if (weight[item] == 0)
return 1;
- if ((crush_hash32_2(x, item) & 0xffff) < weight[item])
+ if ((crush_hash32_2(CRUSH_HASH_RJENKINS1, x, item) & 0xffff)
+ < weight[item])
return 0;
return 1;
}
}
out << "\n";
+ int hash = crush.get_bucket_hash(i);
+ out << "\thash " << hash << "\t# " << crush_hash_name(hash) << "\n";
+
for (int j=0; j<n; j++) {
int item = crush.get_bucket_item(i, j);
int w = crush.get_bucket_item_weight(i, j);
case CEPH_PG_LAYOUT_HYBRID:
{
- int h = crush_hash32(pps);
+ int h = crush_hash32(CRUSH_HASH_RJENKINS1, pps);
for (unsigned i=0; i<size; i++)
osds.push_back( (h+i) % g_conf.num_osd );
}
int t = 1;
int osd = 0;
while (t++) {
- osd = crush_hash32_3(i, pps, t) % g_conf.num_osd;
+ osd = crush_hash32_3(CRUSH_HASH_RJENKINS1, i, pps, t) % g_conf.num_osd;
unsigned j = 0;
for (; j<i; j++)
if (osds[j] == osd) break;