Google
 

Trailing-Edge - PDP-10 Archives - bb-h138f-bm - 7-sources/rmsixm.b36
There are 6 other files named rmsixm.b36 in the archive. Click here to see a list.
%TITLE 'I D X 2   -- index file support routines'
!<BLF/REQUIRE 'RMSBLF.REQ'>
MODULE idx2 (IDENT = '2.0'
		) =
BEGIN

GLOBAL BIND
    ix2v = 2^24 + 0^18 + 400;			! Edit date: 22-Apr-83

!+
!
!
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1977, 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.
!
!
!
!    AUTHOR:	S. BLOUNT
!
!    THIS MODULE CONTAINS ROUTINES WHICH MANIPULATE AND
!    ACCESS THE INDEX STRUCTURE OF AN INDEXED FILE. THE
!    ROUTINES CONTAINED IN THIS MODULE GENERALLY ARE LESS
!    USED THAN THE ONES IN "RMSIDX". THUS, THIS MODULE CAN
!    BE SELECTIVELY LOADED WITH OTHER MODULES WHICH ARE NOT
!    COMMONLY EXECUTED ( E.G., ERROR PROCESSING, DEBUGGING
!    ROUTINES, ETC ).
!
!
!
!    **********	TABLE OF CONTENTS	**************
!
!
!
!
!    ROUTINE			FUNCTION
!    =======			========
!
!    MAKIDX			CREATE AN INDEX STRUCTURE FOR A KEY
!
!    ALCROOT			ALLOCATE A ROOT FOR AN INDEX
!
!    MAKROOT			CREATE NEW ROOT ON ROOT SPLIT
!
!    ADJIPTR			ADJUST THE INDEX POINTER FOR INDEX UPDATE
!
!
!
!    REVISION HISTORY:
!
!    EDIT		DATE		WHO			PURPOSE
!    ====		====		===			=======
!
!    1		29-SEP-76	SB		UPDATE IDB LEVELS ON ROOT SPLIT
!    2		23-FEB-77	SB		SET HIKEY FLAG IN INDEX RECORD
!    3		8-MAR-77	SB		TAKE OUR BUG MSG IN ALCROOT
!
!    *************************************************
!    *						*
!    *		NEW REVISION HISTORY		*
!    *						*
!    *************************************************
!
!    PRODUCT	MODULE	 SPR
!    EDIT	 EDIT	 QAR		DESCRIPTION
!    ======	======	=====		===========
!
!	400	400	xxxxx		Clean up BLISS code (RL, 22-Apr-83)
!
!    ***** END OF REVISION HISTORY *****
!
!-

REQUIRE 'RMSREQ';
%SBTTL 'MAKIDX - initialize index structure'

GLOBAL ROUTINE makidx =
! MAKIDX
! =========
! ROUTINE TO INITIALIZE THE INDEX STRUCTURE FOR A SPECIFIC KEY.
!	THIS ROUTINE PERFORMS THE FOLLOWING FUNCTIONS:
!		1.	ALLOCATE AND FORMAT A ROOT BUCKET
!		2.	UPDATE THE ROOT POINTER IN THE INDEX DESCRIPTOR
!			IN THE FILE PROLOGUE, AND IN THE IN-CORE
!			KEY DESCRIPTOR BLOCK
!		3.	ALLOCATE AND FORMAT A NEW DATA BUCKET AND
!			UPDATE THE POINTER IN THE PROLOGUE TO IT.
!		4.	CREATE A SINGLE INDEX RECORD WHICH CONTAINS
!			THE HIGHEST KEY VALUE POSSIBLE.
! INPUT:
!	<NONE>
!
!	ON INPUT, KDB MUST BE SET UP TO POINT TO THE KEY DESCRIPTOR
!	BLOCK OF THE KEY.
! OUTPUT:
!	TRUE:		OK
!	FALSE:		ERROR
!			<NONE>
! ROUTINES CALLED:
!	ALCBKT
!	ALCROOT
!	DUMPIRECORD
!	DUMP
!	CRASH
    BEGIN

    LOCAL
	databd : BLOCK [bdsize],		! BUCKET DESCRIPTOR FOR DATA BUCKET
	rootbd : BLOCK [bdsize],		! BUCKET DESCRIPTOR FOR ROOT
	dataptr : REF BLOCK,			! PTR TO DATA BUCKET
	rootptr : REF BLOCK,			! PTR TO ROOT BUCKET
	irecordptr : REF BLOCK,			! PTR TO INDEX RECORD
	rootbucket,				! BUCKET FOR INDEX ROOT
	databucket;				! THE BUCKET NUMBER OF THE DATA

