Google
 

Trailing-Edge - PDP-10 Archives - BB-JF18A-BM - sources/rms/rmsdel.b36
There are 6 other files named rmsdel.b36 in the archive. Click here to see a list.
%TITLE 'D E L E T E   -- $DELETE processor'
!<BLF/REQUIRE 'RMSBLF.REQ'>
MODULE delete (IDENT = '3.0'
		) =
BEGIN

!
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984, 1986.
!	ALL RIGHTS RESERVED.
!
!	THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED  AND
!	COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND 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.  NO TITLE TO AND OWNERSHIP OF  THE
!	SOFTWARE IS HEREBY TRANSFERRED.
!
!	THE INFORMATION IN THIS SOFTWARE IS  SUBJECT  TO  CHANGE  WITHOUT
!	NOTICE  AND  SHOULD  NOT  BE CONSTRUED AS A COMMITMENT BY DIGITAL
!	EQUIPMENT CORPORATION.
!
!	DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF
!	ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!

!++
! FACILITY:	RMS
!
! ABSTRACT:
!
!	DELETE contains all routines which
!	process the $DELETE macro in RMS-20.
!
! ENVIRONMENT:	User mode, interrupts deferred until JSYS return.
!
! AUTHOR: Ron Lusk , CREATION DATE: 16-Mar-83
!
! MODIFIED BY:
!
!	, : VERSION
! 01	- Remote $Delete code
!--

!
! TABLE OF CONTENTS
!
!
!	$DELETE	    -	Dispatcher for $DELETE macro
!	DELSQR	    -	Process $DELETE for SEQ/REL files
!	CHECKRP	    -	Check file position, record locking
!	DELIDX	    -	Process $DELETE for indexed files
!	DODELIDX    -	Perform the work for indexed files
!	DELUDR	    -	Compress a primary data record and RRV
!
!
! INCLUDE FILES:
!

REQUIRE 'rmsreq';

!
! MACROS:
!
!	None.
!
! EQUATED SYMBOLS:
!

GLOBAL BIND
    delev = 2^24 + 0^18 + 400;			! Module version number

!
! OWN STORAGE:
!
!	None.
!
! EXTERNAL REFERENCES:

EXTERNAL ROUTINE
    Dap$Delete;
%SBTTL '$DELETE - record deletion dispatcher'

GLOBAL ROUTINE $delete (rabblock, errorreturn) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	$DELETE always operates on the record designated by
!	the CURRENT-RECORD.  This is the record indicated by
!	the DATARFA field in the Record Status Table, and
!	residing in the current bucket.
!
! FORMAL PARAMETERS
!
!	RABLOCK	    -	User's Record Access Block
!	    ISI	    -	Internal Stream Identifier, points
!			to Record Status Table
!	    ROP	    -	Record Options
!		FDL -	Fast Delete (indexed files only)
!	    STS	    -	Status information (returned)
!	    STV	    -	Additional status information
!
!	ERRORRETURN -	Address of user's error routine
!
! IMPLICIT INPUTS
!
!	?
!
! ROUTINE VALUE:
!
!	None, yet not NOVALUE.
!
! SIDE EFFECTS:
!
!	?
!
!--

    BEGIN
    rmsentry ($delete);
    !
    !   Fetch the user's RAB and error address.
    !
    rab = .rabblock;				! Get RAB address
    erradr = .errorreturn;			! And user error address
    rsetup (axdel);				! Set up world

    IF .Fst[Fst$v_Remote]
    THEN
        BEGIN
        Dap$Delete( .Rab, .erradr );
        UsrRet();
        END;


    !
    !   Make sure the file is positioned and is a disk file.
    !
    checkrp ();

!+
!   Dispatch to the proper routine for each file organization.
!-

    CASE fileorg FROM 0 TO 3 OF
	SET

	[orgasc] :
	    usererror (er$iop);			! ASCII - Bad operation

	[orgseq] :
	    delsqr ();				! Sequential files

	[orgrel] :
	    delsqr ();				! Relative files

	[orgidx] :
	    delidx ();				! Indexed files
	TES;

    !
    !   The $DELETE was performed successfully. All locking or
    !   unlocking was performed in the appropriate routine.
    !
    setsuccess;
    usrret ()					! ***Exit to user***
    END;					! End of $DELETE
