Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * pg_logicalinspect.c 4 : * Functions to inspect contents of PostgreSQL logical snapshots 5 : * 6 : * Copyright (c) 2024, PostgreSQL Global Development Group 7 : * 8 : * IDENTIFICATION 9 : * contrib/pg_logicalinspect/pg_logicalinspect.c 10 : * 11 : *------------------------------------------------------------------------- 12 : */ 13 : #include "postgres.h" 14 : 15 : #include "funcapi.h" 16 : #include "replication/snapbuild_internal.h" 17 : #include "utils/array.h" 18 : #include "utils/builtins.h" 19 : #include "utils/pg_lsn.h" 20 : 21 4 : PG_MODULE_MAGIC; 22 : 23 4 : PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_meta); 24 4 : PG_FUNCTION_INFO_V1(pg_get_logical_snapshot_info); 25 : 26 : /* Return the description of SnapBuildState */ 27 : static const char * 28 4 : get_snapbuild_state_desc(SnapBuildState state) 29 : { 30 4 : const char *stateDesc = "unknown state"; 31 : 32 4 : switch (state) 33 : { 34 0 : case SNAPBUILD_START: 35 0 : stateDesc = "start"; 36 0 : break; 37 0 : case SNAPBUILD_BUILDING_SNAPSHOT: 38 0 : stateDesc = "building"; 39 0 : break; 40 0 : case SNAPBUILD_FULL_SNAPSHOT: 41 0 : stateDesc = "full"; 42 0 : break; 43 4 : case SNAPBUILD_CONSISTENT: 44 4 : stateDesc = "consistent"; 45 4 : break; 46 : } 47 : 48 4 : return stateDesc; 49 : } 50 : 51 : /* 52 : * Retrieve the logical snapshot file metadata. 53 : */ 54 : Datum 55 4 : pg_get_logical_snapshot_meta(PG_FUNCTION_ARGS) 56 : { 57 : #define PG_GET_LOGICAL_SNAPSHOT_META_COLS 3 58 : SnapBuildOnDisk ondisk; 59 : HeapTuple tuple; 60 4 : Datum values[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0}; 61 4 : bool nulls[PG_GET_LOGICAL_SNAPSHOT_META_COLS] = {0}; 62 : TupleDesc tupdesc; 63 : char path[MAXPGPATH]; 64 4 : int i = 0; 65 4 : text *filename_t = PG_GETARG_TEXT_PP(0); 66 : 67 : /* Build a tuple descriptor for our result type */ 68 4 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) 69 0 : elog(ERROR, "return type must be a row type"); 70 : 71 4 : sprintf(path, "%s/%s", 72 : PG_LOGICAL_SNAPSHOTS_DIR, 73 : text_to_cstring(filename_t)); 74 : 75 : /* Validate and restore the snapshot to 'ondisk' */ 76 4 : SnapBuildRestoreSnapshot(&ondisk, path, CurrentMemoryContext, false); 77 : 78 4 : values[i++] = UInt32GetDatum(ondisk.magic); 79 4 : values[i++] = Int64GetDatum((int64) ondisk.checksum); 80 4 : values[i++] = UInt32GetDatum(ondisk.version); 81 : 82 : Assert(i == PG_GET_LOGICAL_SNAPSHOT_META_COLS); 83 : 84 4 : tuple = heap_form_tuple(tupdesc, values, nulls); 85 : 86 4 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); 87 : 88 : #undef PG_GET_LOGICAL_SNAPSHOT_META_COLS 89 : } 90 : 91 : Datum 92 4 : pg_get_logical_snapshot_info(PG_FUNCTION_ARGS) 93 : { 94 : #define PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 14 95 : SnapBuildOnDisk ondisk; 96 : HeapTuple tuple; 97 4 : Datum values[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0}; 98 4 : bool nulls[PG_GET_LOGICAL_SNAPSHOT_INFO_COLS] = {0}; 99 : TupleDesc tupdesc; 100 : char path[MAXPGPATH]; 101 4 : int i = 0; 102 4 : text *filename_t = PG_GETARG_TEXT_PP(0); 103 : 104 : /* Build a tuple descriptor for our result type */ 105 4 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) 106 0 : elog(ERROR, "return type must be a row type"); 107 : 108 4 : sprintf(path, "%s/%s", 109 : PG_LOGICAL_SNAPSHOTS_DIR, 110 : text_to_cstring(filename_t)); 111 : 112 : /* Validate and restore the snapshot to 'ondisk' */ 113 4 : SnapBuildRestoreSnapshot(&ondisk, path, CurrentMemoryContext, false); 114 : 115 4 : values[i++] = CStringGetTextDatum(get_snapbuild_state_desc(ondisk.builder.state)); 116 4 : values[i++] = TransactionIdGetDatum(ondisk.builder.xmin); 117 4 : values[i++] = TransactionIdGetDatum(ondisk.builder.xmax); 118 4 : values[i++] = LSNGetDatum(ondisk.builder.start_decoding_at); 119 4 : values[i++] = LSNGetDatum(ondisk.builder.two_phase_at); 120 4 : values[i++] = TransactionIdGetDatum(ondisk.builder.initial_xmin_horizon); 121 4 : values[i++] = BoolGetDatum(ondisk.builder.building_full_snapshot); 122 4 : values[i++] = BoolGetDatum(ondisk.builder.in_slot_creation); 123 4 : values[i++] = LSNGetDatum(ondisk.builder.last_serialized_snapshot); 124 4 : values[i++] = TransactionIdGetDatum(ondisk.builder.next_phase_at); 125 : 126 4 : values[i++] = UInt32GetDatum(ondisk.builder.committed.xcnt); 127 4 : if (ondisk.builder.committed.xcnt > 0) 128 : { 129 : Datum *arrayelems; 130 : 131 2 : arrayelems = (Datum *) palloc(ondisk.builder.committed.xcnt * sizeof(Datum)); 132 : 133 6 : for (int j = 0; j < ondisk.builder.committed.xcnt; j++) 134 4 : arrayelems[j] = TransactionIdGetDatum(ondisk.builder.committed.xip[j]); 135 : 136 2 : values[i++] = PointerGetDatum(construct_array_builtin(arrayelems, 137 2 : ondisk.builder.committed.xcnt, 138 : XIDOID)); 139 : } 140 : else 141 2 : nulls[i++] = true; 142 : 143 4 : values[i++] = UInt32GetDatum(ondisk.builder.catchange.xcnt); 144 4 : if (ondisk.builder.catchange.xcnt > 0) 145 : { 146 : Datum *arrayelems; 147 : 148 2 : arrayelems = (Datum *) palloc(ondisk.builder.catchange.xcnt * sizeof(Datum)); 149 : 150 6 : for (int j = 0; j < ondisk.builder.catchange.xcnt; j++) 151 4 : arrayelems[j] = TransactionIdGetDatum(ondisk.builder.catchange.xip[j]); 152 : 153 2 : values[i++] = PointerGetDatum(construct_array_builtin(arrayelems, 154 2 : ondisk.builder.catchange.xcnt, 155 : XIDOID)); 156 : } 157 : else 158 2 : nulls[i++] = true; 159 : 160 : Assert(i == PG_GET_LOGICAL_SNAPSHOT_INFO_COLS); 161 : 162 4 : tuple = heap_form_tuple(tupdesc, values, nulls); 163 : 164 4 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); 165 : 166 : #undef PG_GET_LOGICAL_SNAPSHOT_INFO_COLS 167 : }