/****************************************************************
 *								*
 *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#ifndef __MLKDEF_H__
#define __MLKDEF_H__

/* mlkdef.h */

#include <sys/types.h>

typedef struct	mlk_tp_struct
{
	struct mlk_tp_struct	*next;		/* next stacking struct */
	unsigned int		level : 9;	/* incremental lock level */
	unsigned int		zalloc : 1;	/* if true, there is a ZALLOC posted for this lock */
	unsigned int		tplevel : 8;	/* $TLEVEL when this was stacked */
	unsigned int		unused : 14;	/* ** Reserved ** */
} mlk_tp;

typedef struct				/* One of these nodes is required for each process which is blocked on a lock */
{
        ptroff_t	next;		/* relative pointer to the next mlk_prcblk.  If the entry is in the free
					 * list, then this is a relative pointer to the next free entry. */
	uint4		process_id;	/* the pid of the blocked process */
	short		ref_cnt;	/* number of times process references prcblk */
	unsigned short	unlock;		/* boolean to indicate activity on lock */
} mlk_prcblk;

typedef struct				/* lock node.  The member descriptions below are correct if the entry
					 * is in the tree.  If the entry is in the free list, then all
					 * of the members are meaningless, except for rsib, which is a
					 * relative pointer to the next item in the free list */
{
	ptroff_t	value;		/* relative pointer to the shrsub for this node (always present) */
	ptroff_t	parent;		/* relative pointer to the parent node (zero if name level) */
	ptroff_t	children;	/* relative pointer to the eldest child of this node (zero if none) */
	ptroff_t	lsib;		/* relative pointers to the "left sibling" and "right sibling" */
	ptroff_t	rsib;		/* note that each level of the tree is sorted, for faster lookup */
	ptroff_t	pending;	/* relative pointer to a mlk_prcblk, or zero if no entries are are blocked on this node */
	int4		owner;		/* process id of the owner, if zero, this node is un-owned, and there
					 * must, by defintion, be either a non-zero 'pending' entry, or a
					 * non-zero 'children' entry and in the latter case, at least one
					 * child must have a 'pending' entry */
	uint4		sequence;	/* The sequence number at the time that this node was created.  If
					 * during a direct re-access via pointer from a mlk_pvtblk, the
					 * sequence numbers do not match, then we must assume that the
					 * lock was stolen from us by LKE or some other abnormal event. */
	UINTPTR_T	auxowner;	/* For gt.cm, this contains information on the remote owner of the lock.*/
	int4		image_count;	/* the number of image activiations since login */
	int4		login_time;	/* the low-order 32 bits of the time that the process logged in.  login_time
					 * and image_count can be used together to determine whether the process has
					 * abnormally terminated. */
	int4		auxpid;		/* If non-zero auxowner, this is the pid of the client that is holding the lock */
	unsigned char	auxnode[16];	/* If non-zero auxowner, this is the nodename of the client that is holding the lock */
} mlk_shrblk;

typedef struct				/* the subscript value of a single node in a tree.  Stored separately so that
					 * the mlk_shrblk's can all have fixed positions, and yet we can
					 * efficiently store variable length subscripts. Each entry is rounded to
					 * a length of 4 bytes to eliminiate unaligned references. */
{
	ptroff_t	backpointer;	/* relative pointer to mlk_shrblk which owns this entry, so that we can
					 * efficiently compress the space.  If this is zero, then the item is
					 * an abandon entry. */
	unsigned char	length;		/* length of the data */
	unsigned char	data[1];	/* the data itself, actually data[length] */
} mlk_shrsub;

/* WARNING:  GT.CM and GT.CX rely on the fact that this structure is at the start of the lock space
 * and that the array of pids is at the top of this structure */
#define NUM_CLST_LCKS 64

typedef struct	mlk_ctldata_struct	/* this describes the entire shared lock section */
{
	ptroff_t	prcfree;		/* relative pointer to the first empty mlk_prcblk */
	ptroff_t	blkfree;		/* relative pointer to the first free mlk_shrblk.
						 * if zero, the blkcnt must also equal zero */
	ptroff_t	blkroot;		/* relative pointer to the first name level mlk_shrblk.
						 * if zero, then there are no locks in this section */
	ptroff_t	subbase;		/* relative pointer to the base of the mlk_shrsub area */
	ptroff_t	subfree;		/* relative pointer to the first free cell in the shrsub area */
	ptroff_t	subtop;			/* relative pointer to the top of the shrsub area */
	uint4		max_prccnt;		/* maximum number of entries in the prcfree chain */
	uint4		max_blkcnt;		/* maximum number of entires in the blkfree chain */
	int4		prccnt;			/* number of entries in the prcfree chain */
	int4		blkcnt;			/* number of entires in the blkfree chain */
	uint4		clus_pids[NUM_CLST_LCKS];	/* Pids of processes on other machines in the cluster to be woken up */
	unsigned int	wakeups;			/* lock wakeup counter */
} mlk_ctldata;

