Google
 

Trailing-Edge - PDP-10 Archives - 704rmsf2 - 10,7/rms10/rmssrc/rmssdr.b36
There are 6 other files named rmssdr.b36 in the archive. Click here to see a list.
MODULE SDR =


BEGIN

GLOBAL BIND	SDRV = 1^24 + 0^18 + 9;		!EDIT DATE: 3-APR-78

%([

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

!COPYRIGHT (C) 1977, 1979 BY DIGITAL EQUIPMENT CORPORATION


AUTHOR:	S. BLOUNT /EGM



	THIS MODULE CONTAINS ALL ROUTINES WHICH DEAL PRIMARILY
	WITH SECONDARY DATA RECORDS. SEVERAL OTHER ROUTINES
	THROUGHOUT RMS-20 ALSO PROCESS SECONDARY RECORDS (CALLED
	"SIDR" RECORDS ) BUT THESE ROUTINES PROCESS ONLY THESE
	DATA RECORDS.

**********	TABLE OF CONTENTS	**************



	ROUTINE			FUNCTION
	=======			========

	MAKESIDR		CREATE A SECONDARY DATA RECORD

	BLDCSIDR		BUILD A CONTINUATION SIDR

	DOSIDR			PROCESS THE SIDR INSERTION

	INSRTSIDR		OUTER-LEVEL SIDR INSERTION ROUTINE

	BLDISIDR		BUILD AN INITIAL SIDR

	DELSIDR			DELETE A SIDR RECORD

	SQUEEZESIDR		SQUEEZE ONE SIDR RECORD FROM BUCKET

	PUTSIDR			INSERT CURRENT RECORD INTO SECONDARY INDEX




REVISION HISTORY:

PRODUCT	LOCAL
EDIT	EDIT	DATE		WHO		PURPOSE
====	====	====		===		=======

-	1	11-OCT-76	SB	ADD DELSIDR
-	2	28-OCT-76	SB	FIX BUG IN MOVEDOWN ARG IN DOSIDR
-	3	7-NOV-76	SB	ADD DELETED RFA BIT
-	4	9-DEC-76	SB	FIX BUG SO THAT IF ALL
					SIDR RECORDS ARE MOVED OUT
					OF THE BUCKET ON A SPLIT, THE
					NEW HIGH-KE IS OF R-NEW
-	5	8-MAR-77	SB	TAKE OUR CHECK FOR SIDR ALREADY DELETED
-	6	3-MAY-77	SB	ADD FIX FOR SIDRELEMENT FIELD
6	7	26-JAN-78	SB	IF SIDR BKT IS FULL, FREESPACE
					WAS NEGATIVE, CHECK WAS BAD

*************************************************
*						*
*		NEW REVISION HISTORY		*
*						*
*************************************************

PRODUCT	MODULE	 SPR
 EDIT	 EDIT	 QAR		DESCRIPTION
======	======	=====		===========

12	8	11439	RST KEY BUFFER IS NOT BEING UPDATED WHEN A SIDR
			BUCKET SPLITS. THIS CAUSES THE ALTERNATE KEY ROOT
			BUCKET TO BE UPDATED INCORRECTLY, SOMETIMES WITH
			KEY VALUES FROM OTHER INDEX LEVELS (SUCH AS PRIMARY).
			THE END RESULT IS THAT A VALID GET/FIND LOSES.
			MAKE SURE THE LAST KEY FROM THE ORIGINAL BUCKET IS
			COPIED TO THE RST KEY BUFFER AFTER A SPLIT OCCURS.
			ALSO - FIX AN OFF BY 1 BUG (END POINTER) WHICH
			GARBAGES THE CURRENT AND FOLLOWING SIDR AFTER SPLIT
			MOVES THE CURRENT SIDR TO A NEW BUCKET.

****************** Start RMS-10 V1.1 *********************
********************* TOPS-10 ONLY ***********************

PRODUCT	MODULE	 SPR
 EDIT	 EDIT	 QAR		DESCRIPTION
======	======	=====		===========

 100	  9	Dev		Make declarations for routine names
				be EXTERNAL ROUTINE so RMS will compile 
				under BLISS V4 (RMT, 10/22/85).

	***** END OF REVISION HISTORY *****




])%



	%([ FORWARD DECLARATIONS ])%
	FORWARD ROUTINE		BLDISIDR,
			DELSIDR;


	%([ EXTERNAL DECLARATIONS ])%

	EXTERNAL ROUTINE
	    ALCBKT,		! ALLOCATE A NEW BUCKET
	    CRASH,		! FOR DEBUGGING
	    FNDDATA,	! FIND SIDR BUCKET ON LEVEL 0
	    FNDREC,		! LOCATE DATA RECORD
	    ALCNEWIDS,	! ASSIGN NEW ID'S TO SIDRS
	    PUTBKT,		! WRITE OUT A FIL BUCKET
	    SPLIT,		! SPLIT A DATA BUCKET
	    ALCRFA,		! ALLOCATE A RECORD ADDRESS
	    DUMP,		! SAME
	    MOVEKEY;		! MOVE A KEY STRING


	%([ ERROR MESSAGES REFERENCED IN THIS MODULE ])%

	EXTERNAL
	    MSGFLAGS,	! BAD FLAG VALUES
	    MSGNOCALL,	! ROUTINE SHOULD NOT HAVE BEEN CALED
	    MSGRFA,		! BAD RFA VALUE FOUND IN SIDR
	    MSGSPLIT,	! BAD SPLIT PARAMETERS
	    MSGFAILURE,	! A ROUTINE FAILED
	    MSGCOUNT,	! BAD COUNT VALUE
	    MSGINPUT,	! BAD INPUT VALUES
	    MSGPTR;		! BAD PTR VALUE




REQUIRE 'RMSREQ';
EXTDECLARATIONS;



! MAKESIDR
! ========

! ROUTINE TO CREATE A SECONDARY INDEX DATA RECORD (SIDR).
!	THIS ROUTINE ASSUME THAT THE CORRECT POSITION TO
!	CREATE THE RECORD HAS BEEN FOUND. NO ADJUSTMENT
!	OF THE BUCKET HEADER INFO, NOR ANY INDEX UPDATES
!	ARE DONE WITHIN THIS ROUTINE.
!	THE RFA FOR THE SIDR MUST BE ALLOCATED BEFORE THIS
!	ROUTNE IS CALLED

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RFA		RFA OF SIDR RECORD
!		RRV		RECORD POINTER TO INSERT INTO SIDR
!		USERPTR		ADDRESS OF SEARCH KEY STRING
!
!	SIDRPTR		ADDRESS TO WRITE RECORD

! OUTPUT:
!	<NO STATUS RETURNED>

! INPUT ARGS MODIFIED:
!	RECORD DESCRIPTOR:
!		<NONE>

! ROUTINES CALLED:
!	<NONE>

GLOBAL ROUTINE MAKESIDR ( RECDESC, SIDRPTR ): NOVALUE =
BEGIN

	ARGUMENT	(RECDESC,BASEADD);
	ARGUMENT	(SIDRPTR,BASEADD);

MAP
    RECDESC:	POINTER,
    SIDRPTR:	POINTER;

