From d0dead5dedc0f91d7279d351a6432e2592f8d578 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas.vondra@postgresql.org>
Date: Sat, 11 Feb 2023 23:44:21 +0100
Subject: [PATCH 6/6] PoC caching hash values in BRIN bloom

Cache of hash values initialized when processing the first page range.
The cache is not
---
 src/backend/access/brin/brin_bloom.c | 59 ++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index c2939ac809..b57db6be14 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -129,6 +129,7 @@
 #include "utils/builtins.h"
 #include "utils/datum.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
@@ -260,6 +261,8 @@ typedef struct BloomFilter
 	char		data[FLEXIBLE_ARRAY_MEMBER];
 } BloomFilter;
 
+static uint64 *cache_h1 = NULL;
+static uint64 *cache_h2 = NULL;
 
 /*
  * bloom_init
@@ -405,6 +408,32 @@ bloom_contains_value(BloomFilter *filter, uint32 value)
 	return true;
 }
 
+/*
+ * bloom_contains_value
+ * 		Check if the bloom filter contains a particular value.
+ */
+static bool
+bloom_contains_hashes(BloomFilter *filter, uint64 h1, uint64 h2)
+{
+	int			i;
+
+	/* compute the requested number of hashes */
+	for (i = 0; i < filter->nhashes; i++)
+	{
+		/* h1 + h2 + f(i) */
+		uint32		h = (h1 + i * h2) % filter->nbits;
+		uint32		byte = (h / 8);
+		uint32		bit = (h % 8);
+
+		/* if the bit is not set, the value is not there */
+		if (!(filter->data[byte] & (0x01 << bit)))
+			return false;
+	}
+
+	/* all hashes found in bloom filter */
+	return true;
+}
+
 typedef struct BloomOpaque
 {
 	/*
@@ -440,6 +469,9 @@ brin_bloom_opcinfo(PG_FUNCTION_ARGS)
 		MAXALIGN((char *) result + SizeofBrinOpcInfo(1));
 	result->oi_typcache[0] = lookup_type_cache(PG_BRIN_BLOOM_SUMMARYOID, 0);
 
+	cache_h1 = NULL;
+	cache_h2 = NULL;
+
 	PG_RETURN_POINTER(result);
 }
 
@@ -641,6 +673,28 @@ brin_bloom_consistent(PG_FUNCTION_ARGS)
 							  elmlen, elmbyval, elmalign,
 							  &elem_values, &elem_nulls, &num_elems);
 
+			if (cache_h1 == NULL && cache_h2 == NULL)
+			{
+				MemoryContext oldcxt;
+
+				oldcxt = MemoryContextSwitchTo(bdesc->bd_context);
+				cache_h1 = palloc0(num_elems * sizeof(uint64));
+				cache_h2 = palloc0(num_elems * sizeof(uint64));
+				MemoryContextSwitchTo(oldcxt);
+
+				finfo = bloom_get_procinfo(bdesc, attno, PROCNUM_HASH);
+
+				for (int i = 0; i < num_elems; i++)
+				{
+					Datum	element = elem_values[i];
+
+					hashValue = DatumGetUInt32(FunctionCall1Coll(finfo, colloid, element));
+
+					cache_h1[i] = hash_bytes_uint32_extended(hashValue, BLOOM_SEED_1) % filter->nbits;
+					cache_h2[i] = hash_bytes_uint32_extended(hashValue, BLOOM_SEED_2) % filter->nbits;
+				}
+			}
+
 			switch (key->sk_strategy)
 			{
 				case BloomEqualStrategyNumber:
@@ -658,11 +712,8 @@ brin_bloom_consistent(PG_FUNCTION_ARGS)
 						for (int i = 0; i < num_elems; i++)
 						{
 							bool	tmp = false;
-							Datum	element = elem_values[i];
 
-							hashValue = DatumGetUInt32(FunctionCall1Coll(finfo, colloid,
-																		 element));
-							tmp = bloom_contains_value(filter, hashValue);
+							tmp = bloom_contains_hashes(filter, cache_h1[i], cache_h2[i]);
 
 							if (DatumGetBool(tmp))
 							{
-- 
2.39.1

