-- File: WalnutDBLockImpl.mesa
-- Contents:
-- procedures for locking access to Walnut's database & log
-- this file contains ALL of (and only) the ENTRY PROCs

-- Created by: Willie-Sue November 2, 1982
-- Last edited by:
-- Rick Cattell on XXX
-- Willie-Sue on April 13, 1983 12:27 pm

DIRECTORY
 GVBasics USING [Timestamp],
 GVRetrieve USING [Handle],
IO USING [STREAM],
 DB,
 WalnutDB,
 WalnutDBAccess,
 WalnutDBLock,
 WalnutDBLog,
 WalnutWindow;

WalnutDBLockImpl: CEDAR MONITOR
IMPORTS DB, WalnutDB, WalnutDBAccess, WalnutDBLog, WalnutWindow
EXPORTS WalnutDB, WalnutDBLock =
  
BEGIN OPEN WalnutDB;

databaseIsBusy: BOOLFALSE;
databaseAvailable: CONDITION;
CheckForDatabaseBusy: INTERNAL PROC = INLINE
{ UNTIL ~databaseIsBusy DO WAIT databaseAvailable; ENDLOOP;};

-- ********************************************************
InitializeDBVars: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutDBAccess.DoInitializeDBVars[];
END;

MsgRecToMsg: PUBLIC ENTRY PROC[mr: MsgRec] RETURNS[msg: Msg, existed: BOOL] =
-- Converts msg from record to entity form
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
[msg, existed]← WalnutDBAccess.DoMsgRecToMsg[mr];
END;

DeclareMsg: PUBLIC ENTRY PROC[mName: ROPE] RETURNS [msg: Msg, existed: BOOL] =
-- Creates a new Msg entity, and sets its name to be mName.
-- is called when messages have been read from the log or another file.
-- If the Msg already exists, returns it and returns existed=TRUE.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
[msg, existed]← WalnutDBAccess.DoDeclareMsg[mName];
END;

DeclareMsgSet: PUBLIC ENTRY PROC[mName: ROPE] RETURNS[msgSet: MsgSet, existed: BOOL] =
-- Creates a new MsgSet entity, and sets its name to be mName.
-- is called when user creates a message set, or reads a log file
-- If the MsgSet already exists, returns it.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 [msgSet, existed]← WalnutDBAccess.DoDeclareMsgSet[mName];
END;

-- ********************************************************
MGetPList: PUBLIC ENTRY PROC[m: Msg, prop: Attribute] RETURNS [LIST OF Value] =
-- Finds all the values of prop for m and returns them.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.GetPList[m, prop]]
END;

MGetP: PUBLIC ENTRY PROC[m: Msg, prop: Attribute] RETURNS [Value] =
-- Finds the one unique value for prop for m or NIL if none.
-- SIGNALs NonUniquePropertyValue if more than one value.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.GetP[m, prop]];
END;

MSetPList: PUBLIC ENTRY PROC[m: Msg, prop: Attribute, vl: LIST OF Value] =
-- Sets the values of prop for m to be those in vl.
-- Erases any previous property values.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutWindow.SetWalnutUpdatesPending[TRUE];
 DB.SetPList[m, prop, vl];
END;

MSetP: PUBLIC ENTRY PROC[m: Msg, prop: Attribute, v: Value] RETURNS [Relship]=
-- Sets the value of prop for m to be v.
-- Erase any previous property values if this is 2nd attribute of reln
-- (not on any attribute, so that props formed from N-aries will work).
-- Returns the relship used by the prop.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutWindow.SetWalnutUpdatesPending[TRUE];
RETURN[DB.SetP[m, prop, v]];
END;

--MEraseP: PUBLIC ENTRY PROC[m: Msg, prop: Attribute, v: Entity] =
-- BEGIN ENABLE UNWIND => NULL;
-- CheckForDatabaseBusy[];
-- WalnutDBAccess.DoEraseP[m, prop, v];
-- END;

--MErasePList: PUBLIC ENTRY PROC[m: Msg, first: Attribute] =
-- BEGIN ENABLE UNWIND => NULL;
-- CheckForDatabaseBusy[];
-- WalnutDBAccess.DoErasePList[m, first];
-- END;

DomainOf: PUBLIC ENTRY PROC[e: Entity] RETURNS[Domain] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.DomainOf[e]];
END;

RelationOf: PUBLIC ENTRY PROC[rel: Relship] RETURNS[Relation] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.RelationOf[rel]];
END;

Null: PUBLIC ENTRY PROC[e: Entity] RETURNS[BOOL] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.Null[e]];
END;

GetName: PUBLIC ENTRY PROC[e: Entity] RETURNS [ROPE] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.GetName[e]];
END;

GetFE: PUBLIC ENTRY PROC[rel: Relship, a: Attribute] RETURNS [Entity] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.V2E[DB.GetF[rel, a]]];
END;

GetFS: PUBLIC ENTRY PROC[rel: Relship, a: Attribute] RETURNS [ROPE] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.GetFS[rel, a]];
END;

CreateEntity: PUBLIC ENTRY PROC[d: Domain, name: ROPENIL]
  RETURNS[Entity] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.DeclareEntity[d, name, NewOrOld]];
END;

NameToEntity: PUBLIC ENTRY PROC[d: Domain, name: ROPE, oldOnly: BOOL]
  RETURNS[e: Entity] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBAccess.DoNameToEntity[d, name, oldOnly]];