REGISTER
    KEYSIZEINWORDS;			! SIZE OF KEY STRING


	TRACE ('MAKESIDR');

	%([ STORE THE FLAGS AND THE ID OF THE SIDR ])%

	KEYSIZEINWORDS = .KDB [ KDBKSZW ];	! GET THIS NOW
	SIDRPTR [ DRFLAGS ] = DEFSIDRFLAGS;
	SIDRPTR [ DRRECORDID ] = IDOFRFA (  .RECDESC [ RDRFA ] );
	SIDRPTR [ SIDRRECSIZE ] = .KEYSIZEINWORDS + 1;	! KEY + 1 PTR
	SIDRPTR [ SIDRDUPCOUNT ] = ZERO;		! FOR FUTURE
	INC ( SIDRPTR, SIDRHDRSIZE );

	%([ MOVE THE KEY STRING INTO THE RECORD ])%

	MOVEWORDS ( 	%(FROM)%	.RECDESC [ RDUSERPTR ],
			%(TO)%		.SIDRPTR,
			%(SIZE)%	.KEYSIZEINWORDS );

	%([ BUMP PTR PAST THE DATA PORTION ])%

	INC ( SIDRPTR, .KEYSIZEINWORDS );

	SIDRPTR [ WHOLEWORD ] = .RECDESC [ RDRRV ];	! STORE PTR

	RETURN 
END; %(OF MAKESIDR)%



! BLDCSIDR
! ========

! ROUTINE TO BUILD A CONTINUATION SECONDARY INDEX DATA RECORD (SIDR)
!	THIS ROUTINE IS CALLED WHEN THE CURRENT BUCKET BECOMES FILLED
!	WITH OTHER RECORDS (MAYBE DUPLICATES OF THIS KEY VALUE), AND
!	A NEW SIDR IS NEEDED. THIS SIDR IS ALLOCATED IN ITS OWN
!	BUCKET WHICH IS THEN <NOT> ENTERED INTO THE INDEX STRUCTURE.
!	THIS MEANS THAT THE INDEX WILL CONTAIN ONE INDEX RECORD
!	WHICH REPRESENTS MORE THAN ONE DATA BUCKET...NAMELY ALL
!	THOSE BUCKETS WHICH CONTAIN A SINGLE CONTINUATION SIDR
!	FOR THIS KEY.  THUS, ONCE A CONTINUATION SIDR HAS BEEN
!	BUILT IN A PARTICULAR BUCKET, NO OTHER RECORDS ARE
!	ENTERED INTO THE BUCKET. THAT SIDR WILL CONTINUE TO GROW
!	UNTIL IT FILLS THE BUCKET...AT WHICH TIME A NEW CONTINUATION
!	SIDR IS BUILT IN A NEW BUCKET.
!
!	THIS ROUTINE DOES THE FOLLOWING:
!
!		1.	ALLOCATE A NEW BUCKET TO USE
!		2.	LINK IT INTO THE BUCKET CHAIN
!		3.	BUILD A NEW SIDR AT THE TOP OF IT.
!
! NOTES:
!
!	1.	A CONTINUATION SIDR LOOKS JUST LIKE THE INITIAL SIDR.
!		IF DUP COUNTS ARE EVER SUPPORTED, THAT FIELD IN THE
!		CONTINUATION SIDR CAN BE USED FOR SOME OTHER PURPOSE
!		SINCE THE DUP COUNT IS NEEDED ONLY IN THE INITIAL
!		SIDR RECORD.
!
!	2.	THE COUNT FIELD IN THE RECORD DESC. IS NOT ALTERED
!		HERE, SO IF A SIDR BUCKET IS SPLITTING, WHOEVER CALLS
!		THIS ROUTINE MUST UPDATE THE COUNT FIELD.

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RRV		RECORD POINTER TO USE
!		RECPTR		<IGNORED>
!
!	SIDRBD		BUCKET DESCRIPTOR OF SIDR BUCKET (OLD BUCKET)
!	NEWBD		BUCKET DESCRIPTOR OF NEW BUCKET (RETURNED)

! OUTPUT:
!	TRUE:	OK, SIDR CREATED
!	FALSE:	ERROR
!		NO MORE BUCKET LEFT
!		BUCKET BUSY

! ROUTNES CALLED:
!	ALCBKT
!	MAKESIDR

GLOBAL ROUTINE BLDCSIDR ( RECDESC, SIDRBD, NEWBD ) =
BEGIN
	ARGUMENT	(RECDESC,BASEADD);
	ARGUMENT	(SIDRBD,BASEADD);	
	ARGUMENT	(NEWBD,BASEADD);
MAP
    RECDESC:	POINTER,
    SIDRBD:	POINTER,
    NEWBD:	POINTER;

LOCAL
    BKTSIZE,		! SIZE OF THIS BUCKET
    THISLEVEL,		! LEVEL OF THIS BUCKET
    NEWFLAGS,		! FLAGS FOR NEW BUCKET
    TPTR:	POINTER;

REGISTER
    OLDBKTPTR:	POINTER,	! PTR TO OLD SIDR BUCKET
    NEWBKTPTR:	POINTER;


	TRACE ('BLDCSIDR');

	OLDBKTPTR = .SIDRBD [ BKDBKTADR ];	! GET SOME POINTERS
	NEWFLAGS = .OLDBKTPTR [ BHFLAGS ] AND BHFLGEND;	! SAVE END BIT

	%([ ALLOCATE A NEW BUCKET ])%

	IF CALLALCBKT (%(TYPE)%		PCI ( BTYPEDATA ),
			%(FLAGS)%	LCI ( NEWFLAGS ),
			%(LEVEL)%	PCI ( DATALEVEL ),
			%(BD)%		BPT ( NEWBD ) ) IS FALSE
	THEN
		RETURN FALSE;


	%([ WE NOW HAVE A BUCKET. FIRST, WE MUST CLEAR THE END
	   BIT OF THE OLD BUCKET ])%

	CLRFLAG ( OLDBKTPTR [ BHFLAGS ], BHFLGEND );

	%([ LINK THIS BUCKET INTO THE CHAIN ])%

	NEWBKTPTR = .NEWBD [ BKDBKTADR ];
	NEWBKTPTR [ BHNEXTBKT ] = .OLDBKTPTR [ BHNEXTBKT ];	! MOVE VALUE OVER
	OLDBKTPTR [ BHNEXTBKT ] = .NEWBD [ BKDBKTNO ];	! LINK TO LAST ONE

	%([ NOW, CREATE A NEW SIDR RECORD AT THE TOP OF THE BUCKET ])%

	TPTR = .NEWBKTPTR + BHHDRSIZE;		! STORE IN LOCAL
	RECDESC [ RDRECPTR ] = .TPTR;		! RETURN IT TO CALLER

	%([ ALLOCATE RFA FOR SIDR RECORD ])%

	RECDESC [ RDRFA ] = CALLALCRFA ( BPT ( NEWBD ) );

	CALLMAKESIDR (	%(RD)%	BPT ( RECDESC ),
			%(PTR)%	LPT ( TPTR ) );

	%([ BUMP THE BUCKET HEADER DATA ])%

	INC ( NEWBKTPTR [ BHNEXTBYTE ], SIDRHDRSIZE + .KDB [ KDBKSZW ] + 1 );

	GOODRETURN
END; %(OF BLDCSIDR)%


! DOSIDR
! ======

! ROUTINE TO PERFORM THE ACTUAL INSERTION OF A SIDR RECORD.
!	THIS ROUTINE DETERMINES WHETHER THE INSERTION WILL
!	CAUSE THE CREATION OF A BRAND NEW SIDR RECORD, A
!	CONTINUATION RECORD (DUPS ALLOWED ONLY), OR JUST
!	THE ADDITION OF A RECORD POINTER THE THE END OF AN
!	EXISTING SIDR ARRAY.
!
!	NO INDEX MODIFICATION OR FILE BUCKET UPDATING IS DONE
!	WITHIN THIS ROUTINE

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RRV		RECORD POINTER TO INSERT INTO SIDR
!		RECPTR		ADDRESS OF SEARCH TERMINATION
!				(I.E., 1ST RECORD WITH KEY > K(S) )
!		LASTRECPTR	RECORD BEFORE SEARCH TERMINATION RECORD
!
!	SIDRBD		BUCKET DESCRIPTOR OF CURRENT SIDR BUCKET
!	SPLITBD		BUCKET DESCRIPTOR OF EXTRA BUCKET (RETURNED)

