🌐 AI搜索 & 代理 主页
Skip to content

Commit dbdc717

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 1476028 commit dbdc717

File tree

1 file changed

+78
-43
lines changed

1 file changed

+78
-43
lines changed

src/backend/storage/ipc/dsm_registry.c

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,10 @@ init_dsm_registry(void)
155155
{
156156
/* Initialize dynamic shared hash table for registry. */
157157
dsm_registry_dsa = dsa_create(LWTRANCHE_DSM_REGISTRY_DSA);
158+
dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, NULL);
159+
158160
dsa_pin(dsm_registry_dsa);
159161
dsa_pin_mapping(dsm_registry_dsa);
160-
dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, NULL);
161162

162163
/* Store handles in shared memory for other backends to use. */
163164
DSMRegistryCtx->dsah = dsa_get_handle(dsm_registry_dsa);
@@ -188,6 +189,8 @@ GetNamedDSMSegment(const char *name, size_t size,
188189
DSMRegistryEntry *entry;
189190
MemoryContext oldcontext;
190191
void *ret;
192+
NamedDSMState *state;
193+
dsm_segment *seg;
191194

192195
Assert(found);
193196

@@ -210,36 +213,36 @@ GetNamedDSMSegment(const char *name, size_t size,
210213
init_dsm_registry();
211214

212215
entry = dshash_find_or_insert(dsm_registry_table, name, found);
216+
state = &entry->dsm;
213217
if (!(*found))
214218
{
215-
NamedDSMState *state = &entry->dsm;
216-
dsm_segment *seg;
217-
218219
entry->type = DSMR_ENTRY_TYPE_DSM;
220+
state->handle = DSM_HANDLE_INVALID;
221+
state->size = size;
222+
}
223+
else if (entry->type != DSMR_ENTRY_TYPE_DSM)
224+
ereport(ERROR,
225+
(errmsg("requested DSM segment does not match type of existing entry")));
226+
else if (state->size != size)
227+
ereport(ERROR,
228+
(errmsg("requested DSM segment size does not match size of existing segment")));
229+
230+
if (state->handle == DSM_HANDLE_INVALID)
231+
{
232+
*found = false;
219233

220234
/* Initialize the segment. */
221235
seg = dsm_create(size, 0);
222236

237+
if (init_callback)
238+
(*init_callback) (dsm_segment_address(seg));
239+
223240
dsm_pin_segment(seg);
224241
dsm_pin_mapping(seg);
225242
state->handle = dsm_segment_handle(seg);
226-
state->size = size;
227-
ret = dsm_segment_address(seg);
228-
229-
if (init_callback)
230-
(*init_callback) (ret);
231243
}
232-
else if (entry->type != DSMR_ENTRY_TYPE_DSM)
233-
ereport(ERROR,
234-
(errmsg("requested DSM segment does not match type of existing entry")));
235-
else if (entry->dsm.size != size)
236-
ereport(ERROR,
237-
(errmsg("requested DSM segment size does not match size of existing segment")));
238244
else
239245
{
240-
NamedDSMState *state = &entry->dsm;
241-
dsm_segment *seg;
242-
243246
/* If the existing segment is not already attached, attach it now. */
244247
seg = dsm_find_mapping(state->handle);
245248
if (seg == NULL)
@@ -250,10 +253,9 @@ GetNamedDSMSegment(const char *name, size_t size,
250253

251254
dsm_pin_mapping(seg);
252255
}
253-
254-
ret = dsm_segment_address(seg);
255256
}
256257

258+
ret = dsm_segment_address(seg);
257259
dshash_release_lock(dsm_registry_table, entry);
258260
MemoryContextSwitchTo(oldcontext);
259261

@@ -274,6 +276,7 @@ GetNamedDSA(const char *name, bool *found)
274276
DSMRegistryEntry *entry;
275277
MemoryContext oldcontext;
276278
dsa_area *ret;
279+
NamedDSAState *state;
277280

278281
Assert(found);
279282

@@ -292,14 +295,28 @@ GetNamedDSA(const char *name, bool *found)
292295
init_dsm_registry();
293296

294297
entry = dshash_find_or_insert(dsm_registry_table, name, found);
298+
state = &entry->dsa;
295299
if (!(*found))
296300
{
297-
NamedDSAState *state = &entry->dsa;
298-
299301
entry->type = DSMR_ENTRY_TYPE_DSA;
302+
state->handle = DSA_HANDLE_INVALID;
303+
state->tranche = -1;
304+
}
305+
else if (entry->type != DSMR_ENTRY_TYPE_DSA)
306+
ereport(ERROR,
307+
(errmsg("requested DSA does not match type of existing entry")));
308+
309+
if (state->tranche == -1)
310+
{
311+
*found = false;
300312

301313
/* Initialize the LWLock tranche for the DSA. */
302314
state->tranche = LWLockNewTrancheId(name);
315+
}
316+
317+
if (state->handle == DSA_HANDLE_INVALID)
318+
{
319+
*found = false;
303320

304321
/* Initialize the DSA. */
305322
ret = dsa_create(state->tranche);
@@ -309,17 +326,11 @@ GetNamedDSA(const char *name, bool *found)
309326
/* Store handle for other backends to use. */
310327
state->handle = dsa_get_handle(ret);
311328
}
312-
else if (entry->type != DSMR_ENTRY_TYPE_DSA)
329+
else if (dsa_is_attached(state->handle))
313330
ereport(ERROR,
314-
(errmsg("requested DSA does not match type of existing entry")));
331+
(errmsg("requested DSA already attached to current process")));
315332
else
316333
{
317-
NamedDSAState *state = &entry->dsa;
318-
319-
if (dsa_is_attached(state->handle))
320-
ereport(ERROR,
321-
(errmsg("requested DSA already attached to current process")));
322-
323334
/* Attach to existing DSA. */
324335
ret = dsa_attach(state->handle);
325336
dsa_pin_mapping(ret);
@@ -346,6 +357,7 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
346357
DSMRegistryEntry *entry;
347358
MemoryContext oldcontext;
348359
dshash_table *ret;
360+
NamedDSHState *dsh_state;
349361

350362
Assert(params);
351363
Assert(found);
@@ -365,45 +377,57 @@ GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
365377
init_dsm_registry();
366378

367379
entry = dshash_find_or_insert(dsm_registry_table, name, found);
380+
dsh_state = &entry->dsh;
368381
if (!(*found))
369382
{
370-
NamedDSHState *dsh_state = &entry->dsh;
371-
dshash_parameters params_copy;
372-
dsa_area *dsa;
373-
374383
entry->type = DSMR_ENTRY_TYPE_DSH;
384+
dsh_state->dsa_handle = DSA_HANDLE_INVALID;
385+
dsh_state->dsh_handle = DSHASH_HANDLE_INVALID;
386+
dsh_state->tranche = -1;
387+
}
388+
else if (entry->type != DSMR_ENTRY_TYPE_DSH)
389+
ereport(ERROR,
390+
(errmsg("requested DSHash does not match type of existing entry")));
391+
392+
if (dsh_state->tranche == -1)
393+
{
394+
*found = false;
375395

376396
/* Initialize the LWLock tranche for the hash table. */
377397
dsh_state->tranche = LWLockNewTrancheId(name);
398+
}
399+
400+
if (dsh_state->dsa_handle == DSA_HANDLE_INVALID)
401+
{
402+
dshash_parameters params_copy;
403+
dsa_area *dsa;
404+
405+
*found = false;
378406

379407
/* Initialize the DSA for the hash table. */
380408
dsa = dsa_create(dsh_state->tranche);
381-
dsa_pin(dsa);
382-
dsa_pin_mapping(dsa);
383409

384410
/* Initialize the dshash table. */
385411
memcpy(&params_copy, params, sizeof(dshash_parameters));
386412
params_copy.tranche_id = dsh_state->tranche;
387413
ret = dshash_create(dsa, &params_copy, NULL);
388414

415+
dsa_pin(dsa);
416+
dsa_pin_mapping(dsa);
417+
389418
/* Store handles for other backends to use. */
390419
dsh_state->dsa_handle = dsa_get_handle(dsa);
391420
dsh_state->dsh_handle = dshash_get_hash_table_handle(ret);
392421
}
393-
else if (entry->type != DSMR_ENTRY_TYPE_DSH)
422+
else if (dsa_is_attached(dsh_state->dsa_handle))
394423
ereport(ERROR,
395-
(errmsg("requested DSHash does not match type of existing entry")));
424+
(errmsg("requested DSHash already attached to current process")));
396425
else
397426
{
398-
NamedDSHState *dsh_state = &entry->dsh;
399427
dsa_area *dsa;
400428

401429
/* XXX: Should we verify params matches what table was created with? */
402430

403-
if (dsa_is_attached(dsh_state->dsa_handle))
404-
ereport(ERROR,
405-
(errmsg("requested DSHash already attached to current process")));
406-
407431
/* Attach to existing DSA for the hash table. */
408432
dsa = dsa_attach(dsh_state->dsa_handle);
409433
dsa_pin_mapping(dsa);
@@ -439,6 +463,17 @@ pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
439463
Datum vals[3];
440464
bool nulls[3] = {0};
441465

466+
/* Do not show partially-initialized entries. */
467+
if (entry->type == DSMR_ENTRY_TYPE_DSM &&
468+
entry->dsm.handle == DSM_HANDLE_INVALID)
469+
continue;
470+
if (entry->type == DSMR_ENTRY_TYPE_DSA &&
471+
entry->dsa.handle == DSA_HANDLE_INVALID)
472+
continue;
473+
if (entry->type == DSMR_ENTRY_TYPE_DSH &&
474+
entry->dsh.dsa_handle == DSA_HANDLE_INVALID)
475+
continue;
476+
442477
vals[0] = CStringGetTextDatum(entry->name);
443478
vals[1] = CStringGetTextDatum(DSMREntryTypeNames[entry->type]);
444479

0 commit comments

Comments
 (0)