Skip to content

Commit 08b1040

Browse files
committed
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.
1 parent c05abfb commit 08b1040

File tree

3 files changed

+53
-25
lines changed

3 files changed

+53
-25
lines changed

src/backend/storage/ipc/shmem.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.48 2000/01/26 05:56:58 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.49 2000/02/26 05:25:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -332,27 +332,29 @@ ShmemIsValid(unsigned long addr)
332332
HTAB *
333333
ShmemInitHash(char *name, /* table string name for shmem index */
334334
long init_size, /* initial table size */
335-
long max_size, /* max size of the table (NOT USED) */
335+
long max_size, /* max size of the table */
336336
HASHCTL *infoP, /* info about key and bucket size */
337337
int hash_flags) /* info about infoP */
338338
{
339339
bool found;
340340
long *location;
341341

342342
/*
343-
* Hash tables allocated in shared memory have a fixed directory; it
344-
* can't grow or other backends wouldn't be able to find it. The
345-
* segbase is for calculating pointer values. The shared memory
343+
* Hash tables allocated in shared memory have a fixed directory;
344+
* it can't grow or other backends wouldn't be able to find it.
345+
* So, make sure we make it big enough to start with.
346+
*
347+
* The segbase is for calculating pointer values. The shared memory
346348
* allocator must be specified too.
347349
*/
348-
infoP->dsize = infoP->max_dsize = DEF_DIRSIZE;
350+
infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
349351
infoP->segbase = (long *) ShmemBase;
350352
infoP->alloc = ShmemAlloc;
351353
hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE;
352354

353355
/* look it up in the shmem index */
354356
location = ShmemInitStruct(name,
355-
sizeof(HHDR) + DEF_DIRSIZE * sizeof(SEG_OFFSET),
357+
sizeof(HHDR) + infoP->dsize * sizeof(SEG_OFFSET),
356358
&found);
357359

358360
/*

src/backend/utils/hash/dynahash.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.28 2000/01/26 05:57:24 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.29 2000/02/26 05:25:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -328,10 +328,7 @@ init_htab(HTAB *hashp, int nelem)
328328
{
329329
*segp = seg_alloc(hashp);
330330
if (*segp == (SEG_OFFSET) 0)
331-
{
332-
hash_destroy(hashp);
333-
return 0;
334-
}
331+
return -1;
335332
}
336333

337334
#if HASH_DEBUG
@@ -392,6 +389,34 @@ hash_estimate_size(long num_entries, long keysize, long datasize)
392389
return size;
393390
}
394391

392+
/*
393+
* Select an appropriate directory size for a hashtable with the given
394+
* maximum number of entries.
395+
* This is only needed for hashtables in shared memory, whose directories
396+
* cannot be expanded dynamically.
397+
* NB: assumes that all hash structure parameters have default values!
398+
*
399+
* XXX this had better agree with the behavior of init_htab()...
400+
*/
401+
long
402+
hash_select_dirsize(long num_entries)
403+
{
404+
long nBuckets,
405+
nSegments,
406+
nDirEntries;
407+
408+
/* estimate number of buckets wanted */
409+
nBuckets = 1L << my_log2((num_entries - 1) / DEF_FFACTOR + 1);
410+
/* # of segments needed for nBuckets */
411+
nSegments = 1L << my_log2((nBuckets - 1) / DEF_SEGSIZE + 1);
412+
/* directory entries */
413+
nDirEntries = DEF_DIRSIZE;
414+
while (nDirEntries < nSegments)
415+
nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
416+
417+
return nDirEntries;
418+
}
419+
395420

396421
/********************** DESTROY ROUTINES ************************/
397422

src/include/utils/hsearch.h

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/*-------------------------------------------------------------------------
22
*
33
* hsearch.h
4-
* for hashing in the new buffer manager
4+
* for hash tables, particularly hash tables in shared memory
55
*
66
*
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: hsearch.h,v 1.13 2000/01/26 05:58:38 momjian Exp $
10+
* $Id: hsearch.h,v 1.14 2000/02/26 05:25:53 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -25,12 +25,15 @@
2525
* whole lot of records per bucket or performance goes down.
2626
*
2727
* In a hash table allocated in shared memory, the directory cannot be
28-
* expanded because it must stay at a fixed address.
28+
* expanded because it must stay at a fixed address. The directory size
29+
* should be selected using hash_select_dirsize (and you'd better have
30+
* a good idea of the maximum number of entries!). For non-shared hash
31+
* tables, the initial directory size can be left at the default.
2932
*/
3033
#define DEF_SEGSIZE 256
31-
#define DEF_SEGSIZE_SHIFT 8/* log2(SEGSIZE) */
34+
#define DEF_SEGSIZE_SHIFT 8 /* must be log2(DEF_SEGSIZE) */
3235
#define DEF_DIRSIZE 256
33-
#define DEF_FFACTOR 1/* default fill factor */
36+
#define DEF_FFACTOR 1 /* default fill factor */
3437

3538
#define PRIME1 37 /* for the hash function */
3639
#define PRIME2 1048583
@@ -42,13 +45,13 @@
4245
*/
4346
typedef struct element
4447
{
45-
unsigned long next; /* secret from user */
48+
unsigned long next; /* secret from user */
4649
long key;
4750
} ELEMENT;
4851

4952
typedef unsigned long BUCKET_INDEX;
5053

51-
/* segment is an array of bucket pointers */
54+
/* segment is an array of bucket pointers */
5255
typedef BUCKET_INDEX *SEGMENT;
5356
typedef unsigned long SEG_OFFSET;
5457

@@ -65,10 +68,8 @@ typedef struct hashhdr
6568
long nsegs; /* Number of allocated segments */
6669
long keysize; /* hash key length in bytes */
6770
long datasize; /* elem data length in bytes */
68-
long max_dsize; /* 'dsize' limit if directory is fixed
69-
* size */
70-
BUCKET_INDEX freeBucketIndex;
71-
/* index of first free bucket */
71+
long max_dsize; /* 'dsize' limit if directory is fixed size */
72+
BUCKET_INDEX freeBucketIndex; /* index of first free bucket */
7273
#ifdef HASH_STATISTICS
7374
long accesses;
7475
long collisions;
@@ -84,7 +85,6 @@ typedef struct htab
8485
SEG_OFFSET *dir; /* 'directory' of segm starts */
8586
long *(*alloc) (); /* memory allocator (long * for alignment
8687
* reasons) */
87-
8888
} HTAB;
8989

9090
typedef struct hashctl
@@ -115,7 +115,7 @@ typedef struct hashctl
115115
#define HASH_ALLOC 0x100 /* Setting memory allocator */
116116

117117

118-
/* seg_alloc assumes that INVALID_INDEX is 0*/
118+
/* seg_alloc assumes that INVALID_INDEX is 0 */
119119
#define INVALID_INDEX (0)
120120
#define NO_MAX_DSIZE (-1)
121121
/* number of hash buckets allocated at once */
@@ -141,6 +141,7 @@ extern long *hash_search(HTAB *hashp, char *keyPtr, HASHACTION action,
141141
bool *foundPtr);
142142
extern long *hash_seq(HTAB *hashp);
143143
extern long hash_estimate_size(long num_entries, long keysize, long datasize);
144+
extern long hash_select_dirsize(long num_entries);
144145

145146
/*
146147
* prototypes from functions in hashfn.c

0 commit comments

Comments
 (0)