! OUTPUT:
!	TRUE:	OK, SIDR IS INSERTED
!	FALSE:	ERROR
!		NO MORE BUCKETS
!		BUCKET BUSY

! INPUT ARGS MODIFIED:
!	RECORD DESCRIPTOR:
!		RECPTR		ADDRESS OF THE SIDR RECORD
!		SIDRELEMENT	OFFSET INTO SIDR OF CURRENT RECORD POINTER
!

! NOTES:
!	
!	1.	IF NO DUP RECORDS WERE SEEN, THEN RECPTR POINTS TO
!		THE PLACE WHERE WE NEED TO INSERT THE NEW SIDR
!		RECORD. IF DUPS WERE SEEN, THEN RECPTR POINTS TO
![12]		THE FINAL DUPLICATE SIDR ARRAY (INCLUDING CONTINUATIONS),
![12]		AND LASTRECPTR HAS BEEN RESET TO POINT TO THE PREVIOUS SIDR.


GLOBAL ROUTINE DOSIDR ( RECDESC, SIDRBD, SPLITBD ) =
BEGIN

	ARGUMENT	(RECDESC,BASEADD);
	ARGUMENT	(SIDRBD,BASEADD);
	ARGUMENT	(SPLITBD,BASEADD);

MAP
    RECDESC:	POINTER,
    SIDRBD:	POINTER,
    SPLITBD:	POINTER;
LABEL LOOP;

REGISTER
    SIDRPTR:	POINTER,	! PTR TO CURRENT SIDR
    TPTR:	POINTER,		! TEMP POINTER
    TEMPAC;			! TEMP AC

LOCAL
    TOPOFBKTPTR:	POINTER,	! PTR TO TOP OF CURRENT BUCKET
    ENDBKTPTR:	POINTER,	! PTR TO END OF CURRENT BUCKET
    DATAPTR:	POINTER,	! PTR TO DATA PORTION OF SIDR
    FREESPACE,		! AMOUNT OF SPACE LEFT IN THIS BUCKET
    DUMMYBD:	FORMATS[ BDSIZE ],	! DUMMY BKT DESC USED FOR SPLIT
    KEYSIZEINWORDS,		! SAME AS IN KDB
    savestatus,			! **B36. TO SAVE STATUS OF A ROUTINE
!** [12] ROUTINE:DOSIDR AT LINE 6976, EGM, 3-APR-78
%([12])%    ENDOFSIDRPTR:	POINTER,	! PTR TO EN OF CURRENT SIDR
%([12])%    KEYBUFFPTR:	POINTER;	! PTR TO RST KEY BUFFER


	TRACE ('DOSIDR');
	CHECKEXACTCOUNT;

	%([ SET UP SOME BUCKET POINTERS ])%

	TOPOFBKTPTR = .SIDRBD [ BKDBKTADR ];
	FREESPACE = ( .KDB [ KDBDBKZ ] ^ B2W ) - ( ENDBKTPTR = 
			.TOPOFBKTPTR [ BHNEXTBYTE ] );
	LOOKAT ('	FREE-SPACE: ', FREESPACE );
	INC ( ENDBKTPTR, .TOPOFBKTPTR );	! FORM ABS PTR TO END

	%([ DID WE SEE A DUPLICATE RECORD? IF SO, THEN WE NEED
	   TO TRY TO ADD ONE MORE POINTER TO THE ARRAY. IF NOT,
	   WE MUST CREATE AN ENTIRELY NEW SIDR RECORD ])%

	IF DUPLICATEFLAG ( RECDESC ) IS OFF
	THEN	%(THIS IS THE FIRST INSERT OF THIS KEY)%

		BEGIN

		%([ INDICATE THAT THE CURRENT POINTER IS FIRST IN ARRAY ])%

		RECDESC [ RDSIDRELEMENT ] = 1;
		RETURN CALLBLDISIDR (	%(RD)%		BPT ( RECDESC ),
					%(BD)%		BPT ( SIDRBD ),
					%(SPLIT)%	BPT ( SPLITBD ) )
		END; %(OF IF NO DUP WAS SEEN)%

	%([ WE HAVE ALREADY PROCESSED A DUP OF THIS KEY VALUE ])%

	%IF DBUG %THEN
	IF ( CHKFLAG ( KDB [ KDBFLAGS ], FLGDUP ) IS OFF ) THEN RMSBUG ( MSGFLAGS );
	%FI

!** [12] ROUTINE:DOSIDR AT LINE 7013, EGM, 3-APR-78
%([12])%	SIDRPTR = .RECDESC [ RDRECPTR ];	! GET ADDRESS OF LAST SIDR
	LOOKAT ('	CURRENT SIDR REC IS AT: ', SIDRPTR );

	%([ CHECK THAT IT IS IN THE CURRENT BUCKET ])%

	IF ( ( .SIDRPTR LEQ .TOPOFBKTPTR )
			OR
		( .SIDRPTR GTR .ENDBKTPTR ) ) THEN RMSBUG ( MSGPTR );

	%([ UNLESS THIS BUCKET IS COMPLETELY FILLED, WE CAN ALWAYS
	   FIT ONE MORE RECORD POINTER INTO THE ARRAY. THEREFORE,
	   WE MUST DETERMINE IF THE BUCKET IS FULL AND IF NOT,
	   WE WILL MORE THE BOTTOM DOWN AND INSERT THE RECORD
	   POINTER. IF SO, WE MUST EITHER SPLIT THE BUCKET OR
	   CREATE A CONTINUATION SIDR ])%

	KEYSIZEINWORDS = .KDB [ KDBKSZW ];		! MAKE THIS HANDY
	DATAPTR = .SIDRPTR + SIDRHDRSIZE;	! GET PTR TO DATA PORTION OF SIDR
	ENDOFSIDRPTR = .DATAPTR + .SIDRPTR [ SIDRRECSIZE ] -1;

	%([ COMPUTE THE OFFSET INTO THE SIDR OF THE CURRENT POINTER ])%

	RECDESC [ RDSIDRELEMENT ] = .ENDOFSIDRPTR - .DATAPTR -.KEYSIZEINWORDS + 1;

	IF .FREESPACE LEQ ZERO		!**[6]**MAY BE NEGATIVE IF COMPLETELY FULL
	THEN	%(THE BUCKET IS COMPLETELY FULL)%

		BEGIN
		RTRACE (%STRING('	BKT IS FULL...',%CHAR(13),%CHAR(10)));

		%([ WE CAN'T FIT THE NEW SIDR IN THE BUCKET, SO
		   WE MUST SPLIT. HOWEVER, IF THIS ARRAY IS
		   THE LAST RECORD IN THE BUCKET, THEN WE
		   DON'T WANT TO SPLIT THE BUCKETS EVENLY
		   BECAUSE THAT WOULD UNNECESSARILY DISTRIBUTE
		   DUP RECORDS ACROSS BUCKETS. WHAT WE NEED TO
		   DO IS TO BUILD A CONTINUATION RECORD IN A
		   NEW BUCKET BY ITSELF. THEN, IT WILL GROW 
		   UNTIL IT FILLS UP THAT BUCKET, THEN ANOTHER
		   CONTINUATION WILL BE ALLOCATED, ETC. ])%

		IF ( .ENDOFSIDRPTR + 1 ) IS .ENDBKTPTR
		THEN	%(WE NEED A CONTINUATION RECORD)%

			BEGIN
			RTRACE (%STRING('	BUILDING CONT. RECORD',%CHAR(13),%CHAR(10)));
			SAVESTATUS = CALLBLDCSIDR (BPT ( RECDESC ),
						BPT ( SIDRBD ),
						BPT ( SPLITBD ) );

			%([ WE MUST INSURE THAT THE CONTINUATION SIDR
			   GETS WRITTEN OUT, BUT IT SHOULD NOT BE
			   ENTERED INTO THE INDEX. ])%

			RECDESC [ RDCOUNT ] = 1;	! BKT WILL BE UPDATED

			RETURN .SAVESTATUS
			END; %(OF IF THIS IS LAST SIDR IN BUCKET)%

		RECDESC [ RDLENGTH ] = ZERO;		! JUST SPLIT, DONT INSERT

		%([ SPLIT THE SIDR BUCKET ])%

		IF CALLSPLIT (  BPT ( RECDESC ),
				BPT ( SIDRBD ),
				BPT ( SPLITBD ),
				LCT ( DUMMYBD ) ) IS FALSE
		THEN
			RETURN FALSE;

		%([ WE NOW MUST ASSIGN NEW ID'S FOR ALL THE SIDR
		   RECORDS WHICH MOVED TO THE NEW BUCKET. ])%

		CALLALCNEWIDS ( %(NEW BKT)%	BPT ( SPLITBD ) );

		%([ CHECK TO SEE IF THE SIDR MOVED TO THE NEW
		   BUCKET ])%

		%([ NOW, THE SIDR IS EITHER IN THE CURRENT BUCKET
		   OR IT WAS MOVED TO THE TOP OF THE NEXT BUCKET.
		   THIS IS TRUE BECAUSE THE SPLIT ALGORITHM ALWAYS
		   TRIES TO KEEP R-NEW ON THE CURRENT BUCKET AND
		   SINCE THE SIZE OF R-NEW WAS ZERO, THIS WILL ALWAYS
		   BE TRUE. SO, WE MUST CHECK RECPTR AND IF IT POINTS
		   TO THE END OF THIS BUCKET, THEN WE KNOW THE SIDR
		   IS REALLY AT THE TOP OF THE NEXT BUCKET. ])%

		IF ( .SIDRPTR - .TOPOFBKTPTR ) IS ( .TOPOFBKTPTR [ BHNEXTBYTE ] )
		THEN	%(THE SIDR HAS MOVED TO TOP OF NEXT BUCKET)%

			BEGIN
			SIDRPTR = .SPLITBD [ BKDBKTADR ] + BHHDRSIZE;
			RTRACE (%STRING('	SIDR MOVED TO NEW BKT',%CHAR(13),%CHAR(10)));
			TOPOFBKTPTR = .SPLITBD [ BKDBKTADR ];
