NearbyServiceCacheImpl.Mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Bill Jackson (bj) March 29, 1987 7:01:38 pm PST
DIRECTORY
XNS;
NearbyServiceCacheImpl: CEDAR MONITOR
IMPORTS XNS ~ {
Server Objects
CachedServer: TYPE ~ REF CachedServerObject;
CachedServerObject: TYPE ~ RECORD [
address: REF XNS.Address, -- readonly, REF to conform to CrRPC.RefAddress
knowDomainsServed: BOOLFALSE, -- hint, no ML
inactiveUntil: BasicTime.GMT ← BasicTime.earliestGMT -- ML
];
numHeaders: CARDINAL ~ 101;
serversByAddress: RefTab.Ref ~ RefTab.Create[mod~numHeaders, equal~EqualAddressesIgnoringSocket, hash~HashAddress];
HashAddress: RefTab.HashProc ~ {
host: XNS.Host ← NARROW[key, REF XNS.Address].host;
acc: CARDINAL ← ((((host.a*5+host.b)*5+host.c)*5+host.d)*5+host.e)*5+host.f;
RETURN [acc];
};
EqualAddressesIgnoringSocket: RefTab.EqualProc ~ {
ra1: REF XNS.Address ← NARROW[key1];
ra2: REF XNS.Address ← NARROW[key2];
RETURN [(ra1.net = ra2.net) AND (ra1.host = ra2.host)];
};
GetServerByAddress: PROC [ra: REF XNS.Address, makeActive: BOOL]
RETURNS [s: CachedServer] ~ {
Net and host are significant, socket is set to XNS.unknownSocket
ENABLE UNWIND => NULL;
val: RefTab.Val;
found: BOOL;
[found, val] ← RefTab.Fetch[x~serversByAddress, key~ra];
IF NOT found THEN {
val ← NEW[CachedServerObject ← [address~ra]];
[] ← RefTab.Insert[x~serversByAddress, key~ra, val~val] };
s ← NARROW[val];
IF makeActive THEN MarkServerUsable[s];
};
ServerIsUsableInternal: INTERNAL PROC [s: CachedServer] RETURNS [usable: BOOL] ~ {
usable ← ( BasicTime.Period[from: s.inactiveUntil, to: BasicTime.Now[]] >= 0 );
};
MarkServerUsable: ENTRY PROC [s: CachedServer] ~ {
ENABLE UNWIND => NULL;
s.inactiveUntil ← BasicTime.earliestGMT;
};
MarkServerBusy: ENTRY PROC [s: CachedServer, secondsBusy: INT ← 10] ~ {
ENABLE UNWIND => NULL;
s.inactiveUntil ← BasicTime.Update[BasicTime.Now[], secondsBusy];
};
MarkServerDown: ENTRY PROC [s: CachedServer, secondsDown: INT ← 600] ~ {
ENABLE UNWIND => NULL;
s.inactiveUntil ← BasicTime.Update[BasicTime.Now[], secondsDown];
s.knowDomainsServed ← FALSE;
};
MarkServerDead: ENTRY PROC [s: CachedServer] ~ {
ENABLE UNWIND => NULL;
s.inactiveUntil ← BasicTime.latestGMT;
s.knowDomainsServed ← FALSE;
};
Lists of Servers
CachedServerListHead: TYPE ~ REF CachedServerList;
CachedServerList: TYPE ~ REF CachedServerListElement;
CachedServerListElement: TYPE ~ RECORD [
next: CachedServerList, -- ML
server: CachedServer -- readonly
];
AddServerToList: ENTRY PROC [listHead: CachedServerListHead,
server: CachedServer] RETURNS [new: BOOL] ~ {
ENABLE UNWIND => NULL;
new ← AddServerToListInternal[listHead, server];
};
AddServerToListInternal: INTERNAL PROC [listHead: CachedServerListHead,
server: CachedServer] RETURNS [new: BOOL] ~ {
FOR p: CachedServerList ← listHead^, p.next WHILE p # NIL DO
IF p.server = server THEN RETURN [FALSE];
ENDLOOP;
listHead^ ← NEW[CachedServerListElement ← [next~listHead^, server~server]];
RETURN [TRUE];
};
DeleteServerFromListInternal: INTERNAL PROC [listHead: CachedServerListHead,
server: CachedServer] ~ {
p, prev: CachedServerList ← NIL;
IF listHead = NIL THEN RETURN;
p ← listHead^;
WHILE (p # NIL) AND (p.server # server) DO prev ← p; p ← p.next ENDLOOP;
IF p = NIL THEN RETURN;
IF prev = NIL THEN listHead^ ← p ELSE prev.next ← p;
};
ServerFilterProc: TYPE ~ PROC [CachedServer] RETURNS [ok: BOOL];
GetBestServerFromList: ENTRY PROC [listHead: CachedServerListHead,
filter: ServerFilterProc ← NIL]
RETURNS [bestServer: CachedServer ← NIL] ~ {
ENABLE UNWIND => NULL;
bestHops: CARDINALLAST[CARDINAL];
IF listHead = NIL THEN RETURN [NIL];
FOR p: CachedServerList ← listHead^, p.next WHILE p # NIL DO
server: CachedServer ~ p.server;
hops: CARDINAL;
IF NOT ServerIsUsableInternal[server] THEN LOOP;
hops ← XNSRouter.GetHops[server.address.net];
IF hops >= bestHops THEN LOOP;
IF hops >= XNSRouter.unreachable THEN LOOP;
IF filter # NIL THEN IF NOT filter[server].ok THEN LOOP;
bestServer ← server;
bestHops ← hops;
ENDLOOP;
};
Initialization
Init: PROC ~ {
};
Init[];
}...