Skip to content

Commit 1bd7458

Browse files
committed
Use fast-hash for Query ID jumbling
1 parent 4abf411 commit 1bd7458

2 files changed

Lines changed: 48 additions & 59 deletions

File tree

src/backend/nodes/queryjumblefuncs.c

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
#include "access/transam.h"
4141
#include "catalog/pg_proc.h"
42-
#include "common/hashfn.h"
42+
#include "common/hashfn_unstable.h"
4343
#include "common/int.h"
4444
#include "miscadmin.h"
4545
#include "nodes/nodeFuncs.h"
@@ -48,8 +48,6 @@
4848
#include "parser/scanner.h"
4949
#include "parser/scansup.h"
5050

51-
#define JUMBLE_SIZE 1024 /* query serialization buffer size */
52-
5351
/* GUC parameters */
5452
int compute_query_id = COMPUTE_QUERY_ID_AUTO;
5553

@@ -186,8 +184,7 @@ InitJumble(void)
186184
jstate = palloc_object(JumbleState);
187185

188186
/* Set up workspace for query jumbling */
189-
jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
190-
jstate->jumble_len = 0;
187+
fasthash_init(&jstate->jumble, 0);
191188
jstate->clocations_buf_size = 32;
192189
jstate->clocations = (LocationLen *) palloc(jstate->clocations_buf_size *
193190
sizeof(LocationLen));
@@ -221,74 +218,40 @@ DoJumble(JumbleState *jstate, Node *node)
221218
if (jstate->has_squashed_lists)
222219
jstate->highest_extern_param_id = 0;
223220

224-
/* Process the jumble buffer and produce the hash value */
225-
return DatumGetInt64(hash_any_extended(jstate->jumble,
226-
jstate->jumble_len,
227-
0));
221+
/* Produce the final hash value (lengths are folded in by AppendJumble) */
222+
return (int64) fasthash_final64(&jstate->jumble, 0);
228223
}
229224

230225
/*
231-
* AppendJumbleInternal: Internal function for appending to the jumble buffer
226+
* AppendJumbleInternal: Internal function for appending to the jumble state
227+
*
228+
* Accumulates the given value into the streaming fasthash state, processing
229+
* it in 8-byte chunks.
232230
*
233231
* Note: Callers must ensure that size > 0.
234232
*/
235233
static pg_attribute_always_inline void
236234
AppendJumbleInternal(JumbleState *jstate, const unsigned char *item,
237235
Size size)
238236
{
239-
unsigned char *jumble = jstate->jumble;
240-
Size jumble_len = jstate->jumble_len;
237+
Size orig_size PG_USED_FOR_ASSERTS_ONLY = size;
241238

242239
/* Ensure the caller didn't mess up */
243240
Assert(size > 0);
244241

245-
/*
246-
* Fast path for when there's enough space left in the buffer. This is
247-
* worthwhile as means the memcpy can be inlined into very efficient code
248-
* when 'size' is a compile-time constant.
249-
*/
250-
if (likely(size <= JUMBLE_SIZE - jumble_len))
242+
while (size >= FH_SIZEOF_ACCUM)
251243
{
252-
memcpy(jumble + jumble_len, item, size);
253-
jstate->jumble_len += size;
254-
255-
#ifdef USE_ASSERT_CHECKING
256-
jstate->total_jumble_len += size;
257-
#endif
258-
259-
return;
244+
fasthash_accum(&jstate->jumble, (const char *) item, FH_SIZEOF_ACCUM);
245+
item += FH_SIZEOF_ACCUM;
246+
size -= FH_SIZEOF_ACCUM;
260247
}
261248

262-
/*
263-
* Whenever the jumble buffer is full, we hash the current contents and
264-
* reset the buffer to contain just that hash value, thus relying on the
265-
* hash to summarize everything so far.
266-
*/
267-
do
268-
{
269-
Size part_size;
270-
271-
if (unlikely(jumble_len >= JUMBLE_SIZE))
272-
{
273-
int64 start_hash;
274-
275-
start_hash = DatumGetInt64(hash_any_extended(jumble,
276-
JUMBLE_SIZE, 0));
277-
memcpy(jumble, &start_hash, sizeof(start_hash));
278-
jumble_len = sizeof(start_hash);
279-
}
280-
part_size = Min(size, JUMBLE_SIZE - jumble_len);
281-
memcpy(jumble + jumble_len, item, part_size);
282-
jumble_len += part_size;
283-
item += part_size;
284-
size -= part_size;
249+
if (size > 0)
250+
fasthash_accum(&jstate->jumble, (const char *) item, size);
285251

286252
#ifdef USE_ASSERT_CHECKING
287-
jstate->total_jumble_len += part_size;
253+
jstate->total_jumble_len += orig_size;
288254
#endif
289-
} while (size > 0);
290-
291-
jstate->jumble_len = jumble_len;
292255
}
293256

294257
/*
@@ -302,6 +265,12 @@ AppendJumble(JumbleState *jstate, const unsigned char *value, Size size)
302265
FlushPendingNulls(jstate);
303266

304267
AppendJumbleInternal(jstate, value, size);
268+
269+
/*
270+
* Fold in the length so variable-length values are self-delimiting, which
271+
* lets DoJumble finalize with a zero tweak (see hashfn_unstable.h).
272+
*/
273+
fasthash_accum(&jstate->jumble, (const char *) &size, sizeof(size));
305274
}
306275

307276
/*
@@ -369,6 +338,28 @@ AppendJumble64(JumbleState *jstate, const unsigned char *value)
369338
AppendJumbleInternal(jstate, value, 8);
370339
}
371340

341+
/*
342+
* AppendJumbleString
343+
* Add the given NUL-terminated string to the jumble state.
344+
*
345+
* Length is computed on the fly while hashing, avoiding a separate strlen.
346+
*/
347+
static pg_noinline void
348+
AppendJumbleString(JumbleState *jstate, const char *str)
349+
{
350+
Size size;
351+
352+
if (jstate->pending_nulls > 0)
353+
FlushPendingNulls(jstate);
354+
355+
size = fasthash_accum_cstring(&jstate->jumble, str);
356+
fasthash_accum(&jstate->jumble, (const char *) &size, sizeof(size));
357+
358+
#ifdef USE_ASSERT_CHECKING
359+
jstate->total_jumble_len += size;
360+
#endif
361+
}
362+
372363
/*
373364
* FlushPendingNulls
374365
* Incorporate the pending_nulls value into the jumble buffer.
@@ -549,7 +540,7 @@ do { \
549540
#define JUMBLE_STRING(str) \
550541
do { \
551542
if (expr->str) \
552-
AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
543+
AppendJumbleString(jstate, expr->str); \
553544
else \
554545
AppendJumbleNull(jstate); \
555546
} while(0)

src/include/nodes/queryjumble.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef QUERYJUMBLE_H
1515
#define QUERYJUMBLE_H
1616

17+
#include "common/hashfn_unstable.h"
1718
#include "nodes/parsenodes.h"
1819

1920
/*
@@ -37,11 +38,8 @@ typedef struct LocationLen
3738
*/
3839
typedef struct JumbleState
3940
{
40-
/* Jumble of current query tree */
41-
unsigned char *jumble;
42-
43-
/* Number of bytes used in jumble[] */
44-
Size jumble_len;
41+
/* Streaming hash state for the current query jumble */
42+
fasthash_state jumble;
4543

4644
/* Array of locations of constants that should be removed */
4745
LocationLen *clocations;

0 commit comments

Comments
 (0)