#ifndef XLOG_INTERNAL_H
#define XLOG_INTERNAL_H
#include "access/xlogdefs.h"
#include "access/xlogreader.h"
#include "datatype/timestamp.h"
#include "lib/stringinfo.h"
#include "pgtime.h"
#include "storage/block.h"
#include "storage/relfilelocator.h"
#define XLOG_PAGE_MAGIC 0xD116
typedef struct XLogPageHeaderData
{
uint16 xlp_magic;
uint16 xlp_info;
TimeLineID xlp_tli;
XLogRecPtr xlp_pageaddr;
uint32 xlp_rem_len;
} XLogPageHeaderData;
#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData))
typedef XLogPageHeaderData *XLogPageHeader;
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std;
uint64 xlp_sysid;
uint32 xlp_seg_size;
uint32 xlp_xlog_blcksz;
} XLogLongPageHeaderData;
#define SizeOfXLogLongPHD MAXALIGN(sizeof(XLogLongPageHeaderData))
typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define XLP_FIRST_IS_CONTRECORD 0x0001
#define XLP_LONG_HEADER 0x0002
#define XLP_BKP_REMOVABLE 0x0004
#define XLP_FIRST_IS_OVERWRITE_CONTRECORD 0x0008
#define XLP_ALL_FLAGS 0x000F
#define XLogPageHeaderSize(hdr) \
(((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD)
#define WalSegMinSize 1024 * 1024
#define WalSegMaxSize 1024 * 1024 * 1024
#define DEFAULT_MIN_WAL_SEGS 5
#define DEFAULT_MAX_WAL_SEGS 64
#define IsPowerOf2(x) (x > 0 && ((x) & ((x)-1)) == 0)
#define IsValidWalSegSize(size) \
(IsPowerOf2(size) && \
((size) >= WalSegMinSize && (size) <= WalSegMaxSize))
#define XLogSegmentsPerXLogId(wal_segsz_bytes) \
(UINT64CONST(0x100000000) / (wal_segsz_bytes))
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest) \
(dest) = (segno) * (wal_segsz_bytes) + (offset)
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes) \
((xlogptr) & ((wal_segsz_bytes) - 1))
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes) \
logSegNo = (xlrp) / (wal_segsz_bytes)
#define XLByteToPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \
logSegNo = ((xlrp) - 1) / (wal_segsz_bytes)
#define XLogMBVarToSegs(mbvar, wal_segsz_bytes) \
((mbvar) / ((wal_segsz_bytes) / (1024 * 1024)))
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes) \
(((xlrp) / (wal_segsz_bytes)) == (logSegNo))
#define XLByteInPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \
((((xlrp) - 1) / (wal_segsz_bytes)) == (logSegNo))
#define XRecOffIsValid(xlrp) \
((xlrp) % XLOG_BLCKSZ >= SizeOfXLogShortPHD)
#define XLOGDIR "pg_wal"
#define XLOG_CONTROL_FILE "global/pg_control"
#define MAXFNAMELEN 64
#define XLOG_FNAME_LEN 24
static inline void
XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
{
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli,
(uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
}
static inline void
XLogFileNameById(char *fname, TimeLineID tli, uint32 log, uint32 seg)
{
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg);
}
static inline bool
IsXLogFileName(const char *fname)
{
return (strlen(fname) == XLOG_FNAME_LEN && \
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN);
}
static inline bool
IsPartialXLogFileName(const char *fname)
{
return (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") &&
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
strcmp(fname + XLOG_FNAME_LEN, ".partial") == 0);
}
static inline void
XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
{
uint32 log;
uint32 seg;
sscanf(fname, "%08X%08X%08X", tli, &log, &seg);
*logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg;
}
static inline void
XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
{
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli,
(uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)));
}
static inline void
TLHistoryFileName(char *fname, TimeLineID tli)
{
snprintf(fname, MAXFNAMELEN, "%08X.history", tli);
}
static inline bool
IsTLHistoryFileName(const char *fname)
{
return (strlen(fname) == 8 + strlen(".history") &&
strspn(fname, "0123456789ABCDEF") == 8 &&
strcmp(fname + 8, ".history") == 0);
}
static inline void
TLHistoryFilePath(char *path, TimeLineID tli)
{
snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli);
}
static inline void
StatusFilePath(char *path, const char *xlog, const char *suffix)
{
snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix);
}
static inline void
BackupHistoryFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
{
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli,
(uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)));
}
static inline bool
IsBackupHistoryFileName(const char *fname)
{
return (strlen(fname) > XLOG_FNAME_LEN &&
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
strcmp(fname + strlen(fname) - strlen(".backup"), ".backup") == 0);
}
static inline void
BackupHistoryFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes)
{
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli,
(uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)),
(uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)));
}
typedef struct xl_parameter_change
{
int MaxConnections;
int max_worker_processes;
int max_wal_senders;
int max_prepared_xacts;
int max_locks_per_xact;
int wal_level;
bool wal_log_hints;
bool track_commit_timestamp;
} xl_parameter_change;
typedef struct xl_restore_point
{
TimestampTz rp_time;
char rp_name[MAXFNAMELEN];
} xl_restore_point;
typedef struct xl_overwrite_contrecord
{
XLogRecPtr overwritten_lsn;
TimestampTz overwrite_time;
} xl_overwrite_contrecord;
typedef struct xl_end_of_recovery
{
TimestampTz end_time;
TimeLineID ThisTimeLineID;
TimeLineID PrevTimeLineID;
int wal_level;
} xl_end_of_recovery;
typedef struct XLogRecData
{
struct XLogRecData *next;
char *data;
uint32 len;
} XLogRecData;
typedef enum
{
RECOVERY_TARGET_ACTION_PAUSE,
RECOVERY_TARGET_ACTION_PROMOTE,
RECOVERY_TARGET_ACTION_SHUTDOWN,
} RecoveryTargetAction;
struct LogicalDecodingContext;
struct XLogRecordBuffer;
typedef struct RmgrData
{
const char *rm_name;
void (*rm_redo) (XLogReaderState *record);
void (*rm_desc) (StringInfo buf, XLogReaderState *record);
const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
void (*rm_mask) (char *pagedata, BlockNumber blkno);
void (*rm_decode) (struct LogicalDecodingContext *ctx,
struct XLogRecordBuffer *buf);
} RmgrData;
extern PGDLLIMPORT RmgrData RmgrTable[];
extern void RmgrStartup(void);
extern void RmgrCleanup(void);
extern void RmgrNotFound(RmgrId rmid);
extern void RegisterCustomRmgr(RmgrId rmid, const RmgrData *rmgr);
#ifndef FRONTEND
static inline bool
RmgrIdExists(RmgrId rmid)
{
return RmgrTable[rmid].rm_name != NULL;
}
static inline RmgrData
GetRmgr(RmgrId rmid)
{
if (unlikely(!RmgrIdExists(rmid)))
RmgrNotFound(rmid);
return RmgrTable[rmid];
}
#endif
extern pg_time_t GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN);
extern XLogRecPtr RequestXLogSwitch(bool mark_unimportant);
extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli);
extern void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
bool detailed_format, StringInfo buf,
uint32 *fpi_len);
extern PGDLLIMPORT bool ArchiveRecoveryRequested;
extern PGDLLIMPORT bool InArchiveRecovery;
extern PGDLLIMPORT bool StandbyMode;
extern PGDLLIMPORT char *recoveryRestoreCommand;
#endif