#include <stdio.h>
#include <stdlib.h>

#define BLCKSZ (8192 * 1)

typedef char bool;
typedef unsigned int uint32;
typedef uint32 TransactionId;
typedef uint32 MultiXactOffset;
typedef unsigned long int uint64;


#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)

#define Min(x, y) ((x) < (y) ? (x) : (y))

#define true	((bool) 1)
#define false	((bool) 0)

#define SLRU_PAGES_PER_SEGMENT	32

#define MXACT_MEMBER_BITS_PER_XACT			8
#define MXACT_MEMBER_FLAGS_PER_BYTE			1
#define MXACT_MEMBER_XACT_BITMASK	((1 << MXACT_MEMBER_BITS_PER_XACT) - 1)

/* how many full bytes of flags are there in a group? */
#define MULTIXACT_FLAGBYTES_PER_GROUP		4
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP	\
		(MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)
/* size in bytes of a complete group */
#define MULTIXACT_MEMBERGROUP_SIZE \
		(sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)
#define MULTIXACT_MEMBERGROUPS_PER_PAGE (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)
#define MULTIXACT_MEMBERS_PER_PAGE	\
		(MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

/*
 * Because the number of items per page is not a divisor of the last item
 * number (member 0xFFFFFFFF), the last segment does not use the maximum number
 * of pages, and moreover the last used page therein does not use the same
 * number of items as previous pages.  (Another way to say it is that the
 * 0xFFFFFFFF member is somewhere in the middle of the last page, so the page
 * has some empty space after that item.)
 *
 * This constant is the number of members in the last page of the last segment.  
 */
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE \
		((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1))

/* page in which a member is to be found */
#define MXOffsetToMemberPage(xid) ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)


#define MXOffsetToFlagsOffset(xid) \
		((((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_MEMBERGROUP) % \
		  	  (TransactionId) MULTIXACT_MEMBERGROUPS_PER_PAGE) * \
		 	 (TransactionId) MULTIXACT_MEMBERGROUP_SIZE)
#define MXOffsetToFlagsBitShift(xid) \
		(((xid) % (TransactionId) MULTIXACT_MEMBERS_PER_MEMBERGROUP) * \
		 	 MXACT_MEMBER_BITS_PER_XACT)

static void
ZeroMultiXactMemberPage(int pageno, bool writeXlog)
{
	printf("zeroing page %u: page %u in segment %05X\n", pageno,
			pageno % SLRU_PAGES_PER_SEGMENT,
			pageno / SLRU_PAGES_PER_SEGMENT);
}

static void
ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
{

	while (nmembers > 0)
	{
		int		flagsoff;
		int		flagsbit;
		uint64	diff64;
		uint32	difference;

		flagsoff = MXOffsetToFlagsOffset(offset);
		flagsbit = MXOffsetToFlagsBitShift(offset);

		if (flagsoff == 0 && flagsbit == 0)
		{
			int		pageno;

			pageno = MXOffsetToMemberPage(offset);

			ZeroMultiXactMemberPage(pageno, true);
		}

		if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
		{
			difference = MaxMultiXactOffset - offset + 1;
		}
		else
			difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;

		nmembers -= difference;
		offset += difference;
	}
}

int
main(int argc, char **argv)
{
	MultiXactOffset	offset;
	int		stepsize;

	if (argc != 3)
	{
		fprintf(stderr, "arguments: initial_offset step_size\n");
		exit(0);
	}

	offset = strtoul(argv[1], NULL, 10);
	printf("initial offset: %u\n", offset);

	stepsize = strtoul(argv[2], NULL, 10);
	printf("step size: %d\n", stepsize);

	for (; ; offset += stepsize)
		ExtendMultiXactMember(offset, stepsize);

	return 0;
}