mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
168 lines
4.8 KiB
C
168 lines
4.8 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* pg_logicalinspect.c
|
|
* Functions to inspect contents of PostgreSQL logical snapshots
|
|
*
|
|
* Copyright (c) 2024-2025, PostgreSQL Global Development Group
|
|
*
|
|
* IDENTIFICATION
|
|
* contrib/pg_logicalinspect/pg_logicalinspect.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "funcapi.h"
|
|
#include "replication/snapbuild_internal.h"
|
|
#include "utils/array.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/pg_lsn.h"
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_meta);
|
|
PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_info);
|
|
|
|
/* Return the description of SnapBuildState */
|
|
static const char *
|
|
get_snapbuild_state_desc(SnapBuildState state)
|
|
{
|
|
const char *stateDesc = "unknown state";
|
|
|
|
switch (state)
|
|
{
|
|
case SNAPBUILD_START:
|
|
stateDesc = "start";
|
|
break;
|
|
case SNAPBUILD_BUILDING_SNAPSHOT:
|
|
stateDesc = "building";
|
|
break;
|
|
case SNAPBUILD_FULL_SNAPSHOT:
|
|
stateDesc = "full";
|
|
break;
|
|
case SNAPBUILD_CONSISTENT:
|
|
stateDesc = "consistent";
|
|
break;
|
|
}
|
|
|
|
return stateDesc;
|
|
}
|
|
|
|
/*
|
|
* Retrieve the logical snapshot file metadata.
|
|
*/
|
|
Datum
|
|
pg_get_logical_snapshot_meta(PG_FUNCTION_ARGS)
|
|
{
|
|
#define PG_GET_LOGICAL_SNAPSHOT_META_COLS 3
|
|
SnapBuildOnDisk ondisk;
|
|
HeapTuple tuple;
|
|
Datum values[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
|
|
bool nulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0};
|
|
TupleDesc tupdesc;
|
|
char path[MAXPGPATH];
|
|
int i = 0;
|
|
text *filename_t = PG_GETARG_TEXT_PP(0);
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
sprintf(path, "%s/%s",
|
|
PG_LOGICAL_SNAPSHOTS_DIR,
|
|
text_to_cstring(filename_t));
|
|
|
|
/* Validate and restore the snapshot to 'ondisk' */
|
|
SnapBuildRestoreSnapshot(&ondisk, path, CurrentMemoryContext, false);
|
|
|
|
values[i++] = UInt32GetDatum(ondisk.magic);
|
|
values[i++] = Int64GetDatum((int64) ondisk.checksum);
|
|
values[i++] = UInt32GetDatum(ondisk.version);
|
|
|
|
Assert(i == PG_GET_LOGICAL_SNAPSHOT_META_COLS);
|
|
|
|
tuple = heap_form_tuple(tupdesc, values, nulls);
|
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
|
|
|
|
#undef PG_GET_LOGICAL_SNAPSHOT_META_COLS
|
|
}
|
|
|
|
Datum
|
|
pg_get_logical_snapshot_info(PG_FUNCTION_ARGS)
|
|
{
|
|
#define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14
|
|
SnapBuildOnDisk ondisk;
|
|
HeapTuple tuple;
|
|
Datum values[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
|
|
bool nulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0};
|
|
TupleDesc tupdesc;
|
|
char path[MAXPGPATH];
|
|
int i = 0;
|
|
text *filename_t = PG_GETARG_TEXT_PP(0);
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
sprintf(path, "%s/%s",
|
|
PG_LOGICAL_SNAPSHOTS_DIR,
|
|
text_to_cstring(filename_t));
|
|
|
|
/* Validate and restore the snapshot to 'ondisk' */
|
|
SnapBuildRestoreSnapshot(&ondisk, path, CurrentMemoryContext, false);
|
|
|
|
values[i++] = CStringGetTextDatum(get_snapbuild_state_desc(ondisk.builder.state));
|
|
values[i++] = TransactionIdGetDatum(ondisk.builder.xmin);
|
|
values[i++] = TransactionIdGetDatum(ondisk.builder.xmax);
|
|
values[i++] = LSNGetDatum(ondisk.builder.start_decoding_at);
|
|
values[i++] = LSNGetDatum(ondisk.builder.two_phase_at);
|
|
values[i++] = TransactionIdGetDatum(ondisk.builder.initial_xmin_horizon);
|
|
values[i++] = BoolGetDatum(ondisk.builder.building_full_snapshot);
|
|
values[i++] = BoolGetDatum(ondisk.builder.in_slot_creation);
|
|
values[i++] = LSNGetDatum(ondisk.builder.last_serialized_snapshot);
|
|
values[i++] = TransactionIdGetDatum(ondisk.builder.next_phase_at);
|
|
|
|
values[i++] = UInt32GetDatum(ondisk.builder.committed.xcnt);
|
|
if (ondisk.builder.committed.xcnt > 0)
|
|
{
|
|
Datum *arrayelems;
|
|
|
|
arrayelems = (Datum *) palloc(ondisk.builder.committed.xcnt * sizeof(Datum));
|
|
|
|
for (int j = 0; j < ondisk.builder.committed.xcnt; j++)
|
|
arrayelems[j] = TransactionIdGetDatum(ondisk.builder.committed.xip[j]);
|
|
|
|
values[i++] = PointerGetDatum(construct_array_builtin(arrayelems,
|
|
ondisk.builder.committed.xcnt,
|
|
XIDOID));
|
|
}
|
|
else
|
|
nulls[i++] = true;
|
|
|
|
values[i++] = UInt32GetDatum(ondisk.builder.catchange.xcnt);
|
|
if (ondisk.builder.catchange.xcnt > 0)
|
|
{
|
|
Datum *arrayelems;
|
|
|
|
arrayelems = (Datum *) palloc(ondisk.builder.catchange.xcnt * sizeof(Datum));
|
|
|
|
for (int j = 0; j < ondisk.builder.catchange.xcnt; j++)
|
|
arrayelems[j] = TransactionIdGetDatum(ondisk.builder.catchange.xip[j]);
|
|
|
|
values[i++] = PointerGetDatum(construct_array_builtin(arrayelems,
|
|
ondisk.builder.catchange.xcnt,
|
|
XIDOID));
|
|
}
|
|
else
|
|
nulls[i++] = true;
|
|
|
|
Assert(i == PG_GET_LOGICAL_SNAPSHOT_INFO_COLS);
|
|
|
|
tuple = heap_form_tuple(tupdesc, values, nulls);
|
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
|
|
|
|
#undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS
|
|
}
|