mirror of
https://github.com/postgres/postgres.git
synced 2025-08-17 01:02:17 +03:00
Modify ShmemInitStruct and ShmemInitHash to throw errors internally,
rather than returning NULL for some-but-not-all failures as they used to. Remove now-redundant tests for NULL from call sites. We had to do something about this because many call sites were failing to check for NULL; and changing it like this seems a lot more useful and mistake-proof than adding checks to the call sites without them.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.103 2010/01/02 16:57:51 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.104 2010/04/28 16:54:16 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -213,13 +213,13 @@ InitShmemIndex(void)
|
||||
int hash_flags;
|
||||
|
||||
/*
|
||||
* Create the shared memory shmem index.
|
||||
*
|
||||
* Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
|
||||
* hashtable to exist already, we have a bit of a circularity problem in
|
||||
* initializing the ShmemIndex itself. The special "ShmemIndex" hash
|
||||
* table name will tell ShmemInitStruct to fake it.
|
||||
*/
|
||||
|
||||
/* create the shared memory shmem index */
|
||||
info.keysize = SHMEM_INDEX_KEYSIZE;
|
||||
info.entrysize = sizeof(ShmemIndexEnt);
|
||||
hash_flags = HASH_ELEM;
|
||||
@@ -227,8 +227,6 @@ InitShmemIndex(void)
|
||||
ShmemIndex = ShmemInitHash("ShmemIndex",
|
||||
SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
|
||||
&info, hash_flags);
|
||||
if (!ShmemIndex)
|
||||
elog(FATAL, "could not initialize Shmem Index");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -236,8 +234,9 @@ InitShmemIndex(void)
|
||||
* shared memory hash table.
|
||||
*
|
||||
* We assume caller is doing some kind of synchronization
|
||||
* so that two people don't try to create/initialize the
|
||||
* table at once.
|
||||
* so that two processes don't try to create/initialize the same
|
||||
* table at once. (In practice, all creations are done in the postmaster
|
||||
* process; child processes should always be attaching to existing tables.)
|
||||
*
|
||||
* max_size is the estimated maximum number of hashtable entries. This is
|
||||
* not a hard limit, but the access efficiency will degrade if it is
|
||||
@@ -247,6 +246,10 @@ InitShmemIndex(void)
|
||||
* init_size is the number of hashtable entries to preallocate. For a table
|
||||
* whose maximum size is certain, this should be equal to max_size; that
|
||||
* ensures that no run-time out-of-shared-memory failures can occur.
|
||||
*
|
||||
* Note: before Postgres 9.0, this function returned NULL for some failure
|
||||
* cases. Now, it always throws error instead, so callers need not check
|
||||
* for NULL.
|
||||
*/
|
||||
HTAB *
|
||||
ShmemInitHash(const char *name, /* table string name for shmem index */
|
||||
@@ -274,13 +277,6 @@ ShmemInitHash(const char *name, /* table string name for shmem index */
|
||||
hash_get_shared_size(infoP, hash_flags),
|
||||
&found);
|
||||
|
||||
/*
|
||||
* If fail, shmem index is corrupted. Let caller give the error message
|
||||
* since it has more information
|
||||
*/
|
||||
if (location == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* if it already exists, attach to it rather than allocate and initialize
|
||||
* new space
|
||||
@@ -295,18 +291,20 @@ ShmemInitHash(const char *name, /* table string name for shmem index */
|
||||
}
|
||||
|
||||
/*
|
||||
* ShmemInitStruct -- Create/attach to a structure in shared
|
||||
* memory.
|
||||
* ShmemInitStruct -- Create/attach to a structure in shared memory.
|
||||
*
|
||||
* This is called during initialization to find or allocate
|
||||
* This is called during initialization to find or allocate
|
||||
* a data structure in shared memory. If no other process
|
||||
* has created the structure, this routine allocates space
|
||||
* for it. If it exists already, a pointer to the existing
|
||||
* table is returned.
|
||||
* structure is returned.
|
||||
*
|
||||
* Returns: real pointer to the object. FoundPtr is TRUE if
|
||||
* the object is already in the shmem index (hence, already
|
||||
* initialized).
|
||||
* Returns: pointer to the object. *foundPtr is set TRUE if the object was
|
||||
* already in the shmem index (hence, already initialized).
|
||||
*
|
||||
* Note: before Postgres 9.0, this function returned NULL for some failure
|
||||
* cases. Now, it always throws error instead, so callers need not check
|
||||
* for NULL.
|
||||
*/
|
||||
void *
|
||||
ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
@@ -320,7 +318,9 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
{
|
||||
PGShmemHeader *shmemseghdr = ShmemSegHdr;
|
||||
|
||||
/* Must be trying to create/attach to ShmemIndex itself */
|
||||
Assert(strcmp(name, "ShmemIndex") == 0);
|
||||
|
||||
if (IsUnderPostmaster)
|
||||
{
|
||||
/* Must be initializing a (non-standalone) backend */
|
||||
@@ -340,6 +340,12 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
*/
|
||||
Assert(shmemseghdr->index == NULL);
|
||||
structPtr = ShmemAlloc(size);
|
||||
if (structPtr == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("not enough shared memory for data structure"
|
||||
" \"%s\" (%lu bytes requested)",
|
||||
name, (unsigned long) size)));
|
||||
shmemseghdr->index = structPtr;
|
||||
*foundPtr = FALSE;
|
||||
}
|
||||
@@ -356,7 +362,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
LWLockRelease(ShmemIndexLock);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of shared memory")));
|
||||
errmsg("could not create ShmemIndex entry for data structure \"%s\"",
|
||||
name)));
|
||||
}
|
||||
|
||||
if (*foundPtr)
|
||||
@@ -364,15 +371,17 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
/*
|
||||
* Structure is in the shmem index so someone else has allocated it
|
||||
* already. The size better be the same as the size we are trying to
|
||||
* initialize to or there is a name conflict (or worse).
|
||||
* initialize to, or there is a name conflict (or worse).
|
||||
*/
|
||||
if (result->size != size)
|
||||
{
|
||||
LWLockRelease(ShmemIndexLock);
|
||||
|
||||
elog(WARNING, "ShmemIndex entry size is wrong");
|
||||
/* let caller print its message too */
|
||||
return NULL;
|
||||
ereport(ERROR,
|
||||
(errmsg("ShmemIndex entry size is wrong for data structure"
|
||||
" \"%s\": expected %lu, actual %lu",
|
||||
name,
|
||||
(unsigned long) size,
|
||||
(unsigned long) result->size)));
|
||||
}
|
||||
structPtr = result->location;
|
||||
}
|
||||
@@ -380,26 +389,24 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||
{
|
||||
/* It isn't in the table yet. allocate and initialize it */
|
||||
structPtr = ShmemAlloc(size);
|
||||
if (!structPtr)
|
||||
if (structPtr == NULL)
|
||||
{
|
||||
/* out of memory */
|
||||
Assert(ShmemIndex);
|
||||
/* out of memory; remove the failed ShmemIndex entry */
|
||||
hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
|
||||
LWLockRelease(ShmemIndexLock);
|
||||
|
||||
ereport(WARNING,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("could not allocate shared memory segment \"%s\"",
|
||||
name)));
|
||||
*foundPtr = FALSE;
|
||||
return NULL;
|
||||
errmsg("not enough shared memory for data structure"
|
||||
" \"%s\" (%lu bytes requested)",
|
||||
name, (unsigned long) size)));
|
||||
}
|
||||
result->size = size;
|
||||
result->location = structPtr;
|
||||
}
|
||||
Assert(ShmemAddrIsValid(structPtr));
|
||||
|
||||
LWLockRelease(ShmemIndexLock);
|
||||
|
||||
Assert(ShmemAddrIsValid(structPtr));
|
||||
return structPtr;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user