mirror of
https://github.com/postgres/postgres.git
synced 2025-11-15 03:41:20 +03:00
Teach DSM registry to ERROR if attaching to an uninitialized entry.
If DSM entry initialization fails, backends could try to use an uninitialized DSM segment, DSA, or dshash table (since the entry is still added to the registry). To fix, keep track of whether initialization completed, and ERROR if a backend tries to attach to an uninitialized entry. We could instead retry initialization as needed, but that seemed complicated, error prone, and unlikely to help most cases. Furthermore, such problems probably indicate a coding error. Reported-by: Alexander Lakhin <exclusion@gmail.com> Reviewed-by: Sami Imseih <samimseih@gmail.com> Discussion: https://postgr.es/m/dd36d384-55df-4fc2-825c-5bc56c950fa9%40gmail.com Backpatch-through: 17
This commit is contained in:
@@ -93,6 +93,7 @@ typedef struct DSMRegistryEntry
|
|||||||
{
|
{
|
||||||
char name[NAMEDATALEN];
|
char name[NAMEDATALEN];
|
||||||
DSMREntryType type;
|
DSMREntryType type;
|
||||||
|
bool initialized;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
NamedDSMState dsm;
|
NamedDSMState dsm;
|
||||||
@@ -216,6 +217,7 @@ GetNamedDSMSegment(const char *name, size_t size,
|
|||||||
dsm_segment *seg;
|
dsm_segment *seg;
|
||||||
|
|
||||||
entry->type = DSMR_ENTRY_TYPE_DSM;
|
entry->type = DSMR_ENTRY_TYPE_DSM;
|
||||||
|
entry->initialized = false;
|
||||||
|
|
||||||
/* Initialize the segment. */
|
/* Initialize the segment. */
|
||||||
seg = dsm_create(size, 0);
|
seg = dsm_create(size, 0);
|
||||||
@@ -228,13 +230,21 @@ GetNamedDSMSegment(const char *name, size_t size,
|
|||||||
|
|
||||||
if (init_callback)
|
if (init_callback)
|
||||||
(*init_callback) (ret);
|
(*init_callback) (ret);
|
||||||
|
|
||||||
|
entry->initialized = true;
|
||||||
}
|
}
|
||||||
else if (entry->type != DSMR_ENTRY_TYPE_DSM)
|
else if (entry->type != DSMR_ENTRY_TYPE_DSM)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("requested DSM segment does not match type of existing entry")));
|
(errmsg("requested DSM segment \"%s\" does not match type of existing entry",
|
||||||
|
name)));
|
||||||
|
else if (!entry->initialized)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("requested DSM segment \"%s\" failed initialization",
|
||||||
|
name)));
|
||||||
else if (entry->dsm.size != size)
|
else if (entry->dsm.size != size)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("requested DSM segment size does not match size of existing segment")));
|
(errmsg("requested DSM segment \"%s\" does not match size of existing entry",
|
||||||
|
name)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NamedDSMState *state = &entry->dsm;
|
NamedDSMState *state = &entry->dsm;
|
||||||
@@ -297,6 +307,7 @@ GetNamedDSA(const char *name, bool *found)
|
|||||||
NamedDSAState *state = &entry->dsa;
|
NamedDSAState *state = &entry->dsa;
|
||||||
|
|
||||||
entry->type = DSMR_ENTRY_TYPE_DSA;
|
entry->type = DSMR_ENTRY_TYPE_DSA;
|
||||||
|
entry->initialized = false;
|
||||||
|
|
||||||
/* Initialize the LWLock tranche for the DSA. */
|
/* Initialize the LWLock tranche for the DSA. */
|
||||||
state->tranche = LWLockNewTrancheId(name);
|
state->tranche = LWLockNewTrancheId(name);
|
||||||
@@ -308,10 +319,17 @@ GetNamedDSA(const char *name, bool *found)
|
|||||||
|
|
||||||
/* Store handle for other backends to use. */
|
/* Store handle for other backends to use. */
|
||||||
state->handle = dsa_get_handle(ret);
|
state->handle = dsa_get_handle(ret);
|
||||||
|
|
||||||
|
entry->initialized = true;
|
||||||
}
|
}
|
||||||
else if (entry->type != DSMR_ENTRY_TYPE_DSA)
|
else if (entry->type != DSMR_ENTRY_TYPE_DSA)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("requested DSA does not match type of existing entry")));
|
(errmsg("requested DSA \"%s\" does not match type of existing entry",
|
||||||
|
name)));
|
||||||
|
else if (!entry->initialized)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("requested DSA \"%s\" failed initialization",
|
||||||
|
name)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NamedDSAState *state = &entry->dsa;
|
NamedDSAState *state = &entry->dsa;
|
||||||
@@ -372,6 +390,7 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
|
|||||||
dsa_area *dsa;
|
dsa_area *dsa;
|
||||||
|
|
||||||
entry->type = DSMR_ENTRY_TYPE_DSH;
|
entry->type = DSMR_ENTRY_TYPE_DSH;
|
||||||
|
entry->initialized = false;
|
||||||
|
|
||||||
/* Initialize the LWLock tranche for the hash table. */
|
/* Initialize the LWLock tranche for the hash table. */
|
||||||
dsh_state->tranche = LWLockNewTrancheId(name);
|
dsh_state->tranche = LWLockNewTrancheId(name);
|
||||||
@@ -389,10 +408,17 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
|
|||||||
/* Store handles for other backends to use. */
|
/* Store handles for other backends to use. */
|
||||||
dsh_state->dsa_handle = dsa_get_handle(dsa);
|
dsh_state->dsa_handle = dsa_get_handle(dsa);
|
||||||
dsh_state->dsh_handle = dshash_get_hash_table_handle(ret);
|
dsh_state->dsh_handle = dshash_get_hash_table_handle(ret);
|
||||||
|
|
||||||
|
entry->initialized = true;
|
||||||
}
|
}
|
||||||
else if (entry->type != DSMR_ENTRY_TYPE_DSH)
|
else if (entry->type != DSMR_ENTRY_TYPE_DSH)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("requested DSHash does not match type of existing entry")));
|
(errmsg("requested DSHash \"%s\" does not match type of existing entry",
|
||||||
|
name)));
|
||||||
|
else if (!entry->initialized)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("requested DSHash \"%s\" failed initialization",
|
||||||
|
name)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NamedDSHState *dsh_state = &entry->dsh;
|
NamedDSHState *dsh_state = &entry->dsh;
|
||||||
|
|||||||
Reference in New Issue
Block a user