/*
 * multixact.h
 *
 * PostgreSQL multi-transaction-log manager
 *
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/multixact.h
 */
#ifndef MULTIXACT_H
#define MULTIXACT_H

#include "access/xlogreader.h"
#include "lib/stringinfo.h"

#define InvalidMultiXactId UINT64CONST(0)
#define FirstMultiXactId UINT64CONST(1)
#define MaxMultiXactId UINT64CONST(0xFFFFFFFFFFFFFFFF)

#define MultiXactIdIsValid(multi) ((multi) != InvalidMultiXactId)

#define MaxMultiXactOffset UINT64CONST(0xFFFFFFFFFFFFFFFF)

#define MULTIXACTDIR (g_instance.datadir_cxt.multixactDir)

/*
 * Possible multixact lock modes ("status").  The first four modes are for
 * tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the
 * next two are used for update and delete modes.
 */
typedef enum {
        MultiXactStatusForShare = 0x00,  /* set FOR_SHARE = 0 here for compatibility */
        MultiXactStatusForKeyShare = 0x01,
        MultiXactStatusForNoKeyUpdate = 0x02,
        MultiXactStatusForUpdate = 0x03,
        /* an update that doesn't touch "key" columns */
        MultiXactStatusNoKeyUpdate = 0x04,
        /* other updates, and delete */
        MultiXactStatusUpdate = 0x05
} MultiXactStatus;

#define MaxMultiXactStatus MultiXactStatusUpdate

/* does a status value correspond to a tuple update? */
#define ISUPDATE_from_mxstatus(status) \
                        ((status) > MultiXactStatusForUpdate)

typedef struct MultiXactMember {
        TransactionId xid;
        MultiXactStatus status;
} MultiXactMember;

/*
 * In htup.h, we define MaxTransactionId, and first four bits are reserved.
 * We use low 60 bits to record member xid and high 3 bits to record member status.
 */
#define MULTIXACT_MEMBER_XID_MASK UINT64CONST((UINT64CONST(1) << 60) - 1)
#define GET_MEMBER_XID_FROM_SLRU_XID(xid) ((xid) & MULTIXACT_MEMBER_XID_MASK)
#define GET_MEMBER_STATUS_FROM_SLRU_XID(xid) (MultiXactStatus((xid) >> 61))
#define GET_SLRU_XID_FROM_MULTIXACT_MEMBER(member) \
    (((TransactionId)((member)->status) << 61) | (((member)->xid) & MULTIXACT_MEMBER_XID_MASK))

/*
 * Defines for MultiXactOffset page sizes.	A page is the same BLCKSZ as is
 * used everywhere else in openGauss.
 *
 * We need four bytes per offset and also four bytes per member
 */
#define MULTIXACT_OFFSETS_PER_PAGE (BLCKSZ / sizeof(MultiXactOffset))
#define MULTIXACT_MEMBERS_PER_PAGE (BLCKSZ / sizeof(TransactionId))

#define MultiXactIdToOffsetPage(xid) ((xid) / (MultiXactOffset)MULTIXACT_OFFSETS_PER_PAGE)
#define MultiXactIdToOffsetEntry(xid) ((xid) % (MultiXactOffset)MULTIXACT_OFFSETS_PER_PAGE)

#define MXOffsetToMemberPage(xid) ((xid) / (TransactionId)MULTIXACT_MEMBERS_PER_PAGE)
#define MXOffsetToMemberEntry(xid) ((xid) % (TransactionId)MULTIXACT_MEMBERS_PER_PAGE)


/* ----------------
 *		multixact-related XLOG entries
 * ----------------
 */

#define XLOG_MULTIXACT_ZERO_OFF_PAGE 0x00
#define XLOG_MULTIXACT_ZERO_MEM_PAGE 0x10
#define XLOG_MULTIXACT_CREATE_ID 0x20

#define XLOG_MULTIXACT_MASK 0x70
#define XLOG_MULTIXACT_INT64_PAGENO 0x80

#define MULTIXACT_OFFSET_BUFFERS (g_instance.attr.attr_storage.num_slru_buffers[MUTLIXACT_OFFSET])
#define MULTIXACT_MEMBER_BUFFERS (g_instance.attr.attr_storage.num_slru_buffers[MULTIXACT_MEMBER])

typedef struct xl_multixact_create {
    MultiXactId mid;                           /* new MultiXact's ID */
    MultiXactOffset moff;                      /* its starting offset in members file */
    int32 nxids;                               /* number of member XIDs */
    TransactionId xids[FLEXIBLE_ARRAY_MEMBER]; /* low 60 bits record member xid, high 3 bits record member status */
} xl_multixact_create;

#define MinSizeOfMultiXactCreate offsetof(xl_multixact_create, xids)

MultiXactId MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
    TransactionId xid2, MultiXactStatus status2);
extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status);
extern bool MultiXactIdIsRunning(MultiXactId multi);
extern bool MultiXactIdIsCurrent(MultiXactId multi);
extern MultiXactId ReadNextMultiXactId(void);
extern bool DoMultiXactIdWait(MultiXactId multi, MultiXactStatus status, int *remaining, bool nowait, int waitSec = 0);
extern void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, int *remaining, int waitSec = 0);
extern bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status, int *remaining);
extern void MultiXactIdSetOldestMember(void);
extern int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember** members);

extern void AtEOXact_MultiXact(void);
extern void AtPrepare_MultiXact(void);
extern void PostPrepare_MultiXact(TransactionId xid);

extern Size MultiXactShmemSize(void);
extern void MultiXactShmemInit(void);
extern void BootStrapMultiXact(void);
extern void StartupMultiXact(void);
extern void ShutdownMultiXact(void);
extern void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid);
extern void MultiXactGetCheckptMulti(bool is_shutdown, MultiXactId* nextMulti, MultiXactOffset* nextMultiOffset);
extern void CheckPointMultiXact(void);
extern MultiXactId GetOldestMultiXactId(void);
extern void TruncateMultiXact(MultiXactId cutoff_multi = InvalidMultiXactId);
extern void MultiXactSetNextMXact(MultiXactId nextMulti, MultiXactOffset nextMultiOffset);
extern void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset);
extern void MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB);

extern void multixact_twophase_recover(TransactionId xid, uint16 info, void* recdata, uint32 len);
extern void multixact_twophase_postcommit(TransactionId xid, uint16 info, void* recdata, uint32 len);
extern void multixact_twophase_postabort(TransactionId xid, uint16 info, void* recdata, uint32 len);

extern void multixact_redo(XLogReaderState* record);
extern void multixact_desc(StringInfo buf, XLogReaderState* record);
extern const char* multixact_type_name(uint8 subtype);
extern void get_multixact_pageno(uint8 info, int64 *pageno, XLogReaderState *record);
extern void SSMultiXactShmemClear(void);

#endif /* MULTIXACT_H */