-- File Merge.mesa -- Written by Martin Newell, June 1980 -- Last updated: December 21, 1981 3:40 PM by DF DIRECTORY crD: FROM "CoreDefs" USING [CloseFile, OpenFile, PageNumber, ReadPages, UFileHandle, UFileTruncate, WritePages], InlineDefs: FROM "InlineDefs" USING[BITAND, BITSHIFT], MergeDefs: FROM "MergeDefs" USING[MergeValue], MiscDefs: FROM "MiscDefs" USING [Zero], Mopcodes: FROM "Mopcodes" USING [zEXCH, zPOP], ovD: FROM "OverviewDefs" USING [ErrorCode, ok], -- SegmentDefs: FROM "SegmentDefs" USING [NewFile, Read, OldFileOnly, DestroyFile], StringDefs: FROM "StringDefs" USING [AppendString], SystemDefs: FROM "SystemDefs" USING [AllocateResidentPages, FreePages]; Merge: PROGRAM IMPORTS crD, InlineDefs, MiscDefs, StringDefs, SystemDefs EXPORTS MergeDefs = BEGIN OPEN crD, InlineDefs, MergeDefs, MiscDefs, Mopcodes, ovD, StringDefs, SystemDefs; InitMerge: PUBLIC PROCEDURE [fileName: STRING] = -- Initialize merge to use file fileName BEGIN GenValue _ ZeroValue; OpenMergeFile[fileName]; END; ConsolidateMerge: PUBLIC PROCEDURE = BEGIN n, k, nbuff: CARDINAL; m, r, t: MergeValue; ncount: LONG CARDINAL _ 0; -- go through the node number table, sequentiallly renumbering root nodes k _ LowHalf[GenValue]; FOR n IN [1 .. k] DO m _ LOOPHOLE[LONG[n], MergeValue]; nbuff _ Lock[m,0]; r _ IntLookup[m,nbuff].r; IF m=r THEN BEGIN t _ LOOPHOLE[(ncount _ ncount + 1) + 2B10]; [] _ SetValue[m,nbuff,t]; END ELSE t _ r; Unlock[nbuff]; ENDLOOP; -- Set Consolidate Flag Pass2 _ TRUE; END; FinishMerge: PUBLIC PROCEDURE = -- Close files and release structures BEGIN CloseMergeFile[]; END; GenMergeValue: PUBLIC PROCEDURE RETURNS[n: MergeValue] = --Generate new Merge value BEGIN RETURN[GenValue _ GenValue + 1]; END; Merge: PUBLIC PROCEDURE [n1,n2: MergeValue] RETURNS[r: MergeValue] = --Merge numbers n1 and n2 towards smaller of the two --Returns resulting value of Lookup[n1] (=Lookup[n2]) BEGIN r1,r2: MergeValue; n1buff,n2buff,r1buff,r2buff: CARDINAL; n1buff _ Lock[n1,0]; n2buff _ Lock[n2,0]; --find roots, r1,r2 of n1,n2 [r1,r1buff] _ IntLookup[n1,n1buff]; [] _ Lock[r1,r1buff]; [r2,r2buff] _ IntLookup[n2,n2buff]; [] _ Lock[r2,r2buff]; --merge roots --new root is min of r1 and r2 IF LessThan[r1,r2] THEN BEGIN r _ r1; [] _ SetValue[r2,r2buff,r]; END ELSE BEGIN r _ r2; [] _ SetValue[r1,r1buff,r]; END; --shorten paths from n1 and n2 to new root [] _ SetValue[n1,n1buff,r]; [] _ SetValue[n2,n2buff,r]; UnlockAll[]; END; Lookup: PUBLIC PROCEDURE[n: MergeValue] RETURNS[r: MergeValue] = --Return smallest number to which n has been merged, transitively closed BEGIN nbuff: CARDINAL; nbuff _ Lock[n,0]; r _ IntLookup[n,nbuff].r; [] _ SetValue[n,nbuff,r]; Unlock[nbuff]; END; Lookup2: PUBLIC PROCEDURE[n: MergeValue] RETURNS[r: MergeValue] = --Return smallest number to which n has been merged, transitively closed BEGIN nbuff: CARDINAL; nbuff _ Lock[n,0]; r _ IntLookup2[n,nbuff].r; Unlock[nbuff]; END; --Private procedures-- BufferTable: ARRAY [0..4) OF BufferDesc; BufferDesc: TYPE = RECORD [ page: INTEGER, dirty: BOOLEAN, lock: INTEGER, buffer: POINTER ]; next4: ARRAY [0..4) OF CARDINAL _ [1, 2, 3, 0]; FileName: STRING _ [40]; uFH: crD.UFileHandle _ NIL; bufferArea: POINTER; Pass2: BOOLEAN _ FALSE; OpenMergeFile: PROCEDURE[fileName: STRING] = BEGIN i: CARDINAL; erc: ovD.ErrorCode; buffer: POINTER; FileName.length _ 0; AppendString[FileName,fileName]; [erc,uFH] _ crD.OpenFile[[["Extractor"],[""]],[fileName],update]; IF erc#ovD.ok THEN MergeError["Problem opening file"]; IF crD.UFileTruncate[0,0,uFH]#ovD.ok THEN MergeError["Problem opening old file"]; bufferArea _ AllocateResidentPages[4]; buffer _ bufferArea; FOR i IN [0..4) DO BufferTable[i] _ [ page: -1, dirty: FALSE, lock: 0, buffer: buffer]; buffer _ buffer + 256; ENDLOOP; END; CloseMergeFile: PROCEDURE = BEGIN FreePages[bufferArea]; IF crD.UFileTruncate[0,0,uFH]#ovD.ok THEN MergeError["Problem truncating file"]; IF crD.CloseFile[uFH]#ovD.ok THEN MergeError["Problem closing file"]; uFH _ NIL; --DestroyFile[NewFile[FileName,Read,OldFileOnly]]; END; IntLookup: PROCEDURE[n: MergeValue, nbuff: CARDINAL] RETURNS[r: MergeValue, rbuff: CARDINAL] = --Return smallest number to which n has been merged, transitively closed BEGIN t: MergeValue; flag : BOOLEAN _ FALSE; --find root, r, of n [t,nbuff,flag] _ GetValue[n,nbuff]; r _ n; rbuff _ nbuff; UNTIL flag OR r=t DO r _ t; [t,rbuff,flag] _ GetValue[r,rbuff]; --rbuff is only a hint on rhs ENDLOOP; END; IntLookup2: PROCEDURE[n: MergeValue, nbuff: CARDINAL] RETURNS[r: MergeValue, rbuff: CARDINAL] = --Return smallest number to which n has been merged, transitively closed BEGIN t: MergeValue; flag : BOOLEAN _ FALSE; --find root, r, of n [t,nbuff,flag] _ GetValue[n,nbuff]; r _ n; rbuff _ nbuff; UNTIL flag OR r=t DO r _ t; [t,rbuff,flag] _ GetValue[r,rbuff]; --rbuff is only a hint on rhs REPEAT FINISHED => IF Pass2 AND flag THEN r _ t; ENDLOOP; END; SetValue: PROCEDURE[n: MergeValue, nbuff: CARDINAL, v: MergeValue] RETURNS[realnbuff: CARDINAL] = BEGIN vptr: POINTER TO MergeValue; npage,noffset: CARDINAL; IF n=v THEN RETURN; --not uncommon [npage,noffset] _ PageAddress[n]; realnbuff _ GetPage[npage,nbuff]; vptr _ BufferTable[realnbuff].buffer + noffset; IF vptr^#v THEN --avoid setting .dirty if possible BEGIN vptr^ _ v; BufferTable[realnbuff].dirty _ TRUE; END; END; GetValue: PROCEDURE[n: MergeValue, nbuff: CARDINAL] RETURNS[v: MergeValue, realnbuff: CARDINAL, done: BOOLEAN] = BEGIN vptr: POINTER TO MergeValue; npage,noffset: CARDINAL; [npage,noffset] _ PageAddress[n]; realnbuff _ GetPage[npage,nbuff]; vptr _ BufferTable[realnbuff].buffer + noffset; IF ((v _ vptr^) = ZeroValue) THEN v _ n; IF done _ (LOOPHOLE[v, LONG CARDINAL] >= 2B10) THEN v _ LOOPHOLE[(LOOPHOLE[v, LONG CARDINAL] - 2B10)]; END; Lock: PROCEDURE[n: MergeValue, nbuff: CARDINAL] RETURNS[realnbuff: CARDINAL] = BEGIN npage,noffset: CARDINAL; [npage,noffset] _ PageAddress[n]; realnbuff _ GetPage[npage,nbuff]; BufferTable[realnbuff].lock _ BufferTable[realnbuff].lock + 1; END; Unlock: PROCEDURE[buff: CARDINAL] = BEGIN BufferTable[buff].lock _ BufferTable[buff].lock - 1; END; UnlockAll: PROCEDURE = BEGIN i: CARDINAL; FOR i IN [0..4) DO BufferTable[i].lock _ 0; ENDLOOP; END; LessThan: PROCEDURE[n1,n2: MergeValue] RETURNS[BOOLEAN] = BEGIN c1: LONG CARDINAL _ LOOPHOLE[n1]; c2: LONG CARDINAL _ LOOPHOLE[n2]; RETURN[c1