!** [12] ROUTINE:DOSIDR AT LINE 7106, EGM, 3-APR-78
%([12])%			ENDOFSIDRPTR = .SIDRPTR + SIDRHDRSIZE
%([12])%				+ .SIDRPTR [ SIDRRECSIZE ] - 1
%([12])%			END; %(OF IF SIDR MOVED)%
%([12])%
%([12])%		%([ RDLASTRECPTR NOW POINTS TO THE LAST SIDR ARRAY )%
%([12])%		%(  IN THE ORIGINAL BUCKET, HAVING BEEN RESET )%
%([12])%		%(  BY SPLIT (SIDR IN OLD) OR LEFT AS RECIEVED FROM )%
%([12])%		%(  PUTSIDR (SIDR IN NEW). )%
%([12])%		%(  MOVE THIS NEW HIGH KEY VALUE INTO THE RST )%
%([12])%		%(  KEY BUFFER. ])%
%([12])%
%([12])%		TPTR = .RECDESC [ RDLASTRECPTR ] + SIDRHDRSIZE;
%([12])%		KEYBUFFPTR = .RST [ RSTKEYBUFF ] + ( .FST [ FSTKBFSIZE ] / 2 );
%([12])%		MOVEWORDS ( 	%(FROM)%	.TPTR,
%([12])%				%(TO)%	.KEYBUFFPTR,
%([12])%				%(SIZE)%	.KDB [ KDBKSZW ] )

		END; 	%(OF IF BUCKET IS FULL)%

	%([ RE-COMPUTE THE ENDOF THIS BUCKET DATA ])%

	ENDBKTPTR = .TOPOFBKTPTR + .TOPOFBKTPTR [ BHNEXTBYTE ];

	%([ MOVE THE DATA DOWN IN THE BUCKET ])%

	TEMPAC = .ENDBKTPTR - .ENDOFSIDRPTR - 1;		! COMPUTE HOW MUCH TO MOVE
	IF .TEMPAC ISNT ZERO
	THEN	%(WE NEED TO MOVE SOME DATA DOWN)%
		BEGIN
		MOVEDOWN (	%(START)%	(.ENDOFSIDRPTR + 1),
				%(END)%	.ENDBKTPTR -1,
				%(SIZE)%	1 )
		END; %(OF IF WE NEED TO MOVE DATA)%

	%([ BUMP THE END-OF-BUCKET INDICATOR ])%

	INC ( TOPOFBKTPTR [ BHNEXTBYTE ], 1);

	%([ STORE THE NEW RECORD POINTER ])%

	ENDOFSIDRPTR [ 1, WRD ] = .RECDESC [ RDRRV ];

	%([ BUMP THE SIZE OF THIS SIDR RECORD ])%

	INC ( SIDRPTR [ SIDRRECSIZE ], 1 );

	%([ RESET RECPTR TO POINT TO THE LOCATION OF THE SIDR ])%

	RECDESC [ RDRECPTR ] = .SIDRPTR;

	GOODRETURN
END; %(OF DOSIDR)%


! INSRTSIDR
! =========

! ROUTINE TO INSERT A SECONDARY DATA RECORD (SIDR).
!	THIS ROUTINE ACTUALLY IS THE OUTER-LEVEL ROUTINE
!	WHICH GUIDES THE INSERTION OF THE SIDR. IT PERFORMS
!	NO DATA MANIPULATION OR RECORD CREATION. SUCH
!	ACTIONS ARE DONE BY "DOSIDR".  THIS ROUTINE SIMPLY
!	CALLS DOSIDR AND THEN UPDATES ANY FILE PAGES
!	WHICH NEED TO BE WRITTEN TO THE FILE.

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RRV		RECORD POINTER TO INSERT INTO SIDR
!		RECPTR		ADDRESS OF SEARCH TERMINATION
!				(I.E., 1ST RECORD WITH K > K(S) )
!		LASTRECPTR	RECORD BEFORE SEARCH TERMINATION RECORD
!
!	SIDRBD		BUCKET DESCRIPTOR OF CURRENT SIDR BUCKET
!	SPLITBD		BUCKET DESCRIPTOR OF EXTRA BUCKET (RETURNED)

! OUTPUT:
!	TRUE:	SIDR RECORD INSERTED PROPERLY AND FILE UPDATED
!	FALSE:	ERROR
!		NO MORE BUCKETS

! ROUTINES CALLED:
!	DOSIDR

GLOBAL ROUTINE INSRTSIDR ( RECDESC, SIDRBD, SPLITBD ) =
BEGIN

	ARGUMENT	(RECDESC,BASEADD);
	ARGUMENT	(SIDRBD,BASEADD);
	ARGUMENT	(SPLITBD,BASEADD);

MAP
    RECDESC:	POINTER,
    SIDRBD:	POINTER,
    SPLITBD:	POINTER;
	TRACE ('INSRTSIDR');

	%([ CLEAR THE NUMBER OF NEW SPLIT BUCKETS ])%

	RECDESC [ RDCOUNT ] = ZERO;

	%([ DO THE INSERTION ])%

	IF CALLDOSIDR ( %(REC DESC)%	BPT ( RECDESC ),
			%(BKT)%		BPT ( SIDRBD ),
			%(SPLIT)%	BPT ( SPLITBD ) ) IS FALSE

	%([ WHAT HAPPENED? ])%

	THEN
		RETURN FALSE;

	%([ IF WE SPLIT, THEN WE MUST UPDATE THE NEW FILE BUCKET ])%

	IF .RECDESC [ RDCOUNT ] IS 1
	THEN
		CALLPUTBKT (	%(UPDATE)%	PCI ( TRUE ),
				%(BUCKET)%	BPT ( SPLITBD ) );

	%([ UPDATE THE BUCKET IN WHICH THE SIDR WAS INSERTED ])%

	CALLPUTBKT (	%(UPDATE)%	PCI ( TRUE ),
			%(BUCKET)%	BPT ( SIDRBD ) );

	GOODRETURN

