--Transport Mechanism Filestore - Mailbox restart --

-- [Indigo]<Grapevine>MS>MailboxRestart.mesa

-- Andrew Birrell  10-Sep-82 16:37:56 --

DIRECTORY
   BitMapDefs       USING[ Create, Set ],
   BodyDefs         USING[ oldestTime, RName, Timestamp ],
   BTreeDefs        USING[ CreateAndInitializeBTree, NullProc ],
   MailboxAlloc,
   ObjectDirDefs    USING[ noObject, ObjectNumber, RestartObject ],
   RestartDefs, --EXPORT only--
   VMDefs           USING[ OpenFile, Page, ReadPage, Release,
                           MarkStartWait, PageIndex, PageNumber,
                           GetFileLength ];

MailboxRestart: MONITOR[ initHeap: BOOLEAN ]
   IMPORTS BitMapDefs, BTreeDefs, MailboxAlloc, ObjectDirDefs,
           VMDefs
   EXPORTS RestartDefs --MailboxRestart--
   SHARES  MailboxAlloc =
BEGIN

OPEN MailboxAlloc;

initMBX: BOOLEAN ← FALSE;
maxMBXPages: CARDINAL ← 4000;

DuplicatePage: ERROR = CODE;

Init: ENTRY PROCEDURE =
   BEGIN
   pos: VMDefs.PageNumber;

   handle ← VMDefs.OpenFile[options:oldOrNew,
                            name: "MBX.Mailboxes"L, cacheFraction: 0];

   lockMap ← BitMapDefs.Create[maxMBXPages];
   pageMap ← BitMapDefs.Create[maxMBXPages];
   conflictMap ← BitMapDefs.Create[maxMBXPages];

   tree ← 
     BTreeDefs.CreateAndInitializeBTree [
        fileH: LOOPHOLE[VMDefs.OpenFile[options:oldOrNew,
                        name: "MBX.BTree", cacheFraction: 10] ],
        initializeFile: TRUE, useDefaultOrderingRoutines: TRUE,
        isFirstGreaterOrEqual: BTreeDefs.NullProc,
        areTheyEqual: BTreeDefs.NullProc ];

   nextVirginPage ← VMDefs.GetFileLength[handle].page;

   FOR pos IN [0 .. nextVirginPage )
   DO BEGIN
      page: VMDefs.Page = VMDefs.ReadPage[[handle,pos],lookAhead];
      base: VMDefs.PageIndex = FIRST[VMDefs.PageIndex];
      header: POINTER TO MBXHeader = LOOPHOLE[page,POINTER]+base;
      IF initMBX OR initHeap
      THEN BEGIN
           header.first←header.free;
           VMDefs.MarkStartWait[ page ];
           END;
      IF header.first # header.free
      THEN BEGIN
           buffer: DESCRIPTOR FOR ARRAY OF ObjectDirDefs.ObjectNumber;
           index: CARDINAL;
           rName: BodyDefs.RName = LOOPHOLE[page,POINTER]
                                      +base+SIZE[MBXHeader];
           otherValue: TreeRec = FindInTree[rName];
           otherN: CARDINAL;
           oldest: BodyDefs.Timestamp; -- estimate of oldest in mailbox --
           timeWantedInThisPage: BOOLEAN;
           WITH otherV: otherValue SELECT FROM
             empty => { oldest ← BodyDefs.oldestTime;
                        timeWantedInThisPage ← TRUE };
             found =>
               BEGIN
               otherP: VMDefs.Page =
                          VMDefs.ReadPage[[handle,otherV.where],0];
               otherH: POINTER TO MBXHeader =
                           LOOPHOLE[otherP,POINTER] + base;
               otherN ← otherH.number;
               IF header.number = otherN THEN ERROR DuplicatePage[];
               oldest ← otherV.oldest;
               timeWantedInThisPage ← (otherN > header.number OR
                                       oldest = BodyDefs.oldestTime);
               VMDefs.Release[otherP];
               END;
           ENDCASE => ERROR;
           BitMapDefs.Set[pageMap, pos];
           buffer ← DESCRIPTOR[page+header.first,
                  (header.free-header.first)/SIZE[ObjectDirDefs.ObjectNumber] ];
           FOR index IN [0..LENGTH[buffer])
           DO IF buffer[index].type = TOC
              THEN ObjectDirDefs.RestartObject[buffer[index]];
              IF buffer[index] # ObjectDirDefs.noObject
              THEN BEGIN
                   body: ObjectDirDefs.ObjectNumber =
                                         GetBodyObj[buffer[index]];
                   ObjectDirDefs.RestartObject[body];
                   IF timeWantedInThisPage
                   AND body.type # archived
                   THEN BEGIN
                        oldest ← ReadPostmark[body];
                        timeWantedInThisPage ← FALSE;
                        END;
                   END;
              mailboxContents ← mailboxContents + 1;
           ENDLOOP;
           WITH otherV: otherValue SELECT FROM
             empty =>
                BEGIN
                ChangeInTree[who:rName, where:pos, lock:pos,
                             oldest:oldest];
                mailboxes ← mailboxes+1;
                END;
             found =>
                ChangeInTree[who:rName,
                   where: IF header.number > otherN THEN pos
                          ELSE otherV.where,
                   lock:  IF header.number = 0 THEN pos
                          ELSE otherV.lock,
                   oldest:oldest];
           ENDCASE => ERROR;
           END;
      VMDefs.Release[page];
      END
   ENDLOOP;

   END;

ArchiverProcess: PROCESS;

START MailboxAlloc; Init[];

ArchiverProcess ← FORK MailboxAlloc.Archiver[];

END.