diff --git a/src/opr/Makefile.in b/src/opr/Makefile.in index 37b56640ae..095e691fcf 100644 --- a/src/opr/Makefile.in +++ b/src/opr/Makefile.in @@ -6,6 +6,7 @@ objects = assert.o casestrcpy.o rbtree.o all: $(TOP_INCDIR)/afs/opr.h \ $(TOP_INCDIR)/afs/opr_assert.h \ + $(TOP_INCDIR)/opr/jhash.h \ $(TOP_INCDIR)/opr/queue.h \ $(TOP_INCDIR)/opr/rbtree.h \ $(TOP_LIBDIR)/libopr.a @@ -24,6 +25,9 @@ $(TOP_INCDIR)/afs/opr.h: opr.h $(TOP_INCDIR)/afs/opr_assert.h: opr_assert.h $(INSTALL_DATA) opr_assert.h $@ +$(TOP_INCDIR)/opr/jhash.h: jhash.h + $(INSTALL_DATA) jhash.h $@ + $(TOP_INCDIR)/opr/queue.h: queue.h $(INSTALL_DATA) queue.h $@ diff --git a/src/opr/NTMakefile b/src/opr/NTMakefile index dbaf2f0743..8ef134c293 100644 --- a/src/opr/NTMakefile +++ b/src/opr/NTMakefile @@ -13,6 +13,7 @@ INCFILEDIR = $(DESTDIR)\include\afs INCFILES = \ $(INCFILEDIR)\opr.h \ $(INCFILEDIR)\opr_assert.h \ + $(DESTDIR)\include\opr\jhash.h \ $(DESTDIR)\include\opr\queue.h \ $(DESTDIR)\include\opr\rbtree.h diff --git a/src/opr/jhash.h b/src/opr/jhash.h new file mode 100644 index 0000000000..5e16311361 --- /dev/null +++ b/src/opr/jhash.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006 Bob Jenkins + * Copyright (c) 2011 Your File System Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This is an OPR version of Bob Jenkins' hash routines. His original copyright + * declaration reads: + * + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * You can use this free for any purpose. It's in the public domain. + * It has no warranty. + */ + +#ifndef OPENAFS_OPR_JHASH_H +#define OPENAFS_OPR_JHASH_H 1 + +#define opr_jhash_size(n) ((uint32_t)1<<(n)) +#define opr_jhash_mask(n) (opr_jhash_size(n)-1) +#define opr_jhash_rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +#define opr_jhash_mix(a,b,c) \ +{ \ + a -= c; a ^= opr_jhash_rot(c, 4); c += b; \ + b -= a; b ^= opr_jhash_rot(a, 6); a += c; \ + c -= b; c ^= opr_jhash_rot(b, 8); b += a; \ + a -= c; a ^= opr_jhash_rot(c,16); c += b; \ + b -= a; b ^= opr_jhash_rot(a,19); a += c; \ + c -= b; c ^= opr_jhash_rot(b, 4); b += a; \ +} + +#define opr_jhash_final(a,b,c) \ +{ \ + c ^= b; c -= opr_jhash_rot(b,14); \ + a ^= c; a -= opr_jhash_rot(c,11); \ + b ^= a; b -= opr_jhash_rot(a,25); \ + c ^= b; c -= opr_jhash_rot(b,16); \ + a ^= c; a -= opr_jhash_rot(c,4); \ + b ^= a; b -= opr_jhash_rot(a,14); \ + c ^= b; c -= opr_jhash_rot(b,24); \ +} + +static_inline uint32_t +opr_jhash(const uint32_t *k, size_t length, uint32_t initval) +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; + + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + opr_jhash_mix(a, b, c); + length -= 3; + k += 3; + } + + /* All the case statements fall through */ + switch(length) { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + opr_jhash_final(a, b, c); + case 0: /* case 0: nothing left to add */ + break; + } + + return c; +} + +/* Simplified version of the above function to hash just one int */ + +static_inline uint32_t +opr_jhash_int(uint32_t a, uint32_t initval) { + uint32_t b, c; + + a += 0xdeadbeef + 4 + initval; + b = c = 0xdeadbeef + 4 + initval; + opr_jhash_final(a, b, c); + + return c; +} + +#endif diff --git a/tests/TESTS b/tests/TESTS index 1cd3ac2184..217546b7b2 100644 --- a/tests/TESTS +++ b/tests/TESTS @@ -4,6 +4,7 @@ auth/keys auth/superuser auth/authcon cmd/command +opr/jhash opr/queues opr/rbtree ptserver/pt_util diff --git a/tests/opr/.gitignore b/tests/opr/.gitignore index ccae8353c2..e63b4b4bc6 100644 --- a/tests/opr/.gitignore +++ b/tests/opr/.gitignore @@ -2,4 +2,5 @@ # git ls-files -i --exclude-standard # to check that you haven't inadvertently ignored any tracked files. +/jhash-t /rbtree-t diff --git a/tests/opr/Makefile.in b/tests/opr/Makefile.in index 17d6f9f4ad..6ff8b2ee09 100644 --- a/tests/opr/Makefile.in +++ b/tests/opr/Makefile.in @@ -7,7 +7,7 @@ MODULE_CFLAGS = -I$(srcdir)/.. LIBS=../tap/libtap.a $(abs_top_builddir)/lib/libopr.a -tests = queues-t rbtree-t +tests = jhash-t queues-t rbtree-t all check test tests: $(tests) @@ -17,5 +17,8 @@ queues-t: queues-t.o rbtree-t: rbtree-t.o $(LIBS) $(AFS_LDRULE) rbtree-t.o ../tap/libtap.a $(LIBS) $(XLIBS) +jhash-t: jhash-t.o + $(AFS_LDRULE) jhash-t.o ../tap/libtap.a $(XLIBS) + clean distclean: $(RM) -f $(tests) *.o core diff --git a/tests/opr/jhash-t.c b/tests/opr/jhash-t.c new file mode 100644 index 0000000000..4fa518fa5b --- /dev/null +++ b/tests/opr/jhash-t.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Your File System Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include + +/* Bob Jenkins' lookup3.c comes with a load of self test functions, but + * unfortunately, they all use 'hashlittle' (his unaligned hash function). As + * we have only got 'hashword' (word aligned arrays) in OpenAFS, we need to roll + * our own tests. + */ + +int +main(int argc, char **argv) +{ + plan(8); + uint32_t test[] = {3526055646, 2064483663, 3234460805, 3963629775}; + + is_int(256, opr_jhash_size(8), "opr_jhash_size returns expected value"); + is_int(255, opr_jhash_mask(8), "opr_jhash_mask returns expected value"); + + is_int(0xdeadbeef, opr_jhash(test, 0, 0), "empty array hashes as expected"); + is_int(766530906, opr_jhash(test, 4, 0), "simple array works"); + is_int(3782684773, opr_jhash(test, 4, 1), "changing initval works"); + + test[2]++; + is_int(1977082159, opr_jhash(test, 4, 0), "modifying value works"); + + is_int(1100796964, opr_jhash(test, 1, 0), + "single value works through jhash"); + is_int(1100796964, opr_jhash_int(test[0], 0), + "single value works through jhash_int"); + + return 0; +}