<> <> <> <> <<>> <> <> DIRECTORY Atom USING [GetPName], BasicTime USING [GMT], DB USING [Aborted, CopyEntity, Error, ErrorCode, Failure, CreateRelship, DeclareEntity, DomainSubset, EntityInfo, FirstRelship, GetF, GetSegmentInfo, LookupEntity, LookupProperty, NextEntity, NullDomain, ReleaseEntitySet, SetF, B2V, E2V, I2V, L2VS, S2V, T2V, V2B, V2I, V2S, V2T, Entity, EntitySet, Relship, ValueSequence], IO, RefTab USING [Ref], Rope, WalnutDB, WalnutDefs USING [Error, MsgSet, Segment, ServerInfo], WalnutKernelDefs USING [LogExpungePhase], WalnutRoot USING [CommitAndContinue, StatsReport], WalnutSchema; WalnutDBOpsImpl: CEDAR PROGRAM IMPORTS Atom, DB, IO, WalnutDB, WalnutDefs, WalnutRoot, WalnutSchema EXPORTS WalnutDB = BEGIN OPEN WalnutSchema; <> GMT: TYPE = BasicTime.GMT; ROPE: TYPE = Rope.ROPE; MsgSet: TYPE = WalnutDefs.MsgSet; Entity: TYPE = DB.Entity; EntitySet: TYPE = DB.EntitySet; Relship: TYPE = DB.Relship; ServerInfo: TYPE = WalnutDefs.ServerInfo; <> walnutSegment: PUBLIC ATOM _ $Walnut; activeMsgSet: PUBLIC MsgSet _ ["Active", -1]; deletedMsgSet: PUBLIC MsgSet _ ["Deleted", -1]; activeMessageSet: PUBLIC Entity; deletedMessageSet: PUBLIC Entity; unacceptedEntity: PUBLIC Entity; msgSetsTable: PUBLIC RefTab.Ref _ NIL; debugging: BOOL _ FALSE; DBErrorSeen: SIGNAL = CODE; <> DeclareDB: PUBLIC PROC[segment: WalnutDefs.Segment, schemaInvalid: BOOL] = { IF schemaInvalid OR DB.NullDomain[MsgSetDomain] THEN InitSchema[segment, schemaInvalid] ELSE { walnutSegment _ segment; msgSetsTable _ NIL; }; }; InitSchema: PUBLIC PROC[segment: WalnutDefs.Segment, schemaInvalid: BOOL _ TRUE] = { init: DB.ValueSequence; fullNeeded: BOOL; aaName: ATOM = WalnutDB.CanonicalName[activeMsgSet.name]; caName: ROPE = Atom.GetPName[aaName]; walnutSegment _ segment; msgSetsTable _ NIL; IF schemaInvalid THEN { WalnutSchema.SetSchemaVersion[walnutSegment]; WalnutRoot.CommitAndContinue[]; }; WalnutSchema.Initialize[segment]; fullNeeded _ (DB.LookupEntity[MsgSetDomain, caName] = NIL); BEGIN adName: ATOM = WalnutDB.CanonicalName[deletedMsgSet.name]; e: Entity _ DB.DeclareEntity[MsgSetDomain, caName]; activeMessageSet _ DB.CopyEntity[e]; e _ DB.DeclareEntity[MsgSetDomain, Atom.GetPName[adName]]; deletedMessageSet _ DB.CopyEntity[e]; END; unacceptedEntity _ DB.CopyEntity[DB.DeclareEntity[UnacceptedDomain, "TRUE"]]; IF fullNeeded THEN { init _ DB.L2VS[LIST [ DB.E2V[activeMessageSet], [integer[0]], [integer[1]], [rope[activeMsgSet.name]] ] ]; [] _ DB.CreateRelship[msBasicInfo, init]; init _ DB.L2VS[LIST [ DB.E2V[deletedMessageSet], [integer[0]], [integer[1]], [rope[deletedMsgSet.name]] ] ]; [] _ DB.CreateRelship[msBasicInfo, init]; }; }; <> IsReadOnly: PUBLIC PROC RETURNS[readonly: BOOL] = { readonly_ DB.GetSegmentInfo[walnutSegment].readOnly }; GetDBName: PUBLIC PROC RETURNS[fileName: ROPE] = { fileName_ DB.GetSegmentInfo[walnutSegment].filePath }; GetRootInfo: PUBLIC PROC RETURNS[rootFileStamp: GMT, rootFileKey, mailFor: ROPE] = { Gri: PROC = { rRootInfo: Relship = DB.FirstRelship[gRootInfo]; rootFileStamp _ DB.V2T[DB.GetF[rRootInfo, gRootFileStamp]]; rootFileKey _ DB.V2S[DB.GetF[rRootInfo, gRootFileKey]]; mailFor _ DB.V2S[DB.GetF[rRootInfo, gMailFor]]; }; CarefullyApply[Gri]; }; SetRootInfo: PUBLIC PROC[rootFileStamp: GMT, rootFileKey, mailFor: ROPE] = { Sri: PROC = { rRootInfo: Relship = DB.FirstRelship[gRootInfo]; DB.SetF[rRootInfo, gRootFileStamp, DB.T2V[rootFileStamp]]; DB.SetF[rRootInfo, gRootFileKey, DB.S2V[rootFileKey]]; DB.SetF[rRootInfo, gMailFor, DB.S2V[mailFor]]; }; CarefullyApply[Sri]; }; GetRootFileVersion: PUBLIC PROC RETURNS[rootFileStamp: GMT] = { Gri: PROC = { rRootInfo: Relship = DB.FirstRelship[gRootInfo]; rootFileStamp _ DB.V2T[DB.GetF[rRootInfo, gRootFileStamp]]; }; CarefullyApply[Gri]; }; SetRootFileVersion: PUBLIC PROC[rootFileStamp: GMT] = { Sri: PROC = { rRootInfo: Relship = DB.FirstRelship[gRootInfo]; DB.SetF[rRootInfo, gRootFileStamp, DB.T2V[rootFileStamp]]; }; CarefullyApply[Sri]; }; GetOpInProgressPos: PUBLIC PROC RETURNS[inProgressPos: INT] = { Goip: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; inProgressPos_ DB.V2I[DB.GetF[rLogInfo, gOpInProgressPos]] }; CarefullyApply[Goip]; }; SetOpInProgressPos: PUBLIC PROC[inProgressPos: INT] = { Siop: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; DB.SetF[rLogInfo, gOpInProgressPos, DB.I2V[inProgressPos]]; }; CarefullyApply[Siop]; }; GetParseLogInProgress: PUBLIC PROC RETURNS[inProgress: BOOL] = { Gplp: PROC = { rParseLogInfo: Relship = DB.FirstRelship[gParseLogInfo]; inProgress_ DB.V2B[DB.GetF[rParseLogInfo, gParseLogInProgress]] }; CarefullyApply[Gplp]; }; SetParseLogInProgress: PUBLIC PROC[inProgress: BOOL] = { Splp: PROC = { rParseLogInfo: Relship = DB.FirstRelship[gParseLogInfo]; DB.SetF[rParseLogInfo, gParseLogInProgress, DB.B2V[inProgress]]; }; CarefullyApply[Splp]; }; GetParseLogPos: PUBLIC PROC RETURNS[pos: INT] = { Gplp: PROC = { rParseLogInfo: Relship = DB.FirstRelship[gParseLogInfo]; pos _ DB.V2I[DB.GetF[rParseLogInfo, gParseLogPos]] }; CarefullyApply[Gplp]; }; SetParseLogPos: PUBLIC PROC[pos: INT] = { Splp: PROC = { rParseLogInfo: Relship = DB.FirstRelship[gParseLogInfo]; DB.SetF[rParseLogInfo, gParseLogPos, DB.I2V[pos]]; }; CarefullyApply[Splp]; }; CarefullyApply: PUBLIC PROC [proc: PROC[]] = { exp: ROPE; eCode: ATOM; BEGIN ENABLE BEGIN DB.Error => { IF debugging THEN SIGNAL DBErrorSeen; eCode _ $DBError; exp _ RopeForDBError[code]; GOTO Quit }; DB.Failure => { eCode _ $DBFailure; exp _ info; GOTO Quit}; DB.Aborted => { eCode _ $TransactionAbort; GOTO Quit }; END; proc[]; EXITS Quit => { WalnutRoot.StatsReport[IO.PutFR["\n ***DB error - code: %g, exp: %g ", IO.atom[eCode], IO.rope[exp]]]; ERROR WalnutDefs.Error[$db, eCode, exp]; }; END; }; GetMsgDisplayInfo: PUBLIC PROC[m: Entity] RETURNS[hasBeenRead: BOOL, tocEntry: ROPE, startOfSubject: INT] = { rel: Relship = DB.LookupProperty[mDisplayInfo, m]; hasBeenRead_ DB.V2B[DB.GetF[rel, mDIHasBeenRead]]; tocEntry_ DB.V2S[DB.GetF[rel, mDITOCEntry]]; startOfSubject_ DB.V2I[DB.GetF[rel, mDIStartOfSubject]]; }; ChangeCountInMsgSet: PUBLIC PROC[ms: Entity, inc: INT] = { rel: Relship = DB.LookupProperty[msBasicInfo, ms]; new: INT _ DB.V2I[DB.GetF[rel, msBICount]] + inc; IF new < 0 THEN new _ 0; -- empty didn't used to change the count! DB.SetF[rel, msBICount, DB.I2V[new]]; new _ DB.V2I[DB.GetF[rel, msBIVersion]] + 1; DB.SetF[rel, msBIVersion, DB.I2V[new]]; }; ChangeCountOfMsgs: PUBLIC PROC[delta: INT] = { rVersionInfo: Relship = DB.FirstRelship[gVersionInfo]; numNow: INT = DB.V2I[DB.GetF[rVersionInfo, gMsgCount]]; DB.SetF[rVersionInfo, gMsgCount, DB.I2V[numNow + delta]]; }; <> RopeForDBError: PROC[code: DB.ErrorCode] RETURNS[ROPE] = { SELECT code FROM AlreadyExists => RETURN["AlreadyExists"]; IllegalAttribute => RETURN["IllegalAttribute"]; IllegalDomain => RETURN["IllegalDomain"]; IllegalEntity => RETURN["IllegalEntity"]; IllegalProperty => RETURN["IllegalRelship"]; IllegalRelation => RETURN["IllegalRelation"]; IllegalString => RETURN["IllegalString"]; MismatchedExistingRelation => RETURN["MismatchedExistingRelation"]; MismatchedExistingSegment => RETURN["MismatchedExistingSegment"]; MultipleMatch => RETURN["MultipleMatch"]; NILArgument => RETURN["NILArgument"]; NullifiedArgument => RETURN["NullifiedArgument"]; NotFound => RETURN["NotFound"]; TransactionNotOpen => RETURN["TransactionNotOpen"]; TransactionAlreadyOpen => RETURN["TransactionAlreadyOpen"]; QuotaExceeded => RETURN["QuotaExceeded"]; Unknown => RETURN["Unknown"]; ENDCASE => RETURN["Other Error"]; }; <> GetExpungeInfo: PUBLIC PROC RETURNS[ firstDestroyedMsgPos, bytesInDestroyedMsgs: INT] = { Gei: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; firstDestroyedMsgPos _ DB.V2I[DB.GetF[rLogInfo, gFirstDestroyedMsgPos]]; bytesInDestroyedMsgs _ DB.V2I[DB.GetF[rLogInfo, gBytesInDestroyedMsgs]] }; WalnutDB.CarefullyApply[Gei]; }; SetExpungeInfo: PUBLIC PROC[firstDestroyedMsgPos, bytesInDestroyedMsgs: INT] = { Sei: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; DB.SetF[rLogInfo, gFirstDestroyedMsgPos, DB.I2V[firstDestroyedMsgPos]]; DB.SetF[rLogInfo, gBytesInDestroyedMsgs, DB.I2V[bytesInDestroyedMsgs]]; }; WalnutDB.CarefullyApply[Sei]; }; GetLogExpungePhase: PUBLIC PROC RETURNS[exp: WalnutKernelDefs.LogExpungePhase] = { Gep: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; ph: INT _ DB.V2I[DB.GetF[rExpungeInfo, gLogExpungePhase]]; SELECT ph FROM 0 => exp_ idle; 1 => exp_ initializingExpungeLog; 2 => exp_ writingExpungeLog; 3 => exp_ swappingLogs; ENDCASE => { SIGNAL WalnutDefs.Error[$db, $Bug, IO.PutFR[badExpVal, IO.int[ph]] ]; exp_ idle }; }; WalnutDB.CarefullyApply[Gep]; }; badExpVal: ROPE = "Bad expungePhase value (%g)"; SetLogExpungePhase: PUBLIC PROC[exp: WalnutKernelDefs.LogExpungePhase] = { Sep: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; val: INT; SELECT exp FROM idle => val _ 0; initializingExpungeLog => val _ 1; writingExpungeLog => val _ 2; swappingLogs => val _ 3; ENDCASE => { ph: INTEGER _ LOOPHOLE[exp]; SIGNAL WalnutDefs.Error[$db, $Bug,IO.PutFR[badExpVal, IO.int[val]] ]; val _ 0; }; DB.SetF[rExpungeInfo, gLogExpungePhase, DB.I2V[val]]; }; WalnutDB.CarefullyApply[Sep]; }; GetExpungeProgressInfo: PUBLIC PROC RETURNS[currentLogPos, expungeLogPos: INT] = { Gepi: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; currentLogPos _ DB.V2I[DB.GetF[rExpungeInfo, gCurrentLogPos]]; expungeLogPos _ DB.V2I[DB.GetF[rExpungeInfo, gExpungeLogPos]]; }; WalnutDB.CarefullyApply[Gepi]; }; SetExpungeProgressInfo: PUBLIC PROC[currentLogPos, expungeLogPos: INT] = { Sepi: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; DB.SetF[rExpungeInfo, gCurrentLogPos, DB.I2V[currentLogPos]]; DB.SetF[rExpungeInfo, gExpungeLogPos, DB.I2V[expungeLogPos]]; }; WalnutDB.CarefullyApply[Sepi]; }; GetExpungeFileID: PUBLIC PROC RETURNS[expungeFileID: INT] = { Gefi: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; expungeFileID _ DB.V2I[DB.GetF[rExpungeInfo, gExpungeFileID]] }; WalnutDB.CarefullyApply[Gefi]; }; SetExpungeFileID: PUBLIC PROC[expungeFileID: INT] = { Sefi: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; DB.SetF[rExpungeInfo, gExpungeFileID, DB.I2V[expungeFileID]] }; WalnutDB.CarefullyApply[Sefi]; }; GetTimeOfLastExpunge: PUBLIC PROC RETURNS[when: GMT] = { Gtle: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; when _ DB.V2T[DB.GetF[rExpungeInfo, gTimeOfLastExpunge]] }; WalnutDB.CarefullyApply[Gtle]; }; SetTimeOfLastExpunge: PUBLIC PROC[when: GMT] = { Stle: PROC = { rExpungeInfo: Relship = DB.FirstRelship[gExpungeInfo]; DB.SetF[rExpungeInfo, gTimeOfLastExpunge, DB.T2V[when]] }; WalnutDB.CarefullyApply[Stle]; }; GetTimeOfLastScavenge: PUBLIC PROC RETURNS[when: GMT] = { Gtls: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; when _ DB.V2T[DB.GetF[rLogInfo, gTimeOfLastScavenge]] }; WalnutDB.CarefullyApply[Gtls]; }; SetTimeOfLastScavenge: PUBLIC PROC[when: GMT] = { Stls: PROC = { rLogInfo: Relship = DB.FirstRelship[gLogInfo]; DB.SetF[rLogInfo, gTimeOfLastScavenge, DB.T2V[when]] }; WalnutDB.CarefullyApply[Stls]; }; SetAcceptNewMailPos: PUBLIC PROC[pos: INT] = { Sanmp: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; DB.SetF[rNewMailInfo, gAcceptNewMailLogPos, DB.I2V[pos]] }; WalnutDB.CarefullyApply[Sanmp]; }; GetAcceptNewMailPos: PUBLIC PROC RETURNS[pos: INT] = { Ganmp: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; pos _ DB.V2I[DB.GetF[rNewMailInfo, gAcceptNewMailLogPos]] }; WalnutDB.CarefullyApply[Ganmp]; }; SetAddingServerMsgs: PUBLIC PROC[addingServerMsgs: BOOL] = { Sasm: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; DB.SetF[rNewMailInfo, gAddingServerMsgs, DB.B2V[addingServerMsgs]] }; WalnutDB.CarefullyApply[Sasm]; }; GetAddingServerMsgs: PUBLIC PROC RETURNS[addingServerMsgs: BOOL] = { Sasm: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; addingServerMsgs_ DB.V2B[DB.GetF[rNewMailInfo, gAddingServerMsgs]] }; WalnutDB.CarefullyApply[Sasm]; }; EnumerateServers: PUBLIC PROC RETURNS[serverList: LIST OF ServerInfo] = { Gsi: PROC = { enum: EntitySet _ DB.DomainSubset[ServerDomain, NIL, NIL, First]; se: Entity; FOR se _ DB.NextEntity[enum], DB.NextEntity[enum] UNTIL se = NIL DO rel: Relship = DB.LookupProperty[sBasicInfo, se]; si: ServerInfo; si.server _ DB.EntityInfo[se].name; si.num _ DB.V2I[DB.GetF[rel, sBINum]]; serverList _ CONS[si, serverList]; ENDLOOP; DB.ReleaseEntitySet[enum]; }; WalnutDB.CarefullyApply[Gsi]; }; GetServerInfo: PUBLIC PROC[server: ROPE] RETURNS[num: INT] = { Gsr: PROC = { se: Entity = DB.LookupEntity[ServerDomain, server]; IF se # NIL THEN { rel: Relship = DB.LookupProperty[sBasicInfo, se]; num _ DB.V2I[DB.GetF[rel, sBINum]] } ELSE num _ 0; }; WalnutDB.CarefullyApply[Gsr]; }; SetNewMailInfo: PUBLIC PROC[logLen: INT, when: GMT, server: ROPE, num: INT] = { Snmi: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; IF server # NIL THEN { se: Entity _ DB.LookupEntity[ServerDomain, server]; IF se = NIL THEN { -- create this entity init: DB.ValueSequence = DB.L2VS[LIST[ DB.E2V[DB.DeclareEntity[ServerDomain, server]], DB.I2V[num] ] ]; [] _ DB.CreateRelship[sBasicInfo, init]; } ELSE { rel: Relship = DB.LookupProperty[sBasicInfo, se]; DB.SetF[rel, sBINum, DB.I2V[num]]; }; }; DB.SetF[rNewMailInfo, gNewMailLogLength, DB.I2V[logLen]]; DB.SetF[rNewMailInfo, gLastNewMailTimeStamp, DB.T2V[when]] }; WalnutDB.CarefullyApply[Snmi]; }; SetNewMailLogLength: PUBLIC PROC[logLen: INT] = { Gnml: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; DB.SetF[rNewMailInfo, gNewMailLogLength, DB.I2V[logLen]]; }; WalnutDB.CarefullyApply[Gnml]; }; GetNewMailLogLength: PUBLIC PROC RETURNS[logLen: INT] = { Gnml: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; logLen _ DB.V2I[DB.GetF[rNewMailInfo, gNewMailLogLength]] }; WalnutDB.CarefullyApply[Gnml]; }; GetLastNewMailTimeStamp: PUBLIC PROC RETURNS[when: GMT] = { Glnmts: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; when _ DB.V2T[DB.GetF[rNewMailInfo, gLastNewMailTimeStamp]] }; WalnutDB.CarefullyApply[Glnmts]; }; SetCopyMailLogPos: PUBLIC PROC[pos: INT] = { Scml: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; DB.SetF[rNewMailInfo, gCopyNewMailLogPos, DB.I2V[pos]] }; WalnutDB.CarefullyApply[Scml]; }; GetCopyMailLogPos: PUBLIC PROC RETURNS[pos: INT] = { Gcml: PROC = { rNewMailInfo: Relship = DB.FirstRelship[gNewMailInfo]; pos _ DB.V2I[DB.GetF[rNewMailInfo, gCopyNewMailLogPos]] }; WalnutDB.CarefullyApply[Gcml]; }; SetReadArchivePos: PUBLIC PROC[pos: INT] = { Srap: PROC = { rReadArchiveInfo: Relship = DB.FirstRelship[gReadArchiveInfo]; DB.SetF[rReadArchiveInfo, gReadArchiveLogPos, DB.I2V[pos]] }; WalnutDB.CarefullyApply[Srap]; }; GetReadArchivePos: PUBLIC PROC RETURNS[pos: INT] = { Grap: PROC = { rReadArchiveInfo: Relship = DB.FirstRelship[gReadArchiveInfo]; pos _ DB.V2I[DB.GetF[rReadArchiveInfo, gReadArchiveLogPos]] }; WalnutDB.CarefullyApply[Grap]; }; SetCopyReadArchivePos: PUBLIC PROC[pos: INT] = { Scra: PROC = { rReadArchiveInfo: Relship = DB.FirstRelship[gReadArchiveInfo]; DB.SetF[rReadArchiveInfo, gCopyReadArchiveLogPos, DB.I2V[pos]] }; WalnutDB.CarefullyApply[Scra]; }; GetCopyReadArchivePos: PUBLIC PROC RETURNS[pos: INT] = { Gcra: PROC = { rReadArchiveInfo: Relship = DB.FirstRelship[gReadArchiveInfo]; pos _ DB.V2I[DB.GetF[rReadArchiveInfo, gCopyReadArchiveLogPos]] }; WalnutDB.CarefullyApply[Gcra]; }; END.