pgbench_hash_v4.patch

text/plain

Filename: pgbench_hash_v4.patch
Type: text/plain
Part: 0
Message: Re: General purpose hashing func in pgbench

Patch

Format: unified
Series: patch v4
File+
src/bin/pgbench/exprparse.y 18 0
src/bin/pgbench/pgbench.c 86 0
src/bin/pgbench/pgbench.h 3 1
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index e23ca51..847b011 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -349,6 +349,15 @@ static const struct
 	{
 		"!case_end", -2, PGBENCH_CASE
 	},
+	{
+		"hash", -3, PGBENCH_HASH_MURMUR2
+	},
+	{
+		"hash_murmur2", -3, PGBENCH_HASH_MURMUR2
+	},
+	{
+		"hash_fnv1a", -3, PGBENCH_HASH_FNV1A
+	},
 	/* keep as last array element */
 	{
 		NULL, 0, 0
@@ -447,6 +456,15 @@ make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
 			expr_yyerror_more(yyscanner, "odd and >= 3 number of arguments expected",
 							  "case control structure");
 	}
+	/* special case: hash functions with optional arguments */
+	if (PGBENCH_FUNCTIONS[fnumber].nargs == -3)
+	{
+		int len = elist_length(args);
+
+		if (len < 1 || len > 2)
+			expr_yyerror_more(yyscanner, "unexpected number of arguments",
+							  PGBENCH_FUNCTIONS[fnumber].fname);
+	}
 
 	expr->etype = ENODE_FUNCTION;
 	expr->u.function.function = PGBENCH_FUNCTIONS[fnumber].tag;
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 31ea6ca..6bf94cc 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -61,6 +61,14 @@
 #define ERRCODE_UNDEFINED_TABLE  "42P01"
 
 /*
+ * Hashing constants
+ */
+#define FNV_PRIME 0x100000001b3
+#define FNV_OFFSET_BASIS 0xcbf29ce484222325
+#define MM2_MUL 0xc6a4a7935bd1e995
+#define MM2_ROT 47
+
+/*
  * Multi-platform pthread implementations
  */
 
@@ -439,6 +447,8 @@ static int	num_scripts;		/* number of scripts in sql_script[] */
 static int	num_commands = 0;	/* total number of Command structs */
 static int64 total_weight = 0;
 
+static int hash_seed;			/* default seed used in hash functions */
+
 static int	debug = 0;			/* debug flag */
 
 /* Builtin test scripts */
@@ -915,6 +925,51 @@ getZipfianRand(TState *thread, int64 min, int64 max, double s)
 }
 
 /*
+ * FNV-1a hash function
+ */
+static int64
+getHashFnv1a(int64 val, uint64 seed)
+{
+	int64	result;
+	int		i;
+
+	result = FNV_OFFSET_BASIS ^ seed;
+	for (i = 0; i < 8; ++i)
+	{
+		int32 octet = val & 0xff;
+
+		val = val >> 8;
+		result = result ^ octet;
+		result = result * FNV_PRIME;
+	}
+
+	return result;
+}
+
+/*
+ * Murmur2 hash function
+ */
+static int64
+getHashMurmur2(int64 val, uint64 seed)
+{
+	uint64	result = seed ^ (sizeof(int64) * MM2_MUL);
+	uint64	k = (uint64) val;
+
+	k *= MM2_MUL;
+	k ^= k >> MM2_ROT;
+	k *= MM2_MUL;
+
+	result ^= k;
+	result *= MM2_MUL;
+
+	result ^= result >> MM2_ROT;
+	result *= MM2_MUL;
+	result ^= result >> MM2_ROT;
+
+	return (int64) result;
+}
+
+/*
  * Initialize the given SimpleStats struct to all zeroes
  */
 static void
@@ -2209,6 +2264,34 @@ evalStandardFunc(
 				return true;
 			}
 
+			/* hashing */
+		case PGBENCH_HASH_FNV1A:
+		case PGBENCH_HASH_MURMUR2:
+			{
+				int64	val;
+				int64	seed;
+				int64	result;
+
+				Assert(nargs >= 1);
+
+				if (!coerceToInt(&vargs[0], &val))
+					return false;
+
+				/* read optional seed value */
+				if (nargs > 1)
+				{
+					if (!coerceToInt(&vargs[1], &seed))
+						return false;
+				}
+				else
+					seed = hash_seed;
+
+				result = (func == PGBENCH_HASH_FNV1A) ?
+					getHashFnv1a(val, seed) : getHashMurmur2(val, seed);
+				setIntValue(retval, result);
+				return true;
+			}
+
 		default:
 			/* cannot get here */
 			Assert(0);
@@ -5054,6 +5137,9 @@ main(int argc, char **argv)
 	INSTR_TIME_SET_CURRENT(start_time);
 	srandom((unsigned int) INSTR_TIME_GET_MICROSEC(start_time));
 
+	/* set default seed for hash functions */
+	hash_seed = random();
+
 	/* set up thread data structures */
 	threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
 	nclients_dealt = 0;
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index 0705ccd..6983865 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -97,7 +97,9 @@ typedef enum PgBenchFunction
 	PGBENCH_LE,
 	PGBENCH_LT,
 	PGBENCH_IS,
-	PGBENCH_CASE
+	PGBENCH_CASE,
+	PGBENCH_HASH_FNV1A,
+	PGBENCH_HASH_MURMUR2
 } PgBenchFunction;
 
 typedef struct PgBenchExpr PgBenchExpr;