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: ROPE ← NIL,
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: CARDINAL ← LOOPHOLE[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: ROPE ← NARROW[k];
k2: ROPE ← GetCacheKey[data];
RETURN [k1.Compare[k2, FALSE]];
};
}.