%SBTTL 'DELSQR -- delete SEQ/REL record'

GLOBAL ROUTINE delsqr : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Process the $DELETE macro for sequential and
!	relative files.
!
!	This routine must do the following:
!
!	1)  Determine address of current record
!	2)  Position file to that byte address
!	3)  Set the deleted bit in the record header
!	4)  Unlock the current record
!
! FORMAL PARAMETERS
!
!	None.
!
! IMPLICIT INPUTS
!
!	?
!
! ROUTINE VALUE:
!
!	None: (if there is an error during processing of
!	the $DELETE, this routine will exit directly
!	to the user).
!
! SIDE EFFECTS:
!
!	None.
!
!--

    BEGIN

    LOCAL
	temp,					! Temporary storage
	filepointer : REF BLOCK,		! Pointer to current record
	header,					! Header of current record
	crp,					! Current RFA
	bytenum;				! Byte number of current record

    TRACE ('DELSQR');
    !
    !   Determine the byte number at which this record begins.
    !
    bytenum = (crp = .rst [rstdatarfa]);	! Assume a SEQ file

!+
!   For relative files, we must convert the record number (RFA)
!   into the actual byte number of the target record.
!-

    IF relfile
    THEN 					! Convert CRP for REL files
	BEGIN

	IF (bytenum = numbertorfa (.crp)) EQL false THEN usererror (er$rfa)

	END;

    !
    !   Position file to desired record. It could
    !   be out of position if the record
    !   spanned a page boundary.
    !
    gtbyte (.bytenum, 				! Byte
	false);					! Flag
    !
    !   Fetch the pointer to the record in the file buffer.
    !
    filepointer = .rst [rstpagptr];		! Get the file page pointer
    header = .filepointer [wholeword];		! And the record header
    lookat ('	Record header = ', header);	! **Debug**
    !
    !   Set the "deleted" bit in the record header
    !

%IF dbug
%THEN

    IF chkflag (header, rhdrdelete) NEQ 0 THEN rmsbug (msgflags);

%FI

    filepointer [wholeword] = 			! Store the header back again
    .header OR (rhdrdelete);
    setbfdupd (cbd [bkdbfdadr]);		! Indicate file page
    						! needs updating

!+
!   Unlock the current record and exit.  Note that the
!   UNLOCK macro also clears the "datalocked" bit.
!-

    IF locking THEN unlock (crp);		! Unlock the record

    RETURN 					! Return to $DELETE
    END;					! End of DELSQR
%SBTTL 'CHECKRP -- Check file and record'

GLOBAL ROUTINE checkrp : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	CHECKRP is called by both the $DELETE and $UPDATE
!	processors.  Its function is to make sure that the
!	file is positioned and the current record is locked
!	(if the file is being shared).
!
! FORMAL PARAMETERS
!
!	None.
!
! IMPLICIT INPUTS
!
!	?
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	?
!
!--

    BEGIN

!+
!   File must reside on a DASD (disk device).
!-

    IF NOT dasd THEN usererror (er$dev);

!+
!   Check that the last operation was a $FIND or a $GET.
!-

    IF (.rst [rstlastoper] NEQ c$find) AND 	!
	(.rst [rstlastoper] NEQ c$get)		!
    THEN
	usererror (er$cur);

    RETURN
    END;					! End of CHECKRP
%SBTTL 'DELIDX -- delete indexed record'

GLOBAL ROUTINE delidx : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	DELIDX processes the $DELETE macro for indexed
!	files.  When this routine is called, there must be a
!	current bucket set up and a pointer to the current
!	record must be in the PAGPTR field in the Record
!	Status Table.  The function of this routine is to
!	delete all SIDR entries for this record, then mark
!	the primary record as being deleted.
!
!	Note that if the primary key allows duplicates, then
!	the primary data record will never be compressed out
!	of the bucket.  This is because if a user was
!	positioned in the middle of a series of duplicates
!	and his "current record" was deleted, he would have
!	no way of getting back to his correct position in
!	the file.
!
!	On an error, this routine exits directly to the
!	user.
!
!	If locking is enabled, then we must lock the file
!	index only if we need to delete some SIDR pointers.
!	If no secondary indices have to be accessed, then we
!	don't need to lock anything, since the current
!	bucket is already locked.
!
! FORMAL PARAMETERS
!
!	None.
!
! IMPLICIT INPUTS
!
!	?
!
! ROUTINE VALUE:
!
!	None.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	databd : BLOCK [bdsize],		! Descriptor for current bucket
	recdesc : BLOCK [rdsize],		! Record descriptor packet
	savedstatus,				! Save the results here
	updateflag;				! Flag for updating bucket

    TRACE ('DELIDX');
    !
    !   Fetch the current bucket and make sure there is one.
    !
    fetchcurrentbkt (databd);

    IF nullbd (databd) THEN rmsbug (msgbkt);

    setnullbd (cbd);				! Set it to be null

