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: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL ← TRUE;
WatchFS:
PROC [
REF
ANY]
RETURNS [
REF
ANY ←
NIL] = {
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.