Introduce bloom_filter_size for BRIN bloom opclass
authorTomas Vondra
Sun, 2 Jul 2023 08:24:13 +0000 (10:24 +0200)
committerTomas Vondra
Sun, 2 Jul 2023 08:24:29 +0000 (10:24 +0200)
Move the calculation of Bloom filter parameters (for BRIN indexes) into
a separate function to make reuse easier. At the moment we only call it
from one place, but that may change and it's easier to read anyway.

Reviewed-by: Heikki Linnakangas
Discussion: https://postgr.es/m/0e1f3350-c9cf-ab62-43a5-5dae314de89c%40enterprisedb.com

src/backend/access/brin/brin_bloom.c

index 568faf1cd58ee872349dd1c6620a61cacc6197f8..f47eb81012d3ad832a5116330b44288669307241 100644 (file)
@@ -259,6 +259,48 @@ typedef struct BloomFilter
    char        data[FLEXIBLE_ARRAY_MEMBER];
 } BloomFilter;
 
+/*
+ * bloom_filter_size
+ *     Calculate Bloom filter parameters (nbits, nbytes, nhashes).
+ *
+ * Given expected number of distinct values and desired false positive rate,
+ * calculates the optimal parameters of the Bloom filter.
+ *
+ * The resulting parameters are returned through nbytesp (number of bytes),
+ * nbitsp (number of bits) and nhashesp (number of hash functions). If a
+ * pointer is NULL, the parameter is not returned.
+ */
+static void
+bloom_filter_size(int ndistinct, double false_positive_rate,
+                 int *nbytesp, int *nbitsp, int *nhashesp)
+{
+   double  k;
+   int     nbits,
+           nbytes;
+
+   /* sizing bloom filter: -(n * ln(p)) / (ln(2))^2 */
+   nbits = ceil(-(ndistinct * log(false_positive_rate)) / pow(log(2.0), 2));
+
+   /* round m to whole bytes */
+   nbytes = ((nbits + 7) / 8);
+   nbits = nbytes * 8;
+
+   /*
+    * round(log(2.0) * m / ndistinct), but assume round() may not be
+    * available on Windows
+    */
+   k = log(2.0) * nbits / ndistinct;
+   k = (k - floor(k) >= 0.5) ? ceil(k) : floor(k);
+
+   if (nbytesp)
+       *nbytesp = nbytes;
+
+   if (nbitsp)
+       *nbitsp = nbits;
+
+   if (nhashesp)
+       *nhashesp = (int) k;
+}
 
 /*
  * bloom_init
@@ -275,19 +317,15 @@ bloom_init(int ndistinct, double false_positive_rate)
 
    int         nbits;          /* size of filter / number of bits */
    int         nbytes;         /* size of filter / number of bytes */
-
-   double      k;              /* number of hash functions */
+   int         nhashes;        /* number of hash functions */
 
    Assert(ndistinct > 0);
    Assert((false_positive_rate >= BLOOM_MIN_FALSE_POSITIVE_RATE) &&
           (false_positive_rate < BLOOM_MAX_FALSE_POSITIVE_RATE));
 
-   /* sizing bloom filter: -(n * ln(p)) / (ln(2))^2 */
-   nbits = ceil(-(ndistinct * log(false_positive_rate)) / pow(log(2.0), 2));
-
-   /* round m to whole bytes */
-   nbytes = ((nbits + 7) / 8);
-   nbits = nbytes * 8;
+   /* calculate bloom filter size / parameters */
+   bloom_filter_size(ndistinct, false_positive_rate,
+                     &nbytes, &nbits, &nhashes);
 
    /*
     * Reject filters that are obviously too large to store on a page.
@@ -310,13 +348,6 @@ bloom_init(int ndistinct, double false_positive_rate)
        elog(ERROR, "the bloom filter is too large (%d > %zu)", nbytes,
             BloomMaxFilterSize);
 
-   /*
-    * round(log(2.0) * m / ndistinct), but assume round() may not be
-    * available on Windows
-    */
-   k = log(2.0) * nbits / ndistinct;
-   k = (k - floor(k) >= 0.5) ? ceil(k) : floor(k);
-
    /*
     * We allocate the whole filter. Most of it is going to be 0 bits, so the
     * varlena is easy to compress.
@@ -326,7 +357,7 @@ bloom_init(int ndistinct, double false_positive_rate)
    filter = (BloomFilter *) palloc0(len);
 
    filter->flags = 0;
-   filter->nhashes = (int) k;
+   filter->nhashes = nhashes;
    filter->nbits = nbits;
 
    SET_VARSIZE(filter, len);