-- InitProcsImpl.mesa
-- Last edited by
--   MBrown on January 31, 1984 5:34:13 pm PST
--   Kolling on July 6, 1983 10:52 am

  DIRECTORY
    AccessControl,
    AlpineControl USING [TypeOfRestart],
    AlpineDebug,
    AlpineEnvironment
       USING [FileID, nullFileID, FileStore, PageCount, TransID, VolumeID, VolumeGroupID],
    AlpineFile,
    AlpineIdentity USING [myLocalConversation],
    AlpineImport USING [Handle, Register],
    AlpineOwner,
    AlpineTransaction USING[Create, Finish],
    AlpineTransMgr,
    AlpineTransMgrRpcControl USING [InterfaceRecord, NewInterfaceRecord],
    AlpineVolume,
    AlpineZones USING [],
    ConversationTable USING [Initialize, Fetch],
    CoordinatorControl USING [Initialize, CallAfterAnalysisPass, CallAfterUpdatePass],
    File,
    FileControl USING [Initialize, CallBeforeUpdatePass, CallAfterUpdatePass,
      RegisterVolumeGroup],
    FileMap USING [Handle, Initialize, Register],
    FilePageMgr USING [
      Create, InitializeFilePageMgr, ReadPages, UsePages, ReleaseVMPageSet, VMPageSet],
    OpenFileMap USING [Initialize],
    InitProcs USING [],
    LockControl USING [Initialize, ForkWatchdogProcess],
    LogControl USING [Format, Recover, ForkCheckpointProcess],
    Rope,
    RPC USING [Conversation, ConversationID, EncryptionKey, GetConversationID,
      MakeKey],
    SafeStorage USING [GetSystemZone],
    TransactionMap USING [GetHandle, GetTransID, Handle],
    WorkerControl USING [Initialize, CallAfterAnalysisPass, CallAfterUpdatePass];

