-- file DBLogImpl.mesa -- created by Donahue, November 12, 1982 4:22 pm -- last edited by Donahue, January 3, 1983 4:50 pm DIRECTORY DBLog, DBLoad, DBView, FileIO, IO, Nut, NutDump, Rope; DBLogImpl: MONITOR LOCKS data USING data: DBLog.Log IMPORTS DBLoad, FileIO, IO, Nut, NutDump, Rope, DBView EXPORTS DBLog = { OPEN DBLog, Rope, IO, Nut, DBView; ControlZ: CHARACTER = 032C; LogList: LIST OF Log _ NIL; LogRel: DBView.Relation = DeclareRelation[ "DBLog" ]; LogNameAttr: Attribute = DBView.DeclareAttribute[ r: LogRel, name: "name", type: StringType, uniqueness: Uniqueness[Key] ]; LogLengthAttr: Attribute = DBView.DeclareAttribute[ r: LogRel, name: "length", type: IntType ]; AcquireLock: ENTRY PROC [data: Log] = { -- acquire the lock on the data -- return the live flag -- if FALSE is returned, the lock is not held ENABLE UNWIND => NULL; DO IF data = NIL THEN RETURN; IF NOT data.locked THEN {data.locked _ TRUE; RETURN}; WAIT data.condition; ENDLOOP }; ReleaseLock: ENTRY PROC [data: Log] = { -- release the data lock -- then notify everyone else that the world is OK data.locked _ FALSE; BROADCAST data.condition }; InitializeLog: PUBLIC PROC[fileName: ROPE] RETURNS[ log: Log ] = { log _ NEW[ LogObj _ [name: fileName] ]; InternalOpenLog[ log ]; LogList _ CONS[ log, LogList ] }; InternalOpenLog: PROC[ log: Log ] = { log.stream _ FileIO.Open[ fileName: log.name, accessOptions: write, closeOptions: FileIO.noCloseOptions ]; log.stream.SetIndex[ log.stream.GetLength[] ] }; CommitLog: PUBLIC PROC[log: Log, reOpen: BOOL _ TRUE] = { AcquireLock[log]; SetLogLengthInDB[log]; IF NOT reOpen THEN { log.stream.Close[]; log.stream _ NIL }; ReleaseLock[log] }; GetLogLength: PUBLIC PROC[ log: Log ] RETURNS[length: INT] = { ENABLE UNWIND => NULL; AcquireLock[ log ]; length _ log.stream.GetLength[]; log.stream.Flush[]; ReleaseLock[ log ] }; LogEntity: PUBLIC PROC[ log: Log, entryType: LogEntryType, entity: DBView.Entity ] = { AcquireLock[log]; IO.PutRope[ log.stream, IF entryType = insertion THEN "+" ELSE "-" ]; NutDump.WriteEntity[ log.stream, entity ]; ReleaseLock[log] }; LogRelship: PUBLIC PROC[ log: Log, entryType: LogEntryType, relship: DBView.Relship ] = { AcquireLock[log]; IO.PutRope[ log.stream, IF entryType = insertion THEN "+" ELSE "-" ]; NutDump.WriteRelship[ log.stream, relship ]; ReleaseLock[log] }; LogText: PUBLIC PROC[ log: Log, text: ROPE ] = { AcquireLock[log]; [] _ InternalPutText[ log, text ]; ReleaseLock[log] }; InternalPutText: PROC[ log: Log, text: ROPE ] RETURNS[ len: INT ] = { len _ log.stream.GetLength[]; IO.PutFL[ stream: log.stream, list: LIST[IO.rope["?"], IO.int[text.Length[]], IO.rope["\\"], IO.rope[text], IO.char[CR]]]; len _ log.stream.GetLength[] - len }; NoBreak: BreakProc = TRUSTED{ RETURN[ KeepGoing ] }; ReadString: PROC[ log: Log ] RETURNS[ string: ROPE ] = { -- Terminates on reading a "\"; may return a null string if find immediately. NameBreak: BreakProc = TRUSTED { IF c='\\ THEN RETURN[StopAndTossChar] ELSE RETURN[KeepGoing] }; string _ log.stream.GetRope[NameBreak, NoBreak]; IF string= NIL THEN string _ "" }; ReadName: PROC[ log: Log ] RETURNS[string: ROPE] = { -- Terminates on reading a ":" or a CR; returns NIL in latter case. NameBreak: BreakProc = TRUSTED { lastBreak_ c; IF c = ControlZ THEN {[] _ SkipThruCR[log.stream]; RETURN[StopAndTossChar]} ELSE IF c = '\\ OR c = CR OR c = ': THEN RETURN[StopAndTossChar] ELSE RETURN[KeepGoing] }; lastBreak: CHAR; string _ log.stream.GetRope[NameBreak, NoBreak]; IF string = NIL THEN string _ "" }; SkipThruCR: PROC[ stream: IO.STREAM ] RETURNS[ r: ROPE ] = { ENABLE IO.EndOfStream => GOTO Quit; c: CHARACTER; WHILE (c _ stream.GetChar[]) # CR DO r _ Rope.Cat[r, Rope.FromChar[c]] ENDLOOP; EXITS Quit => RETURN[ IF r = NIL THEN "" ELSE r ] }; DumpLog: PUBLIC PROC[ oldLog: Log, newLog: Log, filter: PROC[entry: ROPE, pos: INT] RETURNS[copy: BOOLEAN] ] = { -- just cycle through the log, applying the filter to all text log entries prefix: CHAR; entry: ROPE; currPos: INT _ 0; AcquireLock[ newLog ]; AcquireLock[ oldLog ]; DO entry _ SkipThruCR[oldLog.stream]; IF entry.Length[] = 0 THEN EXIT; prefix _ Rope.Fetch[entry]; IF prefix = '? THEN IF filter[ entry, currPos ] THEN currPos _ currPos + InternalPutText[ newLog, entry ] ENDLOOP }; SetLogLengthInDB: PROC[ log: Log ] = { logdata: Relship _ DeclareRelship[ r: LogRel, init: LIST[ AttributeValue[ LogNameAttr, S2V[log.name] ] ] ]; log.stream.Flush[]; SetF[ logdata, LogLengthAttr, I2V[ log.stream.GetLength[] ] ] }; AdvanceLogFromLastCommit: PUBLIC PROC[ log: Log ] = { -- get length from the DB and then perform all the log actions from this point DBRels: RelshipSet = RelationSubset[LogRel, LIST[AttributeValue[LogNameAttr,S2V[log.name]]]]; DBrel: Relship = NextRelship[ DBRels ]; { ENABLE IO.EndOfStream => GOTO Quit; pos: INT = V2I[ GetF[ DBrel, LogLengthAttr ] ]; prefix: CHAR; log.stream.SetIndex[pos]; -- text entries are not touched, but the entity and relship entries are added or deleted DO prefix _ GetChar[log.stream]; SELECT prefix FROM '? => { len: ROPE _ ReadString[log]; pos: INT _ log.stream.GetIndex[]; log.stream.SetIndex[ pos+ IO.GetInt[ IO.RIS[len] ] + 1 ] }; '+ => IF PeekChar[ log.stream ] = '/ THEN [] _ DBLoad.CreateEntity[ log.stream ] ELSE [] _ DBLoad.CreateRelship[ log.stream ]; '- => IF PeekChar[ log.stream ] = '/ THEN [] _ DBLoad.DestroyEntity[ log.stream ] ELSE [] _ DBLoad.DestroyRelship[ log.stream ]; ENDCASE => [] _ SkipThruCR[ log.stream ]; ENDLOOP; EXITS Quit => { ReleaseRelshipSet[DBRels]; SetF[ DBrel, LogLengthAttr, I2V[log.stream.GetLength[]] ] } } }; Notified: Nut.NotifyProc = { FOR ll: LIST OF Log _ LogList, ll.rest UNTIL ll = NIL DO SELECT whyNotified FROM afterOpen => AdvanceLogFromLastCommit[ ll.first ]; beforeClose, beforeCommit => { AcquireLock[ll.first]; ll.first.stream.Flush[]; SetLogLengthInDB[ ll.first ]; ReleaseLock[ll.first] }; afterCommit => { AcquireLock[ll.first]; InternalOpenLog[ll.first]; ReleaseLock[ll.first] }; ENDCASE; ReleaseLock[ ll.first ] ENDLOOP }; Nut.Register[ domain: "Domain", notify: Notified ] }. Ę˜˜Jš¸Īc{œĪk œ*žœ*žœžœžœžœžœ žœžœžœ ž œžœžœžœÎĪn œžœžœ œœ.œžœžœžœžœžœžœžœžœ žœžœ žœžœžœ žœžœ Ÿ œžœžœœ2œžœž œŸ œžœžœ žœžœžœEžœŸœžœŋŸ œžœžœžœžœ4žœžœžœ$žœŸ œžœžœ žœ žœžœžœžœnŸ œžœžœXžœžœžœžœPŸ œžœžœYžœžœžœžœRŸœžœžœžœ[Ÿœžœžœžœžœ-žœ,žœžœ žœžœ žœ žœžœKžœžœŸ œžœ žœ žœ NœžœžœžœžœžœžœFžœ žœžœŸœžœ žœ žœDœžœžœžœžœžœžœ žœžœžœžœžœžœžœžœ7žœ žœžœŸ œžœ žœžœžœžœ žœžœžœž œžœžœžœ#žœžœžœžœžœžœžœ Ÿœžœžœ.žœžœžœžœžœ Kœ žœ žœ žœ7žœ*žœžœžœ$žœ žœžœžœ9žœ ŸœžœLžœ’ŸœžœžœOœ.žœ\žœžœžœžœ4žœ"[œžœ%žœžœžœžœ=žœ žœžœžœžœ6žœ6žœžœ0žœ.žœ'žœžœžœžœžœžœžœžœžœ žœũžœ"žœK˜ß4—…—b