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.
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: BOOLEAN ← FALSE;
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;
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.