END;

GetEntitiesInDomain: PUBLIC ENTRY PROC[d: Domain, alphaOrder: BOOL]
  RETURNS[eL: LIST OF Entity] =
-- returns list of entities in given domain
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBAccess.DoGetEntitiesInDomain[d, alphaOrder]];
END;

NumInMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet] RETURNS[num: INT] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBAccess.DoNumInMsgSet[msgSet]];
END;

RelationSubsetList: PUBLIC ENTRY PROC[r: Relation, constraint: AttributeValueList← NIL]
  RETURNS[relList: LIST OF Relship] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBAccess.DoRelationSubsetList[r, constraint]];
END;

-- ********************************************************
-- controlling access to the log file

InitializeLog: PUBLIC ENTRY PROC RETURNS [curLength: INT] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBLog.DoInitializeLog[]];
END;

CloseLogStream: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.DoCloseLogStream[];
END;

OpenWalnutTransaction: PUBLIC ENTRY PROC[trans: DB.Transaction, noLog: BOOL] =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.OpenWTransaction[trans, noLog];
END;

CloseWalnutTransaction: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.CloseWTransaction[];
END;

AbortWalnutTransaction: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.AbortWTransaction[];
END;

MarkWalnutTransaction: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.MarkWTransaction[];
END;

GetLogLength: PUBLIC ENTRY PROC[doFlush: BOOLFALSE] RETURNS[INT] =
{ ENABLE UNWIND => NULL; RETURN[WalnutDBLog.LogLength[doFlush]]};

AddMsgToMsgSet: PUBLIC ENTRY PROC[msg: Msg, msgSet: MsgSet] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutDBLog.DoAddMsgToMsgSet[msg, msgSet]
END;

RemoveMsgFromMsgSet: PUBLIC ENTRY PROC[msg: Msg, msgSet: MsgSet, rel: Relship] =
-- Removes msg from msgSet and makes entry in log for this update.
-- adds msg to Deleted if necessary
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutDBLog.DoRemoveMsgFromMsgSet[msg, msgSet, rel, TRUE]
END;

-- this is entirely inside the monitor so no one can change msgSet while it is being archived
ArchiveMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet, strm: IO.STREAM]
RETURNS[num: INT] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBLog.DoArchiveMsgSet[msgSet, strm]]
END;

DestroyMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet] =
-- Destroys the given msgSet, removing any messages from it first
-- Makes an entry in the log that says this msgSet was destroyed.
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 WalnutDBLog.DoDestroyMsgSet[msgSet];
END;

ReadGVMessageItems: PUBLIC ENTRY PROC
[gvH: GVRetrieve.Handle, timeStamp: GVBasics.Timestamp, gvSender: RName]
RETURNS[BOOL] =
-- reads message items from Grapevine & makes a log entry for this message
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
RETURN[WalnutDBLog.GVMessageToLog[gvH, timeStamp, gvSender]];
END;

AddMessageToLog: PUBLIC ENTRY PROC [entryText, prefix: ROPE] =
-- makes a message LogEntryType on log (used by old mial file reader)
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.DoAddMessageToLog[entryText, prefix];
END;

AddMsgReadEntryToLog: PUBLIC ENTRY PROC[msg: Msg] =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
WalnutDBLog.WriteMsgReadEntryToLog[msg];
END;

DumpMsgs: PUBLIC ENTRY PROC[tempLog: IO.STREAM, doUpdates, tailRewrite: BOOL]
  RETURNS[ok: BOOL] =
BEGIN ENABLE UNWIND => NULL;
CheckForDatabaseBusy[];
RETURN[WalnutDBLog.ExpungeMsgs[tempLog, doUpdates, tailRewrite]];
END;

-- ********************************************************
-- operations that read the log

GetOneMessageFromLog
: PUBLIC ENTRY PROC[startOfNextMessage: INT]
  RETURNS[endPos: INT, anymore: BOOL, msgRec: MsgRec, msgWasNew: BOOL] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 [endPos, anymore, msgRec, msgWasNew]← WalnutDBLog.OneMsgFromLog[startOfNextMessage];
END;

-- ********************************************************
-- EXPORTed to WalnutDBLock (private access)

GetWalnutInfo: PUBLIC ENTRY PROC[attr: Attribute] RETURNS[INT] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.V2I[DB.GetF[walnutInfoRelship, attr]]];
END;

SetWalnutInfo: PUBLIC ENTRY PROC[attr: Attribute, i: INT] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 DB.SetF[walnutInfoRelship, attr, DB.I2V[i]];
 WalnutWindow.SetWalnutUpdatesPending[TRUE];
END;

IsCopyInProgress
: PUBLIC ENTRY PROC RETURNS[BOOL] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[DB.V2B[DB.GetF[walnutInfoRelship, wCopyInProgress]]];
END;

ReadLogFile
: PUBLIC ENTRY PROC[startPos: INT] RETURNS[ok: BOOL] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
RETURN[WalnutDBLog.AddLogEntriesToDB[startPos]];
END;

AcquireDBLock: PUBLIC ENTRY PROC[procToCall: PROC] =
BEGIN ENABLE UNWIND => NULL;
 CheckForDatabaseBusy[];
 procToCall[];
END;

END.