File: gvcst_blk_search.h

package info (click to toggle)
fis-gtm 6.3-007-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 36,284 kB
  • sloc: ansic: 328,861; asm: 5,182; csh: 5,102; sh: 1,918; awk: 291; makefile: 69; sed: 13
file content (371 lines) | stat: -rw-r--r-- 12,808 bytes parent folder | download | duplicates (2)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/****************************************************************
 *								*
 * Copyright (c) 2015-2018 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	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.	*
 *								*
 ****************************************************************/
/*
 * --------------------------------------------------
 * Search for a key in the block
 *
 * Return:
 *	cdb_sc_normal	 - success
 *	cdb_sc_badoffset - record with 0 length encountered,
 *			   possibly a corrupt block
 *	cdb_sc_blklenerr - end of block reached without match
 * --------------------------------------------------
 */

GBLREF	sgmnt_data_ptr_t	cs_data;
GBLREF	gv_namehead		*gv_target;
GBLREF	uint4			dollar_tlevel;

#ifndef GVCST_SEARCH_EXPAND_PREVKEY
#	ifdef GVCST_SEARCH_BLK
	enum cdb_sc 	gvcst_search_blk(gv_key *pKey, srch_blk_status *pStat)
#	endif
#	ifdef GVCST_SEARCH_TAIL
	/* gvcst_search_tail is the "start anywhere" version of gvcst_search_blk.
	 * Currently this is called only for level-0 blocks. The below logic is coded with this assumption.
	 * Getting started is a bit awkward, so excuse the gotos.
	 */
	enum cdb_sc	gvcst_search_tail(gv_key *pKey, srch_blk_status *pStat, gv_key *pOldKey)
#	endif
#else
#	ifdef GVCST_SEARCH_BLK
	GBLREF	gv_key	*gv_altkey;
	/* "gvcst_search_blk_expand_prevkey" is the same as "gvcst_search_blk" except this search happens on a level0 block
	 * and sets gv_altkey to fully expanded key corresponding to pStat->prev_rec. This avoids a later call to gvcst_expand_key,
	 * which would imply TWO searches of the block, and instead does the job with ONE search.
	 */
	enum cdb_sc 	gvcst_search_blk_expand_prevkey(gv_key *pKey, srch_blk_status *pStat)
#	endif
#	ifdef GVCST_SEARCH_TAIL
	/* "gvcst_search_tail_expand_prevkey" is the same as "gvcst_search_tail" except this search sets gv_altkey to the fully
	 * expanded key corresponding to pStat->prev_rec. This avoids a later call to gvcst_expand_key, which would imply
	 * TWO searches of the block, and instead does the job with ONE search.
	 */
	enum cdb_sc	gvcst_search_tail_expand_prevkey(gv_key *pKey, srch_blk_status *pStat, gv_key *pOldKey)
