-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. -- NetDirCache.mesa, HGM, 22-Jan-84 1:18:38 DIRECTORY String USING [Equivalent], Stats USING [StatCounterIndex, StatIncr], NameServerDefs USING [ CacheEntry, CacheEntryObject, SearchNetDirForName, SearchNetDirForAddress], PupTypes USING [PupAddress], ServerHeap USING [Create, Free, Node]; NetDirCache: MONITOR IMPORTS String, Stats, NameServerDefs, ServerHeap EXPORTS NameServerDefs = BEGIN OPEN Stats, NameServerDefs; PupAddress: TYPE = PupTypes.PupAddress; CacheEntry: TYPE = NameServerDefs.CacheEntry; CacheEntryObject: TYPE = NameServerDefs.CacheEntryObject; firstCacheEntry: CacheEntry ¬ NIL; cacheLimit: CARDINAL ¬ 400; cacheWordsInUse: CARDINAL ¬ 0; sequenceNumber: CARDINAL ¬ 0; statHits, statMisses, statNone, statFile: PUBLIC StatCounterIndex; emptyCacheEntryObject: CacheEntryObject ¬ [ next: NIL, size: SIZE[CacheEntryObject], count: 1, sequence: 0, names: DESCRIPTOR[NIL, 0], addrs: DESCRIPTOR[NIL, 0]]; SetCacheSize: PUBLIC PROCEDURE [n: CARDINAL] = BEGIN cacheLimit ¬ n; END; BumpCacheSize: PUBLIC PROCEDURE [n: INTEGER] = BEGIN cacheLimit ¬ cacheLimit + n; END; FlushWholeCache: PUBLIC ENTRY PROCEDURE = BEGIN WHILE firstCacheEntry # NIL DO FlushOneEntry[]; ENDLOOP; IF cacheWordsInUse # 0 THEN ERROR CacheShouldBeEmptyNow; END; EnumerateCache: PUBLIC ENTRY PROCEDURE [proc: PROCEDURE [CacheEntry]] = BEGIN FOR ce: CacheEntry ¬ firstCacheEntry, ce.next UNTIL ce = NIL DO proc[ce]; ENDLOOP; END; SearchCacheForName: PUBLIC ENTRY PROCEDURE [key: LONG STRING, proc: PROCEDURE [CacheEntry]] RETURNS [hit: BOOLEAN] = BEGIN previous: CacheEntry; FOR ce: CacheEntry ¬ firstCacheEntry, ce.next UNTIL ce = NIL DO FOR i: CARDINAL IN [0..LENGTH[ce.names]) DO IF String.Equivalent[key, ce.names[i]] THEN BEGIN StatIncr[statHits]; IF LENGTH[ce.addrs] = 0 THEN StatIncr[statMisses]; ce.count ¬ ce.count + 1; IF firstCacheEntry # ce THEN BEGIN -- move this entry to the head of the list previous.next ¬ ce.next; ce.next ¬ firstCacheEntry; firstCacheEntry ¬ ce; END; proc[ce]; RETURN[TRUE]; END; ENDLOOP; previous ¬ ce; ENDLOOP; StatIncr[statNone]; RETURN[FALSE]; END; SearchCacheForAddress: PUBLIC ENTRY PROCEDURE [key: PupAddress, proc: PROCEDURE [CacheEntry]] RETURNS [hit: BOOLEAN] = BEGIN previous: CacheEntry; FOR ce: CacheEntry ¬ firstCacheEntry, ce.next UNTIL ce = NIL DO FOR i: CARDINAL IN [0..LENGTH[ce.addrs]) DO IF key = ce.addrs[i] THEN BEGIN StatIncr[statHits]; IF LENGTH[ce.addrs] = 0 THEN StatIncr[statMisses]; ce.count ¬ ce.count + 1; IF firstCacheEntry # ce THEN BEGIN -- move this entry to the head of the list previous.next ¬ ce.next; ce.next ¬ firstCacheEntry; firstCacheEntry ¬ ce; END; proc[ce]; RETURN[TRUE]; END; ENDLOOP; previous ¬ ce; ENDLOOP; StatIncr[statNone]; RETURN[FALSE]; END; ForceNameIntoCache: PUBLIC ENTRY PROCEDURE [key: LONG STRING, proc: PROCEDURE [CacheEntry]] RETURNS [hit: BOOLEAN] = BEGIN mine: CacheEntryObject ¬ emptyCacheEntryObject; IF ~NameServerDefs.SearchNetDirForName[key, @mine] THEN RETURN[FALSE]; StatIncr[statFile]; proc[AddToCache[@mine]]; RETURN[TRUE] END; ForceAddressIntoCache: PUBLIC ENTRY PROCEDURE [key: PupAddress, proc: PROCEDURE [CacheEntry]] RETURNS [hit: BOOLEAN] = BEGIN mine: CacheEntryObject ¬ emptyCacheEntryObject; IF ~NameServerDefs.SearchNetDirForAddress[key, @mine] THEN RETURN[FALSE]; StatIncr[statFile]; proc[AddToCache[@mine]]; RETURN[TRUE] END; NothingInCacheToFlush: ERROR = CODE; CacheShouldBeEmptyNow: ERROR = CODE; FlushOneEntry: INTERNAL PROCEDURE = BEGIN previous, ce: CacheEntry; IF firstCacheEntry = NIL THEN ERROR NothingInCacheToFlush; ce ¬ firstCacheEntry; IF firstCacheEntry.next = NIL THEN firstCacheEntry ¬ NIL ELSE BEGIN WHILE ce.next # NIL DO previous ¬ ce; ce ¬ ce.next; ENDLOOP; previous.next ¬ NIL; END; cacheWordsInUse ¬ cacheWordsInUse - ce.size; FOR i: CARDINAL IN [0..LENGTH[ce.names]) DO ServerHeap.Free[ce.names[i]]; ENDLOOP; IF BASE[ce.names] # NIL THEN ServerHeap.Free[BASE[ce.names]]; IF BASE[ce.addrs] # NIL THEN ServerHeap.Free[BASE[ce.addrs]]; ServerHeap.Free[ce]; END; AddToCache: INTERNAL PROCEDURE [his: CacheEntry] RETURNS [ce: CacheEntry] = BEGIN WHILE his.size + cacheWordsInUse > cacheLimit DO FlushOneEntry[]; ENDLOOP; ce ¬ ServerHeap.Node[SIZE[CacheEntryObject]]; ce­ ¬ his­; ce.next ¬ firstCacheEntry; ce.sequence ¬ (sequenceNumber ¬ sequenceNumber + 1); firstCacheEntry ¬ ce; cacheWordsInUse ¬ cacheWordsInUse + ce.size; END; ServerHeap.Create[]; END.