Skip to content

Commit 2fc5c50

Browse files
Teach DSM registry to retry entry initialization if needed.
If DSM registry 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, restructure the code so that the registry retries initialization as needed. This commit also modifies pg_get_dsm_registry_allocations() to leave out partially-initialized entries, as they shouldn't have any allocated memory. DSM registry entry initialization shouldn't fail often in practice, but retrying was deemed better than leaving entries in a permanently failed state (as was done by commit 1165a93, which has since been reverted). Suggested-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Discussion: https://postgr.es/m/E1vJHUk-006I7r-37%40gemulon.postgresql.org Backpatch-through: 17
1 parent c7e0f26 commit 2fc5c50

File tree

1 file changed

+20
-17
lines changed

1 file changed

+20
-17
lines changed

src/backend/storage/ipc/dsm_registry.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,10 @@ init_dsm_registry(void)
101101
{
102102
/* Initialize dynamic shared hash table for registry. */
103103
dsm_registry_dsa = dsa_create(LWTRANCHE_DSM_REGISTRY_DSA);
104+
dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, NULL);
105+
104106
dsa_pin(dsm_registry_dsa);
105107
dsa_pin_mapping(dsm_registry_dsa);
106-
dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, NULL);
107108

108109
/* Store handles in shared memory for other backends to use. */
109110
DSMRegistryCtx->dsah = dsa_get_handle(dsm_registry_dsa);
@@ -134,6 +135,7 @@ GetNamedDSMSegment(const char *name, size_t size,
134135
DSMRegistryEntry *entry;
135136
MemoryContext oldcontext;
136137
void *ret;
138+
dsm_segment *seg;
137139

138140
Assert(found);
139141

@@ -158,29 +160,31 @@ GetNamedDSMSegment(const char *name, size_t size,
158160
entry = dshash_find_or_insert(dsm_registry_table, name, found);
159161
if (!(*found))
160162
{
163+
entry->handle = DSM_HANDLE_INVALID;
164+
entry->size = size;
165+
}
166+
else if (entry->size != size)
167+
ereport(ERROR,
168+
(errmsg("requested DSM segment size does not match size of existing segment")));
169+
170+
if (entry->handle == DSM_HANDLE_INVALID)
171+
{
172+
*found = false;
173+
161174
/* Initialize the segment. */
162-
dsm_segment *seg = dsm_create(size, 0);
175+
seg = dsm_create(size, 0);
176+
177+
if (init_callback)
178+
(*init_callback) (dsm_segment_address(seg));
163179

164180
dsm_pin_segment(seg);
165181
dsm_pin_mapping(seg);
166182
entry->handle = dsm_segment_handle(seg);
167-
entry->size = size;
168-
ret = dsm_segment_address(seg);
169-
170-
if (init_callback)
171-
(*init_callback) (ret);
172-
}
173-
else if (entry->size != size)
174-
{
175-
ereport(ERROR,
176-
(errmsg("requested DSM segment size does not match size of "
177-
"existing segment")));
178183
}
179184
else
180185
{
181-
dsm_segment *seg = dsm_find_mapping(entry->handle);
182-
183186
/* If the existing segment is not already attached, attach it now. */
187+
seg = dsm_find_mapping(entry->handle);
184188
if (seg == NULL)
185189
{
186190
seg = dsm_attach(entry->handle);
@@ -189,10 +193,9 @@ GetNamedDSMSegment(const char *name, size_t size,
189193

190194
dsm_pin_mapping(seg);
191195
}
192-
193-
ret = dsm_segment_address(seg);
194196
}
195197

198+
ret = dsm_segment_address(seg);
196199
dshash_release_lock(dsm_registry_table, entry);
197200
MemoryContextSwitchTo(oldcontext);
198201

0 commit comments

Comments
 (0)