!+
!   Perform the delete operation.
!-

    !
    !   Set the "horizontal-search" flag so we will
    !   go through the secondary index properly.
    !
    recdesc [rdflags] = rdflghorizok;		! Horizontal search is OK
    recdesc [rdstatus] = 0;			! Clear status
    recdesc [rdrecptr] = .rst [rstpagptr];
    kdb = .fst [fstkdb];			! Use primary key
    savedstatus = dodelidx (recdesc, 		! Record descriptor
	databd);				! Bucket descriptor

!+
!   If SAVEDSTATUS is true, then we will
!   eventually update the bucket to disk.
!-

    IF .savedstatus NEQ false			! Delete OK so far
    THEN
	setbfdupd (cbd [bkdbfdadr]);

    IF writebehind OR (.savedstatus EQL false)	! Do output now?
    THEN
	updateflag = false			! No
    ELSE
	updateflag = true;			! Yes, write it out

    !
    !   Release the current bucket.
    !
    putbkt (.updateflag, databd);

!+
!   We now must unlock the file if it was locked.
!-

    IF indexlocked				!
    THEN
	unlockindex;

    IF .savedstatus EQL false THEN usrret ();	! Exit on error

    RETURN
    END;					! End of DELIDX
%SBTTL 'DODELIDX -- delete indexed record'

GLOBAL ROUTINE dodelidx (recdesc : REF BLOCK, databd : REF BLOCK) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	DODELIDX performs the actual deletion of the current
!	record in an indexed file.  This routine is called
!	only by DELIDX.
!
!	This routine will never release the current bucket.
!
!	If any unexpected error occurs (e.g., RRV was not
!	found), then an undefined file condition is set and
!	processing continues.
!
!	On input the KDB must be set up for primary key.
!
!	No compression is done during a $DELETE.  All
!	compression is done on a $PUT.
!
! FORMAL PARAMETERS
!
!	RECDESC	    -	Record descriptor packet
!	    RECPTR  -	address of current record
!	    FLAGS   -	FLGHORIZOK is referenced
!	    STATUS  -	<null>
!
!	DATABD	    -	Bucket descriptor of current bucket.
!
! IMPLICIT INPUTS
!
!	None.
!
! ROUTINE VALUE:
!
!	TRUE	-   Deletion was successful
!	FALSE	-   Error
!		    Could not delete a SIDR
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	nocompressflag,				! Flag for compression of UDR
	sizeofcurentrcd,			! Current record size
	ptrtodata : REF BLOCK,			! Data portion of UDR
	rfatosearchfor;				! RFA of current record

    REGISTER
	recordptr : REF BLOCK;			! Current record pointer

    EXTERNAL
	tbuffer;				! Buffer for key

    TRACE ('DODELIDX');
    !
    !   Set up a pointer to the current record and its data.
    !
    recordptr = .recdesc [rdrecptr];
    ptrtodata = .recordptr + .kdb [kdbhsz];

!+
!   Make a check to make sure the deleted bit is off.
!-

    IF (chkflag (recordptr [drflags], flgdelete) NEQ 0)	!
    THEN
	rmsbug (msgflags);

    !
    !   Initialize some flags.
    !
    nocompressflag = false;			! Assume no errors
    sizeofcurentrcd = .rst [rstrsz];		! Set up size of record

!+
!   Perform this loop once for each secondary key. we
!   will try to delete the SIDR entry for each key.
!-

    recdesc [rdrrv] = .recordptr [drrrvaddress];
    kdb = .kdb [kdbnxt];			! First secondary key

    UNTIL .kdb EQL 0 DO
	BEGIN

!+
!   Record must contain key string.
!-

	IF .sizeofcurentrcd GEQ .kdb [kdbminrsz]
	THEN
	    BEGIN
	    lookat ('	Deleting key: ', kdb [kdbref]);

