/src/postgres/src/backend/access/transam/rmgr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * rmgr.c |
3 | | * |
4 | | * Resource managers definition |
5 | | * |
6 | | * src/backend/access/transam/rmgr.c |
7 | | */ |
8 | | #include "postgres.h" |
9 | | |
10 | | #include "access/rmgr.h" |
11 | | #include "access/xlog_internal.h" |
12 | | #include "fmgr.h" |
13 | | #include "funcapi.h" |
14 | | #include "miscadmin.h" |
15 | | #include "nodes/execnodes.h" |
16 | | #include "utils/builtins.h" |
17 | | #include "utils/fmgrprotos.h" |
18 | | #include "utils/tuplestore.h" |
19 | | |
20 | | /* includes needed for "access/rmgrlist.h" */ |
21 | | /* IWYU pragma: begin_keep */ |
22 | | #include "access/brin_xlog.h" |
23 | | #include "access/clog.h" |
24 | | #include "access/commit_ts.h" |
25 | | #include "access/generic_xlog.h" |
26 | | #include "access/ginxlog.h" |
27 | | #include "access/gistxlog.h" |
28 | | #include "access/hash_xlog.h" |
29 | | #include "access/heapam_xlog.h" |
30 | | #include "access/multixact.h" |
31 | | #include "access/nbtxlog.h" |
32 | | #include "access/spgxlog.h" |
33 | | #include "access/xact.h" |
34 | | #include "catalog/storage_xlog.h" |
35 | | #include "commands/dbcommands_xlog.h" |
36 | | #include "commands/sequence.h" |
37 | | #include "commands/tablespace.h" |
38 | | #include "replication/decode.h" |
39 | | #include "replication/message.h" |
40 | | #include "replication/origin.h" |
41 | | #include "storage/standby.h" |
42 | | #include "utils/relmapper.h" |
43 | | /* IWYU pragma: end_keep */ |
44 | | |
45 | | |
46 | | /* must be kept in sync with RmgrData definition in xlog_internal.h */ |
47 | | #define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \ |
48 | | { name, redo, desc, identify, startup, cleanup, mask, decode }, |
49 | | |
50 | | RmgrData RmgrTable[RM_MAX_ID + 1] = { |
51 | | #include "access/rmgrlist.h" |
52 | | }; |
53 | | |
54 | | /* |
55 | | * Start up all resource managers. |
56 | | */ |
57 | | void |
58 | | RmgrStartup(void) |
59 | 0 | { |
60 | 0 | for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
61 | 0 | { |
62 | 0 | if (!RmgrIdExists(rmid)) |
63 | 0 | continue; |
64 | | |
65 | 0 | if (RmgrTable[rmid].rm_startup != NULL) |
66 | 0 | RmgrTable[rmid].rm_startup(); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | | /* |
71 | | * Clean up all resource managers. |
72 | | */ |
73 | | void |
74 | | RmgrCleanup(void) |
75 | 0 | { |
76 | 0 | for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
77 | 0 | { |
78 | 0 | if (!RmgrIdExists(rmid)) |
79 | 0 | continue; |
80 | | |
81 | 0 | if (RmgrTable[rmid].rm_cleanup != NULL) |
82 | 0 | RmgrTable[rmid].rm_cleanup(); |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | | /* |
87 | | * Emit ERROR when we encounter a record with an RmgrId we don't |
88 | | * recognize. |
89 | | */ |
90 | | void |
91 | | RmgrNotFound(RmgrId rmid) |
92 | 0 | { |
93 | 0 | ereport(ERROR, (errmsg("resource manager with ID %d not registered", rmid), |
94 | 0 | errhint("Include the extension module that implements this resource manager in \"shared_preload_libraries\"."))); |
95 | 0 | } |
96 | | |
97 | | /* |
98 | | * Register a new custom WAL resource manager. |
99 | | * |
100 | | * Resource manager IDs must be globally unique across all extensions. Refer |
101 | | * to https://wiki.postgresql.org/wiki/CustomWALResourceManagers to reserve a |
102 | | * unique RmgrId for your extension, to avoid conflicts with other extension |
103 | | * developers. During development, use RM_EXPERIMENTAL_ID to avoid needlessly |
104 | | * reserving a new ID. |
105 | | */ |
106 | | void |
107 | | RegisterCustomRmgr(RmgrId rmid, const RmgrData *rmgr) |
108 | 0 | { |
109 | 0 | if (rmgr->rm_name == NULL || strlen(rmgr->rm_name) == 0) |
110 | 0 | ereport(ERROR, (errmsg("custom resource manager name is invalid"), |
111 | 0 | errhint("Provide a non-empty name for the custom resource manager."))); |
112 | | |
113 | 0 | if (!RmgrIdIsCustom(rmid)) |
114 | 0 | ereport(ERROR, (errmsg("custom resource manager ID %d is out of range", rmid), |
115 | 0 | errhint("Provide a custom resource manager ID between %d and %d.", |
116 | 0 | RM_MIN_CUSTOM_ID, RM_MAX_CUSTOM_ID))); |
117 | | |
118 | 0 | if (!process_shared_preload_libraries_in_progress) |
119 | 0 | ereport(ERROR, |
120 | 0 | (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
121 | 0 | errdetail("Custom resource manager must be registered while initializing modules in \"shared_preload_libraries\"."))); |
122 | | |
123 | 0 | if (RmgrTable[rmid].rm_name != NULL) |
124 | 0 | ereport(ERROR, |
125 | 0 | (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
126 | 0 | errdetail("Custom resource manager \"%s\" already registered with the same ID.", |
127 | 0 | RmgrTable[rmid].rm_name))); |
128 | | |
129 | | /* check for existing rmgr with the same name */ |
130 | 0 | for (int existing_rmid = 0; existing_rmid <= RM_MAX_ID; existing_rmid++) |
131 | 0 | { |
132 | 0 | if (!RmgrIdExists(existing_rmid)) |
133 | 0 | continue; |
134 | | |
135 | 0 | if (!pg_strcasecmp(RmgrTable[existing_rmid].rm_name, rmgr->rm_name)) |
136 | 0 | ereport(ERROR, |
137 | 0 | (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
138 | 0 | errdetail("Existing resource manager with ID %d has the same name.", existing_rmid))); |
139 | 0 | } |
140 | | |
141 | | /* register it */ |
142 | 0 | RmgrTable[rmid] = *rmgr; |
143 | 0 | ereport(LOG, |
144 | 0 | (errmsg("registered custom resource manager \"%s\" with ID %d", |
145 | 0 | rmgr->rm_name, rmid))); |
146 | 0 | } |
147 | | |
148 | | /* SQL SRF showing loaded resource managers */ |
149 | | Datum |
150 | | pg_get_wal_resource_managers(PG_FUNCTION_ARGS) |
151 | 0 | { |
152 | 0 | #define PG_GET_RESOURCE_MANAGERS_COLS 3 |
153 | 0 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
154 | 0 | Datum values[PG_GET_RESOURCE_MANAGERS_COLS]; |
155 | 0 | bool nulls[PG_GET_RESOURCE_MANAGERS_COLS] = {0}; |
156 | |
|
157 | 0 | InitMaterializedSRF(fcinfo, 0); |
158 | |
|
159 | 0 | for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
160 | 0 | { |
161 | 0 | if (!RmgrIdExists(rmid)) |
162 | 0 | continue; |
163 | 0 | values[0] = Int32GetDatum(rmid); |
164 | 0 | values[1] = CStringGetTextDatum(GetRmgr(rmid).rm_name); |
165 | 0 | values[2] = BoolGetDatum(RmgrIdIsBuiltin(rmid)); |
166 | 0 | tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); |
167 | 0 | } |
168 | |
|
169 | 0 | return (Datum) 0; |
170 | 0 | } |