summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Bossart2025-11-12 20:30:11 +0000
committerNathan Bossart2025-11-12 20:30:11 +0000
commit1165a933aab1355757a43cfd9193b6cce06f573b (patch)
tree6b7288e19f1ade27d9983298b95a1ca6ab431e9f
parent0bdc777e80071abd77674f1e66258d410a010aa9 (diff)
Teach DSM registry to ERROR if attaching to an uninitialized entry.HEADmaster
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 <[email protected]> Reviewed-by: Sami Imseih <[email protected]> Discussion: https://postgr.es/m/dd36d384-55df-4fc2-825c-5bc56c950fa9%40gmail.com Backpatch-through: 17
-rw-r--r--src/backend/storage/ipc/dsm_registry.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/src/backend/storage/ipc/dsm_registry.c b/src/backend/storage/ipc/dsm_registry.c
index a926b9c3f32..7eba8a8cffb 100644
--- a/src/backend/storage/ipc/dsm_registry.c
+++ b/src/backend/storage/ipc/dsm_registry.c
@@ -93,6 +93,7 @@ typedef struct DSMRegistryEntry
{
char name[NAMEDATALEN];
DSMREntryType type;
+ bool initialized;
union
{
NamedDSMState dsm;
@@ -216,6 +217,7 @@ GetNamedDSMSegment(const char *name, size_t size,
dsm_segment *seg;
entry->type = DSMR_ENTRY_TYPE_DSM;
+ entry->initialized = false;
/* Initialize the segment. */
seg = dsm_create(size, 0);
@@ -228,13 +230,21 @@ GetNamedDSMSegment(const char *name, size_t size,
if (init_callback)
(*init_callback) (ret);
+
+ entry->initialized = true;
}
else if (entry->type != DSMR_ENTRY_TYPE_DSM)
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)
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
{
NamedDSMState *state = &entry->dsm;
@@ -297,6 +307,7 @@ GetNamedDSA(const char *name, bool *found)
NamedDSAState *state = &entry->dsa;
entry->type = DSMR_ENTRY_TYPE_DSA;
+ entry->initialized = false;
/* Initialize the LWLock tranche for the DSA. */
state->tranche = LWLockNewTrancheId(name);
@@ -308,10 +319,17 @@ GetNamedDSA(const char *name, bool *found)
/* Store handle for other backends to use. */
state->handle = dsa_get_handle(ret);
+
+ entry->initialized = true;
}
else if (entry->type != DSMR_ENTRY_TYPE_DSA)
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
{
NamedDSAState *state = &entry->dsa;
@@ -372,6 +390,7 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
dsa_area *dsa;
entry->type = DSMR_ENTRY_TYPE_DSH;
+ entry->initialized = false;
/* Initialize the LWLock tranche for the hash table. */
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. */
dsh_state->dsa_handle = dsa_get_handle(dsa);
dsh_state->dsh_handle = dshash_get_hash_table_handle(ret);
+
+ entry->initialized = true;
}
else if (entry->type != DSMR_ENTRY_TYPE_DSH)
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
{
NamedDSHState *dsh_state = &entry->dsh;