-- 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.