-- Transport Mechanism Filestore - private DEFS for heap object directory. --

-- [Idun]<WServices>MS>ObjectDirInternal.mesa

-- Randy Gobbel  	30-Jul-82 14:48:08 --
-- Andrew Birrell	 3-Jun-81 12:59:45 --


DIRECTORY
  Bitmap USING [Map],
  Environment USING [wordsPerPage],
  NSString USING [nullString, String],
  ObjectDir USING [Client, ObjectNumber, ObjectType, noObject],
  ServerLog USING [Handle],
  VMDefs USING [FileHandle, FullAddress, PageAddress, PageIndex,
    PageNumber, pageSize];

ObjectDirInternal: DEFINITIONS =
BEGIN

ObjectNumber: TYPE = ObjectDir.ObjectNumber;
ObjectCount: TYPE = CARDINAL;

gapObjectNumber: ObjectNumber = ObjectDir.noObject;
-- an object number that 'NewObject' will never return --

NewObject: PROCEDURE
  [VMDefs.FullAddress, ObjectDir.ObjectType, ObjectDir.Client]
  RETURNS [ObjectNumber];
-- sets reference count to one --

ObjectBase: PROCEDURE [ObjectNumber, ObjectDir.Client]
  RETURNS [VMDefs.FullAddress];

segmentSize: CARDINAL = 6;  -- number of pages in a segment
headerSize: CARDINAL = SIZE[LONG INTEGER] + SIZE[SegmentIndex];
segmentsPerPage: CARDINAL =
 Environment.wordsPerPage/SIZE[SegmentIndex] - headerSize;
SegmentIndex: TYPE = CARDINAL;
noSegment: SegmentIndex = LAST[SegmentIndex];

-- the 'written' chain is stored permanently on disk --
ChainBlock: TYPE = MACHINE DEPENDENT RECORD [
  vp(0): SELECT OVERLAID * FROM
    sh => [header(0): ARRAY [0..0) OF SerialAndHead],
    chain =>
      [next(0): ARRAY SegmentIndex [0..0) OF SegmentIndex],
    ENDCASE];
SerialAndHead: TYPE = MACHINE DEPENDENT RECORD [
  serialNumber(0): LONG INTEGER,
  chainHead(2): SegmentIndex,
    -- head of written chain, unused on all pages but first of chain file
  fill(3): ARRAY [0..segmentsPerPage) OF UNSPECIFIED];

ObjDirPageNumber: TYPE = [0..PRED[endOfChain]];

DirData: TYPE = MACHINE DEPENDENT RECORD [
  vp(0:0..63): SELECT freedom(0:0..0): * FROM
    free => [
      next(0:1..15): VMDefs.PageIndex,
      dopc(1:0..31): ObjectDirInternal.DOPC],
    used => [
      type(0:1..4): ObjectDir.ObjectType,
      word(0:5..15): VMDefs.PageIndex,
      page(1): VMDefs.PageNumber,
      count(3): ObjectCount],
    ENDCASE];
DirPage: TYPE = RECORD [header: DirPageHeader, data: ARRAY DirIndex OF DirData];

endOfChain: CARDINAL = PRED[unchained];  -- "end of free chain"
unchained: CARDINAL = LAST[CARDINAL];  -- "not on free chain"

DirPageHeader: TYPE = RECORD [
  nextFreePage: CARDINAL, nextFreeIndex: VMDefs.PageIndex];

entriesPerPage: CARDINAL =
  (VMDefs.pageSize - SIZE[DirPageHeader])/SIZE[DirData];

DirIndex: TYPE = [0..entriesPerPage);
-- NOTE: DirIndex values must fit in the "index" field of an object number --

nullAddress: VMDefs.PageAddress = [NIL, 0];

Client: TYPE = LONG POINTER TO ClientObject;
ClientObject: TYPE = RECORD [
  name: NSString.String ← NSString.nullString,
-- stuff from StableStorageImpl
  chainHandle: VMDefs.FileHandle ← NIL,
  chain: LONG POINTER TO ChainBlock ← NIL,
  lastWritten: SegmentIndex ← 0,  -- last segment allocated for a writer
  lastChained: SegmentIndex ← 0,  -- last segment chained onto chain.written
  lastPage: VMDefs.PageAddress ← nullAddress,  -- last page used in chain.written
  freeCount: CARDINAL ← 0,  -- number of free segments
  freeMap: Bitmap.Map, -- free segment bitmap
  segmentCeiling: CARDINAL ← 0, -- size of segment bitmap
  
  handle: VMDefs.FileHandle ← NIL,
  segmentCount: CARDINAL ← 0,  -- number of segments
  -- synchronisation for single-page writers - beware!
  claimedPage: VMDefs.PageAddress ← nullAddress,
  claimed: BOOLEAN ← FALSE,
  unwrittenAllocation: BOOLEAN ← FALSE,
  
-- stuff from ObjectDirImpl
  firstFreePage: CARDINAL ← endOfChain,
    -- first page containing free numbers
  dirHandle: VMDefs.FileHandle ← NIL,
  nextVirginPage: CARDINAL ← 0, -- current size of file
  
  dpNumber: ObjDirPageNumber ← 0,
  dpPage: LONG POINTER TO DirPage ← NIL,
  lastDofpc: ObjectDirInternal.DOPC ← 0,
  log: ServerLog.Handle,
  zone: UNCOUNTED ZONE];
  
  

-- Compactor interface --

DOPC: TYPE = LONG CARDINAL;
-- "DeletedObjectPageCount";  see comments in GetObjectState

ObjectState: TYPE = {inUse, unused, duplicate};

GetObjectState: PROCEDURE [
  obj: ObjectNumber,
  where: VMDefs.FullAddress,
  dorpc: DOPC, -- "r" = read --
  client: ObjectDir.Client]
  RETURNS [ObjectState];
-- If object's reference count is non-zero, returns "inUse".
-- If reference count is zero, but base#where, returns "duplicate"
-- Otherwise returns "unused", and marks object as free with dopc=dorpc
-- Object numbers are re-used only if their dopc is <= compactor's
-- most recently reported dofpc.

ReportDofpc: PROCEDURE
  [dofpc: DOPC -- "f" = flushed --, client: ObjectDir.Client];
-- Compactor has overwritten objects whose dopc is <= dofpc.

MoveObject: PROCEDURE
  [ObjectNumber, VMDefs.FullAddress, ObjectDir.Client];
-- Compactor has moved start of object to given address --

END.