!+
!   Lock the file if it is not already locked.
!-

	    IF locking AND NOT indexlocked
	    THEN
		BEGIN

		IF lockindex (enqblk, enqexc) EQL false	!
		THEN
		    returnstatus (er$edq)

		END;

	    !
	    !   Move the key string.
	    !
	    movekey (.ptrtodata, 		! From record
		tbuffer);			! To buffer
	    !
	    !   Set up the address of this key string.
	    !
	    recdesc [rduserptr] = tbuffer;
	    recdesc [rdusersize] = .kdb [kdbksz];

!+
!   If there was an error, we will set the
!   "no-compress" flag because we don't
!   know what went wrong.
!-

	    IF delsidr (.recdesc) EQL false	!
	    THEN
		nocompressflag = true

	    END;

	!
	!   We have finished processing the current
	!   key...move to next one.
	!
	kdb = .kdb [kdbnxt]
	END;

!+
!   We have now deleted the SIDRs for this record.  We must
!   determine what we are going to about the primary data
!   record.  If there was any kind of error during our
!   processing, or if duplicates are allowed on the primary key,
!   then we should set the "no-compress" flag in the primary
!   data record so the record will never go away.
!-

    kdb = .fst [fstkdb];			! Set up for primary key.
    !
    !   Set the deleted bit in the data record.
    !
    setupd (databd);				! Indicate that this bucket
    						!   is being updated.
    setflag (recordptr [drflags], flgdelete);

!+
!   For duplicates in the primary index, or on an
!   error, don't allow compression.
!-

    IF (duplicates) OR (.nocompressflag NEQ false)	!
    THEN 					! This record cannot go away
	setflag (recordptr [drflags], flgnocompress);

!+
!   Note that at this point, we must not completely
!   remove this record from the file if duplicates
!   are allowed in the primary index.  However, for
!   variable- length records, we can squeeze the
!   primary record so that it is only as big as the
!   primary key.  This may not save us anything (if
!   the key is in the end of the record) or it may
!   be a big winner.
!   [This is not done as of March 83 -- RL]
!-

!+
!   Should we return success or failure?
!-

    IF .nocompressflag NEQ false THEN RETURN false;

    RETURN true;				! Return without compression
    END;					! End of DODELIDX
%SBTTL 'DELUDR -- squeeze UDR and its RRV'

