IPNameCacheImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Hal Murray June 29, 1985 3:46:01 pm PDT
John Larson, July 10, 1987 2:54:54 pm PDT
DIRECTORY
BasicTime USING [GMT, Now, Period, Update],
Rope USING [Cat, Equal, Length, Match, ROPE],
IPDefs USING [Address],
IPNameCache,
IPNameSupport USING [MakeAddressInList, MakeRopeInList];
IPNameCacheImpl: CEDAR MONITOR
IMPORTS BasicTime, Rope, IPNameSupport
EXPORTS IPNameCache =
BEGIN OPEN IPNameCache;
ROPE: TYPE = Rope.ROPE;
-- noticeable default ttl
ttlDefault: INT = 3333;
ZapWholeCache: PUBLIC ENTRY PROC = {
names ← NIL;
aliases ← NIL;
mxList ← NIL;
bogusAddresses ← NIL;
bogusNames ← NIL;
addresses ← NIL;
downNames ← NIL;
downAddresses ← NIL;
downServers ← NIL;
zones ← NIL;
histograms ← NIL; };
Name to Address cache
names: LIST OF NameEntry ← NIL;
GetNames: PUBLIC ENTRY PROC RETURNS [LIST OF NameEntry] = { RETURN[names]; };
NameLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: NameEntry] = {RETURN[NameLookupInternal[name]]};
NameLookupInternal: PROC [name: ROPE] RETURNS [entry: NameEntry] = {
FOR list: LIST OF NameEntry ← names, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.name, name, FALSE] THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateName: PUBLIC ENTRY PROC [
name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: NameEntry] = {
entry ← NameLookupInternal[name];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
entry.addresses ← NIL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeNameEntry[source, ttl, authoritative];
entry.name ← name;
RETURN[entry]; };
MakeNameEntry: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: NameEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[NameRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative ];
names ← CONS[entry, names]; };
AddAddressToName: PUBLIC ENTRY PROC [entry: NameEntry, address: IPDefs.Address] = {
entry.addresses ← IPNameSupport.MakeAddressInList[entry.addresses, address]; };
Alias to Name cache
aliases: LIST OF AliasEntry ← NIL;
GetAliases: PUBLIC ENTRY PROC RETURNS [LIST OF AliasEntry] = { RETURN[aliases]; };
AliasLookup: PUBLIC ENTRY PROC [alias: ROPE] RETURNS [entry: AliasEntry] = {RETURN[AliasLookupInternal[alias]]};
AliasLookupInternal: PROC [alias: ROPE] RETURNS [entry: AliasEntry] = {
FOR list: LIST OF AliasEntry ← aliases, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.alias, alias, FALSE] THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateAlias: PUBLIC ENTRY PROC [
alias: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: AliasEntry] = {
entry ← AliasLookupInternal[alias];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
entry.name ← NIL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeAliasEntry[source, ttl, authoritative];
entry.alias ← alias;
RETURN[entry]; };
MakeAliasEntry: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: AliasEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[AliasRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative ];
aliases ← CONS[entry, aliases]; };
AddNameToAlias: PUBLIC ENTRY PROC [entry: AliasEntry, name: ROPE] = {
entry.name ← name; };
MX cache
mxList: LIST OF MXEntry ← NIL;
GetMXList: PUBLIC ENTRY PROC RETURNS [LIST OF MXEntry] = { RETURN[mxList]; };
MXLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: MXEntry] = {RETURN[MXLookupInternal[name]]};
MXLookupInternal: PROC [name: ROPE] RETURNS [entry: MXEntry] = {
FOR list: LIST OF MXEntry ← mxList, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.name, name, FALSE] THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateMX: PUBLIC ENTRY PROC [
name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: MXEntry] = {
entry ← MXLookupInternal[name];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
entry.mxHosts ← NIL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeMXEntry[source, ttl, authoritative];
entry.name ← name;
RETURN[entry]; };
MakeMXEntry: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: MXEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[MXRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative ];
mxList ← CONS[entry, mxList]; };
AddHostToMX: PUBLIC ENTRY PROC [entry: MXEntry, hostInfo: MXHostInfo] = {
IF ~AlreadyInMXList[entry.mxHosts, hostInfo] THEN
entry.mxHosts ← CONS[hostInfo, entry.mxHosts]; };
AlreadyInMXList: PROC[mxHosts: LIST OF MXHostInfo, hostInfo: MXHostInfo]
RETURNS[BOOL] = {
FOR list: LIST OF MXHostInfo ← mxHosts, list.rest UNTIL list = NIL DO
IF Rope.Equal[list.first.host, hostInfo.host, FALSE] AND list.first.preference = hostInfo.preference THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
Bogus Name cache
bogusNames: LIST OF BogusNameEntry ← NIL;
GetBogusNames: PUBLIC ENTRY PROC RETURNS [LIST OF BogusNameEntry] = { RETURN[bogusNames]; };
BogusNameLookup: PUBLIC ENTRY PROC [bogus: ROPE] RETURNS [entry: BogusNameEntry] = {RETURN[BogusNameLookupInternal[bogus]]};
BogusNameLookupInternal: PROC [bogus: ROPE] RETURNS [entry: BogusNameEntry] = {
FOR list: LIST OF BogusNameEntry ← bogusNames, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.bogus, bogus, FALSE] THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateBogusName: PUBLIC ENTRY PROC [
bogus: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: BogusNameEntry] = {
entry ← BogusNameLookupInternal[bogus];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
NULL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeBogusName[source, ttl, authoritative];
entry.bogus ← bogus;
RETURN[entry]; };
MakeBogusName: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: BogusNameEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[BogusNameRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative ];
bogusNames ← CONS[entry, bogusNames]; };
Down Name cache
downNames: LIST OF DownNameEntry ← NIL;
GetDownNames: PUBLIC ENTRY PROC RETURNS [LIST OF DownNameEntry] = {
RETURN[downNames]; };
DownNameLookup: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: DownNameEntry] = {
entry ← DownNameLookupInternal[name];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items
RETURN[entry]};
DownNameLookupInternal: PROC [name: ROPE] RETURNS [entry: DownNameEntry] = {
FOR list: LIST OF DownNameEntry ← downNames, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.name, name, FALSE] THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateDownName: PUBLIC ENTRY PROC [
name: ROPE, ttl: INT]
RETURNS [entry: DownNameEntry] = {
entry ← DownNameLookupInternal[name];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl > -10 THEN RETURN[NIL];
-- Discard old info
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
RETURN[entry]; };
entry ← MakeDownName[ttl];
entry.name ← name;
RETURN[entry]; };
MakeDownName: PROC [ttl: INT] RETURNS [entry: DownNameEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[DownNameRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl ];
downNames ← CONS[entry, downNames]; };
Address to Name cache
addresses: LIST OF AddressEntry ← NIL;
GetAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF AddressEntry] = { RETURN[addresses]; };
AddressLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: AddressEntry] = {RETURN[AddressLookupInternal[address]]};
AddressLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: AddressEntry] = {
FOR list: LIST OF AddressEntry ← addresses, list.rest UNTIL list = NIL DO
entry ← list.first;
IF entry.address = address THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateAddress: PUBLIC ENTRY PROC [
address: IPDefs.Address, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: AddressEntry] = {
entry ← AddressLookupInternal[address];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
entry.names ← NIL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeAddressEntry[source, ttl, authoritative];
entry.address ← address;
RETURN[entry]; };
MakeAddressEntry: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: AddressEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[AddressRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative];
addresses ← CONS[entry, addresses]; };
AddNameToAddress: PUBLIC ENTRY PROC [entry: AddressEntry, name: ROPE] = {
entry.names ← IPNameSupport.MakeRopeInList[entry.names, name]; };
Bogus Address cache
bogusAddresses: LIST OF BogusAddressEntry ← NIL;
GetBogusAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF BogusAddressEntry] = { RETURN[bogusAddresses]; };
BogusAddressLookup: PUBLIC ENTRY PROC [bogus: IPDefs.Address] RETURNS [entry: BogusAddressEntry] = {RETURN[BogusAddressLookupInternal[bogus]]};
BogusAddressLookupInternal: PROC [bogus: IPDefs.Address] RETURNS [entry: BogusAddressEntry] = {
FOR list: LIST OF BogusAddressEntry ← bogusAddresses, list.rest UNTIL list = NIL DO
entry ← list.first;
IF entry.bogus = bogus THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateBogusAddress: PUBLIC ENTRY PROC [
bogus: IPDefs.Address, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: BogusAddressEntry] = {
entry ← BogusAddressLookupInternal[bogus];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
NULL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
RETURN[entry]; };
entry ← MakeBogusAddress[source, ttl, authoritative];
entry.bogus ← bogus;
RETURN[entry]; };
MakeBogusAddress: PROC [
source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: BogusAddressEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[BogusAddressRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative,
bogus: TRASH ];
bogusAddresses ← CONS[entry, bogusAddresses]; };
Down Address cache
downAddresses: LIST OF DownAddressEntry ← NIL;
GetDownAddresses: PUBLIC ENTRY PROC RETURNS [LIST OF DownAddressEntry] = { RETURN[downAddresses]; };
DownAddressLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: DownAddressEntry] = {
entry ← DownAddressLookupInternal[address];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items
RETURN[entry]};
DownAddressLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: DownAddressEntry] = {
FOR list: LIST OF DownAddressEntry ← downAddresses, list.rest UNTIL list = NIL DO
entry ← list.first;
IF entry.address = address THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateDownAddress: PUBLIC ENTRY PROC [address: IPDefs.Address, ttl: INT]
RETURNS [entry: DownAddressEntry] = {
entry ← DownAddressLookupInternal[address];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl > -10 THEN RETURN[NIL];
-- Discard old info
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
RETURN[entry]; };
entry ← MakeDownAddress[ttl];
entry.address ← address;
RETURN[entry]; };
MakeDownAddress: PROC [ttl: INT] RETURNS [entry: DownAddressEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[DownAddressRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
address: TRASH ];
downAddresses ← CONS[entry, downAddresses]; };
Down Server cache
downServers: LIST OF DownServerEntry ← NIL;
GetDownServers: PUBLIC ENTRY PROC RETURNS [LIST OF DownServerEntry] = {
RETURN[downServers]; };
DownServerLookup: PUBLIC ENTRY PROC [address: IPDefs.Address] RETURNS [entry: DownServerEntry] = {
entry ← DownServerLookupInternal[address];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN RETURN[NIL];}; -- Don't show expired items
RETURN[entry]};
DownServerLookupInternal: PROC [address: IPDefs.Address] RETURNS [entry: DownServerEntry] = {
FOR list: LIST OF DownServerEntry ← downServers, list.rest UNTIL list = NIL DO
entry ← list.first;
IF entry.address = address THEN {
entry.referenced ← BasicTime.Now[];
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateDownServer: PUBLIC ENTRY PROC [
address: IPDefs.Address, ttl: INT]
RETURNS [entry: DownServerEntry] = {
entry ← DownServerLookupInternal[address];
IF entry # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT = BasicTime.Period[from: now, to: entry.expires];
IF thisTtl > -10 THEN RETURN[NIL];
-- Discard old info
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
RETURN[entry]; };
entry ← MakeDownServer[ttl];
entry.address ← address;
RETURN[entry]; };
MakeDownServer: PROC [ttl: INT] RETURNS [entry: DownServerEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[DownServerRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
address: TRASH ];
downServers ← CONS[entry, downServers]; };
Zone to Server cache
zones: LIST OF ZoneEntry ← NIL;
GetZones: PUBLIC ENTRY PROC RETURNS [LIST OF ZoneEntry] = { RETURN[zones]; };
GetZone: PUBLIC ENTRY PROC [name: ROPE] RETURNS [entry: ZoneEntry] = {
bestEntry: ZoneEntry ← NIL;
FOR list: LIST OF ZoneEntry ← zones, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Match[Rope.Cat["*", entry.zone], name, FALSE] THEN {
IF bestEntry = NIL THEN bestEntry ← entry ELSE
IF Rope.Length[bestEntry.zone] < Rope.Length[entry.zone] THEN bestEntry ← entry};
ENDLOOP;
IF bestEntry # NIL THEN bestEntry.zoneLookup ← bestEntry.zoneLookup + 1;
RETURN[bestEntry]; };
ZoneLookup: PUBLIC ENTRY PROC [zone: ROPE] RETURNS [entry: ZoneEntry] = {
RETURN[ZoneLookupInternal[zone]]; };
ZoneLookupInternal: PROC [zone: ROPE] RETURNS [entry: ZoneEntry] = {
FOR list: LIST OF ZoneEntry ← zones, list.rest UNTIL list = NIL DO
entry ← list.first;
IF Rope.Equal[entry.zone, zone, FALSE] THEN {
entry.zoneLookup ← entry.zoneLookup + 1;
RETURN; };
ENDLOOP;
RETURN[NIL]; };
UpdateZone: PUBLIC ENTRY PROC [
name: ROPE, source: IPDefs.Address, ttl: INT, authoritative: BOOL]
RETURNS [entry: ZoneEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
thisTtl: INT;
entry ← ZoneLookupInternal[name];
IF entry # NIL THEN {
thisTtl ← BasicTime.Period[from: now, to: entry.expires];
IF thisTtl < -10 THEN entry.authoritative ← FALSE;
IF entry.authoritative AND ~authoritative THEN RETURN[NIL];
IF ~entry.authoritative AND authoritative THEN {
Discard old info
entry.servers ← NIL; };
entry.source ← source;
entry.loaded ← now;
entry.referenced ← now;
entry.expires ← BasicTime.Update[now, ttl];
entry.ttl ← ttl;
entry.authoritative ← authoritative;
entry.zone ← name;
RETURN[entry]; };
entry ← MakeZoneEntry[source, ttl, authoritative];
entry.zone ← name;
RETURN[entry]; };
AddServer: PUBLIC ENTRY PROC [entry: ZoneEntry, server: ROPE] = {
entry.servers ← IPNameSupport.MakeRopeInList[entry.servers, server]; };
MakeZoneEntry: PROC [source: IPDefs.Address, ttl: INT, authoritative: BOOL] RETURNS [entry: ZoneEntry] = {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← ttl;
IF expires = 0 THEN expires ← ttlDefault;
entry ← NEW[ZoneRecord];
entry^ ← [
loaded: now,
referenced: now,
expires: BasicTime.Update[now, expires],
ttl: ttl,
source: source,
authoritative: authoritative ];
zones ← CONS[entry, zones]; };
histograms: LIST OF HistogramEntry ← NIL;
GetHistograms: PUBLIC ENTRY PROC RETURNS [LIST OF HistogramEntry] = { RETURN[histograms]; };
AddToCacheHits: PUBLIC ENTRY PROC [server: IPDefs.Address, type: IPNameCache.CacheType] = {
histogram: HistogramEntry ← FindHistogram[server];
histogram.cacheHits[type] ← histogram.cacheHits[type].SUCC; };
AddToProbes: PUBLIC ENTRY PROC [server: IPDefs.Address, type: IPNameCache.ProbeType] = {
histogram: HistogramEntry ← FindHistogram[server];
histogram.probes[type] ← histogram.probes[type].SUCC; };
AddToLost: PUBLIC ENTRY PROC [server: IPDefs.Address] = {
histogram: HistogramEntry ← FindHistogram[server];
histogram.lost ← histogram.lost.SUCC; };
AddToCounter: PUBLIC ENTRY PROC [server: IPDefs.Address, ms: INT] = {
histogram: HistogramEntry ← FindHistogram[server];
index: INT;
ms ← ms + IPNameCache.histogramSlotSize - 1;
index ← ms/IPNameCache.histogramSlotSize;
IF index >= IPNameCache.histogramSlots THEN index ← IPNameCache.histogramSlots-1;
histogram.counters[index] ← histogram.counters[index].SUCC; };
FindHistogram: PROC [server: IPDefs.Address] RETURNS[ histogram: HistogramEntry] = {
FOR list: LIST OF HistogramEntry ← histograms, list.rest UNTIL list = NIL DO
histogram ← list.first;
IF histogram.server = server THEN EXIT;
REPEAT FINISHED => {
histogram ← NEW[HistogramRecord];
histogram^ ← [
server: server,
counters: ALL[0] ];
histograms ← CONS[histogram, histograms]; };
ENDLOOP; };
END.