Shared-memory hashtables have non-extensible directories, which means

it's a good idea to choose the directory size based on the expected
number of entries.  But ShmemInitHash was using a hard-wired constant.
Boo hiss.  This accounts for recent report of postmaster failure when
asking for 64K or more buffers.
This commit is contained in:
Tom Lane 2000-02-26 05:25:55 +00:00
parent c05abfb1a8
commit 08b1040374
3 changed files with 53 additions and 25 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.48 2000/01/26 05:56:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.49 2000/02/26 05:25:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -332,7 +332,7 @@ ShmemIsValid(unsigned long addr)
HTAB * HTAB *
ShmemInitHash(char *name, /* table string name for shmem index */ ShmemInitHash(char *name, /* table string name for shmem index */
long init_size, /* initial table size */ long init_size, /* initial table size */
long max_size, /* max size of the table (NOT USED) */ long max_size, /* max size of the table */
HASHCTL *infoP, /* info about key and bucket size */ HASHCTL *infoP, /* info about key and bucket size */
int hash_flags) /* info about infoP */ int hash_flags) /* info about infoP */
{ {
@ -340,19 +340,21 @@ ShmemInitHash(char *name, /* table string name for shmem index */
long *location; long *location;
/* /*
* Hash tables allocated in shared memory have a fixed directory; it * Hash tables allocated in shared memory have a fixed directory;
* can't grow or other backends wouldn't be able to find it. The * it can't grow or other backends wouldn't be able to find it.
* segbase is for calculating pointer values. The shared memory * So, make sure we make it big enough to start with.
*
* The segbase is for calculating pointer values. The shared memory
* allocator must be specified too. * allocator must be specified too.
*/ */
infoP->dsize = infoP->max_dsize = DEF_DIRSIZE; infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
infoP->segbase = (long *) ShmemBase; infoP->segbase = (long *) ShmemBase;
infoP->alloc = ShmemAlloc; infoP->alloc = ShmemAlloc;
hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE; hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE;
/* look it up in the shmem index */ /* look it up in the shmem index */
location = ShmemInitStruct(name, location = ShmemInitStruct(name,
sizeof(HHDR) + DEF_DIRSIZE * sizeof(SEG_OFFSET), sizeof(HHDR) + infoP->dsize * sizeof(SEG_OFFSET),
&found); &found);
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.28 2000/01/26 05:57:24 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.29 2000/02/26 05:25:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -328,10 +328,7 @@ init_htab(HTAB *hashp, int nelem)
{ {
*segp = seg_alloc(hashp); *segp = seg_alloc(hashp);
if (*segp == (SEG_OFFSET) 0) if (*segp == (SEG_OFFSET) 0)
{ return -1;
hash_destroy(hashp);
return 0;
}
} }
#if HASH_DEBUG #if HASH_DEBUG
@ -392,6 +389,34 @@ hash_estimate_size(long num_entries, long keysize, long datasize)
return size; return size;
} }
/*
* Select an appropriate directory size for a hashtable with the given
* maximum number of entries.
* This is only needed for hashtables in shared memory, whose directories
* cannot be expanded dynamically.
* NB: assumes that all hash structure parameters have default values!
*
* XXX this had better agree with the behavior of init_htab()...
*/
long
hash_select_dirsize(long num_entries)
{
long nBuckets,
nSegments,
nDirEntries;
/* estimate number of buckets wanted */
nBuckets = 1L << my_log2((num_entries - 1) / DEF_FFACTOR + 1);
/* # of segments needed for nBuckets */
nSegments = 1L << my_log2((nBuckets - 1) / DEF_SEGSIZE + 1);
/* directory entries */
nDirEntries = DEF_DIRSIZE;
while (nDirEntries < nSegments)
nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
return nDirEntries;
}
/********************** DESTROY ROUTINES ************************/ /********************** DESTROY ROUTINES ************************/

View File

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* hsearch.h * hsearch.h
* for hashing in the new buffer manager * for hash tables, particularly hash tables in shared memory
* *
* *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: hsearch.h,v 1.13 2000/01/26 05:58:38 momjian Exp $ * $Id: hsearch.h,v 1.14 2000/02/26 05:25:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -25,12 +25,15 @@
* whole lot of records per bucket or performance goes down. * whole lot of records per bucket or performance goes down.
* *
* In a hash table allocated in shared memory, the directory cannot be * In a hash table allocated in shared memory, the directory cannot be
* expanded because it must stay at a fixed address. * expanded because it must stay at a fixed address. The directory size
* should be selected using hash_select_dirsize (and you'd better have
* a good idea of the maximum number of entries!). For non-shared hash
* tables, the initial directory size can be left at the default.
*/ */
#define DEF_SEGSIZE 256 #define DEF_SEGSIZE 256
#define DEF_SEGSIZE_SHIFT 8/* log2(SEGSIZE) */ #define DEF_SEGSIZE_SHIFT 8 /* must be log2(DEF_SEGSIZE) */
#define DEF_DIRSIZE 256 #define DEF_DIRSIZE 256
#define DEF_FFACTOR 1/* default fill factor */ #define DEF_FFACTOR 1 /* default fill factor */
#define PRIME1 37 /* for the hash function */ #define PRIME1 37 /* for the hash function */
#define PRIME2 1048583 #define PRIME2 1048583
@ -42,13 +45,13 @@
*/ */
typedef struct element typedef struct element
{ {
unsigned long next; /* secret from user */ unsigned long next; /* secret from user */
long key; long key;
} ELEMENT; } ELEMENT;
typedef unsigned long BUCKET_INDEX; typedef unsigned long BUCKET_INDEX;
/* segment is an array of bucket pointers */ /* segment is an array of bucket pointers */
typedef BUCKET_INDEX *SEGMENT; typedef BUCKET_INDEX *SEGMENT;
typedef unsigned long SEG_OFFSET; typedef unsigned long SEG_OFFSET;
@ -65,10 +68,8 @@ typedef struct hashhdr
long nsegs; /* Number of allocated segments */ long nsegs; /* Number of allocated segments */
long keysize; /* hash key length in bytes */ long keysize; /* hash key length in bytes */
long datasize; /* elem data length in bytes */ long datasize; /* elem data length in bytes */
long max_dsize; /* 'dsize' limit if directory is fixed long max_dsize; /* 'dsize' limit if directory is fixed size */
* size */ BUCKET_INDEX freeBucketIndex; /* index of first free bucket */
BUCKET_INDEX freeBucketIndex;
/* index of first free bucket */
#ifdef HASH_STATISTICS #ifdef HASH_STATISTICS
long accesses; long accesses;
long collisions; long collisions;
@ -84,7 +85,6 @@ typedef struct htab
SEG_OFFSET *dir; /* 'directory' of segm starts */ SEG_OFFSET *dir; /* 'directory' of segm starts */
long *(*alloc) (); /* memory allocator (long * for alignment long *(*alloc) (); /* memory allocator (long * for alignment
* reasons) */ * reasons) */
} HTAB; } HTAB;
typedef struct hashctl typedef struct hashctl
@ -115,7 +115,7 @@ typedef struct hashctl
#define HASH_ALLOC 0x100 /* Setting memory allocator */ #define HASH_ALLOC 0x100 /* Setting memory allocator */
/* seg_alloc assumes that INVALID_INDEX is 0*/ /* seg_alloc assumes that INVALID_INDEX is 0 */
#define INVALID_INDEX (0) #define INVALID_INDEX (0)
#define NO_MAX_DSIZE (-1) #define NO_MAX_DSIZE (-1)
/* number of hash buckets allocated at once */ /* number of hash buckets allocated at once */
@ -141,6 +141,7 @@ extern long *hash_search(HTAB *hashp, char *keyPtr, HASHACTION action,
bool *foundPtr); bool *foundPtr);
extern long *hash_seq(HTAB *hashp); extern long *hash_seq(HTAB *hashp);
extern long hash_estimate_size(long num_entries, long keysize, long datasize); extern long hash_estimate_size(long num_entries, long keysize, long datasize);
extern long hash_select_dirsize(long num_entries);
/* /*
* prototypes from functions in hashfn.c * prototypes from functions in hashfn.c