WalnutDB.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Willie-Sue, August 1, 1985 9:56:18 am PDT
Contents: types and procedures dealing with the Walnut message database
Initiated by Donahue, 19 April 198entry in the log
Last Edited by: Willie-Sue, January 4, 1985 10:38:37 am PST
Last edited by Donahue, December 11, 1984 6:23:23 pm PST
(Changed ShiftMsgPosition to SetMsgEntryPosition to reflect change in dealing with absolute log positions)
(Added operations to set and get new mail and read archive log information -- used on restart)
DIRECTORY
BasicTime USING [GMT],
Rope USING [ROPE, Equal],
ViewerTools USING [TiogaContents],
WalnutDefs USING [
 dontCareDomainVersion, dontCareMsgSetVersion, MsgSet, Segment, ServerInfo],
WalnutKernelDefs USING [LogExpungePhase, MsgLogEntry];
WalnutDB: CEDAR DEFINITIONS
IMPORTS Rope =
BEGIN
Types
ROPE: TYPE = Rope.ROPE;
GMT: TYPE = BasicTime.GMT;
TiogaContents: TYPE = ViewerTools.TiogaContents;
MsgSet: TYPE = WalnutDefs.MsgSet;  -- [ROPE, INT]
dontCareDomainVersion: INT = WalnutDefs.dontCareDomainVersion;
dontCareMsgSetVersion: INT = WalnutDefs.dontCareMsgSetVersion;
LogExpungePhase: TYPE = WalnutKernelDefs.LogExpungePhase;
-- {idle, initializingExpungeLog, writingExpungeLog, swappingLogs};
ServerInfo: TYPE = WalnutDefs.ServerInfo;
LazyEnumerator: TYPE = REF LazyEnumeratorRec;
LazyEnumeratorRec: TYPE;
Builtin Message Sets
activeMsgSet: MsgSet;
deletedMsgSet: MsgSet;
walnutSegment: ATOM;
Operations on Messages
MsgExists: PROC[msg: ROPE] RETURNS [existed: BOOL];
Does a message with this name exist in the database.
DestroyMsg is not allowed; this is ONLY done by the Expunge operation
GetHasBeenRead: PROC[msg: ROPE] RETURNS[BOOL];
returns TRUE if the mHasBeenReadIs attribute for msg is TRUE
SetHasBeenRead: PROC[msg: ROPE];
sets the mHasBeenReadIs attribute for msg to TRUE (no check on old value)
AddNewMsg: PROC[msg: WalnutKernelDefs.MsgLogEntry] RETURNS[mExisted: BOOL];
takes a parsed message from the log & puts it in the database -- if the message already existed in the database, then return TRUE. Note: this guy takes the LogEntry given and has the responsibility for constructing the TOCEntry and herald for the message
GetMsgEntryPosition: PROC[msg: ROPE] RETURNS[pos: INT];
returns the log position for the entry for this message (-1 if the message doesn't exist); used by the lazy evaluator
SetMsgEntryPosition: PROC[to: INT];
Change the message position from what it previously was to the new position; uses a one-entry cache, set by MsgExists, which MUST be called just before SetMsgEntryPosition - this is used by the Expunge code
GetMsgDate: PROC[msg: ROPE] RETURNS[date: GMT];
returns the date by which the message is indexed in the database
GetMsgTextInfo: PROC[msg: ROPE] RETURNS[textStart, textLen, formatLen: INT];
returns information needed to get the tioga text for msg from log
GetMsgText: PROC[msg: ROPE] RETURNS[textStart, textLen, formatLen: INT, herald: ROPE, shortNameLen: INT];
returns information needed to get the tioga text for msg from log (also produces the herald to be used if displaying it in a viewer
GetDisplayProps: PROC[msg: ROPE] RETURNS [hasBeenRead: BOOL, TOCentry: ROPE, startOfSubject: INT];
Return the display properties of a message (the hasbeenread flag and the table of contents entry, and where in TOCentry the subject field begins.
GetCategories: PROC[msg: ROPE] RETURNS [ms: LIST OF ROPE];
Return the display properties of a message (the hasbeenread flag and the table of contents entry.
EqMsg: PROC[msg1, msg2: ROPE] RETURNS [BOOL] =
INLINE{RETURN[Rope.Equal[msg1, msg2, FALSE]] };
SizeOfDatabase: PROC RETURNS[messages, msgSets: INT];
returns the number of messages in the database
Operations on Message Sets
MsgSetExists: PROC[name: ROPE, msDomainVersion: INT]
RETURNS [existed: BOOL, msVersion: INT];
Does this message set already exist in the database.
CreateMsgSet: PROC[name: ROPE, msDomainVersion: INT]
RETURNS [existed: BOOL, msVersion: INT];
NumInMsgSet: PROC[name: ROPE] RETURNS[num: INT, msVersion: INT];
EmptyMsgSet: PROC[msgSet: MsgSet] RETURNS[someInDeleted: BOOL];
Removes any messages from msgSet. Commits periodically.
DestroyMsgSet: PROC[msgSet: MsgSet, msDomainVersion: INT] RETURNS[someInDeleted: BOOL];
Destroys the given msgSet, removing any messages from it first. If the message set is "Deleted" then does nothing. Commits periodically.
VerifyMsgSet: PROC[msgSet: MsgSet] RETURNS[exists: BOOL];
Raises VersionMismatch if the version number is wrong.
VerifyDomainVersion: PROC[msDomainVersion: INT];
Raises VersionMismatch if the msgSetDomain version number is wrong.
ExpungeMsgs: PROC[deletedVersion: INT];
Destroys messages in the Deleted message set. Commits periodically.
MsgsEnumeration: PROC[alphaOrder: BOOLTRUE] RETURNS[mL: LIST OF ROPE];
MsgSetsNames: PROC[alphaOrder: BOOLTRUE]
RETURNS[msL: LIST OF ROPE, msDomainVersion: INT];
MsgsInSetEnumeration: PROC[name: ROPE, fromStart: BOOLTRUE]
RETURNS [mL: LIST OF ROPE, msVersion: INT];
If msgSet is "Active", only the "accepted" messages are returned
EnumerateMsgSets: PROC [alphaOrder: BOOLTRUE, proc: PROC[msgSet: MsgSet]]
RETURNS [msDomainVersion: INT];
EnumerateMsgsInSet: PROC [
name: ROPE,
fromStart: BOOLTRUE,
proc: PROC[msg, TOCentry: ROPE, hasBeenRead: BOOL, startOfSubject: INT] ]
RETURNS [msVersion: INT];
for each msg in msgSet, will call proc with the indicated information about the msg;
raises WalnutDefs.Error if the enumeration fails
If msgSet is "Active", then only the "accepted" messages are enumerated
EnumerateMsgsInMsgSet: PROC[msgSet: MsgSet]
RETURNS[lazyEnum: LazyEnumerator, valid: BOOL];
a lazy enumerator for the messages in the msgSet name, at the time of the call. The enumerator is valid until the next time the msgSet's version changes (by adding or deleting msgs); its use after that will cause a WalnutDefs.Error with code $InvalidEnumerator. See NextMsgInMsgSet for details. valid will be false if the msgSet versions don't match
NextMsgInMsgSet: PROC[lazyEnum: LazyEnumerator, retry: BOOL]
RETURNS[msgID: ROPE, valid: BOOL];
if msgID is NIL and valid is true, then the enumeration is finished; if valid is false, the msgSet version numbers don't match; retry will throw away the current DB enumerator and get a new one and "scan" to the appropriate place
EnumerateUnacceptedMsgs: PROC[
activeVersion: INT,
proc: PROC[msg, TOCentry: ROPE, startOfSubject: INT] ];
for each unaccepted msg, will call proc with the indicated information about the msg;
raises WalnutDefs.Error if the enumeration fails
EqMsgSets: PROC[msgSet1, msgSet2: ROPE] RETURNS [BOOL] =
INLINE{ RETURN[Rope.Equal[msgSet1, msgSet2, FALSE]] };
MsgSetsInfo: PROC RETURNS[version, num: INT];
changes when msgSets are created or destroyed
Operations to Move Messages Among Message Sets
AddMsg: PROC[msg: ROPE, from, to: MsgSet] RETURNS[exists: BOOL];
Adds Msg to MsgSet, if it's not already in it. IF msgSet=deletedMsgSet, does nothing and returns existed=FALSE
RemoveMsg: PROC[msg: ROPE, from: MsgSet, deletedVersion: INT]
RETURNS[deleted: BOOL];
IF removing msg from msgSet would leave it in no MsgSet, then msg gets added to the distinguished MsgSet Deleted, and returns deleted = TRUE
MoveMsg: PROC[msg: ROPE, from, to: MsgSet] RETURNS [exists: BOOL];
Move the message. Note that the result of a move may be that a message becomes deleted (if to was the Deleted message set) or undeleted (if from is the Deleted message set)
AcceptNewMail: PROC[pos: INT, activeVersion: INT];
makes new messages visible to the outside world. Commits periodically.
Other operations
DeclareDB: PROC[segment: WalnutDefs.Segment, readOnly: BOOL];
This procedure need only be called once. Of course, if the readOnly status changes DeclareDB[] will have to be called again to establish the new values.
CheckSchema: PROC[segment: WalnutDefs.Segment, readOnly: BOOL];
To be called after errors, to check if the schema is valid
InitSchema: PROC[segment: WalnutDefs.Segment];
must be called after doing an erase
IsReadOnly: PROC RETURNS[readonly: BOOL];
is the database readOnly
GetDBName: PROC RETURNS[fileName: ROPE];
file storing the database
GetRootInfo: PROC RETURNS[rootFileStamp: GMT, rootFileKey, mailFor: ROPE];
information from the root file that goes with this database
SetRootInfo: PROC[rootFileStamp: GMT, rootFileKey, mailFor: ROPE];
root file that goes with this database
GetRootFileVersion: PROC RETURNS[rootFileStamp: GMT];
rootFileVersion is needed more often
SetRootFileVersion: PROC[rootFileStamp: GMT];
GetCurrentLogFileID: PROC RETURNS[currentLogID: INT];
fileID of currentLog
SetCurrentLogFileID: PROC[currentLogID: INT];
GetOpInProgressPos: PROC RETURNS[inProgressPos: INT];
SetOpInProgressPos: PROC[inProgressPos: INT];
GetParseLogInProgress: PROC RETURNS[inProgress: BOOL];
SetParseLogInProgress: PROC[inProgress: BOOL];
GetParseLogPos: PROC RETURNS[pos: INT];
SetParseLogPos: PROC[pos: INT];  -- commits
Operations used during Expunge, NewMail and reading Archive files
GetExpungeInfo: PROC RETURNS[firstDestroyedMsgPos, bytesInDestroyedMsgs: INT];
SetExpungeInfo: PROC[firstDestroyedMsgPos, bytesInDestroyedMsgs: INT];
GetLogExpungePhase: PROC RETURNS[expungePhase: LogExpungePhase];
SetLogExpungePhase: PROC[expungePhase: LogExpungePhase];  -- commits
GetExpungeProgressInfo: PROC RETURNS[currentLogPos, expungeLogPos: INT];
SetExpungeProgressInfo: PROC[currentLogPos, expungeLogPos: INT];  -- commits
SetExpungeFileID: PROC[expungeFileID: INT];
GetExpungeFileID: PROC RETURNS[expungeFileID: INT];
SetAcceptNewMailPos: PROC[pos: INT];
GetAcceptNewMailPos: PROC RETURNS[pos: INT];
SetAddingServerMsgs: PROC[addingServerMsgs: BOOL];
GetAddingServerMsgs: PROC RETURNS[addingServerMsgs: BOOL];
GetServerInfo: PROC[server: ROPE] RETURNS[num: INT];
returns 0 if server doesn't exist
EnumerateServers: PROC[] RETURNS[serverList: LIST OF ServerInfo];
SetNewMailInfo: PROC[logLen: INT, when: GMT, server: ROPE, num: INT];
sets newMailLog length to logLen; if server doesn't exist, it will be created
SetNewMailLogLength: PROC[logLen: INT];
GetNewMailLogLength: PROC[] RETURNS[logLen: INT];
GetLastNewMailTimeStamp: PROC[] RETURNS[when: GMT];
SetCopyMailLogPos: PROC[pos: INT];
GetCopyMailLogPos: PROC[] RETURNS[pos: INT];
SetReadArchivePos: PROC[pos: INT];
GetReadArchivePos: PROC[] RETURNS[pos: INT];
SetCopyReadArchivePos: PROC[pos: INT];
GetCopyReadArchivePos: PROC[] RETURNS[pos: INT];
END.