*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/hash/dynahash.c,v 1.67 2006/03/05 15:58:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/hash/dynahash.c,v 1.68 2006/06/25 18:29:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static bool dir_realloc(HTAB *hashp);
static bool expand_table(HTAB *hashp);
static void hdefault(HTAB *hashp);
+static int choose_nelem_alloc(Size entrysize);
static bool init_htab(HTAB *hashp, long nelem);
static void hash_corrupted(HTAB *hashp);
/*
* For a shared hash table, preallocate the requested number of elements.
* This reduces problems with run-time out-of-shared-memory conditions.
+ *
+ * For a non-shared hash table, preallocate the requested number of
+ * elements if it's less than our chosen nelem_alloc. This avoids
+ * wasting space if the caller correctly estimates a small table size.
*/
- if (flags & HASH_SHARED_MEM)
+ if ((flags & HASH_SHARED_MEM) ||
+ nelem < hctl->nelem_alloc)
{
if (!element_alloc(hashp, (int) nelem))
{
hctl->freeList = NULL;
}
+/*
+ * Given the user-specified entry size, choose nelem_alloc, ie, how many
+ * elements to add to the hash table when we need more.
+ */
+static int
+choose_nelem_alloc(Size entrysize)
+{
+ int nelem_alloc;
+ Size elementSize;
+ Size allocSize;
+
+ /* Each element has a HASHELEMENT header plus user data. */
+ /* NB: this had better match element_alloc() */
+ elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
+
+ /*
+ * The idea here is to choose nelem_alloc at least 32, but round up
+ * so that the allocation request will be a power of 2 or just less.
+ * This makes little difference for hash tables in shared memory,
+ * but for hash tables managed by palloc, the allocation request
+ * will be rounded up to a power of 2 anyway. If we fail to take
+ * this into account, we'll waste as much as half the allocated space.
+ */
+ allocSize = 32 * 4; /* assume elementSize at least 8 */
+ do {
+ allocSize <<= 1;
+ nelem_alloc = allocSize / elementSize;
+ } while (nelem_alloc < 32);
+
+ return nelem_alloc;
+}
static bool
init_htab(HTAB *hashp, long nelem)
}
/* Choose number of entries to allocate at a time */
- hctl->nelem_alloc = (int) Min(nelem, HASHELEMENT_ALLOC_MAX);
- hctl->nelem_alloc = Max(hctl->nelem_alloc, 1);
+ hctl->nelem_alloc = choose_nelem_alloc(hctl->entrysize);
#if HASH_DEBUG
fprintf(stderr, "init_htab:\n%s%p\n%s%ld\n%s%ld\n%s%d\n%s%ld\n%s%u\n%s%x\n%s%x\n%s%ld\n%s%ld\n",
/* segments */
size = add_size(size, mul_size(nSegments,
MAXALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET))));
- /* elements --- allocated in groups of up to HASHELEMENT_ALLOC_MAX */
- elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
- elementAllocCnt = Min(num_entries, HASHELEMENT_ALLOC_MAX);
- elementAllocCnt = Max(elementAllocCnt, 1);
+ /* elements --- allocated in groups of choose_nelem_alloc() entries */
+ elementAllocCnt = choose_nelem_alloc(entrysize);
nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
+ elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
size = add_size(size,
mul_size(nElementAllocs,
mul_size(elementAllocCnt, elementSize)));
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/hsearch.h,v 1.42 2006/03/05 15:59:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/hsearch.h,v 1.43 2006/06/25 18:29:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* max_dsize value to indicate expansible directory */
#define NO_MAX_DSIZE (-1)
-/* max number of hash elements allocated at once */
-#define HASHELEMENT_ALLOC_MAX (32)
/* hash_search operations */
typedef enum