--Transport Mechanism Filestore - Mailbox restart --
-- MailboxRestart.mesa

-- Andrew Birrell  10-Sep-82 16:37:56 --
-- Hankins	30-Jul-84 15:36:51	Klamath update (MailboxAlloc imports)

DIRECTORY
  BitMapDefs USING [Create, Set],
  BodyDefs USING [oldestTime, RName, Timestamp],
  BTreeDefs USING [CreateAndInitializeBTree, NullProc],
  MailboxAlloc USING [
    archiver, changeInTree, conflictMap, findInTree, getBodyObj, handle, lockMap,
    lookAhead, mailboxContents, mailboxes, MBXHeader, nextVirginPage, pageMap,
    readPostmark, tree, TreeRec],
  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

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

  DuplicatePage: ERROR = CODE;

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

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

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

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

    MailboxAlloc.nextVirginPage ← VMDefs.GetFileLength[MailboxAlloc.handle].page;

    FOR pos IN [0..MailboxAlloc.nextVirginPage) DO
      BEGIN
      page: VMDefs.Page = VMDefs.ReadPage[
        [MailboxAlloc.handle, pos], MailboxAlloc.lookAhead];
      base: VMDefs.PageIndex = FIRST[VMDefs.PageIndex];
      header: POINTER TO MailboxAlloc.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[MailboxAlloc.MBXHeader];
        otherValue: MailboxAlloc.TreeRec = MailboxAlloc.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[
              [MailboxAlloc.handle, otherV.where], 0];
            otherH: POINTER TO MailboxAlloc.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[MailboxAlloc.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 = MailboxAlloc.getBodyObj[
              buffer[index]];
            ObjectDirDefs.RestartObject[body];
            IF timeWantedInThisPage AND body.type # archived THEN
              BEGIN
              oldest ← MailboxAlloc.readPostmark[body];
              timeWantedInThisPage ← FALSE;
              END;
            END;
          MailboxAlloc.mailboxContents ← MailboxAlloc.mailboxContents + 1;
          ENDLOOP;
        WITH otherV: otherValue SELECT FROM
          empty =>
            BEGIN
            MailboxAlloc.changeInTree[
              who: rName, where: pos, lock: pos, oldest: oldest];
            MailboxAlloc.mailboxes ← MailboxAlloc.mailboxes + 1;
            END;
          found =>
            MailboxAlloc.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.