298 lines
8.6 KiB
C
298 lines
8.6 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* polar_monitor_shmem.c
|
|
* views of polardb share memroy
|
|
*
|
|
* Copyright (c) 2021, Alibaba Group Holding Limited
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* IDENTIFICATION
|
|
* external/polar_monitor/polar_monitor_shmem.c
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/htup_details.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "funcapi.h"
|
|
#include "miscadmin.h"
|
|
#include "storage/lwlock.h"
|
|
#include "storage/pg_shmem.h"
|
|
#include "storage/polar_shmem.h"
|
|
#include "storage/shmem.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/guc.h"
|
|
#include "utils/pg_lsn.h"
|
|
|
|
#define SHMEM_TYPE_NORMAL "normal"
|
|
#define SHMEM_TYPE_PERSISTED "persisted"
|
|
|
|
/*
|
|
* record context for stat shared memory.
|
|
*/
|
|
typedef struct
|
|
{
|
|
char name[NAMEDATALEN];
|
|
char type[NAMEDATALEN];
|
|
uint64 size;
|
|
} SharedMemoryRec;
|
|
|
|
/*
|
|
* Function context for stat shared memory.
|
|
*/
|
|
typedef struct
|
|
{
|
|
TupleDesc tupdesc;
|
|
SharedMemoryRec *record;
|
|
} SharedMemoryContext;
|
|
|
|
static long normal_shmem_num_entries(void);
|
|
static long persisted_shmem_num_entries(void);
|
|
static void build_normal_shmem_record(SharedMemoryContext *shmem_ctx, int *index);
|
|
static void build_persisted_shmem_record(SharedMemoryContext *shmem_ctx, int *index);
|
|
|
|
PG_FUNCTION_INFO_V1(polar_show_shared_memory);
|
|
|
|
Datum
|
|
polar_show_shared_memory(PG_FUNCTION_ARGS)
|
|
{
|
|
Datum result;
|
|
HeapTuple tuple;
|
|
FuncCallContext *func_ctx;
|
|
SharedMemoryContext *shmem_ctx;
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
{
|
|
int index = 0;
|
|
MemoryContext oldcontext;
|
|
TupleDesc tupdesc;
|
|
long normal_num_elem = 0;
|
|
long num_elem = 0;
|
|
|
|
/* init first */
|
|
func_ctx = SRF_FIRSTCALL_INIT();
|
|
|
|
/* Calculate the number of shmem entries. */
|
|
normal_num_elem = normal_shmem_num_entries();
|
|
num_elem = normal_num_elem;
|
|
num_elem += persisted_shmem_num_entries();
|
|
|
|
/* switch context when allocating stuff to be used in later calls */
|
|
oldcontext = MemoryContextSwitchTo(func_ctx->multi_call_memory_ctx);
|
|
shmem_ctx = (SharedMemoryContext *) palloc(sizeof(SharedMemoryContext));
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
/*no cover line*/
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
/* Allocate SharedMemoryContext */
|
|
shmem_ctx->record = (SharedMemoryRec *) MemoryContextAllocHuge(
|
|
CurrentMemoryContext,
|
|
sizeof(SharedMemoryRec) * num_elem);
|
|
|
|
/* Set max calls and remember the user function context. */
|
|
func_ctx->max_calls = num_elem;
|
|
func_ctx->user_fctx = shmem_ctx;
|
|
shmem_ctx->tupdesc = BlessTupleDesc(tupdesc);
|
|
|
|
/* return to original context when allocating transient memory */
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
build_normal_shmem_record(shmem_ctx, &index);
|
|
Assert(index >= normal_num_elem);
|
|
|
|
build_persisted_shmem_record(shmem_ctx, &index);
|
|
Assert(index >= num_elem);
|
|
}
|
|
|
|
func_ctx = SRF_PERCALL_SETUP();
|
|
|
|
/* Get the saved state */
|
|
shmem_ctx = func_ctx->user_fctx;
|
|
|
|
if (func_ctx->call_cntr < func_ctx->max_calls)
|
|
{
|
|
uint32 i = func_ctx->call_cntr;
|
|
Datum values[func_ctx->max_calls];
|
|
bool nulls[func_ctx->max_calls];
|
|
|
|
values[0] = CStringGetTextDatum(shmem_ctx->record[i].name);
|
|
values[1] = UInt64GetDatum(shmem_ctx->record[i].size);
|
|
values[2] = CStringGetTextDatum(shmem_ctx->record[i].type);
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
tuple = heap_form_tuple(shmem_ctx->tupdesc, values, nulls);
|
|
result = HeapTupleGetDatum(tuple);
|
|
|
|
SRF_RETURN_NEXT(func_ctx, result);
|
|
}
|
|
else
|
|
SRF_RETURN_DONE(func_ctx);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(polar_shmem_total_size);
|
|
Datum
|
|
polar_shmem_total_size(PG_FUNCTION_ARGS)
|
|
{
|
|
#define SHMEM_TOTAL_SIZE_COLS 2
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
PGShmemHeader *ShmemSegHdr;
|
|
Tuplestorestate *tupstore;
|
|
MemoryContext per_query_ctx;
|
|
MemoryContext oldcontext;
|
|
TupleDesc tupdesc;
|
|
Datum values[SHMEM_TOTAL_SIZE_COLS];
|
|
bool nulls[SHMEM_TOTAL_SIZE_COLS];
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
/*no cover line*/
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
/*no cover line*/
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
errmsg("materialize mode required, but it is not " \
|
|
"allowed in this context")));
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
tupdesc = CreateTemplateTupleDesc(SHMEM_TOTAL_SIZE_COLS, false);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "shmemsize",
|
|
INT8OID, -1, 0);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "shmemtype",
|
|
TEXTOID, -1, 0);
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
rsinfo->setResult = tupstore;
|
|
rsinfo->setDesc = tupdesc;
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
/* Normal shmem total size. */
|
|
ShmemSegHdr = polar_get_shmem_seg_hdr();
|
|
values[0] = UInt64GetDatum(ShmemSegHdr->totalsize);
|
|
values[1] = CStringGetTextDatum(SHMEM_TYPE_NORMAL);
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
/* Persisted shmem total size. */
|
|
if (polar_persisted_buffer_pool_enabled(NULL))
|
|
{
|
|
ShmemSegHdr = polar_get_persisted_shmem_seg_hdr();
|
|
values[0] = UInt64GetDatum(ShmemSegHdr->totalsize);
|
|
values[1] = CStringGetTextDatum(SHMEM_TYPE_PERSISTED);
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
}
|
|
|
|
/* clean up and return the tuplestore */
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
return (Datum) 0;
|
|
}
|
|
|
|
static long
|
|
normal_shmem_num_entries(void)
|
|
{
|
|
HTAB *ShmemIndex;
|
|
long num_elem = 0;
|
|
|
|
/* init hash_seq and get the number of shared memory element */
|
|
LWLockAcquire(ShmemIndexLock, LW_SHARED);
|
|
ShmemIndex = polar_get_shmem_index();
|
|
|
|
/* Plus 1 for Anonymous Shared Memory */
|
|
num_elem = hash_get_num_entries(ShmemIndex) + 1;
|
|
LWLockRelease(ShmemIndexLock);
|
|
|
|
return num_elem;
|
|
}
|
|
|
|
static long
|
|
persisted_shmem_num_entries(void)
|
|
{
|
|
if (!polar_persisted_buffer_pool_enabled(NULL))
|
|
return 0l;
|
|
|
|
/* Plus 1 for Anonymous Shared Memory */
|
|
return POLAR_PERSISTED_SHMEM_NUM + 1;
|
|
}
|
|
|
|
static void
|
|
build_normal_shmem_record(SharedMemoryContext *shmem_ctx, int *index)
|
|
{
|
|
HTAB *ShmemIndex;
|
|
HASH_SEQ_STATUS hstat;
|
|
ShmemIndexEnt *ent;
|
|
PGShmemHeader *ShmemSegHdr;
|
|
Size allocated = 0;
|
|
|
|
LWLockAcquire(ShmemIndexLock, LW_SHARED);
|
|
|
|
ShmemIndex = polar_get_shmem_index();
|
|
ShmemSegHdr = polar_get_shmem_seg_hdr();
|
|
hash_seq_init(&hstat, ShmemIndex);
|
|
|
|
while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
|
|
{
|
|
snprintf(shmem_ctx->record[*index].name, NAMEDATALEN, "%s", ent->key);
|
|
snprintf(shmem_ctx->record[*index].type, NAMEDATALEN, "%s", SHMEM_TYPE_NORMAL);
|
|
shmem_ctx->record[(*index)++].size = ent->size;
|
|
allocated += ent->size;
|
|
}
|
|
|
|
snprintf(shmem_ctx->record[*index].name, NAMEDATALEN, "%s", "Anonymous Shared Memory");
|
|
snprintf(shmem_ctx->record[*index].type, NAMEDATALEN, "%s", SHMEM_TYPE_NORMAL);
|
|
shmem_ctx->record[(*index)++].size = ShmemSegHdr->freeoffset - allocated;
|
|
|
|
LWLockRelease(ShmemIndexLock);
|
|
}
|
|
|
|
static void
|
|
build_persisted_shmem_record(SharedMemoryContext *shmem_ctx, int *index)
|
|
{
|
|
int i;
|
|
PolarShmemInfo *infos;
|
|
PGShmemHeader *polar_shmem_hdr;
|
|
Size allocated = 0;
|
|
|
|
if (!polar_persisted_buffer_pool_enabled(NULL))
|
|
return;
|
|
|
|
infos = polar_get_persisted_shmem_info();
|
|
|
|
/* Minus Anonymous Shared Memory */
|
|
for(i = 0; i < persisted_shmem_num_entries() - 1; i++)
|
|
{
|
|
PolarShmemInfo *info = &infos[i];
|
|
Assert(info);
|
|
snprintf(shmem_ctx->record[*index].name, NAMEDATALEN, "%s", info->name);
|
|
snprintf(shmem_ctx->record[*index].type, NAMEDATALEN, "%s", SHMEM_TYPE_PERSISTED);
|
|
shmem_ctx->record[(*index)++].size = info->size;
|
|
allocated += info->size;
|
|
}
|
|
|
|
polar_shmem_hdr = polar_get_persisted_shmem_seg_hdr();
|
|
snprintf(shmem_ctx->record[*index].name, NAMEDATALEN, "%s", "Anonymous Shared Memory");
|
|
snprintf(shmem_ctx->record[*index].type, NAMEDATALEN, "%s", SHMEM_TYPE_NORMAL);
|
|
shmem_ctx->record[(*index)++].size = polar_shmem_hdr->freeoffset - allocated;
|
|
} |