GLOBAL ROUTINE deludr (recdesc : REF BLOCK, databd : REF BLOCK) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	DELUDR squeezes a primary data record and possibly
!	its RRV out of the current bucket.  This routine is
!	called if update of a SIDR must be aborted (e.g.,
!	improperly duplicated key).  This routine squeezes
!	the UDR out of the bucket and tries to do the same
!	for the RRV (if any).  There should not be any
!	errors during this routine.
!
!	A not on the algorithm and why it was chosen migh be
!	useful at this point.  Since we know the RRVs are
!	always at the bottom of the bucket, squeezing them
!	away is not a very painful operation.  However, it
!	would be nice if we could avoid the I/O which is
!	required to write out the RRV bucket.  Our only
!	alternative is to set the RRV to be deleted and
!	leave it alone.  However, it would then still be
!	possible to have an RRV pointing to a non-existent
!	data record...thus, we must always write out the RRV
!	bucket, and since ther are no indices which point to
!	this RRV, leaving it in the bucket is needless waste
!	of space.  Therfore, we will compress it out of the
!	bucket now. [From original source -- RL, March '83]
!
!	The KDB must be set up for the primary key.
!
! FORMAL PARAMETERS
!
!	RECDESC	    -	Record descriptor packet
!   	    RECPTR  -	address of current record
!	    LENGTH  -	size (in words) of current record
!			(including header)
!	DATABD	    -	Bucket descriptor of current record.
!
! IMPLICIT INPUTS
!
!	?
!
! ROUTINE VALUE:
!
!	TRUE	    -	Record squeezed out of bucket.
!	FALSE	    -	Error
!			Could not find RRV (file consistency
!			problem)
!
! SIDE EFFECTS:
!
!	?
!
!--

    BEGIN

    REGISTER
	recordptr : REF BLOCK,			! Pointer to current record
	tempac;					! AC used for BLT

    LOCAL
	bucketptr : REF BLOCK,			! Pointer to top of bucket
	endptr : REF BLOCK,			! Pointer to end of bucket
	rrvbd : BLOCK [bdsize],			! Descriptor for RRV bucket
	amounttomove,				! Size of chunk to move
	endofrecordptr : REF BLOCK,		! End of current record
	sizeofcurentrcd,			! Current record size
	rrvaddress;				! RRV to find

    TRACE ('DELUDR');

!+
!   Make sure this is a primary key set-up.
!-

    IF NOT primarykey THEN rmsbug (msginput);

    !
    !   Get the address of the current record and
    !   set up some pointers to the bucket.
    !
    recordptr = .recdesc [rdrecptr];
    bucketptr = .databd [bkdbktadr];		! Top of bucket
    endptr = .bucketptr + .bucketptr [bhnextbyte];
    !
    !   Get address of RRV.
    !
    rrvaddress = .recordptr [drrrvaddress];

!+
!   Do we need to squeeze out the RRV too?
!-

%IF 0
%THEN

!++
!   This code does not work, but is rather unimportant
!   because it is exercised only when a secondary key insert
!   aborts and the new record caused a bucket split.
!   Consequently, I'm no-oping it.
!
!   [This note came from some developer of ages past --
!   there is indeed a need for code of this nature, since a
!   fairly serious bug appeared when a secondary key insert
!   aborted and a bucket split had already occurred.  But as
!   of March 1983, this code was still "conditioned" out.
!			    - RL]
!--

    IF bucketofrfa (.rrvaddress) EQL filepage (databd)	!
    THEN 					! There is an RRV record
	BEGIN

!+
!   We may have to lock the file here.
!-

	IF locking AND NOT indexlocked		!
	THEN
	    BEGIN

	    IF lockindex (enqblk, enqshr) EQL false THEN returnstatus (er$edq)

	    END;

!+
!   We must squeeze out the RRV too.
!-

	rtrace (%STRING ('	Squeezing the RRV...', %CHAR (13, 10)));
	recdesc [rdrfa] = .rrvaddress;
	recdesc [rdrecptr] = 0;			! Make sure we start at top

	IF fbyrfa (.recdesc, 			! Record descriptor
		rrvbd, 				! Bucket descriptor
		false) EQL false		! Nolock
	THEN
	    BEGIN				! We couldn't find the RRV
	    rtrace (%STRING ('***Couldn''t get RRV...', %CHAR (13, 10)));
	    fileproblem (er$rrv);
	    RETURN false;
	    END;

!+
!   Get the address of the RRV and its bucket.
!-

	recordptr = .recdesc [rdrecptr];
	bucketptr = .rrvbd [bkdbktadr];
	amounttomove = 				!
	.bucketptr + .bucketptr [bhnextbyte]	!
	- .recordptr - rrvrecsize;		!
	lookat ('	RRV bucket-pointer: ', bucketptr);
	lookat ('	Amount to move: ', amounttomove);

!+
!   Is the RRV at the bottom of the bucket?
!-

	IF .amounttomove NEQ 0
	THEN
	    movewords (				!
		.recordptr + rrvrecsize, 	! From
		.recordptr, 			! To
		.amounttomove);			! Size

						!
	!   Update the bucket header information.
	!
	bucketptr [bhnextbyte] = .bucketptr [bhnextbyte] - rrvrecsize;
	!
	!   Release the RRV bucket and update it.
	!
	putbkt (true, 				! No update
	    rrvbd)				! Bucket
	END;

%FI						! End removed code

!+
!   Now, squeeze out the primary data record.
!-

    sizeofcurentrcd = .recdesc [rdlength];
    endofrecordptr = .recordptr + .sizeofcurentrcd;
    amounttomove = .endptr - .endofrecordptr;
    lookat ('	Squeezing record at: ', recordptr);
    lookat ('	Amount to move: ', amounttomove);
    lookat ('	End of bucket: ', endptr);

    IF .amounttomove NEQ 0
    THEN
	movewords (.endofrecordptr, 		! From
	    .recordptr, 			! To
	    .amounttomove);			! Size

    						!
    !   Adjust the bucket header information.
    !
    bucketptr [bhnextbyte] = .bucketptr [bhnextbyte] - .sizeofcurentrcd;
    RETURN true;
    END;					! End of DELUDR

END						! End of Module DELETE

ELUDOM