Trailing-Edge
-
PDP-10 Archives
-
BB-PBDEB-BB_1990
-
10,7/rms10/rmssrc/utlvfy.b36
There are 11 other files named utlvfy.b36 in the archive. Click here to see a list.
MODULE UTLVFY ( ! Module to verify an index structure of ISAM file
IDENT = '01-01'
) =
BEGIN
! COPYRIGHT (C) 1980
! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS 01754
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY ON A SINGLE
! COMPUTER SYSTEM AND MAY BE COPIED ONLY WITH THE INCLUSION OF THE ABOVE
! COPYRIGHT NOTICE. THIS SOFTWARE, OR ANY OTHER COPIES THEREOF, MAY NOT
! BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON EXCEPT FOR
! USE ON SUCH SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE TERMS. TITLE
! TO AND OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES REMAIN IN DEC.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
! AND SHOULD BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
! CORPORATION.
!
! DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
!
!++
! FACILITY: RMS UTILITY (RMSUTL)
!
! ABSTRACT: This module contains scanning loop for VERIFY.
! It also does fix-ups and shows progress.
!
!
! AUTHOR: S. Cohen CREATION DATE: 23 May 80
!
! MODIFIED BY:
!
!--
!****************** Start RMS-10 V1.1 *********************
!********************* TOPS-10 ONLY ***********************
!
!PRODUCTMODULE SPR
! EDIT EDIT QAR DESCRIPTION
!====== ====== ===== ===========
!
! 100 1 Dev Make declarations for TX$APP and TX$TOUT
! be EXTERNAL ROUTINE so RMS will compile
! under BLISS V4 (RMT, 10/22/85).
! 111 2 Dev (WXD, 3/26/86) Incorporate RMS development
! edit 454 to fix VERIFY problem with scanning
! empty buckets.
! 454 - In SCANBKT, do not scan a bucket with no
! entries, and set PPLEV1 to 0 so that the
! "previous bucket" checks do not take place
! when the succeeding bucket is scanned.
! 113 3 Dev (WXD, 3/31/86) Fix bug in UNCLUTTER that writes
! an RFA over a secondary index id.
!
! 124 4 10-35306 (SMW, 8/8/88) Undo edit 113. Fix problems
! 10-35629 happening when CHKDUP called by SIDRSCAN
! complains about duplicates causing SIDRADJ
! to write over random memory. Add debugging
! statements. Add dot to v$err reference.
! Goes with RMS-20 edit 471.
! REQUIRE FILES:
!
REQUIRE
'SYS:RMSINT';
LIBRARY
'RMSLIB';
EXTERNAL ROUTINE
TX$APP : macrosub,
TX$TOUT : macrosub;
!!! MACROS:
! U$*** - INTERFACE TO $UTLINT (EXTERNAL ACCESS TO RMS ROUTINES)
!
! U$BOTH - CALL $UTLINT & FALL THRU
! U$IFF - CALL $UTLINT IN RMS & TEST FOR FAILURE
! U$IFS - CALL $UTLINT IN RMS & TEST FOR SUCCESS
! U$SUC - CALL $UTLINT & ABORT IF FAILURE
!
! THESE MACROS ACCEPT A $UTLINT FUNCTION CODE MINUS THE U$
! THE REMAINING ARGUMENTS ARE FUNCTION-DEPENDENT
! THE MACROS ASSUME THAT THERE IS A STRUCT CALLED "ARGBLK"
! U$SUC USES THE ERROR LABEL "INTERR"
!
MACRO U$BOTH(FUNCT) =
BLD_ARG_LST (ARGBLK, %NAME(U$,FUNCT), %REMAINING);
$UTLINT (ARGBLK,BUGERR) !NOTE NO ERR LABEL
%;
MACRO U$IFF(FUNCT) =
U$BOTH(FUNCT,%REMAINING);
IF .ARGBLK EQL 0 !FAIL TEST
%;
MACRO U$IFS(FUNCT) =
U$BOTH(FUNCT,%REMAINING);
IF .ARGBLK NEQ 0 !SUCC TEST
%;
MACRO U$SUC(FUNCT) =
BEGIN
BLD_ARG_LST (ARGBLK, %NAME(U$,FUNCT), %REMAINING);
$UTLINT (ARGBLK,INTERR);
END
%;
! ERRUX - EXPLANATION LINE OF ERR FOR UNEXP RMS ERROR
!
MACRO ERRUX =
VERINFO (UTLURF, ZOWN, RMEVEC[.$FIELD(STS,.RAB)-ER$BAS], .$FIELD(STV,.RAB))
%;
! FIXING - TEST IF V$FIX APPLIES
! UNCING - TEST IF UNCLUTTER APPLIES
!
MACRO FIXING = (.V$FIX NEQ 0) %;
MACRO UNCING = (.SC$CASE EQL SC_UNCL) %;
! GB_VERIF - GET A BKT & OUTPUT APPROP MESSAGES IF NECES
!
MACRO GB_VERIF(PAGE$, SIZE$, LOCK$, BD$) =
BEGIN
LOCAL R1;
R1=$CALL (BD$GET, PAGE$, SIZE$, LOCK$, BD$, BBM_NONE);
IF .R1 LSS 0 THEN $EXIT(%NAME('TRAP.U')); !KLUDGE AN UNWIND
IF .R1 GTR 1 !KLUDGILY DETECT CLOB BKT
THEN VERRARB (UTLPNV, 0, PAGE$, .R1, .KDB[KDBREF]);
!TELL USER ABOUT IT
END
%;
! IFSTAT - GENS PART OF "IF" FOR REFFING RMS STATUS CODE
!
MACRO IFSTAT = IF .$FIELD(STS,.RAB) %;
! MODBKT - PERFORM ACTION AND SET BKT UPD FLAG
!
MACRO MODBKT(ACTION,BD) =
BEGIN
ACTION
SETUPD(BD); !INDIC MUST WRITE
END
%;
! VERR - OUTPUTS "USUAL" MSG DESCRIBING PROBLEM DETECTED DIRECTLY BY UTLVFY
!
MACRO VERR(TEXT$) =
VERRARB ( UTLVEM, 0, UPLIT (%ASCIZ TEXT$), .ENT_RFA)
%;
! VERRFIX - OUTPUTS "USUAL" MSG FOR FIXABLE PROBLEM
!
MACRO VERRFIX(TEXT$) =
VERRARB ( UTLVEF, 1, UPLIT (%ASCIZ TEXT$), .ENT_RFA, .FIXSFX)
%;
! VERRC - OUTPUTS "USUAL" MSG FOR PROBLEM DETECTED IN FILE BY CALL TO RMS
!
MACRO VERRC(TEXT$) =
BEGIN
VERRARB ( UTLVEM, 0, UPLIT (%ASCIZ TEXT$), .ENT_RFA);
ERRUX
END
%;
! VERRARB - OUTPUTS ARBITRARY VERIFY ERR MSG TO REPORT FILE
!
MACRO VERRARB(FMT, FIXABLE)=
BEGIN
EXTERNAL %NAME(FMT);
%IF NOT FIXABLE %THEN
CURRERR = .CURRERR+1; !BUMP ERRS DETECTED FOR CURR BKT
IF FIXING OR UNCING !TERMINATE UPDATES FOR SAFETY
THEN BEGIN !YES
VERINFO (UTLCRS); !CHANGING TO RETR MODE
SC$CASE = SC_VER; !UNCL OFF
V$FIX = 0; !FIX OFF
FIXSFX = UPLIT (%ASCIZ ' [Fixable]');
END;
%FI
IF TX$APP NEQ 0 !IF STAT IS KLUDGE TO INSURE
!ADJSP IMMED FOLLS PUSHJ TX$TOUT
THEN $CALLM(TX$APP, %NAME(FMT), %REMAINING);
V$ERR = .V$ERR+1; !FOR SUMMARY MSG ![124]add dot
END %;
! VERINFO - OUTPUTS INFO MSG TO REPORT FILE
!
MACRO VERINFO(FMT)=
BEGIN
EXTERNAL %NAME(FMT);
IF TX$APP NEQ 0 !IF STAT IS KLUDGE TO INSURE
!ADJSP IMMED FOLLS PUSHJ TX$TOUT
THEN $CALLM(TX$APP, %NAME(FMT), %REMAINING);
END %;
![124] pvdbug - outputs debug msg of string followed by octal value
!
MACRO pVdbug(TEXT$, octvalue$) =
%if dbug %then
VERinfo ( UTLdbg, UPLIT (%ASCIZ TEXT$), octvalue$)
%fi
%;
!!! EQUATED SYMBOLS:
LITERAL FLGDUP = XB$DUP; !KLUDGE FOR "DUPLICATES" MACRO
LITERAL RFMFIX = FB$FIX; !DITTO "SIZEOFDATARECRD"
LITERAL SIDHSZ = SIDRHDRSIZE; !SHORTHAND
! EXTERNAL REFERENCES:
!
EXTERNAL
BBM_NONE, !FOR BD$GET TO LET VERIFY HANDLE BAD BKT
BUF$K1, !SPACE FOR KEY
BUF$K2, !SPACE FOR ANOTHER KEY
BUGERR, ! CHKS FOR RMS BUG ERR & EXITS IF ONE
FAB, !FAB OF RMSUTL'S CURR RMS FILE
FST : POINTER, !PTR TO RMS'S INTERNAL FILE STRUCT
INTERR, !FOR CATAS FAILURES FROM RMS CALLS
KDB : POINTER, !PTR TO RMS'S INTERN DESC FOR CURR KEY
KSIZB, !# OF BYTES IN THIS KRF'S KEY
KSIZW, !DITTO, IN WORDS
OUTRAB : POINTER, !RPT FILE RAB
PATH : POINTER, !PTR TO RMS "PATH" VECTOR
RAB, !RAB OF FILE CURRENTLY OPEN IN RMSUTL
RMEVEC:VECTOR, !RMS ERRS NAME-VECTOR
RST : POINTER, !PTR TO RMS'S INTERNAL STREAM DATA
SC$CASE, !CTL TYPE OF SCAN
SC_SPACE, !SPACE CMD
SC_UNCL, !VERIF CMD
SC_VER, !VERIFY CMD
STCINA, !PTR TO MOVST CONV TAB
STRIPT, !STRING PTR WITH BYTE SIZE DATA IN IT
TEXTBP, !BYTE PTR INTO RPT FILE BUFFER
V$ACC, !TRUE IF ACCESSING 2NDARY KEYS
V$ERR, !CNT OF VERIFY ERRORS DETECTED
V$FIX, !TRUE IF FLAWS SHOULD BE FIXED
V$PREQ; !DISP FREQ FOR PROGRESS-REPORT
BIND STPLEN = STRIPT+1; !2ND WD OF STRING PTR
OWN !STATIC VARIABLES FOR MODULE
ARGBLK : FORMATS[5], !SPACE FOR ARGLISTS OF $UTLINT RMS ENTRY
BDCURR : FORMATS[BDSIZE], !BKT DESC, FOR CURR P OF SCAN
BDLINK : FORMATS[BDSIZE], !BKT DESC, FOR P LINKED TO CURR P
BKT : POINTER, !POINTER TO CURR BKT
CID, !ID OF CURR ENTRY IN BKT
CPAGE, !FILE PAGE AT WHICH CURR BKT LOCATED
CURRERR, !# OF NON-FIXABLE PROBS FOR CURR BKT
DUPSTILL, !IF ON, KEYVAL SEEN IN EARLIER BKT STILL HIGHEST SEEN SO FAR
END_RFA, !PHYS ADDR OF RFA TERM SCAN
ENT_HIKEY, !ENTPTR FOR ENTRY WITH HI KEY IN BKT
ENTPTR : POINTER, !PTR TO CURR ENTRY IN BKT
ENT_RFA, !PHYS ADDR OF CURR REC
ENT_RRV, !RRV ADDR (IE. USER RFA ADDR) OF ENTRY
FIXSFX, !PTR TO ASCIZ STRING INDICATING FIX INFO
HSZ_PRIM, !# OF WDS IN HDR OF UDR (3=V, 2=F)
KREF, !KEY OF REFERENCE FOR SCAN
OOPAGE, !P# OF OUT-OF-ORD KEY (TO RECOG BKT LP)
PPAGE, !FILE PAGE AT WHICH PREV BKT LOCATED
PPLEV1, !LEVEL 1 ENT OF PATH ON PREV KEY ACC
PROGRESS, !IN EFFECT SCANCNT MOD V$PREQ
PT1 : POINTER, !TEMP PTR
RDP : FORMATS[RDSIZE], !REC DESC PKT CONTAINS KVAL PTR/LEN
RDP_RFA: FORMATS[RDSIZE], !RECDESC FOR FBYRFA/RRV
RDP_KEY : FORMATS[RDSIZE], !FOR CKEYKU CALL (SIDR,UDR)
SCANCNT, !CNT OF RECS SEEN
SIDR_OCC, !ON IF SIDR HAS AT LEAST 1 NON-NULL RFA
ZOWN : INITIAL (0); !0 VALUE = NULL STRING
GLOBAL ROUTINE VR$CLEAN : NOVALUE =
BEGIN
$CALL (BD$PUT, BDCURR, 0); !INSURE THINGS CLEAN
$CALL (BD$PUT, BDLINK, 0);
RETURN;
END;
GLOBAL ROUTINE VR$SCAN (RFA_LOW,RFA_HI) : NOVALUE =
! VR$SCAN - INIT SCAN OF DATA BKTS
! INPUTS:
! RFA_LOW = THE PHYS ADDR OF ENTRY TO START SCAN
! RFA_HI = PHYS ADDR OF ENTRY THAT TERMINATES SCAN (0 FOR EOF)
! (SEE V$ACC, V$FIX, V$PREQ, & RAB IN EXTERNALS TOO)
! NOTES:
! SET CONSTANT USER AND DATA STRUCT INFO (EG. KEY-OF-REF).
! LOCATE BKT OF LOWER LIMIT OF SCAN & GET PTR TO ITS BKT.
! SET KDB & USE IT TO SET KEY'S PARAMETERS.
! ESTABLISH RFA OF UPPER LIMIT OF SCAN.
! SET KEY PARAMATERS NEEDED IN SCAN.
! CALL APPROP SCANNING ROUTINE
BEGIN
IF FIXING !SET FIX MSG
THEN FIXSFX = UPLIT (%ASCIZ ' [Fixing]')
ELSE FIXSFX = UPLIT (%ASCIZ ' [Fixable]');
END_RFA = .RFA_HI; !MAKE IT GLOBALLY AVAIL
KREF = .$FIELD(KRF,.RAB); !MAKE IT EASY TO USE KEY OF REF
$FIELD(RAC,.RAB) = RB$KEY; !WILL DO KEY ACCESSES
PT1 = .FST[FSTKDB]; !GET PRIM KEY KDB
HSZ_PRIM = .PT1[KDBHSZ]; !NEEDED BY ACCUDR
CPAGE = BUCKETOFRFA(.RFA_LOW); !GET PAGE $FIND WENT TO
GB_VERIF (.CPAGE, .KDB[KDBDBKZ], 0, BDCURR);
!GET BKT ADDR OR BARF
BKT = .BDCURR[BKDBKTADR]; !PRESERVE IT
$CALL (BD$PUT,BDLINK,0); !INSURE CLEAN
RDP_RFA[RDRECPTR] = 0; !START AT BEGIN OF BKT
RDP_RFA[RDRFA] = .RFA_LOW; ! AND LOOK FOR THIS
U$IFF (FBYRFA, RDP_RFA, BDLINK) !GET LOC OF THIS ENTRY
THEN BEGIN
TXTOUT (UTLSNF); !STARTING REC NOT FOUND
ENTPTR = .BKT + BHHDRSIZE; !START AT TOP OF PAGE
END
ELSE ENTPTR = .RDP_RFA[RDRECPTR]; !SET OFFSET
RDP[RDUSERSIZE] = .KSIZB; !FOR MOVEKEY & CKEYKU
RDP[RDUSERPTR] = BUF$K1; !PT TO KEYVAL TOO
RDP_KEY[RDUSERSIZE] = .KSIZB; !SET KEY LEN
IF .SC$CASE EQL SC_SPACE
THEN $CALL (SCANSP) !DO SPACE SCAN
ELSE $CALL (SCANVER); !DO VERIF SCAN
RETURN;
END;
GLOBAL ROUTINE SCANSP : NOVALUE =
! SCANSP - LOOP FOR SPACE SCAN
! NOTES:
! TABULATE TOTAL SPACE AVAILABLE & SPACE USED, REPORT AS PERCENTAGE
BEGIN
LOCAL CSPACE;
LOCAL FREEPT;
LOCAL SIZREC;
LOCAL TSPACE;
LOCAL USPACE;
LOCAL T1; !TEMP FOR SHORT-TERM USE
TSPACE = 0; !NO SPACE TABUL YET
CSPACE = 0;
USPACE = 0;
REPEAT BEGIN !EXIT ONLY ON ERR OR EOF
TSPACE = .TSPACE + (.KDB[KDBDBKZ]*PAGESIZE) - BHHDRSIZE;
USPACE = .USPACE + .BKT [BHNEXTBYTE] - BHHDRSIZE;
!INCREM TOT & USED SPACE SEEN
IF .KREF EQL 0 !IF PRIM KEY
THEN BEGIN !SCAN FOR CLUTTER TOO
FREEPT = .BKT+.BKT[BHNEXTBYTE]; !SCAN TO END OF DATA
WHILE .ENTPTR LSS .FREEPT !SCAN TO 1ST FREE WD
DO BEGIN
IF RRVFLAG(ENTPTR) NEQ 0
THEN BEGIN !REPRES CHUNK OF CLUT
CSPACE = .CSPACE + .FREEPT - .ENTPTR;
EXITLOOP; !RRV'S AT END OF BKT
END;
SIZREC=SIZEOFDATARECRD(ENTPTR); !GET # OF WDS IN CURR ENT
IF DELETEFLAG(ENTPTR) NEQ 0
THEN CSPACE = .CSPACE+.SIZREC; !TACK ON SIZE OF DEL REC
ENTPTR = .ENTPTR + .SIZREC; !HOP TO NEXT ENTRY
END; !END ITER OF MAIN LOOP
END; !END CLUTTER CHK
T1 = CHKFLAG (BKT[BHFLAGS],BHFLGEND); !PRESERVE END STATUS
CPAGE = .BKT[BHNEXTBKT]; !GET P# OF NEXT BKT FOR GETBKT
$CALL (BD$PUT, BDCURR, 0); !RELEASE BKT
IF .T1 NEQ 0
THEN BEGIN !REACHED END OF DATA BKTS
SCANCNT = (.USPACE*100)/.TSPACE;
!COMPUTE PERCENTAGE
VERINFO (UTLSSC, .KREF, .SCANCNT);
!REPORT COMM RESULTS OF SCAN
IF .KREF EQL 0 !DO MORE FOR PRIM KEY
THEN BEGIN
SCANCNT = (.CSPACE*100)/.TSPACE;
VERINFO (UTLBCL, .SCANCNT);
END;
$FLUSH (.RAB); !MAKE RMS FILE UP TO DATE
RETURN;
END;
GB_VERIF (.CPAGE, .KDB[KDBDBKZ], 0, BDCURR);
!GET PTR TO NEXT BKT
BKT = .BDCURR[BKDBKTADR]; !PRESERVE IT
ENTPTR = .BKT + BHHDRSIZE; !PT TO 1ST ENTRY
END; !LOOP
RETURN; !INACCESSIBLE (BLISS STUPID)
END; !END ROUTINE
GLOBAL ROUTINE SCANVER : NOVALUE =
! SCANVER - TOP-LEVEL LOOP FOR VERIFY SCAN
! NOTES:
! DOES BKT I/O & DETECTS EOF
! CALLS SCANBKT TO DO ALL RECORD-LEVEL WORK
BEGIN
LOCAL T1; !TEMP FOR SHORT-TERM USE
ENT_RFA = -1; !IN CASE 1ST DATA BKT EMPTY...
!PREVENTS END_RFA=EOF=0 MATCHING
DUPSTILL = 1; !INDIC 1ST KEY
OOPAGE = 0; !NO PAGE SCANNED YET
PPLEV1 = 0; !INDIC NO PREV BKT YET
PROGRESS = 0; !INIT STATE OF SCAN
SCANCNT = 0; !INIT CNT OF RECS SCANNED
REPEAT BEGIN !EXIT ONLY ON ERR OR EOF
CID = 0; !INIT CURR ID
CURRERR = 0; !INDIC NO ERRS FOR CURR BKT YET
IF .BKT[BHBTYPE] NEQ BTYPEDATA
THEN VERR ('Bucket type not DATA'); !ASSUME TYPCOD WRONG
IF .OOPAGE EQL .CPAGE !BKTS IN LOOP?
THEN VERINFO (UTLASK,.KREF); !YES, TELL USER
IF .OOPAGE EQL .CPAGE !SEP TEST TO OUTWIT BLISS
THEN RETURN; !... AND ABORT SCAN
$CALL (SCANBKT); !PROCESS ENTRIES IN BKT
T1 = CHKFLAG (BKT[BHFLAGS],BHFLGEND); !PRESERVE END STATUS
PPAGE = .CPAGE; !SAVE P# OF PREV BKT
CPAGE = .BKT[BHNEXTBKT]; !GET P# OF NEXT BKT FOR GETBKT
$CALL (BD$PUT, BDCURR, 0); !RELEASE BKT
IF .END_RFA EQL -1
THEN RETURN; !FIXING A SINGLE REC
IF .T1 NEQ 0 OR .ENT_RFA EQL .END_RFA
THEN BEGIN !REACHED END OF DATA BKTS
VERINFO (UTLVCM, .KREF, .SCANCNT);
!REPORT RESULT OF SCAN
$FLUSH (.RAB); !MAKE RMS FILE UP TO DATE
RETURN;
END;
GB_VERIF (.CPAGE, .KDB[KDBDBKZ], 0, BDCURR);
!GET PTR TO NEXT BKT
BKT = .BDCURR[BKDBKTADR]; !PRESERVE IT
ENTPTR = .BKT + BHHDRSIZE; !PT TO 1ST ENTRY
END; !LOOP
RETURN; !INACCESSIBLE (BLISS STUPID)
END; !END ROUTINE
GLOBAL ROUTINE SCANBKT:NOVALUE =
!
! SCANBKT - SCANS THE ENTRIES IN A BKT
! INPUTS
! BKT = PTR TO CURRENT PAGE
! ENTPTR = PTR TO 1ST ENTRY TO PROC IN CURR BKT
! NOTES:
! VERIFIES KEYS ASCEND PROPERLY
! CHKS IF BKT'S RECORDS CAN BE FOUND BY KEY ACCESS
! VERIFIES INTER-PAGE LINKS VS. KEY-GREATER ACCESS
! DOES RRV BACKCHECK (CORRECTING PROB IF V$FIX)
! DOES UDR/SIDR COMPAT CHKS IF APPLIC (SEE ACCUDR)
BEGIN
LABEL ITER,CURRENT,IDXSEQ;
LOCAL CURRDUP; ![%47] # OF UNDEL RECS WITH CURR KEY VAL
LOCAL CVAL; !KEY COMPARE CASE
pvdbug( 'SCANBKT starting on (CPAGE=)', .CPAGE ); ![124]
pvdbug( 'Bucket Header (BKT=)', .BKT ); ![124]
WHILE .ENTPTR LSS .BKT+.BKT[BHNEXTBYTE] !SCAN TO END OF DATA
DO ITER: BEGIN
IF .CURRERR GEQ 3 !TREAT PAGE AS GARBAGE?
THEN BEGIN !YES
VERINFO (UTLASB); !ABORT SCAN
PPLEV1 = 0; !REINIT NEXT/DOWN PTR CONSIS CHK
RETURN;
END;
CURRENT : BEGIN
IF .PROGRESS EQL .V$PREQ !TIME TO REPORT?
THEN BEGIN !YES
PROGRESS=0; !RESET IT
$FLUSH (.RAB); !MAKE RMS FILE UP TO DATE
STRIPT<RH> = BUF$K1; !PT TO CURR KEY STRING
STPLEN = .KSIZB; !SET LENGTH OF KEY
VERINFO (UTLVPR,STRIPT,.STCINA);
$CALLM (RP$PUT); !EMPTY RPT BUFFER
$FLUSH (.OUTRAB); !FORCE RPT DATA TO DSK TOO
END;
CID = .ENTPTR[DRRECORDID]; !SET CURR ID
ENT_RFA = MAKERFA(.CPAGE,.CID);
!SET ITS RFA TOO
IF .END_RFA EQL .ENT_RFA !HIT 1ST OUT OF BNDS KEY?
THEN RETURN; !YES
pvdbug('SCANBKT: ENTPTR=', .entptr); ![124]
pvdbug(' .ENTPTR[0]=', .entptr[0, wrd]); ![124]
%if dbug %then
verinfo(utlvem, uplit (%asciz 'SCANBKT: ENT_RFA='), .ent_rfa ); ![124]
%fi
IF RRVFLAG(ENTPTR) NEQ 0
THEN EXITLOOP; !RRV'S AT END OF BKT
IF DELETEFLAG(ENTPTR) NEQ 0 AND FIXING
THEN BEGIN !DELETED & FIXING
$CALL (DELENT, BDCURR, .ENTPTR); !ZAP IT
LEAVE ITER; !NEXT REC NOW HAS CURR ENTPTR
END;
IF .KREF NEQ 0 !2NDARY KEY?
THEN $CALL (ACCUDR) !ACC USER DATA RECORD
ELSE ENT_RRV = .ENTPTR[DRRRVADDRESS];
!WILL SET CKEY IF HI-ER KEY
BLD_ARG_LST (ARGBLK, 0, RDP, .ENTPTR+.KDB[KDBHSZ]);
IF .KREF EQL 0 !IS IT PRIM KEY?
THEN ARGBLK[RMS_FUNC]=U$CKEYKU !COMPARE KEY STRING TO UDR
ELSE ARGBLK[RMS_FUNC]=U$CKEYKK; !COMP KS TO SIDR KEY
$UTLINT (ARGBLK,BUGERR); !COMPARE KVCURR TO KEY OF REC
IF .ARGBLK NEQ 0 !TRUE IF RECORD HAS EQL OR HIGHER KEY
THEN IF LSSFLAG(RDP) NEQ 0
THEN CVAL =1 !HIGHER ALW OK, PLUS CALL MOVEKEY
ELSE IF DUPLICATES !EQL KEYS, DUPS OK?
THEN CVAL=2 !OK, BUT NO MOVEKEY
ELSE CVAL=4 !DUPS NOT OK, ERR
ELSE CVAL=3; !REC LOWER NEVER OK
IF .DUPSTILL EQL 1 !THEN 1ST TIME THRU
THEN CVAL = 1; !TREAT 1ST KEY AS "HIGHER"
!(LOOP CONTINUED)
! HAVE FINISHED DETERMINING STATUS OF RECORD, NOW DO APPROP STUFF
CASE .CVAL FROM 1 TO 4 OF SET
[1]: BEGIN !NEW HI KEY
IF .KREF EQL 0 !COPY KEYVAL, PR/SEC DEP
THEN U$SUC (MOVEKEY, .ENTPTR+.KDB[KDBHSZ], BUF$K1)
!COPY KEY VAL FOR NEXT ITER
ELSE MOVEWORDS (.ENTPTR+.KDB[KDBHSZ], BUF$K1, .KSIZW);
!JUST BLT THE KEY
ENT_HIKEY = .ENTPTR; !SAVE ADDR OF ENTRY WITH HI KEY
CURRDUP = 0; ![%47] CLEAR CNT OF UNDEL DUPS
DUPSTILL = 0; !CLEAR FLAG
END;
[2]: 0; !NO-OP FOR EQUAL KEYS
[3]: BEGIN !UPDATE KEY TO MIN MESSAGES
CURRDUP = 0; ![%47] CLEAR CNT OF UNDEL DUPS
IF .ENTPTR EQL .BKT+BHHDRSIZE !1ST ENT ON PAGE?
THEN OOPAGE = .CPAGE; !THEN SAVE FOR LOOP DETECTION
VERR('Key value out of order');
IF .KREF EQL 0 !COPY KEYVAL, PR/SEC DEP
THEN U$SUC (MOVEKEY, .ENTPTR+.KDB[KDBHSZ], BUF$K1)
!COPY KEY VAL FOR NEXT ITER
ELSE MOVEWORDS (.ENTPTR+.KDB[KDBHSZ], BUF$K1, .KSIZW);
!JUST BLT THE KEY
END;
[4]: BEGIN
IF .CURRDUP NEQ 0 AND DELETEFLAG (ENTPTR) EQL 0
![%47] DONT CONSID DEL RECS
THEN VERR('Duplicate key encountered');
END;
TES;
IF DELETEFLAG (ENTPTR) NEQ 0
THEN LEAVE CURRENT; !SKIP DELETED RECS
CURRDUP = .CURRDUP + 1; ![%47] INCR CNT OF UNDEL DUPS
IF .V$ACC EQL TRUE
THEN $CALL (ACCKEY); !ACC UDR BY 2NDARY KEYS
IF .KREF EQL 0
THEN $CALL (ACCRRV); !DO RRV BACK CHECK FOR UDR
!IF UNCLUT, DEL RRV IF 1
END; !END "CURRENT" BLK
IF .END_RFA EQL -1 THEN RETURN; !FIXING A SINGLE REC
ENTPTR = .ENTPTR + SIZEOFDATARECRD(ENTPTR); !HOP TO NEXT ENTRY
END; !END ITER OF MAIN LOOP
! END-OF-BKT CHKS
pvdbug( 'SCANBKT: end of bucket, DUPSTILL=', .dupstill ); ![124]
IF .DUPSTILL EQL 0 !1ST KEY OR SAME HI KEY AS LAST BKT?
THEN BEGIN !NO
$CALL (BD$PUT, BDLINK, 0); !INSURE CLEAN SLATE
RDP[RDRECPTR] = 0; !INSURE SEARCH NOT "RESUMED"
U$IFF (FNDDATA,RDP,BDLINK) !FIND HI KEY REC (EVEN IF DEL)
THEN VERRC('Key access aborted') !OOPS, NOTHING FND
ELSE IF CHKFLAG (RDP[RDSTATUS], (RDFLGLSS OR RDFLGPST)) NEQ 0
OR !REC FND, BUT WAS IT EXAC MATCH?
.RDP[RDRECPTR] NEQ .ENT_HIKEY
THEN VERR('Key access failed'); !NO
IF .PPLEV1 NEQ 0 !1ST TIME THRU OR AFT BKT ABORT?
THEN IDXSEQ:BEGIN !NO, SEE IF NOW AT NEXT IDX ENT
IF .PATH[1,WRD] EQL .PPLEV1
THEN LEAVE IDXSEQ; !BKT PTED TO BY SAME IDX ENT
!THIS MEANS INEFFIC IDX, POSSIB
!EXTENSION TO UNCLUTTER...
PPLEV1<PATHOFFSET> = .PPLEV1<PATHOFFSET>+.KSIZW+1;
!UPD OFFSET TO EXPECTED VAL
IF .PATH[1,WRD] EQL .PPLEV1
AND
.CPAGE EQL .PATH[0,PATHBKT]
THEN LEAVE IDXSEQ; !CORR IDX ENT PTS AT CORR BKT
GB_VERIF (.PPLEV1<PATHBKT>,.KDB[KDBIBKZ],0,BDLINK);
!GET IDX BKT TO CHK LAST ENTRY
PT1=.BDLINK[BKDBKTADR]; !MAKE PTR TO IDX BKT
!MAKE FANCY CHKS: PREV IDX ENT MUST BE LAST ON PAGE
! AND CURR IDX ENT MUST BE 1ST ON PREV'S NEXT PAGE
!ALSO, REVERIFY THAT RIGHT BKT PTED TO
IF .PPLEV1<PATHOFFSET> NEQ .PT1[BHNEXTBYTE]
OR
.PATH[1,PATHBKT] NEQ .PT1[BHNEXTBKT]
OR
.PATH[1,PATHOFFSET] NEQ BHHDRSIZE
OR
.CPAGE NEQ .PATH[0,PATHBKT]
THEN VERRARB (UTLBNC, 0, .PPAGE, .CPAGE);
!BKT NOT IN DATA BKT CHAIN
END;
PPLEV1 = .PATH[1,WRD]; !SAV JUST FOUND INFO
DUPSTILL = TRUE; !RESET "NO GTR KEY YET"
END; !END IF NOT .DUPSTILL
!+ !A454
! If the data bucket we just scanned has no entries
! (as in the case of all records deleted and expunged),
! set PPLEV1 to 0, to indicate that there are
! to be no "previous bucket" consistency checks
! when the next bucket is verified.
!-
IF .bkt [bhnextbyte] EQL bhhdrsize ! Header only? !A454
THEN ! !A454
pplev1 = 0; ! No previous bucket !A454
RETURN;
END; !END SCANBKT
GLOBAL ROUTINE ACCKEY : NOVALUE =
!
! ACCKEY - ACCESSES UDR BY THE SPECIFIED 2NDARY KEYS
! INPUTS:
! BKT, ENTPTR
! NOTES:
! ACCKEY CALLED ONLY IF KREF IS 0.
! LOOPS THRU THE KDB'S FOR THE FILE, DOES A KEY ACCESS FOR EACH KEY
! AFTER MOVEKEY-ING IT TO A BUFFER.
! HOWEVER THE KEY ACCESS IS OMITTED IF THE RECORD ISNT LONG ENOUGH.
! IF CANT FIND THE REC BY KEY,
! THEN PUTSIDR IS CALLED IF V$FIX APPLIES
! ELSE THE RRV IS ELIMINATED IF UNCLUTTERING.
BEGIN
LABEL ITER;
LOCAL STS; !TEMP FOR RMS STATUS
RDP_KEY[RDUSERPTR] = BUF$K2; !MAKE KEY ADDR PASSABLE
$FIELD(KBF,.RAB) = BUF$K2; !USER-LEVEL TOO
$FIELD(ROP,.RAB) = RB$RAH OR RB$NRP; !DO EXACT MATCH (READAHEAD TOO)
!NRP FOR PHYS ADDR OF SIDR
WHILE TRUE DO ITER: BEGIN
KDB = .KDB[KDBNXT]; !GET NEXT 2NDARY KEY
IF .KDB EQL 0 THEN EXITLOOP; !PAST LAST KEY
IF .ENTPTR[DRRECSIZE] LSS .KDB[KDBMINRSZ]
THEN LEAVE ITER; !REC TOO SHORT TO ACC BY CUR KEY
pvdbug( 'ACCKEY: KDB[KDBREF] =', .kdb[kdbref] ); ![124]
U$SUC (GETKDB, .KDB[KDBREF]); !RESET CURR KDB IN RMS
U$SUC (MOVEKEY, .ENTPTR+.HSZ_PRIM, BUF$K2);
!COPY KEY VAL FOR THIS KEY
$FIELD(KRF,.RAB)=.KDB[KDBREF]; !SET KRF OF CUR KEY
RDP_KEY[RDUSERSIZE] = .KDB[KDBKSZ]; !MAKE KEY SIZE PASSABLE
$FIELD(KSZ,.RAB) = .KDB[KDBKSZ]; !RESET AT USER-LEVEL TOO
$FIND (.RAB); !DO KEY ACCESS
STS = .$FIELD(STS,.RAB); !GET STS FLD
IFSTAT EQL SU$SUC
THEN IF $CALL(SIDRSCAN) !IS THIS PARTIC REC IN SIDR ARR
THEN BEGIN !YES
IF UNCING !ELIM RRV'S?
THEN $CALL (SIDRADJ); !RESET SIDR PTR TO ENT_RFA
LEAVE ITER; !DONE WITH THIS ENTRY
END;
IF .STS NEQ ER$RNF !FISHY FAILURE?
AND .STS NEQ SU$SUC !SIDRSCAN MAY HAVE FAILED
THEN BEGIN !YES
VERRARB (UTLAKF, 0,.KDB[KDBREF], .ENT_RFA, ZOWN);
!ACC BY KEY N FAILED FOR X/Y
ERRUX !INEXPLIC ERR, TELL USER
END
ELSE BEGIN !ONE OR THE OTHER FAILED
VERRARB (UTLAKF, 1,.KDB[KDBREF], .ENT_RFA, .FIXSFX);
!ACC BY KEY N FAILED FOR X/Y
IF FIXING THEN $CALL (SIDRPUT);
!PUT OUT NEEDED SIDR ENTRY
END;
END; !END KDB LOOP
$CALL (M$KDB, 0); !RESET PRIM KEY
RDP_KEY[RDUSERSIZE] = .KSIZB; !SET KEY LEN
RETURN;
END;
GLOBAL ROUTINE ACCRRV : NOVALUE =
!
! ACCRRV - VERIFIES THAT REC'S RRV (IF ONE) PTS AT IT.
! INPUTS:
! CURRENT ENTRY AS SET BY SCANBKT
! NOTES:
! IF UNCLUTTER MODE APPLIES, THE CHECK IS N/A BECAUSE
! THE RRV IS SIMPLY DELETED, AND THE UDR PTED AT ITSELF.
! IF FIX AND NOT UNCLUT, A BAD PTR IN AN RRV IS SIMPLY RESET
BEGIN
PROGRESS=.PROGRESS+1; !BUMP CNT OF RECS PROCESSED
SCANCNT=.SCANCNT+1; !BUMP CNT OF RECS PROCESSED
IF .ENT_RRV EQL .ENT_RFA
THEN RETURN; !IF REC NEVER MOVED, NO BACK CHK TO MAKE
%if dbug %then
verinfo(utlvem, uplit (%asciz 'ACCRRV: ENT_RRV='), .ent_rrv ); ![124]
%fi
RDP_RFA[RDRECPTR]=0; !CLEAR STARTING POS
RDP_RFA[RDRFA]=.ENT_RRV; !PREP TO PASS IT
$CALL (BD$PUT,BDLINK,0); !INSURE CLEAN
U$IFS (FBYRFA, RDP_RFA, BDLINK) !GET RRV OF THIS UDR
AND NOT UNCING !AND CHK IF NOT SUBSUMED
THEN BEGIN !RRV FOUND
PT1 = .RDP_RFA[RDRECPTR]; !GET PTR TO RRV
IF RRVFLAG(PT1) EQL 0 !PTS BACK AT UDR?
THEN BEGIN !YES, OOPS
VERR ('Data record identified by back pointer');
RETURN;
END;
IF .PT1[DRRRVADDRESS] NEQ .ENT_RFA
THEN BEGIN !RRV/UDR OUT OF SYNC
VERRFIX ('POINTER entry does not point at data record');
IF FIXING
THEN MODBKT (PT1[DRRRVADDRESS] = .ENT_RFA;, BDLINK);
!PT RRV TO RIGHT PLACE
END;
END
ELSE BEGIN !BAD RRV OR ZAPPING ALL RRV'S
IF UNCING OR FIXING !EITHER TYPE OF MODS ALLOWED?
THEN MODBKT (ENTPTR[DRRRVADDRESS] = .ENT_RFA;, BDCURR);
!YES, PT BACK AT SELF
IF NOT UNCING
THEN BEGIN !BAD RRV
VERRFIX ('POINTER entry not found');
ENT_RRV = .ENT_RFA; !INDIC RRV NO GOOD
IF .V$ACC EQL TRUE
THEN $CALL(ACCKEY); !RE-ACC TO DEAL WITH BAD RRV
END
ELSE IF .ARGBLK NEQ 0
THEN $CALL (DELENT,BDLINK,.RDP_RFA[RDRECPTR]);
!ZAP THE RRV IF IT WAS FND
END; !END OF "IF NO RRV"
RETURN;
END;
GLOBAL ROUTINE ACCUDR : NOVALUE =
!
! ACCUDR - COMPARES SIDR KEY VALUE TO ASSOC PRIM DATA KEY VALUE
! NOTES:
! SCANS ALL DUPS IN A PARTIC SIDR.
! FOR EACH, IT MUST GET THE PRIMARY DATA BKT,
! DO THE COMPARE AND REACT TO AN INEQUALITY.
! IF NOFIX, IT JUST PRINTS AN ERR MSG.
! IF V$FIX, IT 0'S THE BAD PTR
BEGIN
LOCAL I; !LOOP CTR
LABEL ITER, EXIST;
SIDR_OCC = 0; !PRESUME EMPTY ENTRY
SCANCNT=.SCANCNT+1; !BUMP CNT OF SIDRS PROCESSED
PROGRESS=.PROGRESS+1; !BUMP CNT OF SIDRS PROCESSED
pvdbug( 'ACCUDR: (ENTPTR=)', .entptr ); ![124]
INCR I FROM SIDHSZ+.KSIZW TO .ENTPTR[SIDRRECSIZE]+SIDHSZ-1
DO ITER: BEGIN !EXA EACH RFA IN SIDR VECTOR
RDP_RFA[RDRFA] = .ENTPTR[.I,WRD]; !SET ARG FOR FBYRRV
RDP_RFA[RDRECPTR]=0; !CLEAR OUTPUT ARG
IF .ENTPTR[.I,WRD] EQL 0 THEN LEAVE ITER;
!NO ENTRY IN THIS SLOT
EXIST: BEGIN !EXISTING ENTRY
SIDR_OCC = 1; !INDIC SIDR NOT EMPTY
RDP_KEY[RDUSERPTR] = 0; !KLUDGY DISTING BETW BAD KEY/REC
$CALL (BD$PUT,BDLINK,0); !INSURE CLEAN
U$IFF(FBYRRV, RDP_RFA, BDLINK) !GET PTR TO UDR
THEN LEAVE EXIST; !NO MATCHING UDR
PT1 = .RDP_RFA[RDRECPTR]; !MATER PTR TO UDR
IF DELETEFLAG(PT1) NEQ 0
THEN LEAVE EXIST; !UDR DELETED
RDP_KEY[RDUSERPTR] = .ENTPTR+SIDHSZ; !SET PTR TO DATA
U$IFF (CKEYKU, RDP_KEY, .PT1+.HSZ_PRIM) OR LSSFLAG(RDP_KEY) NEQ 0
!COMPARE KVCURR TO KEY OF REC
THEN LEAVE EXIST; !KEY VALUES DONT MATCH
IF .SIDR_OCC GEQ 0 !SEEN A VALID ENTRY YET?
THEN SIDR_OCC = -1 !NO, INDIC NON-EMPTY & VALID
ELSE IF NODUPLICATES THEN VERR('Duplicate key encountered');
LEAVE ITER; !ALL OK, DONE THIS ENTRY
END; !EXIST
!BEGIN "NO LONGER EXIST"
VERRARB (UTLNMR, 1, .I+1-SIDHSZ-.KSIZW, .RDP_RFA[RDRFA], .ENT_RFA, .FIXSFX);
!NO MAT UDR FOR SIDR ELEM N
IF FIXING THEN MODBKT(ENTPTR[.I,WRD]=0;, BDCURR);
!ASSUME UDR DELETED OR KEY UPD
IF .RDP_KEY[RDUSERPTR] NEQ 0 !REACH HERE CAUSE KEYS NOT MAT?
THEN VERRARB(UTLAKM, 1, .KREF, .RDP_RFA[RDRFA]);
!YES, INDIC 2ND ERR LIKELY
!END "NO LONGER EXIST"
END; !END ITER
! IF .SIDR_OCC EQL 0 AND UNCING !EMPTY AND UNCLUTTERING?
! THEN $CALL (DELENT, BDCURR, .ENTPTR); !YES, ELIM THE EMPTY SIDR
IF .SIDR_OCC EQL 0 !EMPTY RFA LIST?
THEN VERINFO (UTLERL, .ENT_RFA); !YES, TELL USER
RETURN;
END;
GLOBAL ROUTINE DELENT (BKDESC, RECPTR) : NOVALUE =
! DELENT - EXPUNGES ANY TYPE OF ENTRY FROM A BKT
! INPUTS:
! BKDESC OF THE BKT THAT CONTAINS THE ENTRY
! RECPTR = ADDR IN BUFFER OF THE ENTRY TO BE EXPUNGED
! NOTES:
! IF ENTRY IS UDR, THEN ITS RRV IS ALSO EXPUNGED, IF ONE
BEGIN
MAP BKDESC: POINTER;
MAP RECPTR: POINTER;
$CALL (BK$DENT, .CPAGE, .BKDESC[BKDBKTADR], .RECPTR);
!COMMON ROUTINE DOES THE WORK
SETUPD (BKDESC); !INDIC BKT UPD
RETURN;
END;
GLOBAL ROUTINE SIDRADJ : NOVALUE =
! SIDRADJ - RESET RFA IN SIDR TO POINT AT ACTU REC IF NECES
! NOTES:
! ADJUSTMENT APPLIES ONLY IF UNCLUTTERING.
! RDP_KEY AND BDLINK ARE SETUP IN SIDRSCAN.
BEGIN
IF .ENT_RRV EQL .ENT_RFA !BACK PTR = ACTU ADDR?
THEN RETURN; !YES, SO NO UN-INDIRECTING TO DO
PT1 = .RDP_KEY[RDRECPTR]; !GET ADDR OF SIDR PTING AT CURR REC
![124]remove edit 113
![124] PT1 [(.RDP_KEY[RDSIDRELEMENT] + SIDRHDRSIZE + .KDB[KDBKSZW]), WRD] = .ENT_RFA;
![124]rdsidrelement already past header
PT1 [.RDP_KEY[RDSIDRELEMENT], WRD] = .ENT_RFA; ![124]end remove 113
SETUPD(BDLINK); !SET FLAG SAYING BKT MODIFIED
RETURN;
END; !END SIDRADJ
GLOBAL ROUTINE SIDRPUT : NOVALUE =
! SIDRPUT - CREATE SIDR ENTRY FOR UDR THAT LACKED ONE
BEGIN
IF UNCING
THEN RDP_RFA[RDRRV] = .ENT_RFA !MAP TO REC ITSELF
ELSE RDP_RFA[RDRRV] = .ENT_RRV; !USE RRV, IF ONE
%if dbug %then
verinfo(utlvem, uplit (%asciz 'SIDRPUT: [RDRRV]='), .rdp_rfa[rdrrv] ); ![124]
%fi
$FIELD(RBF,.RAB) = .ENTPTR + .HSZ_PRIM;
!PUTSIDR USES UDR TO LOC KEY VALUE
U$IFF (PUTSIDR, RDP_RFA) !INSERT KEY IN SIDR
THEN VERR ('Could not insert key into secondary index');
RETURN;
END;
GLOBAL ROUTINE SIDRSCAN =
! SIDRSCAN - INSURE THAT RFA AS WELL AS KEY WAS IN THE SIDR
! RETURNS:
! TRUE IF RECORD IS IN SIDR ARRAY, SETTING UP RDP_KEY AND BDLINK (USUALLY)
! FALSE OTHERWISE
! NOTES:
! IF DUPLICATES NOT ALLOWED, THE $FIND DATA IS ADEQUATE.
! OTHERWISE HAVE TO USE RMS ROUTINES TO ACTU SCAN SIDRS.
! HOWEVER IF UNCLUT, THEN RMS ROUTINES ALWAYS CALLED SO THAT RD&BD SETUP.
! THUS ONLY TIME THEY ARE NOT SETUP IS NO UNC & $FIND ADEQ.
BEGIN
IF NOT UNCING
THEN BEGIN !THEN TRY TO DO QUICK CHK
IF .$FIELD(RFA,.RAB) EQL .ENT_RRV
THEN GOODRETURN; !IT WAS 1ST OR NO DUPS
IF NODUPLICATES THEN BADRETURN; !NO DUPS, SO SCAN CANT SUCC
END;
RDP_KEY[RDRECPTR]=0; !CLEAR STARTING POS
RDP_KEY[RDRFA] = .RST[RSTNRP]; !PASS RFA OF THE FND SIDR
!START DUP SRCH WITH THIS REC
$CALL (BD$PUT,BDLINK,0); !INSURE CLEAN
U$SUC (FBYRFA, RDP_KEY, BDLINK); !PHYS LOCATE SIDR FROM ITS RFA
RDP_KEY[RDFLAGS] = RDFLGRETEX; !RET ON MATCH, DONT CORRECT IT
RDP_KEY[RDRRV] = .ENT_RRV; !COMPARE AGAINST THIS
rdp_key[rdsidrelement] = 0; ![124]init index in case bad return
U$IFF (CHKDUP, RDP_KEY, BDLINK) !SCAN FOR RFA MATCH
THEN if .rdp_key[rdsidrelement] eql 0 ![124]check strange failure
then return false ![124]for now
else ![124]
GOODRETURN !FAILURE=MATCH
ELSE BADRETURN; !SUCC=SCANNED ENTIRE SIDR
END;
END ELUDOM