InitProcsImpl: MONITOR
  IMPORTS
    AccessControl,
    AlpineImport,
    AlpineIdentity,
    AlpineTransaction,
    AlpineTransMgr,
    AlpineTransMgrRpcControl,
    ConversationTable,
    CoordinatorControl,
    File,
    FileControl,
    FileMap,
    FilePageMgr,
    LockControl,
    LogControl,
    OpenFileMap,
    Rope,
    RPC,
    SafeStorage,
    TransactionMap,
    WorkerControl
  EXPORTS
    AlpineControl,
    AlpineIdentity,
    AlpineZones,
    InitProcs
  = BEGIN
  VolumeID: TYPE = AlpineEnvironment.VolumeID;
  FileID: TYPE = AlpineEnvironment.FileID;
  FileStore: TYPE = AlpineEnvironment.FileStore;
  PageCount: TYPE = AlpineEnvironment.PageCount;
  ROPE: TYPE = Rope.ROPE;

  -- Exported to AlpineIdentity:
  myFileStore: PUBLIC FileStore;
  myLogVolumeID: PUBLIC VolumeID;
  myEncryptionKey: PUBLIC RPC.EncryptionKey;
  myAlpineImportHandle: PUBLIC AlpineImport.Handle;
  myLocalConversation: PUBLIC RPC.Conversation;
  myLocalConversationID: PUBLIC RPC.ConversationID;

  static: PUBLIC ZONE ← SafeStorage.GetSystemZone[];
    -- AlpineZones.static

  isInitialized: BOOL ← FALSE;
  isStarted: BOOL ← FALSE;

  Initialize: PUBLIC ENTRY PROC [
    filePageMgrNormalChunks, filePageMgrLogChunks, filePageMgrLeaderChunks: NAT,
    coordinatorMapHashArraySlots, transactionMapHashArraySlots: NAT,
    fileMapHashArraySlots, openFileMapHashArraySlots: NAT,
    lockHashArraySlots: NAT,
    fileMapFinalizationQueueLength: NAT,
    nAccessCacheEntries: NAT,
    alpineWheels: ROPE] = {
    -- AlpineControl.Initialize
    IF isInitialized THEN RETURN;
    FilePageMgr.InitializeFilePageMgr[
      nNormalChunksInCache: filePageMgrNormalChunks,
      nLogChunksInCache: filePageMgrLogChunks,
      nLeaderChunksInCache: filePageMgrLeaderChunks];
    ConversationTable.Initialize[17];
    LockControl.Initialize[lockZoneInitialSize: 2048, hashArraySize: 256];
    WorkerControl.Initialize[transactionMapHashArraySlots];
    CoordinatorControl.Initialize[coordinatorMapHashArraySlots];
    FileMap.Initialize[fileMapHashArraySlots, fileMapFinalizationQueueLength];
    OpenFileMap.Initialize[openFileMapHashArraySlots];
    FileControl.Initialize[];
    AccessControl.InitVolatileData[
      nAccessCacheEntries: nAccessCacheEntries,
      alpineWheels: alpineWheels];
    isInitialized ← TRUE;
    };

  Start: PUBLIC ENTRY PROC [
    fileStore: FileStore,
    typeOfRestart: AlpineControl.TypeOfRestart,
    nLogPages, nOwners: INT] = {
    volume: File.Volume;
    volumeID: VolumeID;
    { ENABLE UNWIND => NULL;
      IF NOT isInitialized THEN ERROR;
      IF isStarted THEN RETURN;
      IF (volume ← File.FindVolumeFromName[fileStore]) = NIL THEN {
        IF fileStore.Equal["Local.alpine", FALSE] THEN volume ← File.SystemVolume[]
        ELSE ERROR;
        };
      };
    volumeID ← [File.GetVolumeID[volume]];
    SELECT typeOfRestart FROM
      warmStart => NULL;
      coldStart => EraseFileStore[volumeID, fileStore];
      createServer => {
        IF volume # File.SystemVolume[] THEN File.EraseVolume[volume];
        CreateFileStore[volumeID, nLogPages, fileStore];
        };
      ENDCASE => ERROR;
    Recover[logVolume: volumeID,
      initOwnerFile: typeOfRestart = createServer, nOwners: nOwners];
    isStarted ← TRUE;
    };

  IsStarted: PUBLIC ENTRY PROC [] RETURNS [BOOL] = {
    RETURN [isStarted];
    };

  CreateFileStore: PROC [
    logVolume: VolumeID, logPages: PageCount, fileStore: FileStore] = {
    -- Formats the given volume to a well-defined initial state that is acceptable to
    --Recover below.  This should not be called while the server is running.
    --Call Create, then call Recover, in order to cold-start a server on an empty volume.
    logFile, restartFile: FileID;
    logFile ← CreateFile[logVolume, logPages];
    restartFile ← CreateFile[logVolume, 1];
    SetRootFiles[logVolume, logFile, restartFile];
    LogControl.Format[logVolume, logFile, restartFile, fileStore];
    };
 
  EraseFileStore: PROC [logVolume: VolumeID, fileStore: FileStore] = {
    -- Like CreateFileStore, but assumes that the logVolume already contains a log file
    --and a restart file.  Call EraseFileStore, then call Recover, in order to cold-start a
    --server on an existing volume.
    logFile, restartFile: FileID;
    [logFile, restartFile] ← GetRootFiles[logVolume];
    LogControl.Format[logVolume, logFile, restartFile, fileStore];
    };
 
  Recover: PROC [
    logVolume: VolumeID, initOwnerFile: BOOL, nOwners: INT] = {
    -- Starts the server using the indicated state.
    logFile, restartFile, ownerFile, newOwnerFileID: FileID;
    ownerFileTrans: TransactionMap.Handle;
    -- Temporary kludges (this entire proc might be so regarded ...)
    [logFile, restartFile] ← GetRootFiles[logVolume];
    FileControl.RegisterVolumeGroup[
      volumeGroupID: GetVolumeGroupID[logVolume],
      volumes: CONS[first: logVolume, rest: NIL]];
    -- Recover state from the log.
    LogControl.Recover[logVolume, logFile, restartFile];
    -- Tell AccessControl about the owner file.
    ownerFileTrans ← CreateLocalTrans[];
    IF initOwnerFile THEN {
      ownerFile ← AccessControl.CreateAndInitializeOwnerFile[
            conversation: AlpineIdentity.myLocalConversation,
            transHandle: ownerFileTrans,
            volGroupID: GetVolumeGroupID[logVolume],
            ownerFileVolID: logVolume,
            totalQuota: 10000,
            volumeGroupSize: 15000,
            overCommitQuotaDuringInitializeIfNeeded: TRUE,
            maxNumberOfOwnersAllowed: nOwners,
            nOwnerCacheEntries: 10];
        SetOwnerRootFile[logVolume, ownerFile];
      }
    ELSE ownerFile ← GetOwnerRootFile[logVolume];
    newOwnerFileID ← AccessControl.RegisterVolumeGroup[
        conversation: AlpineIdentity.myLocalConversation,
        transHandle: ownerFileTrans,
        volGroupID: GetVolumeGroupID[logVolume],
        ownerFileUniversalFile: [logVolume, ownerFile],
        nOwnerCacheEntries: 10];
    IF ownerFile # newOwnerFileID THEN SetOwnerRootFile[logVolume, newOwnerFileID];
    CommitLocalTrans[ownerFileTrans];
    LogControl.ForkCheckpointProcess[
      myFileStore: myFileStore,
      wakeupPeriodInSeconds: 60];
    LockControl.ForkWatchdogProcess[
      wakeupPeriod: 1000,
      abortWaitingRequestInterval: 30,
      abortInactiveGrantedRequestInterval: 20];
    };

  CreateLocalTrans: PROC [] RETURNS [TransactionMap.Handle] = {
    transID: AlpineEnvironment.TransID = AlpineTransaction.Create[
      conversation: AlpineIdentity.myLocalConversation,
      createLocalWorker: TRUE];
    RETURN [TransactionMap.GetHandle[transID]];
    };

  CommitLocalTrans: PROC [t: TransactionMap.Handle] = {
    IF AlpineTransaction.Finish[
      conversation: AlpineIdentity.myLocalConversation,
      transID: TransactionMap.GetTransID[t],
      requestedOutcome: commit, continue: FALSE].outcome # commit THEN ERROR;
    };

  CreateFile: PROC [volume: VolumeID, nPages: PageCount]
    RETURNS [createdFileID: FileID] = {
    NoteFileID: SAFE PROC [fileID: FileID] = CHECKED { createdFileID ← fileID };
    FilePageMgr.Create[volumeID: volume, initialSize: nPages, proc: NoteFileID];
    };

  AlpineRootFileRecord: TYPE = MACHINE DEPENDENT RECORD [
    logFile: FileID,
    restartFile: FileID,
    ownerFile: FileID];
    -- Format of file that is stored as File.VolumeFile.alpine in Cedar volume.

  SetRootFiles: PROC [logVolume: VolumeID, logFile, restartFile: FileID] = {
    rootVolume: File.Volume = File.FindVolumeFromID[logVolume];
    rootFP: FileID ← File.GetRoot[rootVolume, $alpine].fp;
    IF rootFP = AlpineEnvironment.nullFileID THEN {
      rootFP ← CreateFile[logVolume, 1];
      File.SetRoot[root: $alpine, file: File.Open[volume: rootVolume, fp: rootFP]];
      };
    {
      rootFileHandle: FileMap.Handle = FileMap.Register[volumeID: logVolume, fileID: rootFP];
      chunk: FilePageMgr.VMPageSet =
        FilePageMgr.UsePages[fileHandle: rootFileHandle, pageRun: [firstPage: 0, count: 1]];
      rootFileRecord: LONG POINTER TO AlpineRootFileRecord = LOOPHOLE[chunk.pages];
      rootFileRecord↑ ← [
        logFile: logFile, restartFile: restartFile, ownerFile: AlpineEnvironment.nullFileID];
      FilePageMgr.ReleaseVMPageSet[
        vMPageSet: chunk, releaseState: writeIndividualWait, keep: FALSE];
      };
    };

  GetRootFiles: PROC [logVolume: VolumeID] RETURNS [logFile, restartFile: FileID] = {
    rootVolume: File.Volume = File.FindVolumeFromID[logVolume];
    rootFP: FileID ← File.GetRoot[rootVolume, $alpine].fp;
    IF rootFP = AlpineEnvironment.nullFileID THEN ERROR;
    {
      rootFileHandle: FileMap.Handle = FileMap.Register[volumeID: logVolume, fileID: rootFP];
      chunk: FilePageMgr.VMPageSet =
        FilePageMgr.ReadPages[fileHandle: rootFileHandle, pageRun: [firstPage: 0, count: 1]];
      rootFileRecord: LONG POINTER TO AlpineRootFileRecord = LOOPHOLE[chunk.pages];
      [logFile: logFile, restartFile: restartFile] ← rootFileRecord↑;
      FilePageMgr.ReleaseVMPageSet[
        vMPageSet: chunk, releaseState: clean, keep: FALSE];
      };
    };

  SetOwnerRootFile: PROC [logVolume: VolumeID, ownerFile: FileID] = {
    rootVolume: File.Volume = File.FindVolumeFromID[logVolume];
    rootFP: FileID ← File.GetRoot[rootVolume, $alpine].fp;
    IF rootFP = AlpineEnvironment.nullFileID THEN ERROR;
    {
      rootFileHandle: FileMap.Handle = FileMap.Register[volumeID: logVolume, fileID: rootFP];
      chunk: FilePageMgr.VMPageSet =
        FilePageMgr.ReadPages[fileHandle: rootFileHandle, pageRun: [firstPage: 0, count: 1]];
      rootFileRecord: LONG POINTER TO AlpineRootFileRecord = LOOPHOLE[chunk.pages];
      rootFileRecord.ownerFile ← ownerFile;
      FilePageMgr.ReleaseVMPageSet[
        vMPageSet: chunk, releaseState: writeIndividualWait, keep: FALSE];
      };
    };

  GetOwnerRootFile: PROC [logVolume: VolumeID]
    RETURNS [ownerRootFile: FileID] = {
    rootVolume: File.Volume = File.FindVolumeFromID[logVolume];
    rootFP: FileID ← File.GetRoot[rootVolume, $alpine].fp;
    IF rootFP = AlpineEnvironment.nullFileID THEN ERROR;
    {
      rootFileHandle: FileMap.Handle = FileMap.Register[volumeID: logVolume, fileID: rootFP];
      chunk: FilePageMgr.VMPageSet =
        FilePageMgr.ReadPages[fileHandle: rootFileHandle, pageRun: [firstPage: 0, count: 1]];
      rootFileRecord: LONG POINTER TO AlpineRootFileRecord = LOOPHOLE[chunk.pages];
      [ownerFile: ownerRootFile] ← rootFileRecord↑;
      FilePageMgr.ReleaseVMPageSet[
        vMPageSet: chunk, releaseState: clean, keep: FALSE];
      };
    };

  GetVolumeGroupID: PROC [volumeID: VolumeID]
    RETURNS [volumeGroupID: AlpineEnvironment.VolumeGroupID] = {
    -- This kludge is guaranteed to work for a 1-volume system ...
    ID: TYPE = RECORD [a, b, c: CARDINAL, sequence: LONG CARDINAL];
    id: ID ← LOOPHOLE[volumeID];
    id.sequence ← id.sequence - 1;
    RETURN [LOOPHOLE[id]];
    };

  -- Procedures exported to InitProcs
 
  CalledBeforeAnalysisPass: PUBLIC PROC [
    fileStore: FileStore, logVolume: VolumeID] = {
    myFileStore ← fileStore;
    myLogVolumeID ← logVolume;
    myEncryptionKey ← RPC.MakeKey["RPC"];
    myAlpineImportHandle ← AlpineImport.Register[fileStore];
    myAlpineImportHandle.first.local ← TRUE;
    { interface: AlpineTransMgrRpcControl.InterfaceRecord ←
        AlpineTransMgrRpcControl.NewInterfaceRecord[];
      interface.RegisterWorker ← AlpineTransMgr.RegisterWorker;
      interface.WorkerPrepare ← AlpineTransMgr.WorkerPrepare;
      interface.WorkerFinish ← AlpineTransMgr.WorkerFinish;
      interface.Refused ← AlpineTransMgr.Refused;
      myAlpineImportHandle.first.transMgrInterface ← interface;
      };
    myLocalConversation ← ConversationTable.Fetch[myAlpineImportHandle];
    myLocalConversationID ← RPC.GetConversationID[myLocalConversation];
    };

  CalledAfterAnalysisPass: PUBLIC PROC [] = {
    WorkerControl.CallAfterAnalysisPass[];
    CoordinatorControl.CallAfterAnalysisPass[];
    };

  CalledBeforeUpdatePass: PUBLIC PROC [] = {
    FileControl.CallBeforeUpdatePass[];
    };

  CalledAfterUpdatePass: PUBLIC PROC [] = {
    FileControl.CallAfterUpdatePass[];
    WorkerControl.CallAfterUpdatePass[];
    CoordinatorControl.CallAfterUpdatePass[];
    };

  END.--InitProcsImpl

CHANGE LOG

Changed by MBrown on April 1, 1983 1:25 pm
-- Checkpoint process is now implemented in LogImpl.  Added some parms to Initialize.

Changed by MBrown on January 31, 1984 5:32:54 pm PST
-- Conversion to Cedar 5.0.