WalnutRoot.Mesa
Copyright Ó 1985, 1987, 1988, 1992 by Xerox Corporation. All rights reserved.
Willie-Sue, August 9, 1988 12:55:44 pm PDT
Doug Terry, August 28, 1990 4:15:33 pm PDT
Contents: types and procedures, take the root file as en explicit parameter
Parses the root file and sets up the Log objects; dispenses the various streams and values parsed from the rootFile
DIRECTORY
BasicTime USING [GMT, nullGMT],
FS USING [nullOpenFile, OpenFile],
IO USING [STREAM],
Rope USING [ROPE],
WalnutDefs USING [CheckReportProc, WalnutOpsHandle],
WalnutKernelDefs USING [WhichTempLog];
WalnutRoot: CEDAR DEFINITIONS = BEGIN
Types
GMT: TYPE = BasicTime.GMT;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
TransactionHandle: TYPE = REF;
AlpTHandle: TYPE = TransactionHandle;
WhichTempLog: TYPE = WalnutKernelDefs.WhichTempLog;
WalnutOpsHandle: TYPE = WalnutDefs.WalnutOpsHandle;
CheckReportProc: TYPE = WalnutDefs.CheckReportProc;
TransInfo: TYPE = REF;
nullTransInfo: TransInfo = NIL;
RootHandle: TYPE = REF RootHandleRec;
RootHandleRec: PUBLIC TYPE = RECORD [ -- clients are to consider this readOnly
baseName: ROPE ¬ NIL, -- full name through directories
createDate: GMT ¬ BasicTime.nullGMT,
expungeInProgress: BOOL ¬ FALSE,
transInfo: TransInfo ¬ nullTransInfo,
alpTH: AlpTHandle ¬ NIL,   -- current transaction
dbTransH: TransactionHandle ¬ NIL,  -- form needed by cypress
rootOpenFileForLogs: FS.OpenFile ¬ FS.nullOpenFile,
currentLog: InternalLogInfo ¬ NIL,   -- only one log for now
expungeLog: InternalLogInfo ¬ NIL,
newMailLog: MiscLogInfo ¬ NIL,
readArchiveLog: MiscLogInfo ¬ NIL,
statsProc: CheckReportProc
];
TransID: TYPE = REF;
InternalLogInfo: TYPE = REF InternalLogInfoObject;
InternalLogInfoObject: TYPE = RECORD [
readStream: STREAM,     -- not used for expungeLog
writeStream: STREAM,
name: ROPE ¬ NIL,      -- full path name of this log (minus version)
shortName: ROPE ¬ NIL,  -- short name without server, etc
internalFileID: INT ¬ -1,
logSeqNo: INT ¬ -1,
logSeqNoPos: INT ¬ -1     -- position in rootLog of logSeqNo
];
MiscLogInfo: TYPE = REF MiscLogInfoRec;
MiscLogInfoRec: TYPE = RECORD [
stream: STREAM,
name: ROPE ¬ NIL,
trans: AlpTHandle ¬ NIL,
rootOpenFile: FS.OpenFile ¬ FS.nullOpenFile -- may have its own transaction
];
Root file Information
Open: PROC[opsH: WalnutOpsHandle, newSegmentOk: BOOL ¬ FALSE, masquerade: BOOL ¬ FALSE, newHandle: BOOL ¬ FALSE] RETURNS[ok: BOOL];
opens wH.rootName as the current root file; finds out the name of the various logs, and who may retrieve mail into this database (one user only).
if newHandle then opsH will be added to the list of handles, assuming no duplicate names or segment names or segment ids.
Shutdown: PROC[opsH: WalnutOpsHandle];
Shutdown the connection to the root. Must do an Open after this.
GetOpsHandleList: PROC RETURNS[LIST OF WalnutOpsHandle];
WalnutRoot is the keeper of the list of WalnutOpsHandles, but the higher level decides what goes on the list - WalnutRoot needs to be able to look at the list
ExamineHandleList: PROC[proc: PROC[ohL: LIST OF WalnutOpsHandle] RETURNS[LIST OF WalnutOpsHandle] ];
used if the caller may want to change the list
Transaction Management
WalnutRoot does all of the transaction management in Walnut. It will set up the necessary coordinator and worker transactions to handle logs and databases stored on different machines (although currently this is not the generally accepted method of usage!).
StartTransaction: PROC[opsH: WalnutOpsHandle, openDB: BOOL ¬ TRUE]
RETURNS[schemaInvalid: BOOL];
Start a transaction to handle the logs and the database -- this may be either the coordinator transaction, if everything is on the same machine, or a new worker transaction if not. In the case of doing an EraseDB, we must not start a transaction on the database at this time
CloseTransaction: PROC[opsH: WalnutOpsHandle];
To allow closing of the currentLog streams and database file when there is no activity
CommitAndContinue: PROC[opsH: WalnutOpsHandle];
Commits and continues the current transaction
AbortTransaction: PROC[opsH: WalnutOpsHandle];
Aborts the DBCache and aborts the transaction
FlushMailStream: PROC[opsH: WalnutOpsHandle];
WalnutRoot handles all the transactions for the streams it gives out
EraseDB: PROC[opsH: WalnutOpsHandle];
Erases the database segment
Managing the CurrentLog
AcquireWriteLock: PROC[opsH: WalnutOpsHandle];
upgrades the lock on the lastLog to write
OpenLogStreams: PROC[opsH: WalnutOpsHandle];
ReleaseWriteLock: PROC[opsH: WalnutOpsHandle];
Closes the log streams and re-opens, to release the write lock; is careful to use the same transaction as before, so the database is not affected
CloseLogStreams: PROC[opsH: WalnutOpsHandle];
closes any open streams; does a commitAndContinue of the transaction; may raise WalnutDefs.Error
Managing the ExpungeLog
GetQuota: PROC[opsH: WalnutOpsHandle] RETURNS[spaceInUse, quota: INT];
to decide if there is enough space to write the expunge log, before really starting
GetStreamsForExpunge: PROC[opsH: WalnutOpsHandle, starting: BOOL, pagesWanted: INT];
all the necessary information is returned within RootHandle
SwapLogs: PROC[opsH: WalnutOpsHandle, expungeFileID: INT, newRootStamp: GMT]
RETURNS[newLogLen: INT];
Swaps the current log and expunge log so that they are interchanged and rewrites the time stamps in the root file for the logs
StopExpunge: PROC[opsH: WalnutOpsHandle];
Used if there was an error during GetExpungeLog; closes the log being expunged
Managing the TempLogs
PrepareToCopyTempLog: PROC[opsH: WalnutOpsHandle, which: WhichTempLog, pagesAlreadyCopied: INT, reportProc: WalnutDefs.CheckReportProc]
RETURNS[ok: BOOL];
makes sure there is enough space to copy the WhichTempLog onto lastLog; returns FALSE if there is not enough space
GetStreamsForCopy: PROC[opsH: WalnutOpsHandle, which: WhichTempLog]
RETURNS[tempStream: STREAM];
used during restart, when a copy was in progress; the same trans is used for both the currentStream and the tempStream
FinishCopy: PROC[opsH: WalnutOpsHandle, which: WhichTempLog];
sets the pagecount of the tempLog to something reasonable and closes the tempStream
AbortTempCopy: PROC[opsH: WalnutOpsHandle, which: WhichTempLog];
returns tempLog if the copy of a temp log was not successful
Access to streams for the various logs
GetNewMailStream: PROC[opsH: WalnutOpsHandle, lengthRequired: INT, pagesWanted: INT ¬ 200]
RETURNS[ok: BOOL, actualLen: INT];
the newMailStream must be at least lenExpected bytes long (it is truncated to that length if longer); if the number of pages in the file not equal to sizeWanted, then page count is changed; is sizeWanted = -1, the pageCount is not changed
ReturnNewMailStream: PROC[opsH: WalnutOpsHandle];
called when finished getting newMail from grapevine
GetReadArchiveStream: PROC[opsH: WalnutOpsHandle, pagesWanted: INT ¬ -1] RETURNS[STREAM];
If pagesWanted is -1 then don't change the length
ReturnReadArchiveStream: PROC[opsH: WalnutOpsHandle];
Utilities
RegisterStatsProc: PROC[opsH: WalnutOpsHandle, proc: CheckReportProc];
UnregisterStatsProc: PROC[opsH: WalnutOpsHandle, proc: CheckReportProc];
StatsReport: CheckReportProc;
END.