-- Coordinator.mesa
-- Defines the volatile state of a coordinator.
-- Last edited by
--   MBrown on January 30, 1984 11:51:40 am PST

  DIRECTORY
    AlpineEnvironment,
    AlpineImport USING [Handle],
    AlpineInternal USING [LogRecordID, nullLogRecordID],
    BasicTime USING [GMT],
    RPC USING [maxShortStringLength];

Coordinator: DEFINITIONS LOCKS c USING c: Handle =
  BEGIN

  Object: TYPE = MONITORED RECORD [
    transID: AlpineEnvironment.TransID ← TRASH, --immutable--
    beginRecord: AlpineInternal.LogRecordID ← AlpineInternal.nullLogRecordID, --immutable--
    state: State ← active,
      --increases monotonically from active to complete
    outcome: Outcome ← unknown,
      -- Changes to abort or commit during state transition collecting -> completing.
    finishInProgress: BOOL ← FALSE,
      -- A process that sets this TRUE is responsible for finishing the transaction.
    aWorkerBecameReady: BOOL ← FALSE,
      -- TRUE iff some worker returns "ready" from WorkerPrepare call.
    workers: WorkerHandle ← NIL,
      -- Elements added only when state = active.
    resultsReturned: CONDITION,
      -- Finish process waits here for remote calls to return, or for timeout
      --in order to delay sending new calls.
    forceRecord: AlpineInternal.LogRecordID ← AlpineInternal.nullLogRecordID,
      -- ID of log record following last-written coordinator log record
    next: Handle ← nullHandle
      --CoordinatorMap data structure
    ];
  Handle: TYPE = REF Object;
  nullHandle: Handle = NIL;

  State: TYPE = {active, collecting, completing, complete};
  
  Outcome: TYPE = AlpineEnvironment.Outcome --{abort, commit, unknown}--;

  WorkerObject: TYPE = RECORD [
    worker: AlpineImport.Handle, --immutable--
    state: WorkerState ← active, --increases monotonically from active to complete--
    communicationTrouble: BOOL ← FALSE,
    callInProgress: Call ← none, --communication in progress with worker--
    resultsOfMostRecentCall: Results ← [none, none[]],
    timeForNextCall: BasicTime.GMT ← TRASH,
      -- meaningful only if communicationTrouble
    lastPrepareResult: Results ← [none, none[]],
    lastFinishResult: Results ← [none, none[]]
    ];
  WorkerHandle: TYPE = LIST OF WorkerObject;

  WorkerState: TYPE = { active, ready, complete };
  Call: TYPE = { none, prepare, finish };
  Results: TYPE = RECORD [
    communicationError: CommunicationError,
    body: SELECT call: Call FROM
      none => [],
      prepare => [prepareResult: AlpineEnvironment.WorkerState],
      finish => []
      ENDCASE
    ];
  CommunicationError: TYPE = { none, bindingFailed, callFailed, busy };
    -- bindingFailed means that no call was made
    -- callFailed means that call may or may not have been made
    -- busy is equivalent to callFailed, but retrying is more likely to succeed.

  -- Format of persistent coordinator state.
  -- Note that coordinatorBegin and coordinatorComplete log records contain no information
  --other than the transaction ID, so we don't define structures for them here.

  RegisterWorkerLogRep: TYPE = MACHINE DEPENDENT RECORD [
    worker: StrBody];
  CompletingLogRep: TYPE = MACHINE DEPENDENT RECORD [
    outcome: AlpineEnvironment.CommitOrAbort];
  StrBody: TYPE = MACHINE DEPENDENT RECORD [
    length: CARDINAL ← 0, maxLength: CARDINAL ← RPC.maxShortStringLength,
    text: PACKED ARRAY[0..RPC.maxShortStringLength) OF CHAR];

  END.