]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crush: make hash function selectable
authorSage Weil <sage@newdream.net>
Sun, 8 Nov 2009 03:59:05 +0000 (19:59 -0800)
committerSage Weil <sage@newdream.net>
Sun, 8 Nov 2009 03:59:05 +0000 (19:59 -0800)
src/crush/CrushWrapper.h
src/crush/builder.c
src/crush/crush.h
src/crush/grammar.h
src/crush/hash.c
src/crush/hash.h
src/crush/mapper.c
src/crushtool.cc
src/osd/OSDMap.h

index 432c7593273ccf5a3a07f348ff9d873be31774b3..e24d572d7adcbacb06cc9836a84996c4760f421d 100644 (file)
@@ -291,6 +291,11 @@ public:
     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);
@@ -369,6 +374,7 @@ public:
 
       ::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);
@@ -463,6 +469,7 @@ public:
 
       ::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);
index a10f7a455efbb30708cff7e78b07b51e085084b5..c0d9e7a2b404f758d5ac6fd86191a6cde3f930e6 100644 (file)
@@ -152,6 +152,7 @@ crush_make_uniform_bucket(int type, int size,
        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;
 
@@ -181,6 +182,7 @@ crush_make_list_bucket(int type, int size,
        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);
@@ -239,6 +241,7 @@ crush_make_tree_bucket(int type, int 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);
@@ -295,6 +298,7 @@ crush_make_straw_bucket(int type,
        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);
index 92c6b3c3a5711c32c16659378c3d00318a1ac225..dcd7e752370077cd6cbba5745a0249667e04e73e 100644 (file)
@@ -102,7 +102,8 @@ extern const char *crush_bucket_alg_name(int alg);
 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;
index a9b7407c99b9f45d0d110e21aebda3cc9cb46b70..272cfd916143d4ecc909306b0a27c3ddbea08d70 100644 (file)
@@ -24,26 +24,26 @@ using namespace boost::spirit;
 
 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
@@ -55,15 +55,16 @@ struct crush_grammar : public grammar<crush_grammar>
 
     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;
@@ -93,6 +94,8 @@ struct crush_grammar : public grammar<crush_grammar>
                                     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 );
index b438c5d278161b9fa20cc0b6d7622c0dd2476188..5873aed694bf5a06a092102a2209c5ad71a9aff8 100644 (file)
@@ -1,5 +1,6 @@
 
 #include <linux/types.h>
+#include "hash.h"
 
 /*
  * Robert Jenkins' function for mixing 32-bit values
@@ -20,7 +21,7 @@
 
 #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;
@@ -31,7 +32,7 @@ __u32 crush_hash32(__u32 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;
@@ -42,7 +43,7 @@ __u32 crush_hash32_2(__u32 a, __u32 b)
        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;
@@ -55,7 +56,7 @@ __u32 crush_hash32_3(__u32 a, __u32 b, __u32 c)
        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;
@@ -69,7 +70,8 @@ __u32 crush_hash32_4(__u32 a, __u32 b, __u32 c, __u32 d)
        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;
@@ -84,3 +86,64 @@ __u32 crush_hash32_5(__u32 a, __u32 b, __u32 c, __u32 d, __u32 e)
        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";
+       }
+}
index 9ce89f85dc7d70342b44314164f924fd31a89901..ab7bb532d250eacb4d8b58ced9615fc84365e490 100644 (file)
@@ -1,12 +1,15 @@
 #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
index 54f3f402af60b4865e6c8b0d25b16efb6efc55bd..2523d448445c11e53c061fc1582842bdb08d9c25 100644 (file)
@@ -78,7 +78,7 @@ static int bucket_perm_choose(struct crush_bucket *bucket,
 
                /* 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 */
@@ -103,7 +103,7 @@ static int bucket_perm_choose(struct crush_bucket *bucket,
                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];
@@ -138,8 +138,8 @@ static int bucket_list_choose(struct crush_bucket_list *bucket,
        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",
@@ -198,7 +198,8 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket,
        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? */
@@ -224,7 +225,7 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket,
        __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) {
@@ -267,7 +268,8 @@ static int is_out(struct crush_map *map, __u32 *weight, int item, int x)
                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;
 }
index dd1cf9cdf569eaa5114f5298bc667ee5e70137fd..7fd99a838b5b0a79a4869ff58786fd67ec107eb8 100644 (file)
@@ -531,6 +531,9 @@ int decompile_crush(CrushWrapper &crush, ostream &out)
     }
     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);
index 776faa8b362fd85bd5ee9742445ab27ab5318ce3..f3e766ee7946f258c655904826563668baea65f7 100644 (file)
@@ -722,7 +722,7 @@ private:
       
     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 );
       }
@@ -734,7 +734,7 @@ private:
          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;