#	endif
#endif
{
	/* register variables named in perceived order of declining impact */
	register int		nFlg, nTargLen, nMatchCnt, nTmp;
	sm_uc_ptr_t		pBlkBase, pRecBase, pTop, pRec, pPrevRec;
	unsigned char		*pCurrTarg, *pTargKeyBase;
#	ifdef GVCST_SEARCH_TAIL
	unsigned char		*pOldKeyBase, *pCurrTargPos;
	int			tmp_cmpc;
#		ifdef GVCST_SEARCH_EXPAND_PREVKEY
		gv_key		*prevKey;
		enum cdb_sc	status;
#		endif
#	endif
	unsigned short		nRecLen;
#	ifdef GVCST_SEARCH_BLK
	boolean_t		level0;
#	endif
#	ifdef GVCST_SEARCH_EXPAND_PREVKEY
	int			prevKeyCmpLen;	/* length of compressed portion of prevKey stored in gv_altkey->base */
	int			prevKeyUnCmpLen;/* Length of uncompressed portion of prevKey */
	sm_uc_ptr_t		prevKeyUnCmp;	/* pointer to beginning of uncompressed portion of prevKey */
	unsigned char		*prevKeyStart;	/* pointer to &gv_altkey->base[0] */
	unsigned char		*prevKeyTop;	/* pointer to allocated end of gv_altkey */
	unsigned char		*tmpPtr;
#	else
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
#	endif
#	if defined(GVCST_SEARCH_TAIL) && !defined(GVCST_SEARCH_EXPAND_PREVKEY)
	assert(0 < memcmp(pKey->base, pOldKey->base, pKey->end + 1));	/* below code assumes this is ensured by caller */
	if (0 == pStat->prev_rec.offset)
		return gvcst_search_blk(pKey, pStat);	/* nice clean start at the begining of a block */
#	endif
	/* The following load code (and code in a few other places) is coded in a "assembler" style
	 * in an attempt to encourage the compiler to get it efficient.
	 * For instance, memory and non-memory instructions are interlaced to encourage pipelining.
	 * Of course a great compiler doesn't need help, but this is portable code and ...
	 */
	DBG_CHECK_SRCH_HIST_AND_CSE_BUFFER_MATCH(pStat);
	pBlkBase = pStat->buffaddr;
#	ifndef GVCST_SEARCH_EXPAND_PREVKEY
#		ifdef GVCST_SEARCH_BLK
		level0 = (0 == ((blk_hdr_ptr_t)pBlkBase)->levl);
		if (level0 && TREF(expand_prev_key))
			return gvcst_search_blk_expand_prevkey(pKey, pStat);
#		endif
#		ifdef GVCST_SEARCH_TAIL
		if (TREF(expand_prev_key))
			return gvcst_search_tail_expand_prevkey(pKey, pStat, pOldKey);
#		endif
#	else
		prevKeyStart = &gv_altkey->base[0];
		prevKeyTop = &gv_altkey->base[gv_altkey->top];
#		ifdef GVCST_SEARCH_BLK
		level0 = TRUE; /* We are in "gvcst_search_blk_expand_prevkey" so we should have been called for a level0 block */
		prevKeyCmpLen = 0;
		prevKeyUnCmp = NULL;
#		endif
#		ifdef GVCST_SEARCH_TAIL
		/* Note: "level0" variable is guaranteed to be TRUE since gvcst_search_tail is currently invoked only for
		 * leaf blocks. We therefore do not compute it like we do in gvcst_search_blk. Assert this assumption.
		 */
		assert(0 == pStat->level);
#		endif
#	endif
	pTop = pBlkBase + MIN(((blk_hdr_ptr_t)pBlkBase)->bsiz, cs_data->blk_size);
	pCurrTarg = pKey->base;
	pTargKeyBase = pCurrTarg;
#	ifdef GVCST_SEARCH_BLK
	pRecBase = pBlkBase;
	nRecLen = SIZEOF(blk_hdr);
	nMatchCnt = 0;
	nTargLen = (int)pKey->end;
	nTargLen++;	/* for the terminating NUL on the key */
#	endif
#	ifdef GVCST_SEARCH_TAIL
	pRecBase = pBlkBase + pStat->curr_rec.offset;
	pRec = pRecBase;
	nMatchCnt = pStat->prev_rec.match;
	pOldKeyBase = pOldKey->base;
	pPrevRec = pBlkBase + pStat->prev_rec.offset;
#		ifdef GVCST_SEARCH_EXPAND_PREVKEY
		prevKey = pStat->blk_target->prev_key;
		if ((NULL == prevKey) || (PREV_KEY_NOT_COMPUTED == prevKey->end))
		{
			status = gvcst_expand_prev_key(pStat, pOldKey, gv_altkey);
			if (cdb_sc_normal != status)
				return status;
			prevKey = gv_altkey;
		} else
		{	/* Since gv_altkey is used elsewhere, ensure that it is in sync with prevKey before performing the search
			 * and returning to the caller.
			 */
			memcpy(gv_altkey->base, prevKey->base, prevKey->end - 1);
		}
		assert(prevKey->end);
		prevKeyCmpLen = prevKey->end - 1;
		prevKeyUnCmp = &prevKey->base[prevKeyCmpLen];
		assert(KEY_DELIMITER == prevKeyUnCmp[0]);
		assert(KEY_DELIMITER == prevKeyUnCmp[1]);
#		endif
	if (pRec >= pTop)
	{	/* Terminated at end of block */
		if (pRec > pTop)
		{
			INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat);
			return cdb_sc_blklenerr;
		}
		if (0 != (nTargLen = nMatchCnt))
		{
			do
			{
				if (*pCurrTarg++ != *pOldKeyBase++)
					break;
			} while (--nTargLen);
		}
		nMatchCnt -= nTargLen;
		nTargLen = 0;
#		ifdef GVCST_SEARCH_EXPAND_PREVKEY
		/* Normally pTop points to an offset in the GDS block. But in this case, we are terminating the
		 * search without a search of the actual block and so we need to point pTop to the same location
		 * where prevKeyUnCmp points and that is prevKey.
		 */
		pTop = &prevKey->base[prevKey->end + 1];	/* + 1 needed to balance pTop-- done at function end */
#		endif
	} else
	{
		nTargLen = pKey->end;
		nTargLen++;		/* for the NUL that terminates the key */
		GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz);
		EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp);
		tmp_cmpc = nTmp;
		nFlg = tmp_cmpc;
		if (0 != nFlg)
		{
			do
			{
				if (0 != (nFlg = *pCurrTarg - *pOldKeyBase++))
					break;
				pCurrTarg++;
			} while (--tmp_cmpc);
			assert(0 <= nFlg); /* because gvcst_search_tail is called ONLY if pTarg->clue.key < pKey */
			if (0 < nFlg)
			{
				nMatchCnt = (int)(pCurrTarg - pTargKeyBase);
				nTargLen -= nMatchCnt;
			}
		}
		if (0 == nFlg)
		{
			tmp_cmpc = nMatchCnt;
			nMatchCnt = (int)(pCurrTarg - pTargKeyBase);
			nTargLen -= nMatchCnt;
			tmp_cmpc -= nMatchCnt;
			if (0 < tmp_cmpc)
			{
				pCurrTargPos = pCurrTarg;
				do
				{
					if (*pCurrTargPos++ != *pOldKeyBase++)
						break;
					nMatchCnt++;
				} while (--tmp_cmpc);
			}
			goto alt_loop_entry;
		}
