File: gds_blk_upgrade.h

package info (click to toggle)
fis-gtm 6.3-014-3
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 36,680 kB
  • sloc: ansic: 333,039; asm: 5,180; csh: 4,956; sh: 1,924; awk: 291; makefile: 66; sed: 13
file content (130 lines) | stat: -rwxr-xr-x 8,269 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/****************************************************************
 *								*
 *	Copyright 2005, 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 GDS_BLK_UPGRADE_INCLUDED
#define GDS_BLK_UPGRADE_INCLUDED

#define UPGRADE_IF_NEEDED	0	/* default */
#define UPGRADE_NEVER		1
#define UPGRADE_ALWAYS		2

int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 bsiz, enum db_ver *ondsk_blkver);

GBLREF	uint4		gtm_blkupgrade_flag;	/* control whether dynamic upgrade is attempted or not */
GBLREF	boolean_t	dse_running;

/* See if block needs to be converted to current version. Assume buffer is at least short aligned.
 * Note: csd->fully_upgraded is not derived within the macro but instead passed in as a parameter to ensure whichever
 * function (dsk_read currently) references this does that once and copies the value into a local variable that is used
 * in all further usages. This way multiple usages are guaranteed to see the same value. Using csd->fully_upgraded in
 * each of those cases could cause different values to be seen (since csd can be concurrently updated).
 */
#define GDS_BLK_UPGRADE_IF_NEEDED(blknum, srcbuffptr, trgbuffptr, curcsd, ondskblkver, upgrdstatus, fully_upgraded)		\
{																\
	/* In order to detect if a block needs to be upgraded or not, we do the following series of tests.			\
	 * If DSE, the variable "gtm_blkupgrade_flag" controls whether upgrade is attempted or not.				\
	 *	If it is UPGRADE_NEVER, we never attempt upgrade.								\
	 *	Likewise, if it is UPGRADE_ALWAYS, we unconditionally upgrade.							\
	 *	If it is UPGRADE_IF_NEEDED, then the following checks are done.							\
	 * 1) If the file-header has "fully_upgraded" set to TRUE, we know for sure no block needs to be upgraded.		\
	 *    This check is performed in this macro itself as it is a quick check and avoids a function call.			\
	 * 2) Else, the block might or might not need an upgrade. To decide, we do some more checks.				\
	 *    V5 onwards, the first 2 bytes of the block header is the version indicator. It is 1 in V5.			\
	 *    In V4, the first 2 bytes of the block header was the block-size which is guaranteed to be				\
	 *    at least SIZEOF(v15_blk_hdr) (the size of the V4 blk_hdr structure) which is 8 bytes in Unix			\
	 *    and 7 bytes in VMS. We use the first 2 bytes in the block header as a first level check.				\
	 *    If they are >= SIZEOF(v15_blk_hdr), we decide it is a V4 format block and try to upgrade.				\
	 *    This check is performed in this macro itself as it is a quick check and avoids a function call.			\
	 * 3) It is quite possible that we might conclude the format incorrectly based on just the above checks.		\
	 *	This can be due to any one of the following.									\
	 *	 => A V4 format block might have a corrupt block-header where the first 2 bytes are exactly 1.			\
	 *	 => A V5 format block might have a corrupt block-header where the first 2 bytes are not 1.			\
	 *	 => We might be reading an unused block (marked free/recycled in the bitmap) from disk.				\
	 *	    This is possible due to a variety of reasons including concurrency issues while				\
	 *		traversing the B-tree that cause us to end up in a restartable situation.				\
	 *	    If we read such a block, then the block contents (including the header) is not valid.			\
	 *	    In VMS it contains uninitialized data. In Unix it contains 0s.						\
	 *	In all the above cases, we have no definitive way of determining exactly which format the block is.		\
	 *	For the case where we incorrectly conclude it is V5 format, we dont do much.					\
	 *	But for the other case, we do better by checking if the V4 block has enough room to accommodate			\
	 *		the extra space needed for the upgrade.									\
	 *	If yes, we go ahead with the upgrade.										\
	 *	If not, we check if the V4 block size is less than the database block size.					\
	 *		If yes, then we believe it is a valid V4 block that is just too big to be upgraded.			\
	 *			We therefore issue a DYNUPGRDFAIL error.							\
	 *		If no, this is a corrupt block and we decide not to upgrade.						\
	 *	Something to consider for the future is to invoke block certification on this block.				\
	 *    This check is involved and hence is done in the function "gds_blk_upgrade" (invoked from this macro).		\
	 * This is not a theoretically foolproof solution but for all practical purposes should be good enough.			\
	 * Note that for a database that has been completely upgraded to V5 format, we do not have any inconclusiveness.	\
	 *															\
	 * Note the clearing of srcbuffptr is done as a flag that gds_blk_upgrd was run (used by dsk_read).			\
	 */															\
	if (!dse_running || (UPGRADE_IF_NEEDED == gtm_blkupgrade_flag))								\
	{															\
		if ((fully_upgraded) || (SIZEOF(v15_blk_hdr) > ((v15_blk_hdr_ptr_t)(srcbuffptr))->bsiz))			\
		{														\
			upgrdstatus = SS_NORMAL;										\
			if (NULL != (void *)(ondskblkver))									\
				*(ondskblkver) = GDSV6;										\
		} else														\
		{														\
			upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr),			\
						      (curcsd)->blk_size, (ondskblkver));					\
                        if (srcbuffptr != trgbuffptr)										\
                                srcbuffptr = NULL;										\
		}														\
	} else if (UPGRADE_NEVER == gtm_blkupgrade_flag)									\
	{															\
		upgrdstatus = SS_NORMAL;											\
		if (NULL != (void *)(ondskblkver))										\
			*(ondskblkver) = GDSV6;											\
	} else if (UPGRADE_ALWAYS == gtm_blkupgrade_flag)									\
	{															\
		upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr),				\
					      (curcsd)->blk_size, (ondskblkver));						\
		if (NULL != (void *)(ondskblkver))										\
			*(ondskblkver) = GDSV4;											\
                if (srcbuffptr != trgbuffptr)											\
                        srcbuffptr = NULL;											\
	}															\
}

