-- Transport Mechanism Mail Server - SL Restart --

-- [Juniper]<Grapevine>MS>SLRestart.mesa

-- Randy Gobbel		19-May-81 12:48:15 --
-- Andrew Birrell	September 13, 1982 3:43 pm --

DIRECTORY
LogDefs		USING[ DisplayNumber, WriteLogEntry ],
ObjectDirDefs	USING[ RestartObject ],
Process		USING[ InitializeCondition, DisableTimeout ],
RestartDefs	--EXPORT only--,
SLDefs		USING[ SLQueue, ItemIndex, ItemAddress, Item ],
SLQueueImpl:	FROM   "SLQueue",
VMDefs		USING[ Page, PageNumber, GetFileLength, OpenFile,
			       FileHandle, UsePage, Release ];

SLRestart: PROGRAM[ initHeap:BOOLEAN ]
   IMPORTS LogDefs, ObjectDirDefs, SLQueueImpl, Process, VMDefs
   EXPORTS RestartDefs -- PROGRAM --
   SHARES  SLQueueImpl =
BEGIN

RestartQueues: PROCEDURE =
   BEGIN
   OPEN SLQueueImpl;
   SLTitle:   ARRAY SLDefs.SLQueue OF STRING =
                  [ express: "SLQueue.Express"L,
                    input: "SLQueue.Input"L,
                    forward: "SLQueue.Forward"L,
                    pending: "SLQueue.Pending"L,
                    foreign: "SLQueue.Foreign"L,
                    mailbox: "SLQueue.Mailbox"L ];
   SLName:    ARRAY SLDefs.SLQueue OF STRING =
                  [ express: "Express queue"L,
                    input: "Input queue"L,
                    forward: "Forward queue"L,
                    pending: "Pending queue"L,
                    foreign: "IFS/MAXC queue"L,
                    mailbox: "Mailbox queue"L ];
   FOR index: SLDefs.SLQueue IN SLDefs.SLQueue
   DO BEGIN
      handle: VMDefs.FileHandle =
                 VMDefs.OpenFile[options:oldOrNew,
                                 name: SLTitle[index], cacheFraction: 2];
      firstPos: SLDefs.ItemAddress = [ page: [ file: handle, page: 0 ],
                                       item: FIRST[SLDefs.ItemIndex] ];
      newFile: BOOLEAN;
      data[index].size ← VMDefs.GetFileLength[ handle ].page;
      newFile ← data[index].size = 0;
      IF newFile
      THEN BEGIN
           data[index].size ← 1 --cause extension to 1 pages--;
           LogDefs.WriteLogEntry["New SL-queue file created"L];
           END;
      IF initHeap OR newFile
      THEN BEGIN -- initialise with empty queue --
           p: VMDefs.PageNumber;
           FOR p IN [ FIRST[VMDefs.PageNumber] .. data[index].size )
           DO IF page # NIL THEN VMDefs.Release[LOOPHOLE[page,VMDefs.Page]];
              page ← LOOPHOLE[VMDefs.UsePage[dataPos←[handle,p]],SLQPage];
              BEGIN
                 index: SLDefs.ItemIndex;
                 FOR index IN SLDefs.ItemIndex
                 DO page[index].state ← free ENDLOOP;
              END;
              ReleaseData[dirty];
           ENDLOOP;
           END;

      Process.InitializeCondition[ @(data[index].itemWritten), 1];
      Process.DisableTimeout[ @(data[index].itemWritten) ];

      -- Adjust object reference counts --
      BEGIN
         pos: SLDefs.ItemAddress ← firstPos;
         count[index] ← 0; -- count of SL's in this queue --
         DO BEGIN
            ptr: POINTER TO SLDefs.Item = GetItem[pos];
            state: DataState ← clean;
            IF ptr.state = reading THEN { ptr.state ← full; state ← dirty };
            IF ptr.state = full
            THEN BEGIN
                 ObjectDirDefs.RestartObject[ptr.body];
                 ObjectDirDefs.RestartObject[ptr.SL];
                 count[index] ← count[index] + 1;
                 END;
            ReleaseData[state];
            NextItem[index, @pos];
            IF pos = firstPos THEN EXIT;
            END;
         ENDLOOP;
      END;

      -- find reader position: skip optional full, then all free items --
      data[index].rPos ← firstPos;
      DO ptr: POINTER TO SLDefs.Item = GetItem[data[index].rPos];
         IF ptr.state = free THEN { ReleaseData[clean]; EXIT };
         ReleaseData[clean];
         NextItem[index, @(data[index].rPos)];
         IF data[index].rPos = firstPos THEN EXIT --all items full--;
      ENDLOOP;
      BEGIN
         started: SLDefs.ItemAddress = data[index].rPos;
         DO ptr: POINTER TO SLDefs.Item = GetItem[data[index].rPos];
           IF ptr.state # free THEN { ReleaseData[clean]; EXIT };
           ReleaseData[clean];
           NextItem[index, @(data[index].rPos)];
           IF data[index].rPos = started THEN EXIT --all items free--;
        ENDLOOP;
      END;


      -- find writer position: after all full items --
      data[index].wPos ← data[index].rPos;
      DO ptr: POINTER TO SLDefs.Item ← GetItem[data[index].wPos];
         IF ptr.state = free THEN { ReleaseData[clean]; EXIT };
         ReleaseData[clean];
         NextItem[index, @(data[index].wPos)];
         IF data[index].wPos = data[index].rPos THEN EXIT;
      ENDLOOP;

      LogDefs.DisplayNumber[ SLName[index], [short[@(count[index])]] ];

      END
   ENDLOOP;

   LogDefs.DisplayNumber[ "Messages received"L, [short[@received]] ];
--   LogDefs.DisplayNumber[ "Messages re-processed"L, [short[@reDone]] ];
   END;


START SLQueueImpl; RestartQueues[];


END.