shithub: gefs

Download patch

ref: 8c6bf5fb064673d45f16bd9b97ccb45a54983827
parent: 77d59f66059e6632fa5dec987b05fa52315325d1
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Apr 9 11:07:11 EDT 2023

hash: replace siphash with much faster metrohash

--- a/blk.c
+++ b/blk.c
@@ -366,7 +366,7 @@
 		return -1;
 	bh = UNPACK64(b->data);
 	/* the hash covers the log and offset */
-	if(bh != siphash(b->data+Loghashsz, Logspc-Loghashsz)){
+	if(bh != bufhash(b->data+Loghashsz, Logspc-Loghashsz)){
 		werrstr("corrupt log");
 		return -1;
 	}
@@ -800,7 +800,7 @@
 		packbp(b->buf+4, Ptrsz, &b->deadp);
 		break;
 	case Tlog:
-		h = siphash(b->data + Loghashsz, Logspc-Loghashsz);
+		h = bufhash(b->data + Loghashsz, Logspc-Loghashsz);
 		PACK64(b->data, h);
 		break;
 	case Tdat:
--- a/fns.h
+++ b/fns.h
@@ -56,6 +56,7 @@
 int	blkdealloc(vlong);
 ushort	blkfill(Blk*);
 uvlong	blkhash(Blk*);
+uvlong	bufhash(void*, usize);
 u32int	ihash(uvlong);
 void	finalize(Blk*);
 
@@ -65,7 +66,6 @@
 Tree*	opensnap(char*);
 
 void	closesnap(Tree*);
-uvlong	siphash(void*, usize);
 void	reamfs(char*);
 void	growfs(char*);
 int	loadarena(Arena*, Fshdr *fi, vlong);
--- a/hash.c
+++ b/hash.c
@@ -1,32 +1,28 @@
-/*
- Copyright (c) 2013  Marek Majkowski <marek@popcount.org>
+// metrohash64.cpp
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2015 J. Andrew Rogers
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
- Original location:
-    https://github.com/majek/csiphash/
-
- Solution inspired by code from:
-    Samuel Neves (supercop/crypto_auth/siphash24/little)
-    djb (supercop/crypto_auth/siphash24/little2)
-    Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
-*/
 #include <u.h>
 #include <libc.h>
 #include <fcall.h>
@@ -53,59 +49,98 @@
 	HALF_ROUND(v0,v1,v2,v3,13,16);		\
 	HALF_ROUND(v2,v1,v0,v3,17,21);
 
+#define rotate_right(v, k)\
+	((v >> k) | (v << (64 - k)))
+#define read_u64(ptr) \
+	(*(u64int*)ptr)
+#define read_u32(ptr) \
+	(*(u32int*)ptr)
+#define read_u16(ptr) \
+	(*(u16int*)ptr)
+#define read_u8(ptr) \
+	(*(u8int*)ptr)
 
-static u64int
-siphash24(const void *src, unsigned long src_sz, const char key[16]) {
-	const u64int *_key = (u64int *)key;
-	u64int k0 = _le64toh(_key[0]);
-	u64int k1 = _le64toh(_key[1]);
-	u64int b = (u64int)src_sz << 56;
-	const u64int *in = (u64int*)src;
+uvlong
+metrohash64_1(void * key, u64int len, u32int seed)
+{
+	static const u64int k0 = 0xC83A91E1;
+	static const u64int k1 = 0x8648DBDB;
+	static const u64int k2 = 0x7BDEC03B;
+	static const u64int k3 = 0x2F5870A5;
 
-	u64int v0 = k0 ^ 0x736f6d6570736575ULL;
-	u64int v1 = k1 ^ 0x646f72616e646f6dULL;
-	u64int v2 = k0 ^ 0x6c7967656e657261ULL;
-	u64int v3 = k1 ^ 0x7465646279746573ULL;
+	const uchar * ptr = key;
+	const uchar * const end = ptr + len;
+	
+	u64int hash = ((((u64int) seed) + k2) * k0) + len;
+	
+	if(len >= 32){
+		u64int v[4];
+		v[0] = hash;
+		v[1] = hash;
+		v[2] = hash;
+		v[3] = hash;
+		
+		do{
+			v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
+			v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
+			v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
+			v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
+		}
+		while(ptr <= (end - 32));
 
-	while (src_sz >= 8) {
-		u64int mi = _le64toh(*in);
-		in += 1; src_sz -= 8;
-		v3 ^= mi;
-		DOUBLE_ROUND(v0,v1,v2,v3);
-		v0 ^= mi;
+		v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 33) * k1;
+		v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 33) * k0;
+		v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 33) * k1;
+		v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 33) * k0;
+		hash += v[0] ^ v[1];
 	}
