DIRECTORY Basics, YggEnvironment, YggLog, YggLogBasic, YggLogInline, YggLogBasicInternal, YggLogRep, VM; YggLogBasicWriteImpl: CEDAR MONITOR IMPORTS Basics, YggLog, YggLogBasicInternal, YggLogInline, VM EXPORTS YggLogBasic = BEGIN PageNumber: TYPE = YggEnvironment.PageNumber; RecordID: TYPE = YggLog.RecordID; CallerProgrammingError: ERROR = CODE; curPageRecordID: YggLog.RecordID; curPageWordsUsed: CARD; curPagePtr: LONG POINTER _ NIL; pagesLeft: INT; curVersion: YggLogRep.PageVersion; nPagesWritten: INT _ 0; nPartFullPagesWritten: INT _ 0; OpenForPut: PUBLIC ENTRY PROC [ nextPage: PageNumber, version: YggLogRep.PageVersion, nextRecord: RecordID] = { IF YggLogInline.WordInPageFromRecordID[nextRecord, VM.wordsPerPage] # 0 THEN ERROR CallerProgrammingError; curPageRecordID _ nextRecord; curPageWordsUsed _ 0; curVersion _ version; TRUSTED { [pagesLeft, curPagePtr] _ YggLogBasicInternal.OpenBasicForPut[nextPage, version, nextRecord]; LOOPHOLE[curPagePtr, LONG POINTER TO CARD32]^ _ 0; }; }; CloseForPut: PUBLIC ENTRY PROC [] = { YggLogBasicInternal.CloseBasicForPut[]; curPagePtr _ NIL; }; Put: PUBLIC PROC [ from: YggLog.Block, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID] = TRUSTED { totalLen: INT _ 0; FOR b: YggLog.BlockPtr _ @from, b.rest UNTIL b = NIL DO len: INT = b.length; IF len > 0 THEN { IF b.base # NIL THEN { offset: CARD _ 0; UNTIL offset >= len DO touch: CARDINAL _ LOOPHOLE[b.base + offset*SIZE[INT32], LONG POINTER TO CARDINAL]^; IF offset = len - 1 THEN EXIT; offset _ offset + VM.wordsPerPage; IF offset >= len THEN offset _ len - 1; ENDLOOP; }; totalLen _ totalLen + len; }; ENDLOOP; IF totalLen NOT IN [YggLogBasic.minBlockLen .. YggLogBasic.maxBlockLen] THEN ERROR CallerProgrammingError; [thisRecord, followingRecord] _ PutEntry[totalLen, from, force, writeID]; IF force THEN YggLogBasicInternal.ForceTo[followingRecord: followingRecord]; }; PutEntry: ENTRY PROC [ totalLen: CARDINAL, from: YggLog.Block, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID] = { isContinuation: BOOL _ FALSE; thisRecord _ CurrentRecordID[]; IF writeID THEN TRUSTED { LOOPHOLE[from.base, LONG POINTER TO YggLogRep.CheckpointCompleteRecord].thisRecordID _ thisRecord; }; DO wordsThisBlock: CARD _ MIN[(YggLog.wordsPerPage-SIZE[YggLogRep.Header])-curPageWordsUsed, totalLen]; wordsThisCopy: CARD; totalLen _ totalLen-wordsThisBlock; --words remaining to be logged when this block finished TRUSTED { Header[curPagePtr+curPageWordsUsed]^ _ [ valid: FALSE, version: curVersion, hasContinuation: (totalLen # 0), isContinuation: isContinuation, nWords: wordsThisBlock+SIZE[YggLogRep.Header]]; }; curPageWordsUsed _ curPageWordsUsed+SIZE[YggLogRep.Header] * SIZE[INT32]; DO wordsThisCopy _ MIN[from.length, wordsThisBlock]; TRUSTED {Basics.Copy[ to: curPagePtr+curPageWordsUsed, from: from.base, nwords: wordsThisCopy]; }; curPageWordsUsed _ curPageWordsUsed+wordsThisCopy; IF wordsThisCopy = wordsThisBlock THEN EXIT; wordsThisBlock _ wordsThisBlock-wordsThisCopy; TRUSTED {from _ from.rest^;}; ENDLOOP; IF totalLen # 0 THEN { -- YggLog record not all written. AdvancePage[]; from.base _ from.base+wordsThisCopy; from.length _ from.length-wordsThisCopy; isContinuation _ TRUE; } ELSE { -- YggLog record all written. wpp: CARD = YggLog.wordsPerPage; IF force OR (curPageWordsUsed >= wpp-SIZE[YggLogRep.Header]) THEN AdvancePage[]; RETURN [thisRecord, CurrentRecordID[]]; } ENDLOOP; }; Force: PUBLIC PROC [followingRecord: RecordID] = { AdvanceTo: ENTRY PROC [followingRecord: RecordID] = { TRUSTED {IF ConstArith.Compare[followingRecord, curPageRecordID] # greater THEN RETURN; }; TRUSTED {IF ConstArith.Compare[followingRecord, CurrentRecordID[]] = greater THEN RETURN WITH ERROR CallerProgrammingError; }; AdvancePage[]; }; AdvanceTo[followingRecord]; YggLogBasicInternal.ForceTo[followingRecord]; }; Header: PROC [p: LONG POINTER] RETURNS [LONG POINTER TO YggLogRep.Header] = INLINE { RETURN [LOOPHOLE[p]] }; RecordIDOfNextPut: PUBLIC ENTRY PROC [] RETURNS [RecordID] = { RETURN [CurrentRecordID[]] }; CurrentRecordID: INTERNAL PROC [] RETURNS [RecordID] = INLINE { RETURN [YggLogInline.AddC[curPageRecordID, curPageWordsUsed]] }; AdvancePage: INTERNAL PROC [] = { IF curPageWordsUsed # YggLog.wordsPerPage THEN TRUSTED { nPartFullPagesWritten _ nPartFullPagesWritten + 1; LOOPHOLE[curPagePtr+curPageWordsUsed*SIZE[INT32], LONG POINTER TO CARD32]^ _ 0 }; nPagesWritten _ nPagesWritten + 1; TRUSTED {Header[curPagePtr].valid _ TRUE;}; pagesLeft _ pagesLeft - 1; IF pagesLeft = 0 THEN [curVersion, pagesLeft, curPagePtr] _ YggLogBasicInternal.AdvanceChunk[] ELSE curPagePtr _ curPagePtr + YggLog.wordsPerPage; TRUSTED {Header[curPagePtr].valid _ FALSE;}; curPageRecordID _ YggLogInline.AddC[curPageRecordID, YggLog.wordsPerPage]; curPageWordsUsed _ 0; }; END. CHANGE LOG Created by MBrown on June 15, 1982 3:38 pm Changed by MBrown on June 22, 1982 11:46 am Changed by MBrown on August 9, 1982 5:54 pm Changed by MBrown on August 12, 1982 4:15 pm Changed by MBrown on September 10, 1982 10:09 pm Changed by MBrown on September 21, 1982 2:40 pm Changed by MBrown on October 3, 1982 8:30 pm Changed by MBrown on October 11, 1982 4:21 pm Changed by MBrown on November 10, 1982 3:10 pm ΖYggLogBasicWriteImpl.mesa Copyright c 1985, 1987 by Xerox Corporation. All rights reserved. Implements log writing. Seperate from YggLogBasicImpl to have its own monitor. Last edited by MBrown on January 30, 1984 11:44:13 am PST Carl Hauser, March 10, 1987 5:41:17 pm PST Bob Hagmann May 12, 1988 3:10:19 pm PDT Nonspecific error that clients are not expected to catch. Monitored state: Points to first word of current page buffer. Number of pages in buffer represented by curPagePtr. Version bit for page now being written. for curiosity only Starting and stopping logging nextRecord must be page-aligned. ensure that first store into page clears valid bit. Public writing Compute the total length of the block to be written, and touch all pages in it. Total record length must be in correct range. Append to log, then force to disk if necessary. Note: tail monitor is not held during force. ! YggLog.WriteFailed (with monitor locked; this is a server-crashing error). On entry, there is always room in the current page for a header plus 1 word (i.e. curPageWordsUsed < wordsPerPage-SIZE[YggLogRep.Header]), so this record starts on the current page. Write one log block. Write a header for the log block. The first store to a page should be the one that sets valid _ FALSE. Copy a run of words to the log block. Assert wordsThisBlock > wordsThisCopy = from.length, from.rest # NIL. YggLog block is now full. Is log record all written? Assert curPageWordsUsed = wordsPerPage. Advance page and loop. Assert from.rest = NIL. Advance page if log force or if not enough room on page for a header plus one word. YggLogBasic.Force. If the word before followingRecord is on the current page, skip the rest of the current page. followingRecord must not be later than record about to be written. Note: tail monitor is not held during force. Internal procedures and utilities If page is only partly full then terminate it with 0 word. Mark current page "valid". may raise WriteFailed because log is full Mark new page "invalid" Introduce a separate monitor for log tail. Check for log full only when moving to new chunk. Force log without holding the tail monitor. Implement Force. OpenForPut calls OpenCoreForPut, to avoid any calls from LogCoreImpl to this module. Bug: PutEntry loops with totalLen = wordsThisCopy = wordsThisBlock = 0. Simplified by keeping curPageRecordID as one datum, instead of in two pieces. Added CloseForPut, simplified ERRORs (all are now raised as a nonspecific CallerProgrammingError, since clients won't be catching them). Added RecordIDOfNextPut. Added nPartFullPagesWritten. Hauser, March 8, 1985 10:47:27 am PST Nodified, added copyright. Carl Hauser, October 4, 1985 1:33:03 pm PDT Change "Log" to "AlpineLog" ΚΘ˜šœ™Icodešœ Οmœ7™B—JšœO™Ošœ™Jšœ*™*K™*K™'—˜šΟk ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜J˜——šΟnœž ˜#šž˜Jšœ5˜5—šž˜Jšœ ˜ —Jšž˜J˜Jšœ žœ˜-Jšœ žœ˜!J˜šœžœžœ˜%Jšœ9™9J˜—Jšœ™J˜Jšœ!˜!Jšœžœ˜šœ žœžœžœ˜Jšœ,™,—šœ žœ˜Jšœ4™4—šœ"˜"Jšœ'™'J˜—Jšœžœ˜šœžœ˜Jšœ™——head™šŸ œžœžœžœ˜JšœO˜OJšœ ™ šžœFž˜LJšžœ˜—J˜J˜J˜˜ Jšœ]˜]š žœ žœžœžœžœ˜2Jšœ3™3—J˜—J˜J˜—šŸ œžœžœžœ˜%Jšœ'˜'Jšœ žœ˜J˜J˜——L™˜š Ÿœžœžœžœ žœžœ4˜~JšœP™PJšœ žœ˜šžœ$žœžœž˜7Jšœžœ ˜šžœ žœ˜šžœ žœžœ˜Jšœžœ˜šžœž˜Jš œžœžœžœžœžœžœ˜SJšžœžœžœ˜Jšœ"˜"Jšžœžœ˜'Jšžœ˜—J˜—J˜J˜—Jšžœ˜—Jšœ.™.šžœ žœžœ6ž˜LJšžœ˜—Jšœ0™0Jšœ-™-J˜IJšžœžœ?˜LJ˜——J˜˜šŸœžœžœ˜Jšœ žœžœ žœ˜CJšžœ,˜3Jšœžœžœ˜JšœL™LJšœΆ™ΆJ˜šžœ žœ ˜šžœ ˜Jšžœžœžœ?˜N—J˜—šž˜Jšœ™šœžœ˜Jšžœžœ0˜M—Jšœžœ˜Jšœ$Οc7˜[Jšœ"™"JšœE™E˜ ˜(Jšœžœ˜"J˜@Jšœžœ˜/—J˜—Jšœ$žœžœžœ˜Išž˜Jšœ%™%Jšœžœ˜1šœ˜J˜M—J˜2Jšžœ žœžœ˜,JšœE™EJ˜.J˜Jšžœ˜—Jšœ5™5šžœžœ !˜8Jšœ'™'Jšœ™J˜J˜$J˜(Jšœžœ˜J˜—šžœ ˜$Jšœ™JšœS™SJšœžœ˜ šžœžœžœž˜AJ˜—Jšžœ!˜'J˜—Jšžœ˜—J˜J˜—šŸœžœžœ ˜2Jšœ™šŸ œžœžœ ˜5JšœK™KJšœ™šž œ?˜JJšžœžœ˜—JšœB™Bšž œBž˜QJšžœžœžœ˜,—J˜J˜—J˜Jšœ,™,Jšœ-˜-J˜J˜——™"šŸœžœžœžœžœžœžœžœžœ˜TJšžœžœ˜J˜—š Ÿœžœžœžœžœ˜>Jšžœ˜J˜J˜—š Ÿœžœžœžœžœ˜?Jšžœ:˜@J˜J˜—šŸ œžœžœ˜!Jšœ:™:šžœ(žœ ˜8J˜2Jšžœžœžœžœžœžœžœ ˜Q—J˜"Jšœ™Jšœ$žœ˜+J˜šžœž˜JšœH˜HJšœ)™)—šž˜Jšœ.˜.—Jšœ™Jšœ$žœ˜,JšœJ˜JJ˜J˜J˜—Jšžœ˜J˜J˜J˜—Jšžœž˜ J˜J˜*Jšœ*™*J˜J˜+JšœU™UJšœ™J˜J˜+Jšœ™J˜J˜,JšœD™DJšœ™J˜J˜0JšœG™GJ˜J˜/JšœM™MJ˜J˜,JšœI™IJšœ>™>J˜J˜-Jšœ™J˜J˜.Jšœ™™%K™—™+K™—K™J˜—…—ž',