/* Define types for shared memory resident structures */

#ifdef DB64
# ifdef __osf__
#  pragma pointer_size(save)
#  pragma pointer_size(long)
# else
#  error UNSUPPORTED PLATFORM
# endif
#endif

typedef mlk_prcblk	*mlk_prcblk_ptr_t;
typedef mlk_shrblk	*mlk_shrblk_ptr_t;
typedef mlk_shrsub	*mlk_shrsub_ptr_t;
typedef mlk_ctldata	*mlk_ctldata_ptr_t;

#ifdef DB64
# ifdef __osf__
#  pragma pointer_size(restore)
# endif
#endif

/* Now define main private lock structure */

typedef struct	mlk_pvtblk_struct	/* one of these entries exists for each nref which is locked or being processed */
{
	mlk_ctldata_ptr_t	ctlptr;		/* pointer to the mlk_ctldata for the data base region, duplicated to save
							 * recalculating it each time. */
	mlk_shrblk_ptr_t	nodptr;			/* pointer to the node in the shared data structure which corresponds to
							 * this nref */
	mlk_shrblk_ptr_t	blocked;		/* pointer to the node in the shared data structure which blocked this
							 * operation */
	struct mlk_pvtblk_struct
				*next;			/* pointer to the next mlk_pvtblk in this chain.  The chain may be temporary
							 * if lock processing is underway, or permanent, in which case the chain
							 * represents owned locks. */
	struct gd_region_struct	*region;		/* pointer to the database region in which the lock belongs */
	uint4			sequence;		/* shrblk sequence for nodptr node (node we want) */
	uint4			blk_sequence;		/* shrblk sequence for blocked node (node preventing our lock) */
	mlk_tp			*tp;			/* pointer to saved tp information */
	uint4			total_length;		/* the total length of the 'value' string. */
	uint4			total_len_padded;	/* Length with padding to 4 bytes for each substring */
	unsigned short		subscript_cnt;		/* the number of subscripts (plus one for the name) in this nref */
	unsigned		level : 9;		/* incremental lock level */
	unsigned		zalloc : 1;		/* if true, there is a ZALLOC posted for this lock */
	unsigned		granted : 1;		/* if true, the lock has been granted in the database */
	unsigned		unused : 5;		/* ** Unused ** the number of bits in the bit-fields add up to
								only 16, therefore although they have type unsigned,
								they are accommodated within 2 bytes. Since there is
								no type for bit-fields, unsigned should be the only
								type specified and alignment works according to the
								total number of bits */
	unsigned char		trans;			/* boolean indicating whether already in list */
	unsigned char		translev;		/* level for transaction (accounting for redundancy) */
	unsigned char		old;			/* oldness boolean used for backing out zallocates */
	unsigned char		filler[1];		/* Fill out to align data on word boundary */

	unsigned char		value[1];		/* actually, an array unsigned char value[total_length].  This string
							 * consists of the nref's subscripts each preceeded by the length of
							 * the subscript, held as a single byte.  For example, ^A(45), would be
							 * represented as 02 5E 41 02 34 35, and total length would be 5. */
} mlk_pvtblk;

/* convert relative pointer to absolute pointer */
#define R2A(X) (((sm_uc_ptr_t) &(X)) + (X))

/* store absolute pointer Y in X as a relative pointer */
#define A2R(X, Y) ((X) = (ptroff_t)(((sm_uc_ptr_t)(Y)) - ((sm_uc_ptr_t) &(X))))

/* compute the true size of a mlk_pvtblk */
#define MLK_PVTBLK_SIZE(DLEN, SCNT) (SIZEOF(mlk_pvtblk) - 1 + (DLEN) + (SCNT))

/* compute the true size of a mlk_shrsub include stddef.h*/
#define MLK_SHRSUB_SIZE(X) (ROUND_UP(OFFSETOF(mlk_shrsub, data[0]) + (X)->length, SIZEOF(ptroff_t)))
/* SIZEOF(ptroff_t) - 1 is used for padding because mlk_shrblk_create() ROUND_UPs to SIZEOF(ptroff_t) aligned boundary */
#define MLK_PVTBLK_SHRSUB_SIZE(PVTBLK, SHRSUBNEED) \
(SHRSUBNEED * (OFFSETOF(mlk_shrsub, data[0]) + SIZEOF(ptroff_t) - 1) + PVTBLK->total_length)

#define DEF_LOCK_SIZE OS_PAGELET_SIZE * 200

typedef struct mlk_stats_struct
{
	gtm_uint64_t	n_user_locks_success;
	gtm_uint64_t	n_user_locks_fail;
} mlk_stats_t;

#endif