#	endif
		for (;;)
		{
			pRec = pRecBase + nRecLen;
#			ifdef GVCST_SEARCH_EXPAND_PREVKEY
			if (pRecBase != pBlkBase)
			{	/* nTmp points to the compression count corresponding to pPrevRec */
				if (nTmp > prevKeyCmpLen)
				{
					if (((prevKeyStart + nTmp) >= prevKeyTop) || (NULL == prevKeyUnCmp))
					{
						if (dollar_tlevel)
							TP_TRACE_HIST_MOD(pStat->blk_num, pStat->blk_target, tp_blkmod_gvcst_srch,
									  cs_data, pStat->tn, ((blk_hdr_ptr_t)pBlkBase)->tn,
									  pStat->level);
						else
							NONTP_TRACE_HIST_MOD(pStat, t_blkmod_gvcst_srch);
						return cdb_sc_blkmod;
					}
#					ifdef GVCST_SEARCH_TAIL
					assert((prevKeyUnCmp > pBlkBase)
						|| ((prevKeyUnCmp == &prevKey->base[prevKeyCmpLen])
							&& (prevKeyCmpLen == (prevKey->end - 1))));
#					else
					assert(prevKeyUnCmp > pBlkBase);
#					endif
					memcpy(prevKeyStart + prevKeyCmpLen, prevKeyUnCmp, nTmp - prevKeyCmpLen);
				}
				prevKeyCmpLen = nTmp;
				prevKeyUnCmp = pRecBase + SIZEOF(rec_hdr);
			}
#			endif
			if (pRec >= pTop)
			{	/* Terminated at end of block */
				if (pRec > pTop)	/* If record goes off the end, then block must be bad */
				{
					INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat);
					return cdb_sc_blklenerr;
				}
				nTargLen = 0;
#				ifdef GVCST_SEARCH_BLK
				if (!level0)
					nMatchCnt = 0;	/* star key */
				else
#				endif
				{	/* data block */
					pPrevRec = pRecBase;
					pRecBase = pRec;
				}
				break;
			}
			GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz);
			if (0 == nRecLen)	/* If record length is 0, then block must be bad */
			{
				INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat);
				return cdb_sc_badoffset;
			}
			pPrevRec = pRecBase;
			pRecBase = pRec;
			/* If current compression count > last match, then this record also matches on 'last match' characters.
			 * Keep looping.
			 */
			EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp)
			if (nTmp > nMatchCnt)
				continue;
			if (nTmp < nMatchCnt)
			{	/* Terminate on compression count < previous match, this key is after the target */
#				ifdef GVCST_SEARCH_BLK
				if ((BSTAR_REC_SIZE == nRecLen) && !level0)
					/* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */
					nTargLen = 0;
				else
#				endif
					/* Data block, make match = current compression count */
					nTargLen = nTmp;
				break;
			}
