ceph: make CRUSH hash function a bucket property
Make the integer hash function a property of the bucket it is used on. This allows us to gracefully add support for new hash functions without starting from scatch. Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
1654dd0cf5
commit
fb690390e3
@ -102,7 +102,8 @@ extern const char *crush_bucket_alg_name(int alg);
|
|||||||
struct crush_bucket {
|
struct crush_bucket {
|
||||||
__s32 id; /* this'll be negative */
|
__s32 id; /* this'll be negative */
|
||||||
__u16 type; /* non-zero; type=0 is reserved for devices */
|
__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 weight; /* 16-bit fixed point */
|
||||||
__u32 size; /* num items */
|
__u32 size; /* num items */
|
||||||
__s32 *items;
|
__s32 *items;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Robert Jenkins' function for mixing 32-bit values
|
* Robert Jenkins' function for mixing 32-bit values
|
||||||
@ -20,7 +21,7 @@
|
|||||||
|
|
||||||
#define crush_hash_seed 1315423911
|
#define crush_hash_seed 1315423911
|
||||||
|
|
||||||
__u32 crush_hash32(__u32 a)
|
static __u32 crush_hash32_rjenkins1(__u32 a)
|
||||||
{
|
{
|
||||||
__u32 hash = crush_hash_seed ^ a;
|
__u32 hash = crush_hash_seed ^ a;
|
||||||
__u32 b = a;
|
__u32 b = a;
|
||||||
@ -31,7 +32,7 @@ __u32 crush_hash32(__u32 a)
|
|||||||
return hash;
|
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 hash = crush_hash_seed ^ a ^ b;
|
||||||
__u32 x = 231232;
|
__u32 x = 231232;
|
||||||
@ -42,7 +43,7 @@ __u32 crush_hash32_2(__u32 a, __u32 b)
|
|||||||
return hash;
|
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 hash = crush_hash_seed ^ a ^ b ^ c;
|
||||||
__u32 x = 231232;
|
__u32 x = 231232;
|
||||||
@ -55,7 +56,7 @@ __u32 crush_hash32_3(__u32 a, __u32 b, __u32 c)
|
|||||||
return hash;
|
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 hash = crush_hash_seed ^ a ^ b ^ c ^ d;
|
||||||
__u32 x = 231232;
|
__u32 x = 231232;
|
||||||
@ -69,7 +70,8 @@ __u32 crush_hash32_4(__u32 a, __u32 b, __u32 c, __u32 d)
|
|||||||
return hash;
|
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 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
|
||||||
__u32 x = 231232;
|
__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);
|
crush_hashmix(y, e, hash);
|
||||||
return 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
#ifndef _CRUSH_HASH_H
|
#ifndef _CRUSH_HASH_H
|
||||||
#define _CRUSH_HASH_H
|
#define _CRUSH_HASH_H
|
||||||
|
|
||||||
extern __u32 crush_hash32(__u32 a);
|
#define CRUSH_HASH_RJENKINS1 0
|
||||||
extern __u32 crush_hash32_2(__u32 a, __u32 b);
|
|
||||||
extern __u32 crush_hash32_3(__u32 a, __u32 b, __u32 c);
|
#define CRUSH_HASH_DEFAULT CRUSH_HASH_RJENKINS1
|
||||||
extern __u32 crush_hash32_4(__u32 a, __u32 b, __u32 c,
|
|
||||||
__u32 d);
|
extern const char *crush_hash_name(int type);
|
||||||
extern __u32 crush_hash32_5(__u32 a, __u32 b, __u32 c,
|
|
||||||
__u32 d, __u32 e);
|
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
|
#endif
|
||||||
|
@ -78,7 +78,7 @@ static int bucket_perm_choose(struct crush_bucket *bucket,
|
|||||||
|
|
||||||
/* optimize common r=0 case */
|
/* optimize common r=0 case */
|
||||||
if (pr == 0) {
|
if (pr == 0) {
|
||||||
s = crush_hash32_3(x, bucket->id, 0) %
|
s = crush_hash32_3(bucket->hash, x, bucket->id, 0) %
|
||||||
bucket->size;
|
bucket->size;
|
||||||
bucket->perm[0] = s;
|
bucket->perm[0] = s;
|
||||||
bucket->perm_n = 0xffff; /* magic value, see below */
|
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;
|
unsigned p = bucket->perm_n;
|
||||||
/* no point in swapping the final entry */
|
/* no point in swapping the final entry */
|
||||||
if (p < bucket->size - 1) {
|
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);
|
(bucket->size - p);
|
||||||
if (i) {
|
if (i) {
|
||||||
unsigned t = bucket->perm[p + i];
|
unsigned t = bucket->perm[p + i];
|
||||||
@ -138,8 +138,8 @@ static int bucket_list_choose(struct crush_bucket_list *bucket,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = bucket->h.size-1; i >= 0; i--) {
|
for (i = bucket->h.size-1; i >= 0; i--) {
|
||||||
__u64 w = crush_hash32_4(x, bucket->h.items[i], r,
|
__u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i],
|
||||||
bucket->h.id);
|
r, bucket->h.id);
|
||||||
w &= 0xffff;
|
w &= 0xffff;
|
||||||
dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
|
dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
|
||||||
"sw %x rand %llx",
|
"sw %x rand %llx",
|
||||||
@ -198,7 +198,8 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket,
|
|||||||
while (!terminal(n)) {
|
while (!terminal(n)) {
|
||||||
/* pick point in [0, w) */
|
/* pick point in [0, w) */
|
||||||
w = bucket->node_weights[n];
|
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;
|
t = t >> 32;
|
||||||
|
|
||||||
/* descend to the left or right? */
|
/* descend to the left or right? */
|
||||||
@ -224,7 +225,7 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket,
|
|||||||
__u64 draw;
|
__u64 draw;
|
||||||
|
|
||||||
for (i = 0; i < bucket->h.size; i++) {
|
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 &= 0xffff;
|
||||||
draw *= bucket->straws[i];
|
draw *= bucket->straws[i];
|
||||||
if (i == 0 || draw > high_draw) {
|
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;
|
return 0;
|
||||||
if (weight[item] == 0)
|
if (weight[item] == 0)
|
||||||
return 1;
|
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 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
|
|||||||
ceph_decode_need(p, end, 4*sizeof(u32), bad);
|
ceph_decode_need(p, end, 4*sizeof(u32), bad);
|
||||||
b->id = ceph_decode_32(p);
|
b->id = ceph_decode_32(p);
|
||||||
b->type = ceph_decode_16(p);
|
b->type = ceph_decode_16(p);
|
||||||
b->alg = ceph_decode_16(p);
|
b->alg = ceph_decode_8(p);
|
||||||
|
b->hash = ceph_decode_8(p);
|
||||||
b->weight = ceph_decode_32(p);
|
b->weight = ceph_decode_32(p);
|
||||||
b->size = ceph_decode_32(p);
|
b->size = ceph_decode_32(p);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user