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"
4848#include "parser/scanner.h"
4949#include "parser/scansup.h"
5050
51- #define JUMBLE_SIZE 1024 /* query serialization buffer size */
52-
5351/* GUC parameters */
5452int 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 */
235233static pg_attribute_always_inline void
236234AppendJumbleInternal (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 ) \
550541do { \
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)
0 commit comments