|
31 | 31 | #include "storage/lwlock.h"
|
32 | 32 | #include "storage/shmem.h"
|
33 | 33 | #include "utils/memutils.h"
|
| 34 | +#include "fmgr.h" |
| 35 | +#include "funcapi.h" |
| 36 | +#include "miscadmin.h" |
| 37 | +#include "utils/builtins.h" |
34 | 38 |
|
35 | 39 | typedef struct DSMRegistryCtxStruct
|
36 | 40 | {
|
@@ -198,3 +202,82 @@ GetNamedDSMSegment(const char *name, size_t size,
|
198 | 202 |
|
199 | 203 | return ret;
|
200 | 204 | }
|
| 205 | + |
| 206 | +void |
| 207 | +iterate_dsm_registry(void (*callback)(DSMRegistryEntry *, void *), void *arg); |
| 208 | +void |
| 209 | +iterate_dsm_registry(void (*callback)(DSMRegistryEntry *, void *), void *arg) |
| 210 | +{ |
| 211 | + DSMRegistryEntry *entry; |
| 212 | + dshash_seq_status status; |
| 213 | + /* Ensure DSM registry is initialized */ |
| 214 | + init_dsm_registry(); |
| 215 | + |
| 216 | + /* Use non-exclusive access to avoid blocking other backends */ |
| 217 | + dshash_seq_init(&status, dsm_registry_table, false); |
| 218 | + while ((entry = dshash_seq_next(&status)) != NULL) |
| 219 | + callback(entry, arg); |
| 220 | + dshash_seq_term(&status); |
| 221 | +} |
| 222 | + |
| 223 | +/* SQL SRF showing DSM registry allocated memory */ |
| 224 | +PG_FUNCTION_INFO_V1(pg_get_dsm_registry); |
| 225 | + |
| 226 | +typedef struct |
| 227 | +{ |
| 228 | + Tuplestorestate *tupstore; |
| 229 | + TupleDesc tupdesc; |
| 230 | +} DSMRegistrySRFContext; |
| 231 | + |
| 232 | +static void |
| 233 | +collect_dsm_registry(DSMRegistryEntry *entry, void *arg) |
| 234 | +{ |
| 235 | + DSMRegistrySRFContext *ctx = (DSMRegistrySRFContext *) arg; |
| 236 | + Datum values[2]; |
| 237 | + bool nulls[2] = {false, false}; |
| 238 | + |
| 239 | + values[0] = CStringGetTextDatum(entry->name); |
| 240 | + values[1] = Int64GetDatum(entry->size); |
| 241 | + |
| 242 | + tuplestore_putvalues(ctx->tupstore, ctx->tupdesc, values, nulls); |
| 243 | +} |
| 244 | + |
| 245 | +Datum |
| 246 | +pg_get_dsm_registry(PG_FUNCTION_ARGS) |
| 247 | +{ |
| 248 | + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
| 249 | + MemoryContext per_query_ctx; |
| 250 | + MemoryContext oldcontext; |
| 251 | + TupleDesc tupdesc; |
| 252 | + Tuplestorestate *tupstore; |
| 253 | + DSMRegistrySRFContext ctx; |
| 254 | + |
| 255 | + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) |
| 256 | + ereport(ERROR, (errmsg("pg_get_dsm_registry must be used in a SRF context"))); |
| 257 | + |
| 258 | + /* Set up tuple descriptor */ |
| 259 | + tupdesc = CreateTemplateTupleDesc(2); |
| 260 | + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", TEXTOID, -1, 0); |
| 261 | + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", INT8OID, -1, 0); |
| 262 | + |
| 263 | + /* Switch to per-query memory context */ |
| 264 | + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; |
| 265 | + oldcontext = MemoryContextSwitchTo(per_query_ctx); |
| 266 | + |
| 267 | + /* Initialize tuplestore */ |
| 268 | + tupstore = tuplestore_begin_heap(false, false, work_mem); |
| 269 | + |
| 270 | + ctx.tupstore = tupstore; |
| 271 | + ctx.tupdesc = tupdesc; |
| 272 | + |
| 273 | + /* Collect registry data */ |
| 274 | + iterate_dsm_registry(collect_dsm_registry, &ctx); |
| 275 | + |
| 276 | + /* Switch back and return results */ |
| 277 | + MemoryContextSwitchTo(oldcontext); |
| 278 | + rsinfo->returnMode = SFRM_Materialize; |
| 279 | + rsinfo->setResult = tupstore; |
| 280 | + rsinfo->setDesc = tupdesc; |
| 281 | + |
| 282 | + return (Datum) 0; |
| 283 | +} |
0 commit comments