!+
!    VALUE OF THE HIGHEST KEY POSSIBLE...SEE NOTE BELOW
!-

    LITERAL
	hikeyvalue = -1;

    TRACE ('MAKIDX');

    !+
    !    CHECK INPUT VALUES...JUST CHECK THE KDB POINTER
    !-

    checkinput (kdb, NEQ, 0);

    !+
    !    ALLOCATE A ROOT BUCKET
    !-

    IF alcroot (seqsetlevel, 			! Level
	    rootbd) EQL false			! Bucket descriptor
    THEN
	RETURN false;

    !+
    !    ALLOCATE A NEW DATA BUCKET
    !-

    IF alcbkt (btypedata, 			! Type
	    bhflgend, 				! End of chain
	    datalevel, 				! Level
	    databd) EQL false			! Bucket descriptor
    THEN
	rmsbug (msgfailure);

    !+
    !    FORM A POINTER TO THIS BUCKET
    !-

    databucket = .databd [bkdbktno];
    dataptr = .databd [bkdbktadr];
    dataptr [bhnextbkt] = .databucket;		! POINT TO ITSELF

    !+
    !    FORM A POINTER TO THE ROOT
    !-

    rootbucket = .rootbd [bkdbktno];		! GET BKT # OF ROOT
    rootptr = .rootbd [bkdbktadr];

    !+
    !    SET UP A PTR TO WHERE THE RECORD IS TO GO
    !-

    irecordptr = .rootptr + bhhdrsize;

    !+
    !    CREATE AN INDEX RECORD
    !-

    irecordptr [irflags] = flghikey;		! SET HIGHEST KEY
    irecordptr [irbucket] = .databucket;
    irecordptr = .irecordptr + 1;
!+
!    NOW, WE MUST CREATE A INDEX RECORD WITH THE HIGHEST
!    POSSIBLE KEY VALUE, WHICH IS -1. NOTE THAT THIS VALUE
!    MAY CAUSE PROBLEMS WHEN COMP KEYS ARE SUPPORTED. THUS,
!    IF AND WHEN THIS IS TRUE, A SPECIAL CHECK MAY HAVE TO
!    BE MADE FOR THESE KEY TYPES. ALSO, THE "FLGHIKEY" CAN
!    ALWAYS BE USED TO DETERMINE IF THIS IS THE SPECIAL
!    TYPE OF INDEX RECORD
!-

    INCR j FROM 1 TO .kdb [kdbkszw] DO
	%(ONCE FOR EACH WORD OF THE KEY)%
	BEGIN
	irecordptr [wholeword] = hikeyvalue;	! STORE THE HIGHEST POSSIBLE KEY
	irecordptr = .irecordptr + 1;
	END;					! Of INCR loop

    !+
    !    RESET THE END-POINTER
    !-

    rootptr [bhnextbyte] = .irecordptr - .rootptr;

    !+
    !    RELEASE BOTH BUCKETS
    !-

    putbkt (%(UPDATE)%true, %(BKT-DESC)%databd);
    putbkt (%(UPDATE)%true, %(BKT-DESC)%rootbd);
    RETURN true
    END;

%(OF MAKIDX)%
%SBTTL 'ALCROOT - allocate a new root'

