1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +03:00

Add general purpose hasing functions to pgbench.

Hashing function is useful for simulating real-world workload in test like
WEB workload, as an example - YCSB benchmarks.

Author: Ildar Musin with minor editorization by me
Reviewed by: Fabien Coelho, me
Discussion: https://www.postgresql.org/message-id/flat/0e8bd39e-dfcd-2879-f88f-272799ad7ef2@postgrespro.ru
This commit is contained in:
Teodor Sigaev
2018-03-21 18:01:23 +03:00
parent 8bb3c7d347
commit e51a04840a
5 changed files with 237 additions and 32 deletions

View File

@ -16,6 +16,10 @@
#include "pgbench.h"
#define PGBENCH_NARGS_VARIABLE (-1)
#define PGBENCH_NARGS_CASE (-2)
#define PGBENCH_NARGS_HASH (-3)
PgBenchExpr *expr_parse_result;
static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
@ -226,9 +230,13 @@ make_uop(yyscan_t yyscanner, const char *operator, PgBenchExpr *expr)
/*
* List of available functions:
* - fname: function name, "!..." for special internal functions
* - nargs: number of arguments
* -1 is a special value for least & greatest meaning #args >= 1
* -2 is for the "CASE WHEN ..." function, which has #args >= 3 and odd
* - nargs: number of arguments. Special cases:
* - PGBENCH_NARGS_VARIABLE is a special value for least & greatest
* meaning #args >= 1;
* - PGBENCH_NARGS_CASE is for the "CASE WHEN ..." function, which
* has #args >= 3 and odd;
* - PGBENCH_NARGS_HASH is for hash functions, which have one required
* and one optional argument;
* - tag: function identifier from PgBenchFunction enum
*/
static const struct
@ -259,10 +267,10 @@ static const struct
"abs", 1, PGBENCH_ABS
},
{
"least", -1, PGBENCH_LEAST
"least", PGBENCH_NARGS_VARIABLE, PGBENCH_LEAST
},
{
"greatest", -1, PGBENCH_GREATEST
"greatest", PGBENCH_NARGS_VARIABLE, PGBENCH_GREATEST
},
{
"debug", 1, PGBENCH_DEBUG
@ -347,7 +355,25 @@ static const struct
},
/* "case when ... then ... else ... end" construction */
{
"!case_end", -2, PGBENCH_CASE
"!case_end", PGBENCH_NARGS_CASE, PGBENCH_CASE
},
{
"hash", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
},
{
"hash_murmur2", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
},
{
"hash_fnv1a", PGBENCH_NARGS_HASH, PGBENCH_HASH_FNV1A
},
{
"hash", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
},
{
"hash_murmur2", PGBENCH_NARGS_HASH, PGBENCH_HASH_MURMUR2
},
{
"hash_fnv1a", PGBENCH_NARGS_HASH, PGBENCH_HASH_FNV1A
},
/* keep as last array element */
{
@ -423,29 +449,51 @@ elist_length(PgBenchExprList *list)
static PgBenchExpr *
make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
{
int len = elist_length(args);
PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
Assert(fnumber >= 0);
if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
PGBENCH_FUNCTIONS[fnumber].nargs != elist_length(args))
expr_yyerror_more(yyscanner, "unexpected number of arguments",
PGBENCH_FUNCTIONS[fnumber].fname);
/* check at least one arg for least & greatest */
if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
elist_length(args) == 0)
expr_yyerror_more(yyscanner, "at least one argument expected",
PGBENCH_FUNCTIONS[fnumber].fname);
/* special case: case (when ... then ...)+ (else ...)? end */
if (PGBENCH_FUNCTIONS[fnumber].nargs == -2)
/* validate arguments number including few special cases */
switch (PGBENCH_FUNCTIONS[fnumber].nargs)
{
int len = elist_length(args);
/* check at least one arg for least & greatest */
case PGBENCH_NARGS_VARIABLE:
if (len == 0)
expr_yyerror_more(yyscanner, "at least one argument expected",
PGBENCH_FUNCTIONS[fnumber].fname);
break;
/* 'else' branch is always present, but could be a NULL-constant */
if (len < 3 || len % 2 != 1)
expr_yyerror_more(yyscanner, "odd and >= 3 number of arguments expected",
"case control structure");
/* case (when ... then ...)+ (else ...)? end */
case PGBENCH_NARGS_CASE:
/* 'else' branch is always present, but could be a NULL-constant */
if (len < 3 || len % 2 != 1)
expr_yyerror_more(yyscanner,
"odd and >= 3 number of arguments expected",
"case control structure");
break;
/* hash functions with optional seed argument */
case PGBENCH_NARGS_HASH:
if (len > 2)
expr_yyerror_more(yyscanner, "unexpected number of arguments",
PGBENCH_FUNCTIONS[fnumber].fname);
if (len == 1)
{
PgBenchExpr *var = make_variable("default_seed");
args = make_elist(var, args);
}
break;
/* common case: positive arguments number */
default:
Assert(PGBENCH_FUNCTIONS[fnumber].nargs >= 0);
if (PGBENCH_FUNCTIONS[fnumber].nargs != len)
expr_yyerror_more(yyscanner, "unexpected number of arguments",
PGBENCH_FUNCTIONS[fnumber].fname);
}
expr->etype = ENODE_FUNCTION;