END; %(OF INSRTSIDR)%


! BLDISIDR
! ========

! ROUTINE TO BUILD THE FIRST INSTANCE OF A SPECIFIC SECONDARY
!	DATA RECORD. THIS ROUTINE IS CALLED ONLY WHEN THE SIDR
!	RECORD IS BEING INITIALLY CREATED. CONTINUATION SIDR'S
!	ARE CREATED ONLY BY "BLDCSIDR".

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RRV		RECORD POINTER TO USE
!		RECPTR		ADDRESS TO INSERT SIDR
!
!	SIDRBD		BUCKET DESCRIPTOR OF SIDR BUCKET (OLD BUCKET)
!	NEWBD		BUCKET DESCRIPTOR OF NEW BUCKET (RETURNED)
!
! OUTPUT:
!	TRUE:	SIDR INSERTED CORRECTLY
!	FALSE:	SIDR COULD NOT BE INSERTED (ERROR CODE IS IN USRSTS)
!
! ROUTINES CALLED:
!	SPLIT
!	MAKESIDR
!	ALCNEWIDS

GLOBAL ROUTINE BLDISIDR ( RECDESC, SIDRBD, SPLITBD ) =
BEGIN
	ARGUMENT	(RECDESC,BASEADD);
	ARGUMENT	(SIDRBD,BASEADD);
	ARGUMENT	(SPLITBD,BASEADD);
MAP
    RECDESC:	POINTER,
    SIDRBD:	POINTER,
    SPLITBD:	POINTER;

REGISTER
    PTRAC:	POINTER,
    BKTPTR:	POINTER,		! PTR TO TOP OF CURRENT BUCKET
    TEMPAC;

