STPConnectionCacheImpl.Mesa
Spreitzer, July 29, 1985 6:48:17 pm PDT
DIRECTORY Basics, BasicTime, IO, Process, RedBlackTree, Rope, STP, STPConnectionCache, UserCredentials;
STPConnectionCacheImpl: CEDAR MONITOR
IMPORTS BasicTime, IO, Process, RedBlackTree, Rope, STP, UserCredentials
EXPORTS STPConnectionCache
= {OPEN STPConnectionCache;
Time: TYPE = BasicTime.GMT;
PrivateStuff: TYPE = REF PrivateStuffRec;
PrivateStuffRec: TYPE = RECORD [
client: ROPENIL,
change: CONDITION,
dieAfter: Time ← BasicTime.earliestGMT];
cache: RedBlackTree.Table ← RedBlackTree.Create[GetCacheKey, CacheCompare];
Get: PUBLIC ENTRY PROC [host, client: ROPE] RETURNS [h: Handle] = {
ENABLE UNWIND => NULL;
p: PrivateStuff;
h ← NARROW[cache.Lookup[host]];
IF client = NIL THEN {
self: CARDINALLOOPHOLE[Process.GetCurrent[]];
client ← IO.PutFR["Process %g", IO.card[self]];
};
IF h = NIL THEN {
h ← NEW [HandleRec ← [
host: host,
stpHandle: STP.Create[],
private: p ← NEW [PrivateStuffRec ← []]
]];
TRUSTED {
Process.InitializeCondition[@p.change, Process.SecondsToTicks[5]];
Process.EnableAborts[@p.change];
Process.Detach[FORK CloseIt[h, p]];
};
RedBlackTree.Insert[cache, h, host];
}
ELSE p ← NARROW[h.private];
IF NOT h.stpHandle.IsOpen[] THEN {
name, password: ROPE;
[name, password] ← UserCredentials.Get[];
[] ← h.stpHandle.Open[host];
h.stpHandle.Login[name, password];
};
WHILE p.client # NIL DO WAIT p.change ENDLOOP;
p.client ← client;
BROADCAST p.change;
};
Release: PUBLIC ENTRY PROC [h: Handle, timeout: INT--seconds--] = {
ENABLE UNWIND => NULL;
p: PrivateStuff ← NARROW[h.private];
expire: Time ← BasicTime.Update[BasicTime.Now[], timeout];
p.client ← NIL;
IF BasicTime.Period[from: p.dieAfter, to: expire] > 0 THEN p.dieAfter ← expire;
BROADCAST p.change;
};
CloseIt: ENTRY PROC [h: Handle, p: PrivateStuff] = {
ENABLE UNWIND => NULL;
DO
now: Time;
delta: INT;
WAIT p.change;
now ← BasicTime.Now[];
delta ← BasicTime.Period[from: now, to: p.dieAfter];
IF delta <= 0 THEN {--time to be closed--
IF p.client = NIL THEN {
IF h.stpHandle.IsOpen[] THEN h.stpHandle.Close[];
TRUSTED {
Process.SetTimeout[@p.change, maxDelay];
};
}
ELSE TRUSTED {
Process.SetTimeout[@p.change, minDelay];
};
}
ELSE {
TRUSTED {
Process.SetTimeout[@p.change, Process.SecondsToTicks[MIN[delta, 60]+1]];
};
};
ENDLOOP;
};
minDelay: Process.Ticks ← Process.SecondsToTicks[6];
maxDelay: Process.Ticks ← Process.SecondsToTicks[600];
GetCacheKey: PROC [data: REF ANY] RETURNS [key: ROPE] --RedBlackTree.GetKey-- = {
h: Handle ← NARROW[data];
key ← h.host};
CacheCompare: PROC [k, data: REF ANY] RETURNS [Basics.Comparison] --RedBlackTree.Compare-- = {
k1: ROPENARROW[k];
k2: ROPE ← GetCacheKey[data];
RETURN [k1.Compare[k2, FALSE]];
};
}.