/* This macro is invoked by dsk_read.c when we know for sure we are reading a valid block. This checks that the block
 * we read from disk contains a valid block header. It also checks that we CANNOT have read a V4 format reused block
 * if the database has been fully upgraded. It uses checks similar to those used in the GDS_BLK_UPGRADE_IF_NEEDED
 * macro to determine if it is a V4 or V5 format block header.
 * Note: csd->fully_upgraded is not derived within the macro but instead passed in as a parameter to ensure whichever
 * function (dsk_read currently) references this does that once and copies the value into a local variable that is used
 * in all further usages. This way multiple usages are guaranteed to see the same value. Using csd->fully_upgraded in
 * each of those cases could cause different values to be seen (since csd can be concurrently updated).
 */
#define	GDS_BLK_HDR_CHECK(csd, v5_blk_hdr, fully_upgraded)								\
{															\
	v15_blk_hdr_ptr_t	v4_blk_hdr;										\
															\
	v4_blk_hdr = (v15_blk_hdr_ptr_t)v5_blk_hdr;									\
	if (!(fully_upgraded) || (SIZEOF(v15_blk_hdr) > v4_blk_hdr->bsiz))						\
	{	/* V5 formatted buffer in shared memory (even though might be V4 format in disk) */			\
		assert((unsigned)GDSVLAST > (unsigned)v5_blk_hdr->bver);						\
		assert((LCL_MAP_LEVL == v5_blk_hdr->levl) || ((unsigned)MAX_BT_DEPTH > (unsigned)v5_blk_hdr->levl));	\
		assert((unsigned)size >= (unsigned)v5_blk_hdr->bsiz);							\
		assert(csd->trans_hist.curr_tn >= v5_blk_hdr->tn);							\
	} else														\
	{	/* V4 formatted buffer in shared memory (not converted because fully_upgraded is TRUE).			\
		 * Possible if we are reading a recycled block that is in V4 format from a fully upgraded database.	\
		 * But all recycled blocks are now upgraded by MUPIP REORG UPGRADE so this should be impossible.	\
		 */													\
		assert(FALSE);												\
	}														\
}

#endif