#			ifdef GVCST_SEARCH_TAIL
			alt_loop_entry:
#			endif
			/* Compression count == match count;  Compare current target with current record */
			pRec += SIZEOF(rec_hdr);
			do
			{
				if ((nFlg = *pCurrTarg - *pRec++) != 0)
					break;
				pCurrTarg++;
			} while (--nTargLen);
			if (0 < nFlg)
				nMatchCnt = (int)(pCurrTarg - pTargKeyBase);
			else
			{	/* Key is after target*/
#				ifdef GVCST_SEARCH_BLK
				if ((BSTAR_REC_SIZE == nRecLen) && !level0)
					/* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */
					nTargLen = 0;
				else
#				endif
					nTargLen = (int)(pCurrTarg - pTargKeyBase);
				break;
			}
		}
#	ifdef GVCST_SEARCH_TAIL
	}
#	endif
	pStat->prev_rec.offset = (short)(pPrevRec - pBlkBase);
	pStat->prev_rec.match = (short)nMatchCnt;
	pStat->curr_rec.offset = (short)(pRecBase - pBlkBase);
	pStat->curr_rec.match = (short)nTargLen;
#	ifdef GVCST_SEARCH_EXPAND_PREVKEY
	if (NULL != (tmpPtr = prevKeyUnCmp))	/* Note: Assignment */
	{	/* gv_altkey->base[0] thru gv_altkey->base[prevKeyCmpLen] already holds the compressed portion of prevKey.
		 * Copy over uncompressed portion of prevKey into gv_altkey->base and update gv_altkey->end before returning.
		 */
		pTop--;	/* to check for double KEY_DELIMITER byte sequence without exceeding buffer allocation bounds */
		do
		{
			if (tmpPtr >= pTop)
			{
				if (dollar_tlevel)
					TP_TRACE_HIST_MOD(pStat->blk_num, pStat->blk_target, tp_blkmod_gvcst_srch, cs_data,
							  pStat->tn, ((blk_hdr_ptr_t)pBlkBase)->tn, pStat->level);
				else
					NONTP_TRACE_HIST_MOD(pStat, t_blkmod_gvcst_srch);
				return cdb_sc_blkmod;
			}
			/* It is now safe to do *tmpPtr and *++tmpPtr without worry about exceeding array bounds */
			if ((KEY_DELIMITER == *tmpPtr++) && (KEY_DELIMITER == *tmpPtr))
				break;
		} while (TRUE);
		tmpPtr++;	/* go past second KEY_DELIMITER so that gets copied over to gv_altkey too */
		prevKeyUnCmpLen = tmpPtr - prevKeyUnCmp;
		prevKeyStart += prevKeyCmpLen;
		if (prevKeyStart + prevKeyUnCmpLen > prevKeyTop)
		{
			if (dollar_tlevel)
				TP_TRACE_HIST_MOD(pStat->blk_num, pStat->blk_target, tp_blkmod_gvcst_srch, cs_data, pStat->tn,
						  ((blk_hdr_ptr_t)pBlkBase)->tn, pStat->level);
			else
				NONTP_TRACE_HIST_MOD(pStat, t_blkmod_gvcst_srch);
			return cdb_sc_blkmod;
		}
		memcpy(prevKeyStart, prevKeyUnCmp, prevKeyUnCmpLen);
		gv_altkey->end = prevKeyCmpLen + prevKeyUnCmpLen - 1;	/* remove 2nd KEY_DELIMITER from "end" calculation */
	} else
		gv_altkey->end = 0;
#	endif
	return cdb_sc_normal;
}