GLOBAL ROUTINE alcroot (level, rootbd) =
! ALCROOT
! =========
! ROUTINE TO ALLOCATE A NEW ROOT FOR A PARTICULAR INDEX.
!	THIS ROUTINE ALLOCATES A NEW ROOT, FORMATS IT,
!	AND UPDATES THE ROOT BUCKET POINTER IN THE INDEX
!	DESCRIPTOR BLOCK IN THE FILE PROLOGUE. IT ALSO
!	UPDATES THE ROOT BUCKET NUMBER IN THE CURRENT
!	IN-CORE KEY DESCRIPTOR BLOCK (POINTED TO BY KDB).
! INPUT:
!	LEVEL	=	LEVEL # OF NEW ROOT
!	ROOTBD	=	BUCKET DESCRIPTOR OF NEW ROOT (RETURNED)
! OUTPUT:
!	TRUE:	OK
!	FALSE:	ERROR
!		ROOT HAS ALREADY BEEN CREATED
!		NO BUCKETS LEFT IN FILE
! NOTES:
!	1.	THE ROOT IS <NOT> WRITTEN OUT TO THE FILE
!		IN THIS ROUTINE. THE CALLER IS RESPONSIBLE
!		FOR DOING SO.
! ROUTINES CALLED:
!	ALCBKT
!	GETIDB
!	DUMP
    BEGIN

    LOCAL
	idbptr : REF BLOCK,			! PTR TO INDEX DESCRIPTOR
	savestatus,				! USED TO SAVE STATUS
	plogbktdesc : BLOCK [bdsize];		! BKT DESC OF PROLOGUE

    REGISTER
	rootptr : REF BLOCK;

    MAP
	rootbd : REF BLOCK;

    TRACE ('ALCROOT');
!+
!    FIRST, WE MUST FIND THE INDEX DESCRIPTOR ON DISK
!    AND MAKE SURE THAT A ROOT HAS NOT BEEN CREATED
!    SINCE WE OPENED THE FILE.
!-

    IF (idbptr = getidb (plogbktdesc)) EQL false THEN RETURN false;

    !+
    !    IS THERE NOW A ROOT
    !-

    IF .idbptr [idbroot] NEQ 0
    THEN
	%(THERE IS A NEW ROOT)%savestatus = false	! REMEMBER WE DIDNT DO IT
    ELSE
	BEGIN
!+
!    THERE IS NO ROOT FOR THE FILE. WE MUST ALLOCATE
!    A NEW ROOT BUCKET
!-

	IF alcbkt (btypeindex, 			! Type
		bhflgroot + bhflgend, 		! Flags
		.level, 			! Level
		.rootbd) EQL false		! Bucket descriptor
	THEN
	    RETURN false;

	rootptr = .rootbd [bkdbktadr];
	idbptr [idbroot] = (rootptr [bhnextbkt] = .rootbd [bkdbktno]);
	idbptr [idblevels] = seqsetlevel;	! SET LEVEL #
	savestatus = true
	END;%(OF ELSE THERE IS NO ROOT FOR THE FILE)%

    !+
    !    STORE THE NEW ROOT BUCKET # IN THE IDB
    !-

    kdb [kdbroot] = .idbptr [idbroot];
    clrflag (kdb [kdbflags], flgnoindex);

    !+
    !    RETURN THE BUCKET DESCRIPTOR FOR THE FILE PROLOGUE
    !-

    putbkt (%(NO UPDATE)%false, %(DESC)%plogbktdesc);
    RETURN .savestatus
    END;

%(OF ALCROOT)%
%SBTTL 'MAKROOT - make a new root bucket'