-
-	u64int t = 0; u8int *pt = (u8int *)&t; u8int *m = (u8int *)in;
-	switch (src_sz) {
-	case 7: pt[6] = m[6];
-	case 6: pt[5] = m[5];
-	case 5: pt[4] = m[4];
-	case 4: *((u32int*)&pt[0]) = *((u32int*)&m[0]); break;
-	case 3: pt[2] = m[2];
-	case 2: pt[1] = m[1];
-	case 1: pt[0] = m[0];
+	
+	if((end - ptr) >= 16){
+		u64int v0 = hash + (read_u64(ptr) * k0); ptr += 8; v0 = rotate_right(v0,33) * k1;
+		u64int v1 = hash + (read_u64(ptr) * k1); ptr += 8; v1 = rotate_right(v1,33) * k2;
+		v0 ^= rotate_right(v0 * k0, 35) + v1;
+		v1 ^= rotate_right(v1 * k3, 35) + v0;
+		hash += v1;
 	}
-	b |= _le64toh(t);
+	
+	if((end - ptr) >= 8){
+		hash += read_u64(ptr) * k3; ptr += 8;
+		hash ^= rotate_right(hash, 33) * k1;
+		
+	}
+	
+	if((end - ptr) >= 4){
+		hash += read_u32(ptr) * k3; ptr += 4;
+		hash ^= rotate_right(hash, 15) * k1;
+	}
+	
+	if((end - ptr) >= 2){
+		hash += read_u16(ptr) * k3; ptr += 2;
+		hash ^= rotate_right(hash, 13) * k1;
+	}
+	
+	if((end - ptr) >= 1){
+		hash += read_u8 (ptr) * k3;
+		hash ^= rotate_right(hash, 25) * k1;
+	}
+	
+	hash ^= rotate_right(hash, 33);
+	hash *= k0;
+	hash ^= rotate_right(hash, 33);
 
-	v3 ^= b;
-	DOUBLE_ROUND(v0,v1,v2,v3);
-	v0 ^= b; v2 ^= 0xff;
-	DOUBLE_ROUND(v0,v1,v2,v3);
-	DOUBLE_ROUND(v0,v1,v2,v3);
-	return (v0 ^ v1) ^ (v2 ^ v3);
+	return hash;
 }
 
 uvlong
-siphash(void *src, usize len)
+bufhash(void *src, usize len)
 {
-	static char key[16] = "gefsgefsgefsgefs";
-	return siphash24(src, len, key);
+	return metrohash64_1(src, len, 0x6765);
 }
 
 uvlong
 blkhash(Blk *b)
 {
-	return siphash(b->buf, Blksz);
+	return metrohash64_1(b->buf, Blksz, 0x6765);
 }
 
 u32int
--- a/pack.c
+++ b/pack.c
@@ -522,7 +522,7 @@
 packarena(char *p, int sz, Arena *a, Fshdr *fi)
 {
 	assert(sz == Blksz);
-	memcpy(p, "gefs0002", 8);	p += 8;
+	memcpy(p, "gefs0003", 8);	p += 8;
 	PACK32(p, Blksz);		p += 4;
 	PACK32(p, Bufspc);		p += 4;
 	PACK32(p, fi->snap.ht);		p += 4;
@@ -545,7 +545,7 @@
 	assert(sz == Blksz);
 	memset(a, 0, sizeof(*a));
 	memset(fi, 0, sizeof(*fi));
-	if(memcmp(p, "gefs0002", 8) != 0){
+	if(memcmp(p, "gefs0003", 8) != 0){
 		werrstr("wrong block header %.8s\n", p);
 		return nil;
 	}