FileControlImpl.mesa
Last edited by:
Taft on April 10, 1983 2:44 pm
Loose ends:
1. Perhaps there should be a BackgroundProcess for each volume, or each volume group, or each log? Purpose would be to gain parallelism in those situations where it would not result in unfavorable disk arm motion.
DIRECTORY
AlpineEnvironment,
AlpineInternal,
FileControl,
FileInstance,
FilePrivate,
OpenFileMap,
Process,
SafeStorage USING [GetSystemZone],
TransactionMap,
VolumeGroup;
FileControlImpl: MONITOR
IMPORTS FileInstance, FilePrivate, OpenFileMap, Process, SafeStorage, TransactionMap, VolumeGroup
EXPORTS FileControl, FilePrivate =
BEGIN
FileControl.
CommitPhase1: PUBLIC PROCEDURE [trans: AlpineInternal.TransHandle] RETURNS [readOnly: BOOLEAN] =
BEGIN
fileInstance: FileInstance.Handle ← NIL;
readOnly ← TRUE;
WHILE (fileInstance ← FileInstance.GetNextHandleForTrans[trans, fileInstance])#NIL DO
FilePrivate.PrepareForCommit[fileInstance];
IF FileInstance.GetDeltaVersion[fileInstance]#0 THEN readOnly ← FALSE;
ENDLOOP;
END;
CommitPhase2: PUBLIC PROCEDURE [trans, newTrans: AlpineInternal.TransHandle] =
BEGIN
fileInstance: FileInstance.Handle ← NIL;
openFile: OpenFileMap.Handle ← NIL;
WHILE (fileInstance ← FileInstance.GetNextHandleForTrans[trans, fileInstance])#NIL DO
FilePrivate.PerformImmediateFileActions[fileInstance];
ENDLOOP;
WHILE (openFile ← OpenFileMap.GetNextHandleForTrans[trans, openFile])#NIL DO
IF newTrans=TransactionMap.nullHandle THEN OpenFileMap.Unregister[openFile]
ELSE OpenFileMap.ChangeTransaction[openFile, newTrans];
ENDLOOP;
ForkDeferredFileActions[trans];
END;
Abort: PUBLIC PROCEDURE [trans: AlpineInternal.TransHandle] =
BEGIN
fileInstance: FileInstance.Handle ← NIL;
openFile: OpenFileMap.Handle ← NIL;
WHILE (fileInstance ← FileInstance.GetNextHandleForTrans[trans, fileInstance])#NIL DO
FilePrivate.UndoFileActions[fileInstance];
ENDLOOP;
WHILE (openFile ← OpenFileMap.GetNextHandleForTrans[trans, openFile])#NIL DO
OpenFileMap.Unregister[openFile];
ENDLOOP;
FileInstance.FlushTransState[trans];
TransactionMap.AssertUpdatesAreComplete[trans];
END;
CallBeforeUpdatePass: PUBLIC PROCEDURE =
BEGIN
IF ~initialized OR recovering THEN ERROR;
recovering ← TRUE;
END;
CallAfterUpdatePass: PUBLIC PROCEDURE =
BEGIN
IF ~initialized OR ~recovering THEN ERROR;
recovering ← FALSE;
END;
initialized: BOOLEANFALSE;
Initialize: PUBLIC PROCEDURE =
BEGIN
IF initialized THEN ERROR;
initialized ← TRUE;
stdPZone ← SafeStorage.GetSystemZone[];
Process.Detach[FORK BackgroundProcess];
All other module initialization is accomplished by the configuration's CONTROL list
END;
RegisterVolumeGroup: PUBLIC PROCEDURE [volumeGroupID: AlpineEnvironment.VolumeGroupID, volumes: LIST OF AlpineEnvironment.VolumeID] =
BEGIN
IF ~initialized THEN ERROR;
VolumeGroup.Open[volumeGroupID: volumeGroupID, volumes: volumes, trans: NIL];
END;
FilePrivate.
stdPZone: PUBLIC ZONE;
recovering: PUBLIC BOOLEANFALSE;
Internal procedures
deferredTransList, deferredTransTail: LIST OF TransactionMap.Handle ← NIL;
deferredTransPending: CONDITION;
ForkDeferredFileActions: ENTRY PROCEDURE [trans: TransactionMap.Handle] =
BEGIN
transHandleItem: LIST OF TransactionMap.Handle ← stdPZone.CONS[trans, NIL];
IF deferredTransList=NIL THEN deferredTransList ← transHandleItem
ELSE deferredTransTail.rest ← transHandleItem;
deferredTransTail ← transHandleItem;
NOTIFY deferredTransPending;
END;
AwaitDeferredFileActions: ENTRY PROCEDURE RETURNS [trans: TransactionMap.Handle] =
BEGIN
WHILE deferredTransList=NIL DO
deferredTransTail ← NIL;
WAIT deferredTransPending;
ENDLOOP;
trans ← deferredTransList.first;
deferredTransList ← deferredTransList.rest;
END;
BackgroundProcess: PROCEDURE =
BEGIN
DO
trans: TransactionMap.Handle ← AwaitDeferredFileActions[];
fileInstance: FileInstance.Handle ← NIL;
WHILE (fileInstance ← FileInstance.GetNextHandleForTrans[trans, fileInstance])#NIL DO
FilePrivate.PerformDeferredFileActions[fileInstance];
ENDLOOP;
FileInstance.FlushTransState[trans];
TransactionMap.AssertUpdatesAreComplete[trans];
trans ← NIL; -- so it can be collected now
ENDLOOP;
END;
END.