GLOBAL ROUTINE makroot (old_root_bd, new_index_bd) =
! MAKROOT
! =======
! ROUTINE TO CREATE A NEW ROOT BUCKET WHEN THE OLD ROOT BUCKET
!	SPLITS DUE TO A RECORD INSERTION.
!	THIS ROUTINE DOES THE FOLLOWING OPERATIONS:
!
!		1.	ALLOCATE NEW BUCKET
!		2.	MOVE ALL DATA FROM OLD ROOT INTO THIS BUCKET
!		3.	CREATE 2 INDEX RECORDS IN THE OLD ROOT
!		4.	WRITE OUT THE NEW BUCKET (WITH DATA IN OLD ROOT)
! INPUT:
!	OLD_ROOT_BD		BKT DESCRIPTOR OF OLD ROOT
!	NEW_INDEX_BD		BKT DESCRIPTOR OF NEW BKT IN THE SPLIT
! OUTPUT:
!	TRUE:	OK
!	FALSE:	ERROR
!		NO MORE BUCKETS
! ROUTINES CALLED:
!	MAKEIRECORD
!	ALCBKT
!	DUMP
!	PUTBKT
!	GETIDB
    BEGIN

    MAP
	old_root_bd : REF BLOCK,
	new_index_bd : REF BLOCK;

    REGISTER
	temp_ptr : REF BLOCK;

    LOCAL
	new_bkt_bd : BLOCK [bdsize],		! New root descriptor
	new_bucket,				! New root bkt #
	bucket_number,				! Temp for a bucket number
	root_level,				! Level of new root
	old_root_ptr : REF BLOCK,		! Some pointers
	new_bkt_ptr : REF BLOCK,		! Same
	index_record_ptr : REF BLOCK,
	size_of_key,				! Size of this key string
	last_record_ptr : REF BLOCK,		! Ptr to last rec in old bucket
	split_bkt_ptr : REF BLOCK,		!
	plog_bd : BLOCK [bdsize],		! Descriptor for prologue
	idb_ptr : REF BLOCK;			! Ptr to index descriptor

    TRACE ('MAKROOT');

    !+
    !    GET SOME POINTERS
    !-

    old_root_ptr = .old_root_bd [bkdbktadr];
    root_level = .old_root_ptr [bhlevel];	! AND LEVEL #

    !+
    !    ALLOCATE A NEW BUCKET FOR THE NEW ROOT
    !-

    IF alcbkt (btypeindex, 			! Type
	    0, 					! Flags
	    .root_level, 			! Level
	    new_bkt_bd) EQL false		! Bucket
    THEN
	RETURN false;				! No

    !+
    !    GET A POINTER TO THE NEW BUCKET
    !-

    new_bkt_ptr = .new_bkt_bd [bkdbktadr];
    new_bucket = .new_bkt_bd [bkdbktno];

    !+
    !    SET UP A POINTER TO WRITE INDEX RECORD
    !-

    index_record_ptr = .old_root_ptr + bhhdrsize;
!+
!    WE WILL NOW MOVE ALL THE DATA IN THE OLD ROOT INTO
!    THE BUCKET WHICH WE JUST ALLOCATED. THEN WE WILL
!    CREATE TWO NEW INDEX ENTRIES IN THE OLD ROOT
!-
    movewords (%(FROM)%.old_root_ptr, %(TO)%.new_bkt_ptr, %(SIZE)%.old_root_ptr [bhnextbyte]);
!+
!    SET THE NEXT-BUCKET FIELDS AND RESET THE FLAG FIELD
!    OF THE OLD ROOT BECAUSE "SPTINDEX" CLEARED THE END
!    FLAG BIT WHEN IT SPLIT THE INDEX BUCKET
!-
    new_bkt_ptr [bhflags] = 0;			! CLEAR OLD ROOT FLAGS
    temp_ptr = .new_index_bd [bkdbktadr];	! PTR TO NEW BKT
    temp_ptr [bhnextbkt] = .new_bucket;
    old_root_ptr [bhnextbkt] = .old_root_bd [bkdbktno];
    old_root_ptr [bhflags] = bhflgroot + bhflgend;
