DIRECTORY XNS; NearbyServiceCacheImpl: CEDAR MONITOR IMPORTS XNS ~ { CachedServer: TYPE ~ REF CachedServerObject; CachedServerObject: TYPE ~ RECORD [ address: REF XNS.Address, -- readonly, REF to conform to CrRPC.RefAddress knowDomainsServed: BOOL _ FALSE, -- 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] ~ { 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; }; 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: CARDINAL _ LAST[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; }; Init: PROC ~ { }; Init[]; }... NearbyServiceCacheImpl.Mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Bill Jackson (bj) March 29, 1987 7:01:38 pm PST Server Objects Net and host are significant, socket is set to XNS.unknownSocket Lists of Servers Initialization Κ«˜code™K™