LOCAL
    ENDPTR:	POINTER,		! PTR TO END OF CURRENT BUCKET
    INSERTPTR:	POINTER,	! PTR TO PLACE TO INSERT NEWSIDR
    DUMMYBD:	FORMATS[ BDSIZE ],	! DUMMY BKT DESC FOR SPLIT
    CURRENTBD:	FORMATS[ BDSIZE ],	! CURRENT BUCKET
    SPLITFLAG,		! FOR IS ON IF WE SPLI THE BUCKET
    MAXOFFSET,		! OFFSET INTO BUCKET TO DETERMINE IF FULL
    KEYBUFFPTR:	POINTER,	! PTR TO RST KEY BUFFER
    SPACENEEDED;		! SIZE OF NEW SIDR



	TRACE ('BLDISIDR');

	%([ ASSUME NO SPLITS ])%

	SPLITFLAG = FALSE;

	%([ SET UP SOME POINTERS AND FIGURE OUT HOW MUCH SPACE
	   WE HAVE LEFT IN THIS BUCKET ])%

	INSERTPTR = .RECDESC [ RDRECPTR ];
	BKTPTR = .SIDRBD [ BKDBKTADR ];		! ADDRESS OF BUCKET
	RECDESC [ RDLENGTH ] = ( SPACENEEDED = SIDRHDRSIZE + .KDB [ KDBKSZW ] + 1);	
	LOOKAT ('	SPACE-NEEDED: ',SPACENEEDED );

	%([ CAN THIS NEW SIDR FIT ONTO THE BUCKET? ])%

	MAXOFFSET = .KDB [ KDBDBKZ ] ^ B2W;	! FIND MAX SIZE OF BUCKET
	IF ( CHKFLAG ( RAB [ RABROP ], ROPLOA ) ISON )
	THEN	%(USER WANTS TO SPECIFY LOAD FILL PERCENT)%
		MAXOFFSET = .KDB [ KDBDFLOFFSET ];

	%([ WILL THE NEW SIDR FIT IN THIS BUCKET? ])%

	IF ( .BKTPTR [ BHNEXTBYTE ] + .SPACENEEDED ) GTR .MAXOFFSET
	THEN	%(IT WONT FIT...WE MUST SPLIT THE SIDR BUCKET)%

		BEGIN
		RTRACE (%STRING('	SIDR WONT FIT...',%CHAR(13),%CHAR(10)));

		%([ SPLIT THE SIDR BUCKET ])%

		IF CALLSPLIT ( BPT ( RECDESC ),
				BPT ( SIDRBD ),
				BPT ( SPLITBD ),
				LCT ( DUMMYBD ) ) IS FALSE

		%([ WHAT HAPPENED? ])%

		THEN 
			RETURN FALSE;
		SPLITFLAG = 1;				! SET THIS FLAG FOR LATER

		%IF DBUG %THEN
		IF .RECDESC [ RDCOUNT ] GEQ 2 THEN RMSBUG ( MSGSPLIT );
		%FI

		%([ DETERMINE IF THE INSERTION POINT WAS MOVED
		   TO THE NEW BUCKET ])%

		INSERTPTR = .RECDESC [ RDRECPTR ];	! FETCH ADDR OF SIDR
		END 	%(OF IF WE NEED TO SPLIT)%

	ELSE	%(THE SIDR CAN FIT IN THIS BUCKET...)%

		BEGIN

		%([ WE NOW MUST LOCATE THE END OF THE DATA IN THE
		   CURRENT BUCKET ])%
	
		ENDPTR = .BKTPTR + .BKTPTR [ BHNEXTBYTE ];
	
		%([ COMPUTE AMOUNT OF DATA TO MOVE DOWN ])%
	
		TEMPAC = .ENDPTR - .INSERTPTR;
		LOOKAT ('	AMOUNT-TO-MOVE: ', TEMPAC );
		%IF DBUG %THEN
		IF .TEMPAC LSS ZERO THEN RMSBUG ( MSGCOUNT );
		%FI
	
		IF .TEMPAC ISNT ZERO
		THEN
			BEGIN
			MOVEDOWN (	%(START)%	.INSERTPTR,
					%(END)%	.ENDPTR -1,
					%(SIZE)%	.SPACENEEDED )
			END; %(OF IF WE NEED TO MOVE DATA DOWN)%
	
		%([ ALLOCATE AN RFA FOR THE NEW SIDR (SPLIT ALREADY
		   DID THIS FOR US IF THE BUCKET SPLIT) ])%

		RECDESC [ RDRFA ] = CALLALCRFA ( BPT ( SIDRBD ) );

		%([ BUMP THE BUCKET HEADER NEXT-BYTE VALUE ])%
	
		INC ( BKTPTR [ BHNEXTBYTE ], .SPACENEEDED )
		END; %(OF THE SIDR BUCKET DOES NOT HAVE TO BE SPLIT)%


	%([ CREATE THE SIDR RECORD ])%

	CALLMAKESIDR (	%(RD)%	BPT ( RECDESC ),
			%(PLACE)%	LPT ( INSERTPTR ) );

	%([ IF WE DIDNT'T SPLIT THE SIDR BUCKET, THEN WE CAN EXIT ])%

	IF .SPLITFLAG IS FALSE THEN GOODRETURN;

	%([ WE NOW MUST ASSIGN ID'S FOR ALL SIDR RECORDS WHICH
	   MOVED TO THE NEW BUCKET. WE ALSO MUST MOVE THE NEW
	   HIGH-KEY VALUE IN THE ORIGINAL BUCKET INTO THE KEY
	   BUFFER (THE BOTTOM HALF OF IT) SO THAT "INDEX-UPDATE"
	   WILL KNOW WHAT KEY TO PUT IN THE OLD INDEX RECORD.
	   NOTE THAT THE MOVING OF THIS KEY MUST BE DONE AFTER
	   THE NEW SIDR IS CREATED SINCE THE NEW RECORD TO BE
	   INSERTED MAY BE THE NEW HIGH-KEY RECORD. ])%

	%([ **NOTE THAT THE INDEX-UPDATE FLAG BIT WAS SET BY SPLIT*** ])%

	%([ WE NOW MUST MOVE THE NEW HIGH-KEY VALUE FOR THE
	   ORIGINAL BUCKET INTO THE RST KEY BUFFER ])%

	PTRAC = .RECDESC [ RDLASTRECPTR ] + SIDRHDRSIZE;	! PTR TO KEY
	KEYBUFFPTR = .RST [ RSTKEYBUFF ] + ( .FST [ FSTKBFSIZE ] ^ DIVIDEBY2LSH );
	MOVEWORDS ( 	%(FROM)%	.PTRAC,
			%(TO)%	.KEYBUFFPTR,
			%(SIZE)%	.KDB [ KDBKSZW ] );


	%([ WE NOW MUST ASSIGN NEW ID'S FOR ALL THE SIDR
	   RECORDS WHICH MOVED TO THE NEW BUCKET. ])%

	CALLALCNEWIDS ( %(NEW BKT)%	BPT ( SPLITBD ) );

	GOODRETURN


END; %(OF BLDISIDR)%




! DELSIDR
! =======

! ROUTINE TO DELETE A SINGLE RECORD-POINTER FROM THE SECONDARY
!	INDEX DATA RECORDS. THIS ROUTINE IS CALLED WHENEVER
!	A $PUT TO AN INDEXED FILE RESULTS IN AN ERROR DURING
!	PROCESSING OF ONE OF THE SECONDARY INDICES. IN SUCH A
!	CASE, ALL THE PREVIOUS SECONARY INDICES MUST BE MODIFIED
!	SO THAT THE RECORD IS REMOVED.
!
!	IF THE SECONDARY INDEX ALLOWS DUPLICATES, THEN EACH SIDR
!	POINTER ARRAY MUST BE SCANNED UNTIL THE CORRECT ENTRY IS
!	FOUND AND THEN IT CAN BE DELETED. IF NO DUPLICATES ARE
!	ALLOWED, THEN THE ENTIRE SECONDARY DATA RECORD CAN BE
!	SQUEEZED FROM THE BUCKET.

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		USERPTR		ADDRESS OF SEARCH KEY STRING
!		USERSIZE	SIZE OF SEARCH KEY STRING
!		RRV		RFA OF RECORD TO BE DELETED

! OUTPUT:
!	TRUE:	RECORD FOUND AND DELETED
!	FALSE:	ERROR
!		RECORD NOT FOUND
!
! NOTES:
!
!	1.	THE INDEX MUST BE LOCKED WHEN THIS ROUTINE IS CALLED.

! ROUTINES CALLED:
!	FNDREC


GLOBAL ROUTINE DELSIDR ( RECDESC ) =
BEGIN
	ARGUMENT	(RECDESC,BASEADD);

MAP
    RECDESC:	POINTER;

REGISTER
    SIDRPTR:	POINTER,	! PTR TO CURRENT SIDR
    ARRAYPTR:	POINTER;		! PTR TO SIDR POINTER ARRAY

LOCAL
    SIDRBD:	FORMATS[ BDSIZE ],	! BKT DESC FOR SIDR BUCKETS
    DUMMYBD:	FORMATS[ BDSIZE ],	! A TEMPORARY BKT DESCRIPTOR
    RECORDPOINTER,			! RFA TO SEARCH FOR
    DUMMYPTR:	POINTER,		! USED TO PASS SIDRPTR AS LOCAL
    BKTPTR:	POINTER,			! PTR TO CURRENT SIDR BUCKET
    ENDPTR:	POINTER,			! PTR TO END OF CURRENT BUCKET
    AMOUNTTOMOVE,			! AMOUNT OF DATA TO SQUEEZE
    PTRCOUNT,			! # OF PTRS IN CURRENT ARRAY
    OFFSETTOPTRS,			! OFFSET TO PTRS IN SIDR ARRAY
    SAVEDSTATUS;			! RESULTS OF A ROUTINE

EXTERNAL ROUTINE
    SQUEEZESIDR;

LABEL BIGLOOP;				! LABELS

	TRACE ('DELSIDR');
	CHECKEXACTCOUNT;

	%([ CHECK A FEW THINGS ])%

	%IF DBUG %THEN
	IF .KDB [ KDBREF ] IS REFPRIMARY THEN RMSBUG ( MSGINPUT );
	%FI

	%([ SET UP THE RFA OF OUR TARGET RECORD ])%

	RECORDPOINTER = .RECDESC [ RDRRV ];

	%([ WE WILL TRY TO SEARCH THE ENTIRE INDEX AND POSITION
	   TO THE SIDR RECORD ])%

	IF CALLFNDDATA ( %(RD)%	BPT ( RECDESC ),
			%(BKT)%	LCT ( SIDRBD ) ) IS FALSE
	THEN
		RETURN FALSE;

	%([ DID WE STOP AT THE DATA LEVEL? ])%

	IF .RECDESC [ RDLASTLEVEL ] ISNT DATALEVEL THEN BADRETURN;

	%([ AT THIS POINT, WE WILL DEFINE A DUMMY BLOCK WHICH
	   WE WILL BE ABLE TO EXIT FROM. ])%

BIGLOOP:	BEGIN
	%([ THE RECORD WAS EITHER NOT FOUND, OR THERE WAS AN
	   EXACT MATCH. CHECK IF THE RECORD WAS FOUND ])%

	IF CHKFLAG ( RECDESC [ RDSTATUS ], RDFLGPST+RDFLGLSS) ISON
	THEN	%(THE RECORD WASNT FOUND)%
		LEAVE BIGLOOP WITH ( SAVEDSTATUS = FALSE );

	%([ WE HAVE FOUND AN EXACT MATCH. WE MUST NOW CHECK IF WE
	   CAN FIND THE RECORD POINTER IN THIS ARRAY. ])%

	SIDRPTR = .RECDESC [ RDRECPTR ];		! GET PTR TO SIDR
	OFFSETTOPTRS = SIDRHDRSIZE + .KDB [ KDBKSZW ];	! COMPUTE THIS NOW

	%([ IF NO DUPS ARE ALLOWED, THEN WE MUST COMPARE OUR
	   SEARCH KEY RECORD ADDRESS WITH THE ONE IN THIS SIDR. ])%

	IF CHKFLAG ( KDB [ KDBFLAGS ], FLGDUP ) IS OFF
	THEN	%(NO DUPS ARE ALLOWED)%

		BEGIN
		RTRACE (%STRING('	SEARCHING THIS SIDR...',%CHAR(13),%CHAR(10)));
		ARRAYPTR = .SIDRPTR + .OFFSETTOPTRS;	! PTR TO RFA'S
		IF .ARRAYPTR [ WHOLEWORD ] ISNT .RECORDPOINTER
		THEN	%(THE RECORD WASNT FOUND)%
			LEAVE BIGLOOP WITH ( SAVEDSTATUS = FALSE );

		%([ WE CAN SET THIS RFA TO BE DELETED ])%

		DUMMYPTR = .SIDRPTR;		! STORE PTR AS LOCAL
		CALLSQUEEZESIDR (	LPT ( DUMMYPTR ),
					LCT ( SIDRBD ) );
		SAVEDSTATUS = TRUE
		END	%(IF IF NO DUPS ARE ALLOWED)%

	ELSE	%(DUPS ARE ALLOWED)%
		BEGIN

		%([ WE MUST SCAN ALL SIDR'S UNTIL WE FIND THE CORRECT
		   RECORD POINTER. WE MAY HIT THE END OF THE CHAIN 
		   FIRST, IN WHICH CASE WE MUST EXIT WITH FAILURE. ])%

		REPEAT	%(THIS LOOP FOREVER)%

			BEGIN
			RTRACE (%STRING('	SCANNING SIDR...',%CHAR(13),%CHAR(10)));
			SIDRPTR = .RECDESC [ RDRECPTR ];	! GET SIDR PTR AGAIN
			BKTPTR = .SIDRBD [ BKDBKTADR ];		! FETCH THIS AGAIN
			ENDPTR = .BKTPTR + .BKTPTR [ BHNEXTBYTE ];
			PTRCOUNT = .SIDRPTR [ SIDRRECSIZE ] - .KDB [ KDBKSZW ];
			ARRAYPTR = .SIDRPTR + .OFFSETTOPTRS;	! GET PTR TO RFA'S
			LOOKAT ('	SIDRPTR: ', SIDRPTR );
			LOOKAT ('	# OF PTRS: ', PTRCOUNT );

			%([ LOOP OVER ALL POINTERS IN THE ARRAY ])%

			INCR J FROM 0 TO .PTRCOUNT -1
			DO
				BEGIN
				IF ( .ARRAYPTR [ WHOLEWORD ] AND ( NOT ALLRFAFLAGS ) )  IS .RECORDPOINTER
				THEN
					BEGIN
					LOOKAT ('	FOUND RFA AT: ', ARRAYPTR );
					%([ NOTE NO CHECK FOR SIDR ALREADY DELETED ])%
					SETUPD (SIDRBD);	!INDIC THIS PG TO BE UPDATED
					SETDELETEDRFA ( ARRAYPTR );
					LEAVE BIGLOOP WITH ( SAVEDSTATUS = TRUE)
					END; %(OF IF THIS IS THE RIGHT PTR)%
				INC ( ARRAYPTR, 1 )
				END; %(OF INCR LOOP)%

			%([ AT THIS POINT, WE DIDNT FIND THE RP IN
			   THE SIDR. SO, WE MUST CHECK IF THERE ARE
			   ANY CONTINUATION SIDR'S AND IF SO, WE MUST
			   SCAN ALL OF THEM TO SEE IF WE CAN FIND THE
			   CORRECT RFA. ])%

			RTRACE (%STRING('	DIDNT FIND RFA IN SIDR...',%CHAR(13),%CHAR(10)));
			LOOKAT ('	ARRAY-PTR: ', ARRAYPTR );
			IF .ARRAYPTR ISNT .ENDPTR
			THEN	%(THERE ARE NO MORE CONTINUATION SIDR'S)%
				LEAVE BIGLOOP WITH ( SAVEDSTATUS = FALSE );

			%([ START THE SEARCH AT THE END OF THIS BUCKET.
			   ALSO, INDICATE THAT A HORIZONTAL SEARCH IS OK. ])%
			RTRACE (%STRING('	SEARCHING FOR CONT SIDRS...',%CHAR(13),%CHAR(10)));
			SETFLAG ( RECDESC [ RDFLAGS ], RDFLGHORIZOK );
			RECDESC [ RDRECPTR ] = .ENDPTR;

			%([ WE MUST MOVE THE SIDR BUCKET DESCRIPTOR
			   TO A TEMP LOCATION TO INPUT IT TO FNDREC. ])%

			MOVEBKTDESC ( %(FROM)% SIDRBD, %(TO)% DUMMYBD );
			SAVEDSTATUS = CALLFNDREC (	BPT ( RECDESC ),
							LCT ( DUMMYBD ),
							LCT ( SIDRBD ) );

			%([ AT THIS POINT, FNDREC RETURNED A STATUS OF TRUE
			   UNLESS THERE WAS A FATAL PROBLEM (NO SPACE LEFT
			   FOR BUCKETS, ...). HOWEVER, WE MUST CHECK THE
			   STATUS BITS BECAUSE THE NEW RECORD MAY NOT
			   BE A CONTINUATION RECORD, OR THE END OF THE
			   BUCKET CHAIN MAY HAVE BEEN REACHED. IN ALL THESE
			   CASES, WE MUST EXIT FROM THE LOOP. ])%

			IF	( .SAVEDSTATUS IS FALSE )
					OR
				( CHKFLAG ( RECDESC [ RDSTATUS ], RDFLGLSS+RDFLGPST) ISON )
			THEN	%(THIS WAS NOT A CONTINUATION SIDR)%
				LEAVE BIGLOOP WITH ( SAVEDSTATUS = FALSE )

			END %(OF REPEAT LOOP)%

		END	%(OF ELSE DUPS ARE ALLOWED)%
		END;	%(OF BIGLOOP)%

	%([ COME HERE WITH SAVEDSTATUS = STATUS OF OUR OPERATION.
	   WE MUST RELEASE THE CURRENT BUCKET AND RETURN
	   TO THE CALLER. ])%


	%([ NOTE THAT WE WILL NOT WRITE OUT THIS BUCKET NOW.
	   IT IS VERY LIKELY THAT IT WILL GO OUT SOON, AND WE NEED
	   TO SAVE SOME TIME. ])%

	CALLPUTBKT (	%(NO UPDATE)%	PCI ( FALSE ),
			%(SIDR)%		LCT ( SIDRBD ) );

	
	RETURN .SAVEDSTATUS

END; %(OF DELSIDR)%


! SQUEEZESIDR
! ===========

! ROUTINE TO SQUEEZE A SINGLE SECONDARY DATA RECORD FROM A BUCKET.
!	THIS ROUTINE CAN ONLY BE CALLED IF THE SIDR CONTAINS ONLY
!	ONE RECORD POINTER.

! INPUT:
!	SIDRPTR		ADDRESS OF SIDR RECORD
!	SIDRBD		BUCKET DESCRIPTOR OF SIDR BUCKET

! OUTPUT:
!	<NO STATUS RETURNED>

! ROUTINES CALLED:
!	<NONE>


GLOBAL ROUTINE SQUEEZESIDR ( SIDRPTR, SIDRBD ):NOVALUE =
BEGIN
	ARGUMENT	(SIDRPTR,BASEADD);
	ARGUMENT	(SIDRBD,BASEADD);
MAP
    SIDRPTR:	POINTER,
    SIDRBD:	POINTER;

REGISTER
    BKTPTR:	POINTER,	! PTR TO SIDR BUCKET
    ENDPTR:	POINTER;		! PTR TO END OF SIDR BUCKET

LOCAL
    AMOUNTTOMOVE,		! DATA TO MOVE UP IN BUCKET
    SIZEOFSIDR;		! SIZE OF SIDR HEADER AND KEY


	TRACE ('SQUEEZESIDR');

	%([ PICK UP THE BUCKET ADDRESS AND FIND END OF BUCKET ])%

	SETUPD (SIDRBD);			!INDIC THIS PG TO BE UPDATED
	BKTPTR = .SIDRBD [ BKDBKTADR ];
	ENDPTR = .BKTPTR + .BKTPTR [ BHNEXTBYTE ];
	SIZEOFSIDR = SIDRHDRSIZE + .KDB [ KDBKSZW ] + 1;
	AMOUNTTOMOVE = .ENDPTR - .SIDRPTR - .SIZEOFSIDR;
	LOOKAT ('	AMOUNT-TO-MOVE: ', AMOUNTTOMOVE );
	LOOKAT ('	END OF BKT: ', ENDPTR );
	IF .AMOUNTTOMOVE ISNT ZERO
	THEN	%(WE HAVE SOME TO MOVE)%
		BEGIN
		RTRACE (%STRING('	SQUEEZING BUCKET...',%CHAR(13),%CHAR(10)));
		MOVEWORDS (	%(FROM)%	.SIDRPTR + .SIZEOFSIDR,
				%(TO)%	.SIDRPTR,
				%(SIZE)%	.AMOUNTTOMOVE )
		END; %(OF IF THERE IS DATA TO MOVE)%

	%([ UPDATE THE BUCKET HEADER INFO ])%

	DEC ( BKTPTR [ BHNEXTBYTE ], ( .SIZEOFSIDR) );

	RETURN 

END; %(OF SQUEEZE-SIDR)%


! PUTSIDR
! =======

! ROUTINE TO INSERT A KEY FROM THE USER DATA RECORD INTO A
!	SECONDARY INDEX. THIS ROUTINE IS CALLED FROM $PUT
!	AND $UPDATE WHENEVER A NEW KEY IS BEING INSERTED
!	INTO THE FILE. THE USER DATA RECORD MUST ALREADY HAVE
!	BEEN CHECK TO MAKE SURE IT IS BIG ENOUGH TO HOLD THE
!	ENTIRE KEY STRING FOR THIS KEY OF REFERENCE.

! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RRV		RECORD ADDRESS TO INSERT INTO SECONDARY INDEX

! OUTPUT:
!	TRUE:	OK...RECORD INSERTED INTO SECONDARY INDEX
!	FALSE:	ERROR

! INPUT ARGS MODIFIED:
!
!	RECORD DESCRIPTOR:
!		STATUS		OPERATION STATUS BITS
!			FLGIDXERROR	INDEX UPDATE ERROR OCCURED

! ROUTINES CALLED:
!	MAKIDX
!	FOLLOWPATH
!	CHKDUP
!	INSRTSIDR
!	IDXUPDATE

! NOTES:
!
!	1.	KDB MUST BE SET UP ON ENTRY FOR THE CURRENT KEY.
!
!	2.	THE INDEX MUST BE LOCKED WHEN THIS ROUTINE IS CALLED.

GLOBAL ROUTINE PUTSIDR ( RECDESC ) =
BEGIN

	ARGUMENT	(RECDESC,BASEADD);	! RECORD DESC PACKET
MAP
    RECDESC:	POINTER;
LABEL	LOOP;

LOCAL
    USERRECORDPTR:	POINTER,			! PTR TO USER DATA RECORD
    SECKEYBUFFER:	VECTOR[ MAXKSZW ],		! TEMP BUFFER FOR SEC KEY
    BKTDESC:	FORMATS[ BDSIZE ],		! BUCKET DESC FOR SIDR BUCKET
!** [12] ROUTINE:PUTSIDR AT LINE 7725, EGM, 3-APR-78
%([12])%    SPLITBD1:	FORMATS[ BDSIZE ],		! BKT DESC FOR SPLITS
%([12])%    OLDLASTRECPTR;				! SAVED PTR TO LAST SIDR ARRAY

EXTERNAL ROUTINE
    FOLLOWPATH,			! TRAVERSE THE INDEX
    CHKDUP,					! CHECK FOR DUPS
    MAKIDX,					! CREATE A NEW INDEX
    MOVEKEY,				! MOVE THE SEC KEY INTO BUFFER
    INSRTSIDR,				! INSERT THE NEW SIDR
    IDXUPDATE;				! UPDATE THE INDEX


	TRACE ('PUTSIDR');

	%([ CHECK IF THERE IS AN INDEX ])%

	IF NOINDEXFLAG ISON
	THEN
		BEGIN
		CALLMAKIDX;			! MAKE ONE

		%([ IF THE NO-INDEX IS STILL ON, THERE WAS A PROBLEM ])%

		IF NOINDEXFLAG ISON
		THEN
			BADRETURN
		END; %(OF IF NOINDEX FLAG ISON)%

	%([ FETCH THE ADDRESS OF THE USER'S NEW RECORD ])%

	USERRECORDPTR = .RAB [ RABRBF ];

	%([ MOVE THE SECONDARY KEY STRING TO THE TEMPORARY BUFFER ])%

	CALLMOVEKEY (	%(FROM)%		LPT ( USERRECORDPTR ),
			%(TO)%		LCT ( SECKEYBUFFER ) );
	RECDESC [ RDUSERPTR ] = SECKEYBUFFER;
	RECDESC [ RDUSERSIZE ] = .KDB [ KDBKSZ ];

	%([ ***NEXT INSTR ASSUMES RDFLAGS AND RDSTATUS ARE IN WORD 0 ])%
	RECDESC [ WHOLEWORD ] = ZERO;

	%([ SEARCH THE SECONDARY INDEX ])%

	IF CALLFOLLOWPATH (	BPT ( RECDESC ),
				LCT ( BKTDESC )) IS FALSE

	THEN
		RETURN FALSE;

!** [12] ROUTINE:PUTSIDR AT LINE 7773, EGM, 3-APR-78
%([12])%
%([12])%	%([ SAVE THE LAST RECORD POINTER AROUND THE CALL TO CHKDUP ])%
%([12])%
%([12])%	OLDLASTRECPTR = .RECDESC [ RDLASTRECPTR ];

	%([ CHECK FOR DUPLICATE VALUES ])%



	%([ WE MUST NOW INSERT THE SIDR RECORD INTO
	   THE SIDR BUCKET ])%
LOOP:	BEGIN

	IF CALLCHKDUP ( BPT ( RECDESC ),
			LCT ( BKTDESC ) ) ISNT FALSE
	THEN
!** [12] ROUTINE:PUTSIDR AT LINE 7785, EGM, 3-APR-78
%([12])%	BEGIN
%([12])%
%([12])%		%([ IF DUPLICATES WERE FOUND, BACKUP THE RECORD POINTERS )%
%([12])%		%(  TO CORRECTLY POINT TO THE FINAL DUPLICATE SIDR ARRAY, )%
%([12])%		%(  AND THE PREVIOUS SIDR ARRAY. THIS MUST BE DONE SO THAT )%
%([12])%		%(  THE RST KEY BUFFER CAN BE UPDATED PROPERLY ON A SPLIT ])%
%([12])%
%([12])%		IF DUPLICATEFLAG (RECDESC) ISON
%([12])%		THEN
%([12])%		BEGIN
%([12])%			RECDESC [ RDRECPTR ] = .RECDESC [ RDLASTRECPTR ];
%([12])%			RECDESC [ RDLASTRECPTR ] = .OLDLASTRECPTR
%([12])%		END;
%([12])%
%([12])%		IF CALLINSRTSIDR (	BPT ( RECDESC ),
%([12])%					LCT ( BKTDESC ),
%([12])%					LCT ( SPLITBD1 ) ) ISNT FALSE
%([12])%		THEN
				LEAVE LOOP WITH  TRUE;
		END;
		BEGIN
		CALLPUTBKT (	%(NO)%	PCI ( FALSE ),
				%(BKT)%	LCT ( BKTDESC ) );
		BADRETURN
		END; %(OF IF ERROR IN CHKDUP OR INSRTSIDR)%
	END; %( OF LOOP )%

	%([ CHECK FOR INDEX UPDATE ])%

	IF IDXUPDATEFLAG ( RECDESC ) ISON
	THEN

		BEGIN
		IF CALLIDXUPDATE (	BPT ( RECDESC ),
					LCT ( BKTDESC ),	
					LCT ( SPLITBD1 ),
					PCI ( ZERO ) )	! ONLY 1 EXTRA BKT
			IS FALSE THEN

		%([ WHAT HAPPENED? ])%
	
			SETIDXERRORFLAG ( RECDESC );	! SET THE FLAG
		END; %(OF IF INDEX UPDATE REQUIRED)%

	%([ RETURN AFTER INSERTING NEW SIDR RECORD ])%

	GOODRETURN

END;	%(OF PUTSIDR)%
	
END
ELUDOM