!+
!    NOW, WE MUST FIND THE LAST INDEX RECORD IN THE OLD ROOT.
!    WE CAN DO THIS BECAUSE WE KNOW THE SIZE OF EACH INDEX
!    RECORD, AND WE KNOW WHERE THE BUCKET ENDS.
!-
    size_of_key = .kdb [kdbkszw];		! SIZE OF KEY PORTION OF INDEX RECORD
    last_record_ptr = .new_bkt_ptr + .new_bkt_ptr [bhnextbyte] - .size_of_key;
!+
!    LAST_RECORD_PTR NOW POINTS TO THE LAST KEY (NOT THE INDEX
!    RECORD, BUT THE ACTUAL KEY STRING) IN THE OLD ROOT BUCKET
!-
    lookat ('	LAST-KEY-PTR: ', last_record_ptr);
    bucket_number = .new_bkt_bd [bkdbktno];

    !+
    !    CREATE AN INDEX RECORD WHICH DESCRIBES WHAT USED TO BE THE OLD ROOT
    !-

    makeirecord (.bucket_number, 		! BKT
	.index_record_ptr, 			! PLACE
	.last_record_ptr);			! KEY

    !+
    !    SET UP TO WRITE NEXT INDEX RECORD
    !-

    index_record_ptr = 				! Bump pointer
    .index_record_ptr + .size_of_key + irhdrsize;
    lookat ('	NEXT IDX REC AT: ', index_record_ptr);
    split_bkt_ptr = .new_index_bd [bkdbktadr];
    last_record_ptr = .split_bkt_ptr + .split_bkt_ptr [bhnextbyte] - .size_of_key;
    lookat ('	ADR OF LAST KEY IN NEW BKT: ', last_record_ptr);
    bucket_number = .new_index_bd [bkdbktno];

    !+
    !    CREATE THE SECOND INDEX RECORD
    !-

    makeirecord (%(BKT)%.bucket_number, %(PLACE)%.index_record_ptr, %(KEY)%.last_record_ptr);

    !+
    !    RESET THE BUCKET HEADER DATA IN THE NEW ROOT
    !-

    old_root_ptr [bhnextbyte] = bhhdrsize + (2*(irhdrsize + .size_of_key));

    !+
    !    INCREMENT THE LEVEL NUMBER OF THE OLD ROOT
    !-

    old_root_ptr [bhlevel] = .old_root_ptr [bhlevel] + 1;
!+
!    UPDATE THE NUMBER OF LEVELS IN THIS INDEX IN THE
!    FILE PROLOGUE
!-

    IF (idb_ptr = getidb (plog_bd)) NEQ false
    THEN
	%(WE SUCCEEDED)%
	BEGIN
	idb_ptr [idblevels] = .old_root_ptr [bhlevel];
	putbkt (%(NO UPDATE)%false, %(BKT)%plog_bd)
	END;%(OF IF GETIDB WAS OK)%

!+
!    WE MUST NOW WRITE OUT ALL THE BUCKETS WHICH WERE
!    INVOLVED IN THIS OPERATION. WE HAVE THE FOLLOWING:
!
!    OLD_ROOT_BD	BKT CONTAINING NEW ROOT
!    NEWBKTTBD	BKT WHICH NOW CONTAINS TOP HALF
!    OF OLD ROOT (I.E., 1ST BUCKET IN
!    THE LEVEL UNDER THE ROOT)
!    NEW_INDEX_BD	BKT WHICH NOW CONTAINS BOTTOM HALF
!    OF OLD ROOT.
!
!    WE MUST WRITE THESE NON-ROOT BUCKETS OUT FIRST TO AVOID
!    DATA INTEGRITY PROBLEMS.
!-
    putbkt (%(UPDATE)%true, %(SPLIT-BKT)%.new_index_bd);
    putbkt (%(UPDATE)%true, %(NEW ROOT)%new_bkt_bd);
    putbkt (%(UPDATE)%true, %(ROOT)%.old_root_bd);
    RETURN true
    END;

