Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * xlogreader.h
4 : : * Definitions for the generic XLog reading facility
5 : : *
6 : : * Portions Copyright (c) 2013-2026, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/include/access/xlogreader.h
10 : : *
11 : : * NOTES
12 : : * See the definition of the XLogReaderState struct for instructions on
13 : : * how to use the XLogReader infrastructure.
14 : : *
15 : : * The basic idea is to allocate an XLogReaderState via
16 : : * XLogReaderAllocate(), position the reader to the first record with
17 : : * XLogBeginRead() or XLogFindNextRecord(), and call XLogReadRecord()
18 : : * until it returns NULL.
19 : : *
20 : : * Callers supply a page_read callback if they want to call
21 : : * XLogReadRecord or XLogFindNextRecord; it can be passed in as NULL
22 : : * otherwise. The WALRead function can be used as a helper to write
23 : : * page_read callbacks, but it is not mandatory; callers that use it,
24 : : * must supply segment_open callbacks. The segment_close callback
25 : : * must always be supplied.
26 : : *
27 : : * After reading a record with XLogReadRecord(), it's decomposed into
28 : : * the per-block and main data parts, and the parts can be accessed
29 : : * with the XLogRec* macros and functions. You can also decode a
30 : : * record that's already constructed in memory, without reading from
31 : : * disk, by calling the DecodeXLogRecord() function.
32 : : *-------------------------------------------------------------------------
33 : : */
34 : : #ifndef XLOGREADER_H
35 : : #define XLOGREADER_H
36 : :
37 : : #ifndef FRONTEND
38 : : #include "access/transam.h"
39 : : #endif
40 : :
41 : : #include "access/xlogrecord.h"
42 : : #include "storage/buf.h"
43 : :
44 : : /* WALOpenSegment represents a WAL segment being read. */
45 : : typedef struct WALOpenSegment
46 : : {
47 : : int ws_file; /* segment file descriptor */
48 : : XLogSegNo ws_segno; /* segment number */
49 : : TimeLineID ws_tli; /* timeline ID of the currently open file */
50 : : } WALOpenSegment;
51 : :
52 : : /* WALSegmentContext carries context information about WAL segments to read */
53 : : typedef struct WALSegmentContext
54 : : {
55 : : char ws_dir[MAXPGPATH];
56 : : int ws_segsize;
57 : : } WALSegmentContext;
58 : :
59 : : typedef struct XLogReaderState XLogReaderState;
60 : :
61 : : /* Function type definitions for various xlogreader interactions */
62 : : typedef int (*XLogPageReadCB) (XLogReaderState *xlogreader,
63 : : XLogRecPtr targetPagePtr,
64 : : int reqLen,
65 : : XLogRecPtr targetRecPtr,
66 : : char *readBuf);
67 : : typedef void (*WALSegmentOpenCB) (XLogReaderState *xlogreader,
68 : : XLogSegNo nextSegNo,
69 : : TimeLineID *tli_p);
70 : : typedef void (*WALSegmentCloseCB) (XLogReaderState *xlogreader);
71 : :
72 : : typedef struct XLogReaderRoutine
73 : : {
74 : : /*
75 : : * Data input callback
76 : : *
77 : : * This callback shall read at least reqLen valid bytes of the xlog page
78 : : * starting at targetPagePtr, and store them in readBuf. The callback
79 : : * shall return the number of bytes read (never more than XLOG_BLCKSZ), or
80 : : * -1 on failure. The callback shall sleep, if necessary, to wait for the
81 : : * requested bytes to become available. The callback will not be invoked
82 : : * again for the same page unless more than the returned number of bytes
83 : : * are needed.
84 : : *
85 : : * targetRecPtr is the position of the WAL record we're reading. Usually
86 : : * it is equal to targetPagePtr + reqLen, but sometimes xlogreader needs
87 : : * to read and verify the page or segment header, before it reads the
88 : : * actual WAL record it's interested in. In that case, targetRecPtr can
89 : : * be used to determine which timeline to read the page from.
90 : : *
91 : : * The callback shall set ->seg.ws_tli to the TLI of the file the page was
92 : : * read from.
93 : : */
94 : : XLogPageReadCB page_read;
95 : :
96 : : /*
97 : : * Callback to open the specified WAL segment for reading. ->seg.ws_file
98 : : * shall be set to the file descriptor of the opened segment. In case of
99 : : * failure, an error shall be raised by the callback and it shall not
100 : : * return.
101 : : *
102 : : * "nextSegNo" is the number of the segment to be opened.
103 : : *
104 : : * "tli_p" is an input/output argument. WALRead() uses it to pass the
105 : : * timeline in which the new segment should be found, but the callback can
106 : : * use it to return the TLI that it actually opened.
107 : : */
108 : : WALSegmentOpenCB segment_open;
109 : :
110 : : /*
111 : : * WAL segment close callback. ->seg.ws_file shall be set to a negative
112 : : * number. This shall not raise an error, as it may be called in a memory
113 : : * context reset callback if XLogReaderRegisterResetCallback() has been
114 : : * used.
115 : : */
116 : : WALSegmentCloseCB segment_close;
117 : : } XLogReaderRoutine;
118 : :
119 : : #define XL_ROUTINE(...) &(XLogReaderRoutine){__VA_ARGS__}
120 : :
121 : : typedef struct
122 : : {
123 : : /* Is this block ref in use? */
124 : : bool in_use;
125 : :
126 : : /* Identify the block this refers to */
127 : : RelFileLocator rlocator;
128 : : ForkNumber forknum;
129 : : BlockNumber blkno;
130 : :
131 : : /* Prefetching workspace. */
132 : : Buffer prefetch_buffer;
133 : :
134 : : /* copy of the fork_flags field from the XLogRecordBlockHeader */
135 : : uint8 flags;
136 : :
137 : : /* Information on full-page image, if any */
138 : : bool has_image; /* has image, even for consistency checking */
139 : : bool apply_image; /* has image that should be restored */
140 : : char *bkp_image;
141 : : uint16 hole_offset;
142 : : uint16 hole_length;
143 : : uint16 bimg_len;
144 : : uint8 bimg_info;
145 : :
146 : : /* Buffer holding the rmgr-specific data associated with this block */
147 : : bool has_data;
148 : : char *data;
149 : : uint16 data_len;
150 : : } DecodedBkpBlock;
151 : :
152 : : /*
153 : : * The decoded contents of a record. This occupies a contiguous region of
154 : : * memory, with main_data and blocks[n].data pointing to memory after the
155 : : * members declared here.
156 : : */
157 : : typedef struct DecodedXLogRecord
158 : : {
159 : : /* Private member used for resource management. */
160 : : size_t size; /* total size of decoded record */
161 : : bool oversized; /* outside the regular decode buffer? */
162 : : struct DecodedXLogRecord *next; /* decoded record queue link */
163 : :
164 : : /* Public members. */
165 : : XLogRecPtr lsn; /* location */
166 : : XLogRecPtr next_lsn; /* location of next record */
167 : : XLogRecord header; /* header */
168 : : ReplOriginId record_origin;
169 : : TransactionId toplevel_xid; /* XID of top-level transaction */
170 : : char *main_data; /* record's main data portion */
171 : : uint32 main_data_len; /* main data portion's length */
172 : : int max_block_id; /* highest block_id in use (-1 if none) */
173 : : DecodedBkpBlock blocks[FLEXIBLE_ARRAY_MEMBER];
174 : : } DecodedXLogRecord;
175 : :
176 : : struct XLogReaderState
177 : : {
178 : : /*
179 : : * Operational callbacks
180 : : */
181 : : XLogReaderRoutine routine;
182 : :
183 : : /* ----------------------------------------
184 : : * Public parameters
185 : : * ----------------------------------------
186 : : */
187 : :
188 : : /*
189 : : * System identifier of the xlog files we're about to read. Set to zero
190 : : * (the default value) if unknown or unimportant.
191 : : */
192 : : uint64 system_identifier;
193 : :
194 : : /*
195 : : * Opaque data for callbacks to use. Not used by XLogReader.
196 : : */
197 : : void *private_data;
198 : :
199 : : /*
200 : : * Start and end point of last record read. EndRecPtr is also used as the
201 : : * position to read next. Calling XLogBeginRead() sets EndRecPtr to the
202 : : * starting position and ReadRecPtr to invalid.
203 : : *
204 : : * Start and end point of last record returned by XLogReadRecord(). These
205 : : * are also available as record->lsn and record->next_lsn.
206 : : */
207 : : XLogRecPtr ReadRecPtr; /* start of last record read */
208 : : XLogRecPtr EndRecPtr; /* end+1 of last record read */
209 : :
210 : : /*
211 : : * Set at the end of recovery: the start point of a partial record at the
212 : : * end of WAL (InvalidXLogRecPtr if there wasn't one), and the start
213 : : * location of its first contrecord that went missing.
214 : : */
215 : : XLogRecPtr abortedRecPtr;
216 : : XLogRecPtr missingContrecPtr;
217 : : /* Set when XLP_FIRST_IS_OVERWRITE_CONTRECORD is found */
218 : : XLogRecPtr overwrittenRecPtr;
219 : :
220 : :
221 : : /* ----------------------------------------
222 : : * Decoded representation of current record
223 : : *
224 : : * Use XLogRecGet* functions to investigate the record; these fields
225 : : * should not be accessed directly.
226 : : * ----------------------------------------
227 : : * Start and end point of the last record read and decoded by
228 : : * XLogReadRecord(). NextRecPtr is also used as the position to decode
229 : : * next. Calling XLogBeginRead() sets NextRecPtr and EndRecPtr to the
230 : : * requested starting position.
231 : : */
232 : : XLogRecPtr DecodeRecPtr; /* start of last record decoded */
233 : : XLogRecPtr NextRecPtr; /* end+1 of last record decoded */
234 : : XLogRecPtr PrevRecPtr; /* start of previous record decoded */
235 : :
236 : : /* Last record returned by XLogReadRecord(). */
237 : : DecodedXLogRecord *record;
238 : :
239 : : /* ----------------------------------------
240 : : * private/internal state
241 : : * ----------------------------------------
242 : : */
243 : :
244 : : #ifdef USE_ZSTD
245 : : /* Decompression context reused for zstd-compressed full-page images. */
246 : : void *zstd_dctx;
247 : : #ifndef FRONTEND
248 : : /* Reset callback for zstd_dctx */
249 : : MemoryContextCallback zstd_dctx_cb;
250 : : #endif
251 : : #endif
252 : :
253 : : /*
254 : : * Buffer for decoded records. This is a circular buffer, though
255 : : * individual records can't be split in the middle, so some space is often
256 : : * wasted at the end. Oversized records that don't fit in this space are
257 : : * allocated separately.
258 : : */
259 : : char *decode_buffer;
260 : : size_t decode_buffer_size;
261 : : bool free_decode_buffer; /* need to free? */
262 : : char *decode_buffer_head; /* data is read from the head */
263 : : char *decode_buffer_tail; /* new data is written at the tail */
264 : :
265 : : /*
266 : : * Queue of records that have been decoded. This is a linked list that
267 : : * usually consists of consecutive records in decode_buffer, but may also
268 : : * contain oversized records allocated with palloc().
269 : : */
270 : : DecodedXLogRecord *decode_queue_head; /* oldest decoded record */
271 : : DecodedXLogRecord *decode_queue_tail; /* newest decoded record */
272 : :
273 : : /*
274 : : * Buffer for currently read page (XLOG_BLCKSZ bytes, valid up to at least
275 : : * readLen bytes)
276 : : */
277 : : char *readBuf;
278 : : uint32 readLen;
279 : :
280 : : /* last read XLOG position for data currently in readBuf */
281 : : WALSegmentContext segcxt;
282 : : WALOpenSegment seg;
283 : : uint32 segoff;
284 : :
285 : : /*
286 : : * beginning of prior page read, and its TLI. Doesn't necessarily
287 : : * correspond to what's in readBuf; used for timeline sanity checks.
288 : : */
289 : : XLogRecPtr latestPagePtr;
290 : : TimeLineID latestPageTLI;
291 : :
292 : : /* beginning of the WAL record being read. */
293 : : XLogRecPtr currRecPtr;
294 : : /* timeline to read it from, 0 if a lookup is required */
295 : : TimeLineID currTLI;
296 : :
297 : : /*
298 : : * Safe point to read to in currTLI if current TLI is historical
299 : : * (tliSwitchPoint) or InvalidXLogRecPtr if on current timeline.
300 : : *
301 : : * Actually set to the start of the segment containing the timeline switch
302 : : * that ends currTLI's validity, not the LSN of the switch its self, since
303 : : * we can't assume the old segment will be present.
304 : : */
305 : : XLogRecPtr currTLIValidUntil;
306 : :
307 : : /*
308 : : * If currTLI is not the most recent known timeline, the next timeline to
309 : : * read from when currTLIValidUntil is reached.
310 : : */
311 : : TimeLineID nextTLI;
312 : :
313 : : /*
314 : : * Buffer for current ReadRecord result (expandable), used when a record
315 : : * crosses a page boundary.
316 : : */
317 : : char *readRecordBuf;
318 : : uint32 readRecordBufSize;
319 : :
320 : : /* Buffer to hold error message */
321 : : char *errormsg_buf;
322 : : bool errormsg_deferred;
323 : :
324 : : /*
325 : : * Flag to indicate to XLogPageReadCB that it should not block waiting for
326 : : * data.
327 : : */
328 : : bool nonblocking;
329 : :
330 : : #ifndef FRONTEND
331 : : /* Reset callback for the memory context holding this reader. */
332 : : MemoryContextCallback reset_cb;
333 : : bool reset_cb_registered;
334 : : #endif
335 : : };
336 : :
337 : : /*
338 : : * Check if XLogNextRecord() has any more queued records or an error to return.
339 : : */
340 : : static inline bool
1669 tmunro@postgresql.or 341 :CBC 10057467 : XLogReaderHasQueuedRecordOrError(XLogReaderState *state)
342 : : {
343 [ + + + + ]: 10057467 : return (state->decode_queue_head != NULL) || state->errormsg_deferred;
344 : : }
345 : :
346 : : /* Get a new XLogReader */
347 : : extern XLogReaderState *XLogReaderAllocate(int wal_segment_size,
348 : : const char *waldir,
349 : : XLogReaderRoutine *routine,
350 : : void *private_data);
351 : :
352 : : /* Free an XLogReader */
353 : : extern void XLogReaderFree(XLogReaderState *state);
354 : :
355 : : #ifndef FRONTEND
356 : : /* Register a memory context reset callback */
357 : : extern void XLogReaderRegisterResetCallback(XLogReaderState *state);
358 : : #endif
359 : :
360 : : /* Optionally provide a circular decoding buffer to allow readahead. */
361 : : extern void XLogReaderSetDecodeBuffer(XLogReaderState *state,
362 : : void *buffer,
363 : : size_t size);
364 : :
365 : : /* Position the XLogReader to given record */
366 : : extern void XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr);
367 : : extern XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr,
368 : : char **errormsg);
369 : :
370 : : /* Return values from XLogPageReadCB. */
371 : : typedef enum XLogPageReadResult
372 : : {
373 : : XLREAD_SUCCESS = 0, /* record is successfully read */
374 : : XLREAD_FAIL = -1, /* failed during reading a record */
375 : : XLREAD_WOULDBLOCK = -2, /* nonblocking mode only, no data */
376 : : } XLogPageReadResult;
377 : :
378 : : /* Read the next XLog record. Returns NULL on end-of-WAL or failure */
379 : : extern struct XLogRecord *XLogReadRecord(XLogReaderState *state,
380 : : char **errormsg);
381 : :
382 : : /* Consume the next record or error. */
383 : : extern DecodedXLogRecord *XLogNextRecord(XLogReaderState *state,
384 : : char **errormsg);
385 : :
386 : : /* Release the previously returned record, if necessary. */
387 : : extern XLogRecPtr XLogReleasePreviousRecord(XLogReaderState *state);
388 : :
389 : : /* Try to read ahead, if there is data and space. */
390 : : extern DecodedXLogRecord *XLogReadAhead(XLogReaderState *state,
391 : : bool nonblocking);
392 : :
393 : : /* Validate a page */
394 : : extern bool XLogReaderValidatePageHeader(XLogReaderState *state,
395 : : XLogRecPtr recptr, char *phdr);
396 : :
397 : : /* Forget error produced by XLogReaderValidatePageHeader(). */
398 : : extern void XLogReaderResetError(XLogReaderState *state);
399 : :
400 : : /*
401 : : * Error information from WALRead that both backend and frontend caller can
402 : : * process. Currently only errors from pg_pread can be reported.
403 : : */
404 : : typedef struct WALReadError
405 : : {
406 : : int wre_errno; /* errno set by the last pg_pread() */
407 : : uint32 wre_off; /* Offset we tried to read from. */
408 : : size_t wre_req; /* Bytes requested to be read. */
409 : : ssize_t wre_read; /* Bytes read by the last read(). */
410 : : WALOpenSegment wre_seg; /* Segment we tried to read from. */
411 : : } WALReadError;
412 : :
413 : : extern bool WALRead(XLogReaderState *state,
414 : : char *buf, XLogRecPtr startptr, Size count,
415 : : TimeLineID tli, WALReadError *errinfo);
416 : :
417 : : /* Functions for decoding an XLogRecord */
418 : :
419 : : extern size_t DecodeXLogRecordRequiredSpace(size_t xl_tot_len);
420 : : extern bool DecodeXLogRecord(XLogReaderState *state,
421 : : DecodedXLogRecord *decoded,
422 : : XLogRecord *record,
423 : : XLogRecPtr lsn,
424 : : char **errormsg);
425 : :
426 : : /*
427 : : * Macros that provide access to parts of the record most recently returned by
428 : : * XLogReadRecord() or XLogNextRecord().
429 : : */
430 : : #define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len)
431 : : #define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev)
432 : : #define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
433 : : #define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid)
434 : : #define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid)
435 : : #define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin)
436 : : #define XLogRecGetTopXid(decoder) ((decoder)->record->toplevel_xid)
437 : : #define XLogRecGetData(decoder) ((decoder)->record->main_data)
438 : : #define XLogRecGetDataLen(decoder) ((decoder)->record->main_data_len)
439 : : #define XLogRecHasAnyBlockRefs(decoder) ((decoder)->record->max_block_id >= 0)
440 : : #define XLogRecMaxBlockId(decoder) ((decoder)->record->max_block_id)
441 : : #define XLogRecGetBlock(decoder, i) (&(decoder)->record->blocks[(i)])
442 : : #define XLogRecHasBlockRef(decoder, block_id) \
443 : : (((decoder)->record->max_block_id >= (block_id)) && \
444 : : ((decoder)->record->blocks[block_id].in_use))
445 : : #define XLogRecHasBlockImage(decoder, block_id) \
446 : : ((decoder)->record->blocks[block_id].has_image)
447 : : #define XLogRecBlockImageApply(decoder, block_id) \
448 : : ((decoder)->record->blocks[block_id].apply_image)
449 : : #define XLogRecHasBlockData(decoder, block_id) \
450 : : ((decoder)->record->blocks[block_id].has_data)
451 : :
452 : : #ifndef FRONTEND
453 : : extern FullTransactionId XLogRecGetFullXid(XLogReaderState *record);
454 : : #endif
455 : :
456 : : extern bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page);
457 : : extern char *XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len);
458 : : extern void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id,
459 : : RelFileLocator *rlocator, ForkNumber *forknum,
460 : : BlockNumber *blknum);
461 : : extern bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id,
462 : : RelFileLocator *rlocator, ForkNumber *forknum,
463 : : BlockNumber *blknum,
464 : : Buffer *prefetch_buffer);
465 : :
466 : : #endif /* XLOGREADER_H */
|