From 1ffdf516da8b84e4d58e451d2715d689f0f2141a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 6 Nov 2009 16:43:47 -0800 Subject: [PATCH] osd: use stronger hash function for mapping objects -> pgs The old hash (from linux dcache) was very weak, such that least sig bits may not change and you could get lots of consecutive objects on the same osds (because lsbits of the pg weren't changing). This is Robert Jenkin's hash and is quite strong. Public domain. Rev osd disk format, protocol, since we're totally changing object placement here. --- src/TODO | 2 + src/include/ceph_fs.cc | 93 +++++++++++++++++++++++++++++++----------- src/include/ceph_fs.h | 2 +- src/osd/osd_types.h | 2 +- 4 files changed, 74 insertions(+), 25 deletions(-) diff --git a/src/TODO b/src/TODO index 0a64e7c255ed5..b98dcd0b3beed 100644 --- a/src/TODO +++ b/src/TODO @@ -63,6 +63,8 @@ v0.18 pending wire, disk format changes bugs +- kclient cap reconnect on mds restart +- zeros in pg log, followed by valid data. - mislinked directory? - premature filejournal trimming? - weird osd_lock contention during osd restart? diff --git a/src/include/ceph_fs.cc b/src/include/ceph_fs.cc index a950b40835776..b3ecf1b075213 100644 --- a/src/include/ceph_fs.cc +++ b/src/include/ceph_fs.cc @@ -73,32 +73,79 @@ int ceph_caps_for_mode(int mode) return 0; } -/* Name hashing routines. Initial hash value */ -/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */ -#define ceph_init_name_hash() 0 - -/* partial hash update function. Assume roughly 4 bits per character */ -static unsigned long ceph_partial_name_hash(unsigned long c, - unsigned long prevhash) -{ - return (prevhash + (c << 4) + (c >> 4)) * 11; -} - /* - * Finally: cut down the number of bits to a int value (and try to avoid - * losing bits) + * Robert Jenkin's hash function. + * http://burtleburtle.net/bob/hash/evahash.html + * This is in the public domain. */ -static unsigned long ceph_end_name_hash(unsigned long hash) -{ - return hash & 0xffffffff; -} +#define mix(a, b, c) \ + do { \ + a = a - b; a = a - c; a = a ^ (c >> 13); \ + b = b - c; b = b - a; b = b ^ (a << 8); \ + c = c - a; c = c - b; c = c ^ (b >> 13); \ + a = a - b; a = a - c; a = a ^ (c >> 12); \ + b = b - c; b = b - a; b = b ^ (a << 16); \ + c = c - a; c = c - b; c = c ^ (b >> 5); \ + a = a - b; a = a - c; a = a ^ (c >> 3); \ + b = b - c; b = b - a; b = b ^ (a << 10); \ + c = c - a; c = c - b; c = c ^ (b >> 15); \ + } while (0) -/* Compute the hash for a name string. */ -unsigned int ceph_full_name_hash(const char *name, unsigned int len) +unsigned int ceph_full_name_hash(const char *str, unsigned int length) { - unsigned long hash = ceph_init_name_hash(); - while (len--) - hash = ceph_partial_name_hash(*name++, hash); - return ceph_end_name_hash(hash); + const unsigned char *k = (const unsigned char *)str; + __u32 a, b, c; /* the internal state */ + __u32 len; /* how many key bytes still need mixing */ + + /* Set up the internal state */ + len = length; + a = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + b = a; + c = 0; /* variable initialization of internal state */ + + /* handle most of the key */ + while (len >= 12) { + a = a + (k[0] + ((__u32)k[1] << 8) + ((__u32)k[2] << 16) + + ((__u32)k[3] << 24)); + b = b + (k[4] + ((__u32)k[5] << 8) + ((__u32)k[6] << 16) + + ((__u32)k[7] << 24)); + c = c + (k[8] + ((__u32)k[9] << 8) + ((__u32)k[10] << 16) + + ((__u32)k[11] << 24)); + mix(a, b, c); + k = k + 12; + len = len - 12; + } + + /* handle the last 11 bytes */ + c = c + length; + switch (len) { /* all the case statements fall through */ + case 11: + c = c + ((__u32)k[10] << 24); + case 10: + c = c + ((__u32)k[9] << 16); + case 9: + c = c + ((__u32)k[8] << 8); + /* the first byte of c is reserved for the length */ + case 8: + b = b + ((__u32)k[7] << 24); + case 7: + b = b + ((__u32)k[6] << 16); + case 6: + b = b + ((__u32)k[5] << 8); + case 5: + b = b + k[4]; + case 4: + a = a + ((__u32)k[3] << 24); + case 3: + a = a + ((__u32)k[2] << 16); + case 2: + a = a + ((__u32)k[1] << 8); + case 1: + a = a + k[0]; + /* case 0: nothing left to add */ + } + mix(a, b, c); + + return c; } diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index ae523828c538c..25fc537f4140d 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -38,7 +38,7 @@ #define CEPH_OSD_PROTOCOL 7 /* cluster internal */ #define CEPH_MDS_PROTOCOL 9 /* cluster internal */ #define CEPH_MON_PROTOCOL 5 /* cluster internal */ -#define CEPH_OSDC_PROTOCOL 21 /* server/client */ +#define CEPH_OSDC_PROTOCOL 22 /* server/client */ #define CEPH_MDSC_PROTOCOL 29 /* server/client */ #define CEPH_MONC_PROTOCOL 15 /* server/client */ diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index a515b426a4880..a8d38bce5ebb2 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -24,7 +24,7 @@ -#define CEPH_OSD_ONDISK_MAGIC "ceph osd volume v025" +#define CEPH_OSD_ONDISK_MAGIC "ceph osd volume v026" #define CEPH_OSD_NEARFULL_RATIO .8 #define CEPH_OSD_FULL_RATIO .95 -- 2.39.5