%(OF MAKROOT)%
%SBTTL 'ADJIPTR - Adjust index record pointer'

GLOBAL ROUTINE adjiptr (recdesc, indexbd) =
! ADJIPTR		ADJUST INDEX POINTER
! =======
! ROUTINE TO ADJUST THE POINTER TO THE CURRENT INDEX RECORD SO AS
!	TO CORRECTLY REFLECT THE PLACE WHERE A NEW INDEX RECORD SHOULD
!	BE INSERTED. THIS ROUTINE IS CALLED ONLY WHEN THE KEY OF THE
!	NEW HIGH RECORD IN A SPLIT BUCKET IS GREATER THAN THE KEY OF
!	THE INDEX RECORD DENOTED BY THE PATH ARRAY. THIS IS CAUSED BY
!	THE INSERTION OF A DUP WHICH MUST BE PLACED IN A DIFFERENT BUCKET
!	FROM THE INITIAL SEARCH BUCKET. (SEE THE NOTES IN "IDXUPDATE" FOR
!	A FULL DESCRIPTION OF WHAT'S HAPPENING).
!
! INPUT:
!	RECDESC		RECORD DESCRIPTOR PACKET
!		RECPTR		ADDRESS OF CURRENT INDEX RECORD
!		USERPTR		ADDRESS OF USER SEARCH KEY (NEW HI-KEY VALUE)
!
!	INDEXBD		BUCKET DESCRIPTOR OF CURRENT BUCKET
!
! OUTPUT:
!	<TRUE ALWAYS>
!
! INPUT ARGS MODIFIED:
!
!	RECORD DESCRIPTOR:
!		RECPTR		ADDRESS OF NEW CURRENT INDEX RECORD
!
!	BUCKET DESCRIPTOR:	NEW BUCKET DESCRIPTOR
    BEGIN

    MAP
	recdesc : REF BLOCK,
	indexbd : REF BLOCK;

    LITERAL
	nolock = false;				! Don't lock next bucket

    LOCAL
	nextbd : BLOCK [bdsize],		! Use for next bucket
	savedstatus;				! Temp storage

    TRACE ('ADJIPTR');
!+
!    WE NOW WANT TO REPOSITION OURSELVES ACCORDING TO THE HIGHEST
!    KEY IN THE OLD BUCKET, INSTEAD OF THE KEY OF THE NEW RECORD.
!    MOST LIKELY, THIS CALL WILL MOVE US DOWN ONE INDEX RECORD
!-

    IF sindexbkt (.recdesc, 			! Record
	    .indexbd) NEQ false			! Bucket

	!+
	!    IF WE SUCCEEDED, THEN WE CAN EXIT
	!-

    THEN
	RETURN true;

!+
!    WE DIDN'T FIND IT. THIS MUST BE THE LAST INDEX RECORD
!    IN THE BUCKET
!-
    rtrace ('	*****COULDNT ADJ I PTR');
    savedstatus = gtnbkt (%(THIS BKT)%.indexbd, %(NEXT BKT)%nextbd, %(NO LOCK)%nolock);

    !+
    !    RELEASE THE OLD ONE, REGARDLESS OF IF WE GOT THE NEXT ONE
    !-

    putbkt (%(NO UPDATE)%false, %(BKT)%.indexbd);

    !+
    !    START SEARCH AT TOP OF NEXT BUCKET
    !-

    recdesc [rdrecptr] = 0;

    IF (.savedstatus EQL false) OR (sindexbkt (.recdesc, nextbd) EQL false)
    THEN 					! If either of these failed, we are really screwed up
	rmsbug (msgfailure);

    !+
    !    RESET BUCKET DESCRIPTORS
    !-

    movebktdesc (%(FROM)%nextbd, %(TO)%indexbd);
    RETURN true
    END;

END

ELUDOM