MakeDoUpNodes.Mesa
Last Edited by: Spreitzer, September 3, 1985 2:52:58 pm PDT
DIRECTORY Basics, CedarProcess, FSBackdoor, IO, MakeDo, MakeDoPrivate, Process, RedBlackTree, Rope;
MakeDoUpNodes: CEDAR MONITOR
LOCKS n.up USING n: Node
IMPORTS CedarProcess, FSBackdoor, IO, MakeDo, MakeDoPrivate, RedBlackTree
EXPORTS MakeDo, MakeDoPrivate
=
INVARIANT
Data described in MakeDoPrivate are consistent.
BEGIN OPEN MakeDo, MakeDoPrivate;
NodeRep: PUBLIC TYPE = MakeDoPrivate.NodeRep;
CommandRep: PUBLIC TYPE = MakeDoPrivate.CommandRep;
GetCreated: PUBLIC ENTRY PROC [n: Node] RETURNS [t: Time] = {
ENABLE UNWIND => {};
t ← InnerGetCreated[n];
};
InnerGetCreated: INTERNAL PROC [n: Node] RETURNS [t: Time] = {
IF NOT n.timeValid THEN {
IF n.forceNotExist THEN ERROR;
n.created ← n.class.GetTime[n];
n.timeValid ← TRUE;
IF debugging THEN {
IF n.created # notExistTime
THEN Log[0, "Created[%g]=%g", IO.rope[n.name], IO.time[n.created]]
ELSE Log[0, "Created[%g]=never", IO.rope[n.name]];
};
};
t ← n.created;
};
SuspectNodeChange: PUBLIC PROC [n: Node, stack: Table] =
{ReallySuspectNodeChange[n, leaveNotExist, stack]};
ReallySuspectNodeChange: PUBLIC PROC [n: Node, op: NTOp, stack: Table] = {
InnerReset: INTERNAL PROC [n: Node] = {
ENABLE UNWIND => {};
SELECT op FROM
unforceNotExist => n.forceNotExist ← n.timeValid ← FALSE;
forceNotExist => {
n.timeValid ← n.forceNotExist ← TRUE;
n.created ← notExistTime;
IF debugging THEN Log[0, "Created[%g] forced never", IO.rope[n.name]];
};
leaveNotExist => IF NOT n.forceNotExist
THEN n.timeValid ← FALSE
ELSE IF NOT n.timeValid THEN ERROR;
ENDCASE => ERROR;
};
Inner: ENTRY PROC [n: Node] = {
ENABLE UNWIND => {};
For: INTERNAL PROC [which: CmdDep] = {
created: Time ← InnerGetCreated[n];
FOR e: Edge ← n.to[which].first, e.nNext WHILE e # NIL DO
IF e.n # n THEN ERROR;
IF created # e.traverseCreated THEN {
CmdMayNeedRemaking[e.c, which, stack];
};
ENDLOOP;
which ← which;
};
InnerReset[n];
For[cmd];
For[data];
};
IF debugging THEN Log[0, "%g may have changed", IO.rope[n.name]];
IF stack.Lookup[n] # NIL THEN RETURN;
stack.Insert[n, n];
Inner[n !UNWIND => [] ← stack.Delete[n]];
[] ← stack.Delete[n];
};
NodeMayNeedRemaking: PUBLIC PROC [n: Node, stack: Table] = {
Inner: ENTRY PROC [n: Node] = {
ENABLE UNWIND => {};
For: INTERNAL PROC [which: CmdDep] = {
which ← which;
FOR e: Edge ← n.to[which].first, e.nNext WHILE e # NIL DO
IF e.n # n THEN ERROR;
CmdMayNeedRemaking[e.c, which, stack];
ENDLOOP;
which ← which;
};
IF n.suspect THEN RETURN;
n.suspect ← TRUE;
IF debugging THEN Log[0, "%g may need remaking", IO.rope[n.name]];
For[cmd];
For[data];
};
IF stack.Lookup[n] # NIL THEN RETURN;
stack.Insert[n, n];
Inner[n !UNWIND => [] ← stack.Delete[n]];
[] ← stack.Delete[n];
};
EnumerateConsumers: PUBLIC ENTRY PROC [n: Node, which: CmdDep, to: PROC [Command, CmdDep]] = {
x: BOOLFALSE;
x ← x;
FOR e: Edge ← n.to[which].first, e.nNext WHILE e # NIL DO
to[e.c, which];
ENDLOOP;
x ← x;
};
EnumerateConsumerEdges: PUBLIC ENTRY PROC [n: Node, which: CmdDep, to: PROC [Edge, CmdDep]] = {
x: BOOLFALSE;
x ← x;
FOR e: Edge ← n.to[which].first, e.nNext WHILE e # NIL DO
to[e, which];
ENDLOOP;
x ← x;
};
UnlinkToFrom: PUBLIC PROC [e: Edge--on n.to=c.from--, which: CmdDep] = {
Inner: ENTRY PROC [n: Node] = {
ENABLE UNWIND => ERROR;
IF e.n # n THEN ERROR;
IF e.nNext # NIL THEN e.nNext.nPrev ← e.nPrev ELSE SELECT which FROM cmd => n.to[cmd].last ← e.nPrev; data => n.to[data].last ← e.nPrev; ENDCASE => ERROR;
IF e.nPrev # NIL THEN e.nPrev.nNext ← e.nNext ELSE SELECT which FROM cmd => n.to[cmd].first ← e.nNext; data => n.to[data].first ← e.nNext; ENDCASE => ERROR;
e.nNext ← e.nPrev ← NIL;
};
Inner[e.n];
};
ShouldRemakeNode: PUBLIC ENTRY PROC [n: Node, callerPromisesToDoIt: BOOL] RETURNS [suspect: BOOL] = {
ENABLE UNWIND => {};
IF (suspect ← n.suspect) AND callerPromisesToDoIt THEN n.suspect ← FALSE;
};
fsWatchEnabled: BOOLTRUE;
WatchFS: PROC [REF ANY] RETURNS [REF ANYNIL] = {
ce: REF READONLY FSBackdoor.CreateEvent ← NIL;
stack: Table ← NewRefTable[];
WHILE fsWatchEnabled DO
ce ← FSBackdoor.NextCreateEvent[ce];
{ENABLE ABORTED => CONTINUE;
n: Node ← GetNode[ce.fName, fileClass, FALSE];
IF n # NIL THEN {
IF stack.Size[] # 0 THEN {
out: IO.STREAM = GetCommanderHandle[].out;
out.PutRope["Filesystem watcher recovering.\n"];
stack.DestroyTable[];
};
SuspectNodeChange[n, stack];
};
};
ENDLOOP;
ce ← ce;
};
watcher: CedarProcess.Process;
Start: PROC = {
watcher ← CedarProcess.Fork[action: WatchFS, options: [inheritProperties: TRUE]];
};
Start[];
END.