mac-rom/OS/HFS/BTMAINT1.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

541 lines
16 KiB
Plaintext

;
; File: BTMAINT1.a
;
; Contains: These routines provide multiple-node BTree maintenance
; functions.
;
; Copyright: © 1984-1991 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <2> 9/10/91 JSM Add a header.
; <1.2> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram
; or rom
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
; <1.0> 2/11/88 BBM Adding file for the first time into EASEÉ
; 10/27/86 BB Vectored TreeSearch routine.
; 9/25/86 BB Updated to use new MPW equate files.
; 12/19/85 BB SplitLt now checks for errors returned from InitNode (not
; patched in ROm75).
; 10/25/85 BB Made RotRecLt into an internal subroutine. It is only called by
; RotatLt.
; 10/10/85 BB Added use of new MOVEQ equates for GetBlock and RelBlock. Did
; some minor code clean up.
; 8/9/85 BB Modifed SplitLt to set up node height.
; 8/7/85 BB Added deep shit error call to RotateLt.
; 8/6/85 BB Updated to use equates for index and leaf node types.
; 8/4/85 BB Fixed fit calculation bug in RotateLt.
; 7/17/85 BB ReWorked rotate algorithm in RotateLT.
; 7/8/85 BB Modified SplitLt to maintain links for index nodes.
; 7/8/85 BB Modified TreeSearch to no longer set up left and right sibling
; node addresses in the TPT.
; 6/10/85 BB Cleaned up some.
; 3/15/85 BB Modified to use A6 stack.
; 2/25/85 BB Modified RotateLt and SplitLt to return the node number and
; record index of new (inserted) record.
; 1/17/85 BB Removed use of BTree Global area (BTG).
; 10/1/84 BB Split off from BTmaint.
;
;__________________________________________________________________________________
;
; External
; Routines: RotateLt - Inserts a record into a BTree node via rotation
; of records into the left sibling node.
; SplitLt - Inserts a new record into a BTree node by inserting
; an empty left node and then using RotateLt to insert
; the new record.
; TreeSearch - Searches BTree for a specified key setting up the
; Tree Path Table (TPT) to reflect the search path.
;
; Internal
; Subroutines: RotRecLt - Rotates one record from the right node into the
; left node.
;
;__________________________________________________________________________________
BLANKS ON
STRING ASIS
PRINT OFF
LOAD 'StandardEqu.d'
PRINT ON
PRINT NOGEN
BTMaint1 PROC EXPORT
EXPORT RotateLt,SplitLt,TreeSearch
EXPORT vTreeSearch ;<27Oct86>
IMPORT AllocNode
IMPORT GetNode,RelNode
IMPORT DeleteRec,GetNodeSiz,GetOffset,GetRecA,InitNode,InsertRec
IMPORT LocRec,LocTPR,MovOffLt,MovOffRt,MovRecLt,MovRecRt,SearchNode
;__________________________________________________________________________________
;
; Routine: RotateLt
;
; Function: Inserts a record into a BTree node via rotation of records
; into the left sibling node.
;
; Input: A0.L - pointer to record
; D0.W - size of record
; A2.L - pointer to left node buffer
; A3.L - pointer to right node buffer
; D1.W - index of insert point (in right node)
; A4.L - pointer to BTCB
;
; Output: D0.W - result code
; 0 = ok
; -1 = won't fit
; A1.L - ptr(node buffer) containing new record
; D1.W - index of new record
;
; Called by: BTInsert
;__________________________________________________________________________________
RotateLT
MOVEM.L D2-D7/A2-A5,-(SP) ; save regs
;
; set up some common stuff
;
MOVEA.L A0,A5 ; A5 = ptr(new record)
MOVE.W D0,D5 ; D5 = size of new record
;
; calculate split point
;
MOVEA.L A2,A1 ; point to left node
JSR GetNodeSiz ; get its size
MOVE.W D0,D2 ; D2 = left node size
MOVEA.L A3,A1 ; point to right node
JSR GetNodeSiz ; get its size
ADD.W D2,D0 ; right size + left size
ADD.W D5,D0 ; + (new record size + 2)
ADDQ.W #2,D0 ; = total data size
LSR.W #1,D0 ; total size / 2 = split point
MOVE.W D0,D6 ; D6 = split point
;
; simulate left rotation to determine best fit
;
MOVE.W NDNRecs(A2),D3 ; D3 = init virt indx = #recs in lt node
MOVE.W D1,D4 ; D4 = virtual insert index
ADD.W D3,D4 ; = rt insert indx + #recs in lt node
MOVEQ #-1,D7 ; no current fit or previous fit
RLFitLoop
CMP.W D3,D4 ; at insert point ?
BNE.S @2 ; no, ->
ADD.W D5,D2 ; include new record in lt size
BRA.S @4 ; ->
@2 MOVE.W D3,D0 ; convert virtual index
SUB.W NDNRecs(A2),D0 ;
CMP.W D4,D3 ;
BLE.S @3 ;
SUBQ.W #1,D0 ; ...to a right node index
@3 JSR GetRecA ; get record size
ADD.W D0,D2 ; include record in lt size
@4 ADDQ.W #2,D2 ; include offset also
;
; check for a fit after simulated rotation of each record.
;
RLChkFit
MOVE.W BTCNodeSize(A4),D1 ; max node size
SUBI.W #(lenND+2),D1 ; - length(ND) - 2 = max data size
CMP.W D1,D2 ; left node fit?
BLE.S @1 ; yes ->
SWAP D7 ; have previous fit?
TST.W D7 ;
BGE.S RLRotate ; yes, use it ->
MOVEQ #-1,D0 ; result = 'won't fit'
BRA RLExit1 ; exit ->
@1 MOVE.W D6,D0 ; split point
LSL.W #1,D0 ; X 2 = total data size
SUB.W D2,D0 ; - lt size = rt size
CMP.W D1,D0 ; right node fit?
BGT.S RLCkSplit ; no ->
MOVE.W D3,D7 ; save virtual index for this fit
;
; select best fit if we have reached split point
;
RLCkSplit
CMP.W D6,D2 ; reached split point ?
BLT.S @2 ; no ->
BEQ.S @1 ; right on the money ->
SWAP D7 ; past split point, try previous fit first
@1 TST.W D7 ; have a fit?
BGE.S RLRotate ; yes, use it ->
SWAP D7 ; no, get previous fit
TST.W D7 ; have one?
BGE.S RLRotate ; yes, use it ->
@2 SWAP D7 ; previous fit = current fit
MOVE.W #-1,D7 ; no current fit
ADDQ.W #1,D3 ; bump index to next record
MOVE.W NDNRecs(A2),D1 ; max virtual index
ADD.W NDNRecs(A3),D1 ; = #recs in lt node + #recs in rt node
CMP.W D1,D3 ; any more records?
BLE.S RLFitLoop ; yes, keep trying ->
MOVEQ #-1,D0 ; result = 'won't fit'
BRA.S RLExit1 ; exit ->
;
; we have a fit, do the actual rotation
;
RLRotate
MOVE.W NDNRecs(A2),D3 ; init virt indx = 1st rec in rt node
@1 CMP.W D3,D4 ; at insert point ?
BNE.S @2 ; no ->
MOVEA.L A2,A1 ; ptr(left node)
MOVEA.L A5,A0 ; ptr(new record)
MOVE.W D5,D0 ; size of new record
MOVE.W NDNRecs(A1),D1 ; insert index = end of node
JSR InsertRec ; insert new record in left node
BNE.S RLDeepShit ; trouble ->
MOVEA.L A1,A5 ; save ptr(node buffer) and index
MOVE.W D1,D5 ; ...for new record
BRA.S @3 ; ->
@2 MOVEA.L A2,A0 ; ptr(left node)
MOVEA.L A3,A1 ; ptr(right node)
BSR RotRecLt ; rotate 1st record in right node
BNE.S RLDeepShit ; trouble ->
@3 CMP.W D7,D3 ; reached split index ?
BEQ.S RLCheckRt ; yes ->
ADDQ.W #1,D3 ; bump record index
BRA.S @1 ; rotate another one ->
;
; check if new record goes in right node
;
RLCheckRt
CMP.W D7,D4 ; insert index > split index ?
BLE.S RLExit ; no, not in right node ->
MOVEA.L A3,A1 ; ptr(right node)
MOVEA.L A5,A0 ; ptr(new record)
MOVE.W D5,D0 ; size of new record
MOVE.W D4,D1 ; insert index
SUB.W D7,D1 ; = virt insert index
SUBQ.W #1,D1 ; - split index - 1
JSR InsertRec ; insert new record in right node
BNE.S RLDeepShit ; all done ->
CLR.W D0 ; result = 'ok'
BRA.S RLExit1 ; exit ->
RLDeepShit
MOVEQ #dsBadRotate,D0 ; result = 'bad rotate'
_SysError ; give up
;
; clean up and exit
;
RLExit
CLR.W D0 ; result = ok
MOVEA.L A5,A1 ; return ptr(node buffer) and index
MOVE.W D5,D1 ; ...for new record
RLExit1
MOVEM.L (SP)+,D2-D7/A2-A5 ; restore regs
TST.W D0 ; set condition codes
RTS ; exit RotateLt
;__________________________________________________________________________________
;
; Routine: SplitLt (Split Left)
;
; Function: Inserts a new record into a BTree node by first inserting a
; empty left node and then using RotateLt to insert the new
; record.
;
; Input: A0.L - ptr(record)
; D0.W - size of record
; A2.L - pointer to left node buffer
; 0 = no left node
; A3.L - pointer to right node buffer
; D1.W - index of insert point (in right node)
; A4.L - pointer to BTCB
;
; Output: D0.W - result code
; 0 = ok
; +1 = won't fit
; -n = IO error
; A1.L - ptr(node buffer) containing new record
; D1.W - index of new record
; A2.L - ptr(new left node)
; D2.L - node number of new left node
;
; Called by: BTInsert
;__________________________________________________________________________________
SplitLt
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
MOVEM.L D3-D7/A3,-(A6) ; save regs
;
; set up some common stuff
;
MOVE.L A0,D7 ; D7 = ptr(record)
MOVE.W D0,D6 ; D6 = size of record
MOVE.W D1,D5 ; D5 = insert index
MOVE.W BTCLevel(A4),D0 ; locate TPR
JSR LocTPR ; ... for current level
MOVE.L TPRNodeN(A0),D4 ; D4 = right node number
;
; allocate a new disk node
;
MOVE.W BTCRefNum(A4),D0 ; volume refnum
JSR AllocNode ; allocate the node
BNE.S SLExit1 ; error ->
MOVE.L D1,D3 ; D3 = new left node number
;
; update forward link in original left node and release it
;
MOVE.L A2,D0 ; have a left node ?
BEQ.S SLInit ; no ->
MOVE.L D3,NDFlink(A2) ; left forward link = new node number
MOVEQ #kRBDirty,D1 ; indicate dirty buffer <10Oct85>
MOVEA.L A2,A0 ; ptr(left node buffer)
JSR RelNode ; release left node
BNE.S SLExit1 ; error ->
;
; initialize a new left node
;
SLInit
MOVE.L D3,D1 ; new node number
JSR InitNode ; get an initialized node
BNE.S SLExit1 ; error -> <19Dec85>
MOVEA.L A0,A2 ; A2 = ptr(new left node)
MOVE.B NDType(A3),NDType(A2) ; set to same type as right node
MOVE.L NDBlink(A3),NDBlink(A2) ; finish updating
MOVE.L D4,NDFlink(A2) ;...
MOVE.L D3,NDBlink(A3) ;... links
MOVEQ #1,D0 ; node height
ADD.W BTCDepth(A4),D0 ; = tree depth + 1
SUB.W BTCLevel(A4),D0 ; - current level
MOVE.B D0,NDNHeight(A2) ;
CMPI.B #NDLeafNode,NDType(A2) ; adding a new leaf node?
BNE.S SLRotate ; no ->
TST.L NDBlink(A2) ; new 1st node?
BNE.S SLRotate ; no ->
MOVE.L D3,BTCFNode(A4) ; yes, update 1st node pointer
;
; insert new record via rotate left
;
SLRotate
MOVEA.L D7,A0 ; ptr(new record)
MOVE.W D6,D0 ; size of new record
MOVE.W D5,D1 ; insert index
JSR RotateLT ; insert via rotate left
BEQ.S SLExit ; ok ->
BRA.S SLExit1 ; oh shit!!!
;
; clean up and exit
;
SLExit
CLR.W D0 ; result = ok
MOVE.L D3,D2 ; return left node number in D2
SLExit1
MOVEM.L (A6)+,D3-D7/A3 ; restore regs
MOVE.L (A6)+,-(SP) ; put return address back on stack
TST.W D0 ; set condition codes
RTS ; exit SplitLt
;__________________________________________________________________________________
;
; Routine: TreeSearch
;
; Function: Searches BTree for a specified key, setting up the Tree Path
; Table (TPR) to reflect the search path.
;
; Input: A0.L - ptr(search key)
; A4.L - pointer to BTCB
;
; Output: D0.W - result code
; 0 = ok (record found)
; BTnotfound = record not found
; other = error
; A1.L - ptr(node buffer)
; D1.W - index
; record index if found
; insert index if not found
; D2.L - node number of target leaf node
;
; Called by: BTDelete,BTInsert,BTSearch
;__________________________________________________________________________________
TreeSearch
MOVE.L jTreeSearch,-(SP) ; jump table entry for vTreeSearch <27Oct86>
RTS ; go there <27Oct86>
vTreeSearch ; 'vectored' TreeSearch routine <27Oct86>
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
MOVEM.L D3-D7/A2-A3,-(A6) ; save regs
;
; set up some common stuff
;
MOVE.L A0,D7 ; D7 = ptr(search key)
TST.W BTCDepth(A4) ; tree empty ?
BGT.S @1 ; no ->
MOVEQ #BTnotfound,D0 ; result = 'not found' <14Oct85>
SUBA.L A1,A1 ; no node buffer
CLR.L D1 ; index = 0
CLR.L D2 ; node number = 0
CLR.W BTCLevel(A4) ; current level = 0
BRA.S TSExit ; exit ->
@1 MOVEQ #1,D6 ; start at level 1
MOVE.L BTCRoot(A4),D3 ; root node number
;
; get the node and search for key
;
TSLoop
MOVEQ #0,D1 ; no GetBlock options <10Oct85>
MOVE.L D3,D2 ; node number
JSR GetNode ; get the node
BNE.S TSExit ; error ->
MOVEA.L A0,A1 ; A1 = ptr(node buffer)
MOVEA.L D7,A0 ; ptr(search key)
JSR SearchNode ; search node for key
MOVE.W D0,D5 ; D5 = search result
MOVE.W D1,D4 ; D4 = index
;
; update up TPR info
;
TSUpdTPR
MOVE.W D6,D0 ; locate TPR
JSR LocTPR ; ...for this level
MOVEA.L A0,A3 ; A3 = ptr(TPR)
MOVE.L D3,TPRNodeN(A3) ; set node number
MOVE.W D4,D2 ; assume parent index = insert index
TST.W D5 ; key found ?
BEQ.S @1 ; yes ->
SUBQ.W #1,D2 ; parent index = insert index - 1
BGE.S @1 ; parent index >= 0, ok ->
MOVE.W D4,D2 ; use insert index
@1 MOVE.W D2,TPRRIndx(A3) ; set record index
CMP.W BTCDepth(A4),D6 ; at leaf level ?
BEQ.S TSDone ; yes, all done ->
;
; move to next level down
;
TSNxtLev
MOVE.W D2,D1 ; parent index <10Oct85>
MOVE.L A1,-(SP) ; save ptr to node buffer <10Oct85>
JSR LocRec ; locate child record <10Oct85>
MOVE.L (A1),D3 ; D3 = child node number <10Oct85>
MOVEA.L (SP)+,A1 ; restore ptr to node buffer <10Oct85>
MOVEQ #0,D1 ; no RelBlock options <10Oct85>
MOVEA.L A1,A0 ; ptr(node buffer)
JSR RelNode ; release current node
ADDQ.W #1,D6 ; bump level count
BRA.S TSLoop ; continue the search
;
; at leaf level set up return info
;
TSDone
MOVE.W D6,BTCLevel(A4) ; initialize current level
MOVE.W D4,D1 ; return insert index in D1
MOVE.W D5,D0 ; return search result in D0
MOVE.L D3,D2 ; return node number in D2
TSExit
MOVEM.L (A6)+,D3-D7/A2-A3 ; restore regs
MOVE.L (A6)+,-(SP) ; put return address back on stack
TST.W D0 ; set up condition codes
RTS ; exit TreeSearch
;__________________________________________________________________________________
;
; Internal Subroutines
;__________________________________________________________________________________
;__________________________________________________________________________________
;
; Routine: RotRecLt
;
; Function: Rotates one record from the right node into the left node.
;
; Input: A0.L - ptr(left node)
; A1.L - ptr(right node)
;
; Output: D0.W - result code
; 0 = ok
; -1 = won't fit
;
; Called by: RotateLT
;__________________________________________________________________________________
RotRecLt
MOVEM.L A2-A3,-(SP) ; save registers
;
; insert first record of right node at the end of the left node
;
MOVEA.L A0,A2 ; A2 = ptr(lt node)
MOVEA.L A1,A3 ; A3 = ptr(rt node)
MOVEQ #0,D0 ; index of 1st record
JSR GetRecA ; get the record size
LEA lenND(A1),A0 ; ptr(1st record) in rt node
MOVEA.L A2,A1 ; A1 = ptr(left node)
MOVE.W NDNRecs(A1),D1 ; insert index into left node
JSR InsertRec ; insert record in left node
MOVEA.L A3,A1 ; A1 = ptr(right node)
BEQ.S RRLDelete ; insert ok ->
MOVEQ #-1,D0 ; result = "won't fit"
BRA.S RRLExit ; exit ->
;
; delete record from right node
;
RRLDelete
CLR.W D1 ; index = 0
JSR DeleteRec ; delete it
CLR.W D0 ; result = ok
RRLExit
TST.W D0 ; set condition codes
MOVEM.L (SP)+,A2-A3 ; restore registers
RTS ; exit RotRecLt
END