-- Registration Server - Implementation of using heap and BTree as a registry.
-- [Juniper]<Grapevine>MS>Registry.mesa
-- Randy Gobbel, 20-May-81 13:03:14
-- J. Dion, September 10, 1979.
-- Andrew Birrell, 26-Oct-82 13:18:34
DIRECTORY
BodyDefs USING [maxRNameLength, RName, RNameSize, Timestamp],
HeapDefs,
Inline USING[ LowHalf ],
PupDefs USING [PupNameLookup],
PupStream USING [PupAddress],
Process USING [InitializeCondition, MsecToTicks],
ProtocolDefs,
RegistryDefs,
Time USING [Current, Packed];
Registry: MONITOR
IMPORTS BodyDefs, HeapDefs, Inline, PupDefs, Process, Time
EXPORTS RegistryDefs =
BEGIN
HeapObjectEnded: ERROR = CODE;
MangledHeapObject: ERROR = CODE;
Copy: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
writer: HeapDefs.WriterHandle] =
-- copies one component of an entry --
BEGIN
bLength: CARDINAL = 64;
buffer: ARRAY [0..bLength) OF WORD;
length: CARDINAL ← ReadComponentLength[reader];
WriteComponentLength[writer, length];
WHILE length > 0
DO used: CARDINAL = HeapDefs.HeapReadData[reader,
[@buffer,MIN[length,bLength]] ].used;
length ← length - used;
HeapDefs.HeapWriteData[writer, [@buffer,used] ];
ENDLOOP;
END;
Skip: PUBLIC PROC[reader: HeapDefs.ReaderHandle] =
-- skips one component of an entry --
BEGIN
length: CARDINAL = ReadComponentLength[reader];
IF length > 0 --optimisation--
THEN HeapDefs.SetReaderOffset[reader,
length + HeapDefs.GetReaderOffset[reader]];
END;
SkipIfEmpty: PUBLIC PROC[reader: HeapDefs.ReaderHandle]
RETURNS[empty: BOOLEAN] =
BEGIN
pos: HeapDefs.ObjectOffset = HeapDefs.GetReaderOffset[reader];
length: CARDINAL = ReadComponentLength[reader];
IF length = 0
THEN RETURN[TRUE]
ELSE BEGIN
HeapDefs.SetReaderOffset[reader, pos];
RETURN[FALSE]
END;
END;
WriteList: PUBLIC PROC[writer: HeapDefs.WriterHandle,
name: BodyDefs.RName,
stamp: BodyDefs.Timestamp] =
BEGIN
-- writes single or zero entry list, with no deletions --
IF name = NIL
THEN { WriteEmptyList[writer]; WriteEmptyList[writer] }
ELSE { WriteRNameList[writer,name]; WriteStampList[writer,stamp]; };
WriteEmptyList[writer]; WriteEmptyList[writer];
END;
StartSublist: PUBLIC PROC RETURNS[ writer: HeapDefs.WriterHandle] =
BEGIN
writer ← HeapDefs.HeapStartWrite[temp];
WriteComponentLength[writer, 0]; -- place holder --
END;
AddNameToSublist: PUBLIC PROC[writer: HeapDefs.WriterHandle,
name: BodyDefs.RName] =
BEGIN
HeapDefs.HeapWriteRName[writer, name];
END;
EndSublist: PUBLIC PROC[writer: HeapDefs.WriterHandle, count: CARDINAL]
RETURNS[reader: HeapDefs.ReaderHandle] =
BEGIN
offset: HeapDefs.ObjectOffset ← HeapDefs.GetWriterOffset[writer];
HeapDefs.SetWriterOffset[writer, HeapDefs.objectStart];
WriteComponentLength[writer, Inline.LowHalf[offset-SIZE[CARDINAL]]];
HeapDefs.SetWriterOffset[writer, offset];
WriteComponentLength[writer, count * SIZE[BodyDefs.Timestamp]];
BEGIN
stamp: BodyDefs.Timestamp = MakeTimestamp[];
THROUGH [0..count) DO WriteTimestamp[writer, stamp] ENDLOOP;
END;
WriteEmptyList[writer]; WriteEmptyList[writer]; -- deletions --
BEGIN
GetReader: PROC[obj: HeapDefs.ObjectNumber] =
{ reader ← HeapDefs.HeapStartRead[obj] };
HeapDefs.HeapEndWrite[writer, GetReader];
END;
END;
EnumerateRList: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
work: PROC[BodyDefs.RName]RETURNS[done:BOOLEAN]] =
BEGIN
length: CARDINAL ← ReadComponentLength[reader];
WHILE length > 0
DO name: BodyDefs.RName = [BodyDefs.maxRNameLength];
[] ← HeapDefs.HeapReadRName[reader, name];
length ← length - BodyDefs.RNameSize[name];
IF work[name] THEN EXIT;
ENDLOOP;
END;
ReadPrefix: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
name: BodyDefs.RName]
RETURNS[type: ProtocolDefs.RNameType,
stamp: BodyDefs.Timestamp] =
BEGIN
length: CARDINAL = ReadComponentLength[reader];
stamp ← ReadTimestamp[reader];
[,] ← HeapDefs.HeapReadData[reader, [@type,SIZE[ProtocolDefs.RNameType]]];
[] ← HeapDefs.HeapReadRName[reader, name];
IF length # SIZE[ProtocolDefs.RNameType] + SIZE[BodyDefs.Timestamp] +
BodyDefs.RNameSize[name]
THEN ERROR MangledHeapObject;
END;
WritePrefix: PUBLIC PROC[writer: HeapDefs.WriterHandle,
type: ProtocolDefs.RNameType,
stamp: POINTER TO BodyDefs.Timestamp,
name: BodyDefs.RName] =
BEGIN
WriteComponentLength[writer, SIZE[ProtocolDefs.RNameType] +
SIZE[BodyDefs.Timestamp] +
BodyDefs.RNameSize[name] ];
WriteTimestamp[writer, stamp↑];
HeapDefs.HeapWriteData[writer, [@type,SIZE[ProtocolDefs.RNameType]]];
HeapDefs.HeapWriteRName[writer, name];
END;
ReadPassword: PUBLIC PROC[reader: HeapDefs.ReaderHandle]
RETURNS [pw: ProtocolDefs.Password,
stamp: BodyDefs.Timestamp] =
BEGIN
IF ReadComponentLength[reader] # SIZE [ProtocolDefs.Password] +
SIZE[BodyDefs.Timestamp]
THEN ERROR MangledHeapObject;
stamp ← ReadTimestamp[reader];
[] ← HeapDefs.HeapReadData [reader, [@pw, SIZE [ProtocolDefs.Password]]];
END;
WritePassword: PUBLIC PROC[writer: HeapDefs.WriterHandle,
pw: ProtocolDefs.Password,
stamp: BodyDefs.Timestamp] =
BEGIN
WriteComponentLength[writer,
SIZE[ProtocolDefs.Password]+SIZE[BodyDefs.Timestamp]];
WriteTimestamp[writer, stamp];
HeapDefs.HeapWriteData [writer, [@pw, SIZE [ProtocolDefs.Password]]];
END;
ReadConnect: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
connect: ProtocolDefs.Connect]
RETURNS [stamp: BodyDefs.Timestamp] =
BEGIN
[] ← ReadComponentLength[reader];
stamp ← ReadTimestamp[reader];
connect.length ← LAST[CARDINAL];
[,] ← HeapDefs.HeapReadData[reader, [@(connect.length),SIZE[CARDINAL]] ];
IF connect.length > connect.maxlength
THEN ERROR MangledHeapObject;
[] ← HeapDefs.HeapReadData [reader,
[@(connect.text), (1+connect.length)/2] ];
END;
WriteConnect: PUBLIC PROC[writer: HeapDefs.WriterHandle,
connect: ProtocolDefs.Connect,
stamp: BodyDefs.Timestamp] =
BEGIN
WriteComponentLength[writer,
SIZE[BodyDefs.Timestamp] + SIZE[CARDINAL] + (1+connect.length)/2];
WriteTimestamp[writer, stamp];
HeapDefs.HeapWriteData[writer, [@(connect.length),SIZE[CARDINAL]] ];
HeapDefs.HeapWriteData [writer,
[@(connect.text), (1+connect.length)/2] ];
END;
WriteStampList: PROC[writer: HeapDefs.WriterHandle,
stamp: BodyDefs.Timestamp] =
BEGIN
WriteComponentLength[writer, SIZE [BodyDefs.Timestamp]];
WriteTimestamp[writer, stamp];
END;
WriteRNameList: PROC[writer: HeapDefs.WriterHandle,
name: BodyDefs.RName] =
BEGIN
WriteComponentLength[writer, BodyDefs.RNameSize[name] ];
HeapDefs.HeapWriteRName[writer, name];
END;
WriteEmptyList: PROC[writer: HeapDefs.WriterHandle] = INLINE
BEGIN
zero: CARDINAL ← 0;
HeapDefs.HeapWriteData[writer, [@zero,SIZE[CARDINAL]] ];
END;
ReadComponentLength: PROC[reader: HeapDefs.ReaderHandle]
RETURNS[length: CARDINAL] = INLINE
BEGIN
length ← LAST[CARDINAL];
[,] ← HeapDefs.HeapReadData[reader, [@length,SIZE[CARDINAL]] ];
END;
WriteComponentLength: PROC[writer: HeapDefs.WriterHandle,
length: CARDINAL] =
BEGIN
HeapDefs.HeapWriteData[writer, [@length,SIZE[CARDINAL]] ];
END;
ReadTimestamp: PROC[reader: HeapDefs.ReaderHandle]
RETURNS [stamp: BodyDefs.Timestamp] = INLINE
BEGIN
[,] ← HeapDefs.HeapReadData [reader,
[@stamp, SIZE [BodyDefs.Timestamp]] ];
END;
WriteTimestamp: PROCEDURE [writer: HeapDefs.WriterHandle,
stamp: BodyDefs.Timestamp] =
BEGIN
HeapDefs.HeapWriteData [writer, [@stamp, SIZE [BodyDefs.Timestamp]]];
END;
-- single-name updates --
-- RegistryDefs.UpdateInfo: TYPE = { done, noChange, outOfDate };
-- noChange => name already (not) there (timestamp may have been altered)
-- outOfDate => better timestamp already in list
AddName: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
name: BodyDefs.RName,
stamp: POINTER TO BodyDefs.Timestamp,
writer: HeapDefs.WriterHandle]
RETURNS[ info: RegistryDefs.UpdateInfo ] =
BEGIN
memInfo: RegistryDefs.UpdateInfo =
SingleChangeToSublist[reader, name, stamp, writer, add];
delMemInfo: RegistryDefs.UpdateInfo =
SingleChangeToSublist[reader, name, stamp, writer, remove];
info ← SELECT memInfo FROM
done => IF delMemInfo = outOfDate THEN outOfDate ELSE done,
noChange => IF delMemInfo = noChange THEN noChange ELSE ERROR,
outOfDate => IF delMemInfo = noChange THEN outOfDate ELSE ERROR,
ENDCASE => ERROR;
END;
RemoveName: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
name: BodyDefs.RName,
stamp: POINTER TO BodyDefs.Timestamp,
writer: HeapDefs.WriterHandle]
RETURNS[ info: RegistryDefs.UpdateInfo ] =
BEGIN
memInfo: RegistryDefs.UpdateInfo =
SingleChangeToSublist[reader, name, stamp, writer, remove];
delMemInfo: RegistryDefs.UpdateInfo =
SingleChangeToSublist[reader, name, stamp, writer, add];
info ← SELECT delMemInfo FROM
done => IF memInfo = outOfDate THEN outOfDate ELSE memInfo,
noChange => IF memInfo = noChange THEN noChange ELSE ERROR,
outOfDate => IF memInfo = noChange THEN outOfDate ELSE ERROR,
ENDCASE => ERROR;
END;
SingleChangeToSublist: PROC[reader: HeapDefs.ReaderHandle,
name: BodyDefs.RName,
stamp: POINTER TO BodyDefs.Timestamp,
writer: HeapDefs.WriterHandle,
change: {add,remove} ]
RETURNS[ info: RegistryDefs.UpdateInfo ] =
BEGIN
beforeCount: CARDINAL ← 0;
afterCount: CARDINAL ← 0;
member: BodyDefs.RName = [BodyDefs.maxRNameLength];
originalLength: CARDINAL = ReadComponentLength[reader];
length: CARDINAL ← originalLength;
lengthPos: HeapDefs.ObjectOffset = HeapDefs.GetWriterOffset[writer];
ResetLength: PROC =
BEGIN -- length didn't change after all --
now: HeapDefs.ObjectOffset = HeapDefs.GetWriterOffset[writer];
HeapDefs.SetWriterOffset[writer, lengthPos];
WriteComponentLength[writer, originalLength];
HeapDefs.SetWriterOffset[writer, now];
END;
WriteComponentLength[writer, IF change = add
THEN length + BodyDefs.RNameSize[name]
ELSE length - BodyDefs.RNameSize[name] ];
info ← done;
-- copy preceding names --
WHILE length > 0
DO [] ← HeapDefs.HeapReadRName[reader, member];
length ← length - BodyDefs.RNameSize[member];
SELECT CompareRNames[member, name] FROM
less =>
BEGIN
HeapDefs.HeapWriteRName[writer, member];
beforeCount ← beforeCount + 1;
END;
equal =>
BEGIN
IF change = add
THEN { info ← noChange; HeapDefs.HeapWriteRName[writer, name] };
EXIT
END;
greater =>
BEGIN
IF change = add
THEN HeapDefs.HeapWriteRName[writer, name]
ELSE info ← noChange;
afterCount ← 1;
HeapDefs.HeapWriteRName[writer, member];
EXIT
END;
ENDCASE => ERROR;
REPEAT
FINISHED =>
IF change = add
THEN HeapDefs.HeapWriteRName[writer, name]
ELSE info ← noChange;
ENDLOOP;
-- copy following names --
WHILE length > 0
DO [] ← HeapDefs.HeapReadRName[reader, member];
length ← length - BodyDefs.RNameSize[member];
HeapDefs.HeapWriteRName[writer, member];
afterCount ← afterCount + 1;
ENDLOOP;
SELECT info FROM
done => NULL;
noChange => ResetLength[];
ENDCASE => ERROR;
-- stamp list length --
WriteComponentLength[writer,
IF info = noChange
THEN ReadComponentLength[reader]
ELSE IF change = add
THEN ReadComponentLength[reader] + SIZE[BodyDefs.Timestamp]
ELSE ReadComponentLength[reader] - SIZE[BodyDefs.Timestamp] ];
THROUGH [1..beforeCount]
DO WriteTimestamp[writer, ReadTimestamp[reader] ]; ENDLOOP;
IF change = add
THEN BEGIN
IF info = done
THEN WriteTimestamp[writer, stamp↑]
ELSE BEGIN
prev: BodyDefs.Timestamp = ReadTimestamp[reader];
best: BodyDefs.Timestamp;
SELECT CompareTimestamps[stamp↑, prev ] FROM
less => { best ← prev; info ← outOfDate };
equal => best ← stamp↑;
greater => best ← stamp↑;
ENDCASE => ERROR;
WriteTimestamp[writer, best];
END;
END
ELSE IF info = noChange
THEN NULL
ELSE BEGIN
prev: BodyDefs.Timestamp = ReadTimestamp[reader];
IF CompareTimestamps[stamp↑, prev ] = less THEN info ← outOfDate;
END;
THROUGH [1..afterCount]
DO WriteTimestamp[writer, ReadTimestamp[reader] ]; ENDLOOP;
END;
-- General merge algorithm --
Inlist: TYPE = RECORD [
RNameReader, TimestampReader: HeapDefs.ReaderHandle,
RNameWordsLeft, TimestampWordsLeft: CARDINAL,
RNameStart, TimestampStart: HeapDefs.ObjectOffset,
name: BodyDefs.RName,
stamp: BodyDefs.Timestamp,
empty: BOOLEAN];
Outlist:TYPE = RECORD [
RNameWriter, TimestampWriter: HeapDefs.WriterHandle,
RNameStart: HeapDefs.ObjectOffset,
RNameWordsUsed, TimestampWordsUsed: CARDINAL];
MergeLists: PUBLIC PROC[reader1, reader2: HeapDefs.ReaderHandle,
writer: HeapDefs.WriterHandle]
RETURNS [newer1, newer2: BOOLEAN] =
BEGIN
-- allocate buffers for R-Names locally, to avoid FSP fragmentation --
name1: BodyDefs.RName = [BodyDefs.maxRNameLength];
name2: BodyDefs.RName = [BodyDefs.maxRNameLength];
name3: BodyDefs.RName = [BodyDefs.maxRNameLength];
name4: BodyDefs.RName = [BodyDefs.maxRNameLength];
addlist1, addlist2, dellist1, dellist2: Inlist;
n1, n2: BOOLEAN;
CreateInlist [@addlist1, name1, reader1];
CreateInlist [@dellist1, name2, reader1];
CreateInlist [@addlist2, name3, reader2];
CreateInlist [@dellist2, name4, reader2];
[newer1, newer2] ←
MergeSublists [@addlist1, @addlist2, @dellist1, @dellist2, writer];
ResetInlist [@addlist1];
ResetInlist [@dellist1];
ResetInlist [@addlist2];
ResetInlist [@dellist2];
[n1, n2] ←
MergeSublists [@dellist1, @dellist2, @addlist1, @addlist2, writer];
newer1 ← newer1 OR n1;
newer2 ← newer2 OR n2;
DeleteInlist [@addlist1];
DeleteInlist [@dellist1];
DeleteInlist [@addlist2];
DeleteInlist [@dellist2];
END;
MergeSublists:
PROCEDURE [add1, add2, del1, del2: POINTER TO Inlist, writer: HeapDefs.WriterHandle]
RETURNS [newer1, newer2: BOOLEAN] =
BEGIN
outlist: Outlist;
CreateOutlist [@outlist, writer];
newer1 ← newer2 ← FALSE;
UNTIL CompareElements [add1, add2] = Null
DO WHILE CompareElements [add1, add2] = Less
DO WHILE CompareElements [del2, add1] = Less DO Get [del2] ENDLOOP;
IF ~(CompareElements [del2, add1] = Equal
AND Newer [del2, add1])
THEN BEGIN Put [add1, @outlist]; newer1 ← TRUE END;
Get [add1]
ENDLOOP;
IF CompareElements [add1, add2] = Equal
THEN BEGIN
IF Newer [add1, add2]
THEN BEGIN Put [add1, @outlist]; newer1 ← TRUE END
ELSE BEGIN Put [add2, @outlist]; newer2 ← TRUE END;
Get [add1]; Get [add2]
END;
WHILE CompareElements [add2, add1]= Less
DO WHILE CompareElements [del1, add2]= Less DO Get [del1] ENDLOOP;
IF ~(CompareElements [del1, add2]= Equal
AND Newer [del1, add2])
THEN BEGIN Put [add2, @outlist]; newer2 ← TRUE END;
Get [add2]
ENDLOOP;
ENDLOOP;
DeleteOutlist [@outlist, writer]
END;
CreateInlist:
PROCEDURE [inlist: POINTER TO Inlist, name: BodyDefs.RName,
reader: HeapDefs.ReaderHandle] =
BEGIN
inlist.name ← name;
inlist.RNameReader ← HeapDefs.CopyReader[reader];
inlist.RNameStart ← HeapDefs.GetReaderOffset[reader];
Skip[reader];
inlist.TimestampReader ← HeapDefs.CopyReader [reader];
inlist.TimestampStart ← HeapDefs.GetReaderOffset[reader];
Skip[reader];
inlist.RNameWordsLeft ← ReadComponentLength[inlist.RNameReader];
inlist.TimestampWordsLeft ← ReadComponentLength[inlist.TimestampReader];
Get[inlist];
END;
ResetInlist:
PROCEDURE [inlist: POINTER TO Inlist] =
BEGIN
HeapDefs.SetReaderOffset[inlist.RNameReader, inlist.RNameStart];
HeapDefs.SetReaderOffset[inlist.TimestampReader, inlist.TimestampStart];
inlist.RNameWordsLeft ← ReadComponentLength[inlist.RNameReader];
inlist.TimestampWordsLeft ← ReadComponentLength[inlist.TimestampReader];
Get[inlist];
END;
DeleteInlist:
PROCEDURE [inlist: POINTER TO Inlist] =
BEGIN
HeapDefs.HeapEndRead[inlist.RNameReader];
HeapDefs.HeapEndRead[inlist.TimestampReader];
END;
CreateOutlist:
PROCEDURE [outlist: POINTER TO Outlist, writer: HeapDefs.WriterHandle] =
BEGIN
outlist.RNameWriter ← writer;
outlist.RNameStart ← HeapDefs.GetWriterOffset[writer];
WriteComponentLength[outlist.RNameWriter, 0]--placeholder--;
outlist.RNameWordsUsed ← 0;
outlist.TimestampWriter ← HeapDefs.HeapStartWrite[temp];
outlist.TimestampWordsUsed ← 0;
END;
DeleteOutlist:
PROCEDURE [outlist: POINTER TO Outlist, writer: HeapDefs.WriterHandle] =
BEGIN
CopyToWriter: PROC [object: HeapDefs.ObjectNumber] =
BEGIN
reader: HeapDefs.ReaderHandle = HeapDefs.HeapStartRead [object];
bLength: CARDINAL = 64;
buffer: ARRAY [0..bLength) OF WORD;
length: CARDINAL ← outlist.TimestampWordsUsed;
WHILE length > 0
DO used: CARDINAL = HeapDefs.HeapReadData[reader,
[@buffer,MIN[length,bLength]] ].used;
length ← length - used;
HeapDefs.HeapWriteData[writer, [@buffer,used] ];
ENDLOOP;
HeapDefs.HeapEndRead[reader];
END;
TimestampStart: HeapDefs.ObjectOffset =
HeapDefs.GetWriterOffset[outlist.RNameWriter];
-- write component length for RName list --
HeapDefs.SetWriterOffset[outlist.RNameWriter, outlist.RNameStart];
WriteComponentLength[outlist.RNameWriter, outlist.RNameWordsUsed];
HeapDefs.SetWriterOffset[outlist.RNameWriter, TimestampStart];
IF outlist.RNameWriter # writer THEN ERROR;
-- write component length for timestamp list --
WriteComponentLength[writer, outlist.TimestampWordsUsed];
-- append timestamp list --
HeapDefs.HeapEndWrite[outlist.TimestampWriter, CopyToWriter];
END;
Get:
PROCEDURE [inlist: POINTER TO Inlist] =
BEGIN
IF inlist.RNameWordsLeft > 0
THEN BEGIN
[] ← HeapDefs.HeapReadRName [inlist.RNameReader, inlist.name];
inlist.stamp ← ReadTimestamp [inlist.TimestampReader];
IF inlist.TimestampWordsLeft < SIZE[BodyDefs.Timestamp]
OR inlist.RNameWordsLeft < BodyDefs.RNameSize[inlist.name]
THEN ERROR MangledHeapObject;
inlist.TimestampWordsLeft ← inlist.TimestampWordsLeft -
SIZE[BodyDefs.Timestamp];
inlist.RNameWordsLeft ←
inlist.RNameWordsLeft - BodyDefs.RNameSize[inlist.name];
IF (inlist.TimestampWordsLeft = 0 OR inlist.RNameWordsLeft = 0)
AND inlist.TimestampWordsLeft + inlist.RNameWordsLeft # 0
THEN ERROR MangledHeapObject;
inlist.empty ← FALSE;
END
ELSE inlist.empty ← TRUE;
END;
Put:
PROCEDURE [inlist: POINTER TO Inlist, outlist: POINTER TO Outlist] =
BEGIN
IF inlist.empty THEN ERROR HeapObjectEnded;
HeapDefs.HeapWriteRName [outlist.RNameWriter, inlist.name];
outlist.RNameWordsUsed ← outlist.RNameWordsUsed + BodyDefs.RNameSize [inlist.name];
WriteTimestamp [outlist.TimestampWriter, inlist.stamp];
outlist.TimestampWordsUsed ← outlist.TimestampWordsUsed +
SIZE [BodyDefs.Timestamp];
END;
CompareElements: PROCEDURE [e1, e2: POINTER TO Inlist]
RETURNS [{Less, Equal, Greater, Null}] =
BEGIN
IF e1.empty
THEN IF e2.empty
THEN RETURN [Null]
ELSE RETURN [Greater]
ELSE IF e2.empty
THEN RETURN [Less]
ELSE SELECT CompareRNames [e1.name, e2.name] FROM
less => RETURN[Less];
equal => RETURN[Equal];
greater => RETURN[Greater];
ENDCASE => ERROR;
END;
Newer: PROCEDURE [e1, e2: POINTER TO Inlist] RETURNS [BOOLEAN] =
BEGIN
RETURN [CompareTimestamps [e1.stamp, e2.stamp] = greater]
END;
CompareRNames: PUBLIC PROC[n1, n2: BodyDefs.RName]
RETURNS [RegistryDefs.Comparison] =
BEGIN
length: CARDINAL = MIN [n1.length, n2.length];
i: CARDINAL;
FOR i IN [0 .. length)
DO BEGIN
ch1: CHARACTER = IF n1[i] IN CHARACTER['A .. 'Z]
THEN (n1[i] - 'A) + 'a ELSE n1[i];
ch2: CHARACTER = IF n2[i] IN CHARACTER['A .. 'Z]
THEN (n2[i] - 'A) + 'a ELSE n2[i];
IF ch1 < ch2 THEN RETURN [less];
IF ch1 > ch2 THEN RETURN [greater];
END
ENDLOOP;
IF n1.length < n2.length
THEN RETURN [less]
ELSE IF n1.length = n2.length
THEN RETURN [equal]
ELSE RETURN [greater];
END;
futureLimit: CARDINAL ← 14;
CompareTimestamps: PUBLIC ENTRY PROC[t1, t2: BodyDefs.Timestamp]
RETURNS [RegistryDefs.Comparison] =
BEGIN
-- Garbage check: treat timestamps more than 14 days future as 0 --
latest: Time.Packed =
LOOPHOLE[ prevTime + (LONG[futureLimit] * 24) * 60 * 60 ];
IF t1.time > latest THEN RETURN [less];
IF t2.time > latest THEN RETURN [greater];
IF t1.time < t2.time THEN RETURN [less];
IF t1.time > t2.time THEN RETURN [greater];
IF t1.net < t2.net THEN RETURN [less];
IF t1.net > t2.net THEN RETURN [greater];
IF t1.host < t2.host THEN RETURN [less];
IF t1.host > t2.host THEN RETURN [greater];
RETURN [equal]
END;
prevTime: Time.Packed ← Time.Current[];
aWeeWhile: CONDITION;
MakeTimestamp: PUBLIC ENTRY PROCEDURE RETURNS [stamp: BodyDefs.Timestamp] =
BEGIN
newTime: Time.Packed;
WHILE (newTime ← Time.Current[]) = prevTime
DO WAIT aWeeWhile -- ensure uniqueness of timestamps -- ENDLOOP;
stamp.net ← ThisMachine.net;
stamp.host ← ThisMachine.host;
stamp.time ← prevTime ← newTime;
END;
ThisMachine: PupStream.PupAddress;
-- regPurger subroutines --
CheckStampList: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
limit: BodyDefs.Timestamp]
RETURNS[old: BOOLEAN] =
BEGIN
length: CARDINAL = ReadComponentLength[reader];
THROUGH [0..length/SIZE[BodyDefs.Timestamp])
DO IF CompareTimestamps[ReadTimestamp[reader], limit] = less
THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE]
END;
FilterStampList: PUBLIC PROC[reader: HeapDefs.ReaderHandle,
limit: BodyDefs.Timestamp,
writer: HeapDefs.WriterHandle] =
BEGIN
namePos: HeapDefs.ObjectOffset = HeapDefs.GetWriterOffset[writer];
nameLength: CARDINAL ← 0;
stampLength: CARDINAL;
stampReader: HeapDefs.ReaderHandle = HeapDefs.CopyReader[reader];
Action: PROC[name: BodyDefs.RName] RETURNS[done:BOOLEAN] =
BEGIN
stamp: BodyDefs.Timestamp = ReadTimestamp[stampReader];
done ← FALSE;
IF CompareTimestamps[stamp, limit] # less
THEN BEGIN
HeapDefs.HeapWriteRName[writer, name];
nameLength ← nameLength + BodyDefs.RNameSize[name];
END
ELSE stampLength ← stampLength - SIZE[BodyDefs.Timestamp];
END;
Skip[stampReader];
stampLength ← ReadComponentLength[stampReader];
WriteComponentLength[writer, 0];
EnumerateRList[reader, Action];
BEGIN
newPos: HeapDefs.ObjectOffset = HeapDefs.GetWriterOffset[writer];
HeapDefs.SetWriterOffset[writer, namePos];
WriteComponentLength[writer, nameLength];
HeapDefs.SetWriterOffset[writer, newPos];
END;
HeapDefs.HeapEndRead[stampReader];
WriteComponentLength[writer, stampLength];
THROUGH [0..ReadComponentLength[reader]/SIZE[BodyDefs.Timestamp])
DO stamp: BodyDefs.Timestamp = ReadTimestamp[reader];
IF CompareTimestamps[stamp, limit] # less
THEN WriteTimestamp[writer, stamp];
ENDLOOP;
END;
PupDefs.PupNameLookup [@ThisMachine, "ME"];
Process.InitializeCondition[@aWeeWhile, Process.MsecToTicks[100]];
END.