DIRECTORY Camelot, PBasics, YggEnvironment, YggLog, YggLogBasic, YggLogInline, YggLogBasicInternal, YggLogRep, VM; YggLogBasicWriteImpl: CEDAR MONITOR IMPORTS PBasics, YggLog, YggLogBasic, YggLogBasicInternal, YggLogInline EXPORTS YggLogBasic = BEGIN PageNumber: TYPE = YggEnvironment.PageNumber; RecordID: TYPE = YggLog.RecordID; CallerProgrammingError: ERROR = CODE; curPageRecordID: YggLog.RecordID; curPageWordsUsed: CARD; -- in machine dependent words 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, optr: Camelot.optrT, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID, thisWordNumber: YggEnvironment.WordNumber] = TRUSTED { totalLen: INT _ 0; -- in 32 bit words FOR b: YggLog.BlockPtr _ @from, b.rest UNTIL b = NIL DO len: CARD = b.length; IF len > 0 THEN { IF b.base # NIL THEN { offset: CARD _ 0; UNTIL offset >= len*WordsINWORDS DO touch: CARDINAL _ LOOPHOLE[b.base + offset*SIZE[INT32], LONG POINTER TO CARDINAL]^; IF offset = len - 1 THEN EXIT; offset _ offset + VM.wordsPerPage/WORDS[CARD32]; 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, thisWordNumber] _ PutEntry[totalLen, from, force, writeID]; IF force THEN YggLogBasicInternal.ForceTo[followingRecord: followingRecord]; }; WordsINWORDS: CARD = WORDS[CARD32]; PutEntry: ENTRY PROC [ totalLen: CARDINAL, from: YggLog.Block, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID, thisWordNumber: YggEnvironment.WordNumber] = { isContinuation: BOOL _ FALSE; thisRecord _ CurrentRecordID[]; thisWordNumber _ YggLogBasic.WordNumberFromRecordID[thisRecord]; IF writeID THEN TRUSTED { LOOPHOLE[from.base, LONG POINTER TO YggLogRep.CheckpointCompleteRecord].thisRecordID _ thisRecord; }; DO wordsThisBlock: CARD _ MIN[(YggLog.wordsPerPage-WORDS[YggLogRep.Header])-curPageWordsUsed, totalLen*WordsINWORDS]; -- in machine dependent words wordsThisCopy: CARD; totalLen _ totalLen-wordsThisBlock/WordsINWORDS; -- 32 bit words remaining to be logged when this block finished TRUSTED { pageNumber: INT; pageNumber _ ConstArith.ToInt[ConstArith.Div[curPageRecordID, ConstArith.FromCard[YggLog.wordsPerPage]]]; Header[curPagePtr+(curPageWordsUsed*UNITS[WORD])]^ _ [ valid: FALSE, version: curVersion, hasContinuation: (totalLen # 0), isContinuation: isContinuation, nWords: wordsThisBlock+SIZE[YggLogRep.Header], unused1: pageNumber]; }; curPageWordsUsed _ curPageWordsUsed+WORDS[YggLogRep.Header]; DO wordsThisCopy _ MIN[from.length*WordsINWORDS, wordsThisBlock]; TRUSTED {PBasics.Copy[ to: curPagePtr+(curPageWordsUsed*UNITS[WORD]), from: from.base, nwords: wordsThisCopy/WordsINWORDS]; }; 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/WordsINWORDS; isContinuation _ TRUE; } ELSE { -- YggLog record all written. wpp: CARD = YggLog.wordsPerPage; IF force OR (curPageWordsUsed >= wpp-WORDS[YggLogRep.Header]) THEN AdvancePage[]; RETURN [thisRecord, CurrentRecordID[], thisWordNumber]; } 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*UNITS[WORD]), 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 * UNITS[WORD]; TRUSTED {Header[curPagePtr].valid _ FALSE;}; curPageRecordID _ YggLogInline.AddC[curPageRecordID, YggLog.wordsPerPage]; curPageWordsUsed _ 0; }; END. ΎYggLogBasicWriteImpl.mesa Copyright Σ 1985, 1987, 1989 by Xerox Corporation. All rights reserved. Implements log writing. Separate from YggLogBasicImpl to have its own monitor. Derived from Alpine. Last edited by Bob Hagmann June 16, 1989 3:47:25 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" Κ—˜šœ™IcodešœH™H—Jšœe™ešœ™K™(—˜šΟk ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜J˜——šΟnœ ˜#š˜Jšœ?˜?—š˜Jšœ ˜ —Jš˜J˜Jšœ œ˜-Jšœ œ˜!J˜šœœœ˜%Jšœ9™9J˜—Jšœ™J˜Jšœ!˜!JšœœΟc˜6šœ œœœ˜Jšœ,™,—šœ œ˜Jšœ4™4—šœ"˜"Jšœ'™'J˜—Jšœœ˜šœœ˜Jšœ™——head™šž œœœœ˜JšœO˜OJšœ ™ šœ1œ˜LJšœ˜—J˜J˜J˜šœ˜ Jšœ]˜]š œ œœœœ˜2Jšœ3™3—J˜—J˜J˜—šž œœœœ˜%Jšœ'˜'Jšœ œ˜J˜J˜——L™˜šžœœœ3œ œœVœ˜ΎJšœP™PJšœ œŸ˜&šœ$œœ˜7Jšœœ ˜šœ œ˜šœ œœ˜Jšœœ˜šœ˜#Jšœœœœœœœœœ˜SJšœœœ˜Jšœœœœ˜0Jšœœ˜'Jšœ˜—J˜—J˜J˜—Jšœ˜—Jšœ.™.šœ œœ6˜LJšœ˜—Jšœ0™0Jšœ-™-JšœY˜YJšœœ?˜LJ˜——J˜˜J˜#J˜šžœœœ˜Jšœ œœ œ˜CJšœW˜^Jšœœœ˜JšœL™LJšœsœ?™ΆJ˜Jšœ@˜@šœ œœ˜šœ ˜Jšœœœ?˜N—J˜—š˜Jšœ™šœœ˜Jšœœ?Ÿ˜z—Jšœœ˜Jšœ1Ÿ?˜pJšœ"™"Jšœ?œ™Ešœ˜ Jšœ˜Jšœi˜i˜6Jšœœ˜"J˜@Jšœœ˜.Jšœ˜—J˜—Jšœ$œ˜<š˜Jšœ%™%Jšœœ+˜>šœ˜J˜h—J˜2Jšœ œœ˜,JšœAœ™EJ˜.Jšœ˜Jšœ˜—Jšœ5™5šœœŸ!˜8Jšœ'™'Jšœ™J˜J˜$J˜5Jšœœ˜J˜—šœŸ˜$Jšœœ™JšœS™SJšœœ˜ šœœœ˜BJ˜—Jšœ1˜7J˜—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šœœœœœœœ ˜S—J˜"Jšœ™Jšœœ˜+J˜šœ˜JšœH˜HJšœ)™)—š˜Jšœ0œœ˜<—Jšœ™Jšœœ˜,JšœJ˜JJ˜J˜J˜—Jšœ˜J˜J˜J˜——…—\$±