DIRECTORY AlpineEnvironment, Basics, AlpineLog, LogBasic, LogInline, LogBasicInternal, LogRep, PrincOpsUtils; LogBasicTailImpl: MONITOR IMPORTS Basics, AlpineLog, LogInline, LogBasicInternal, PrincOpsUtils EXPORTS LogBasic = BEGIN PageNumber: TYPE = AlpineEnvironment.PageNumber; RecordID: TYPE = AlpineLog.RecordID; wordsPerPage: CARDINAL = AlpineEnvironment.wordsPerPage; Header: PROC [p: LONG POINTER] RETURNS [LONG POINTER TO LogRep.Header] = INLINE { RETURN [LOOPHOLE[p]] }; CallerProgrammingError: ERROR = CODE; curPageRecordID: AlpineLog.RecordID; curPageWordsUsed: INT [0 .. wordsPerPage]; curPagePtr: LONG POINTER _ NIL; pagesLeft: INT; curVersion: LogRep.PageVersion; nPagesWritten: INT _ 0; nPartFullPagesWritten: INT _ 0; CurrentRecordID: INTERNAL PROC [] RETURNS [RecordID] = INLINE { RETURN [LogInline.AddC[curPageRecordID, curPageWordsUsed]] }; OpenForPut: PUBLIC ENTRY PROC [ nextPage: PageNumber, version: LogRep.PageVersion, nextRecord: RecordID] = { IF LogInline.WordInPageFromRecordID[nextRecord] # 0 THEN ERROR CallerProgrammingError; curPageRecordID _ nextRecord; curPageWordsUsed _ 0; curVersion _ version; [pagesLeft, curPagePtr] _ LogBasicInternal.OpenCoreForPut[nextPage, version, nextRecord]; LOOPHOLE[curPagePtr, LONG POINTER TO CARDINAL]^ _ 0; }; CloseForPut: PUBLIC ENTRY PROC [] = { LogBasicInternal.CloseCoreForPut[]; curPagePtr _ NIL; }; RecordIDOfNextPut: PUBLIC ENTRY PROC [] RETURNS [RecordID] = { RETURN [CurrentRecordID[]] }; Put: PUBLIC --EXTERNAL-- PROC [ from: AlpineLog.Block, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID] = { totalLen: INT _ 0; FOR b: AlpineLog.BlockPtr _ @from, b.rest UNTIL b = NIL DO len: INT = b.length; IF len > 0 THEN { IF b.base # NIL THEN { offset: INT _ - LOOPHOLE[Basics.BITAND[AlpineEnvironment.wordsPerPage-1, LOOPHOLE[b.base, Basics.LongNumber[pair]].lo], INTEGER]; UNTIL offset >= len DO touch: CARDINAL _ LOOPHOLE[b.base + offset, LONG POINTER TO CARDINAL]^; offset _ offset + AlpineEnvironment.wordsPerPage; ENDLOOP; }; totalLen _ totalLen + len; }; ENDLOOP; IF totalLen NOT IN [LogBasic.minBlockLen .. LogBasic.maxBlockLen] THEN ERROR CallerProgrammingError; [thisRecord, followingRecord] _ PutEntry[totalLen, from, force, writeID]; IF force THEN LogBasicInternal.ForceTo[followingRecord: followingRecord]; }; PutEntry: ENTRY PROC [ totalLen: CARDINAL, from: AlpineLog.Block, force: BOOL, writeID: BOOL] RETURNS [thisRecord, followingRecord: RecordID] = { isContinuation: BOOL _ FALSE; thisRecord _ CurrentRecordID[]; IF writeID THEN { IF from.length < LogRep.CheckpointCompleteRecord.SIZE - LogRep.StrBody.SIZE THEN RETURN WITH ERROR CallerProgrammingError; LOOPHOLE[from.base, LONG POINTER TO LogRep.CheckpointCompleteRecord].thisRecordID _ thisRecord; }; DO wordsThisBlock: CARDINAL _ MIN[(wordsPerPage-SIZE[LogRep.Header])-curPageWordsUsed, totalLen]; wordsThisCopy: CARDINAL; totalLen _ totalLen-wordsThisBlock; --words remaining when this block finished Header[curPagePtr+curPageWordsUsed]^ _ [ valid: FALSE, version: curVersion, hasContinuation: (totalLen # 0), isContinuation: isContinuation, nWords: wordsThisBlock+SIZE[LogRep.Header]]; curPageWordsUsed _ curPageWordsUsed+SIZE[LogRep.Header]; DO wordsThisCopy _ MIN[from.length, wordsThisBlock]; PrincOpsUtils.LongCopy[ to: curPagePtr+curPageWordsUsed, from: from.base, nwords: wordsThisCopy]; curPageWordsUsed _ curPageWordsUsed+wordsThisCopy; IF wordsThisCopy = wordsThisBlock THEN EXIT; wordsThisBlock _ wordsThisBlock-wordsThisCopy; from _ from.rest^; ENDLOOP; IF totalLen # 0 THEN { -- AlpineLog record not all written. AdvancePage[]; from.base _ from.base+wordsThisCopy; from.length _ from.length-wordsThisCopy; isContinuation _ TRUE; } ELSE { -- AlpineLog record all written. IF force OR (curPageWordsUsed >= wordsPerPage-SIZE[LogRep.Header]) THEN AdvancePage[]; RETURN [thisRecord, CurrentRecordID[]]; } ENDLOOP; }; Force: PUBLIC PROC [followingRecord: RecordID] = { AdvanceTo: ENTRY PROC [followingRecord: RecordID] = { IF AlpineLog.Compare[followingRecord, curPageRecordID] # greater THEN RETURN; IF AlpineLog.Compare[followingRecord, CurrentRecordID[]] = greater THEN RETURN WITH ERROR CallerProgrammingError; AdvancePage[]; }; AdvanceTo[followingRecord]; LogBasicInternal.ForceTo[followingRecord]; }; AdvancePage: INTERNAL PROC [] = { IF curPageWordsUsed # wordsPerPage THEN { nPartFullPagesWritten _ nPartFullPagesWritten + 1; LOOPHOLE[curPagePtr+curPageWordsUsed, LONG POINTER TO CARDINAL]^ _ 0 }; nPagesWritten _ nPagesWritten + 1; Header[curPagePtr].valid _ TRUE; pagesLeft _ pagesLeft - 1; IF pagesLeft = 0 THEN [curVersion, pagesLeft, curPagePtr] _ LogBasicInternal.AdvanceChunk[] ELSE curPagePtr _ curPagePtr + AlpineEnvironment.wordsPerPage; Header[curPagePtr].valid _ FALSE; curPageRecordID _ LogInline.AddC[curPageRecordID, 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 zLogBasicTailImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Implements log writing. Last edited by MBrown on January 30, 1984 11:44:13 am PST Hauser, March 8, 1985 10:47:59 am PST Carl Hauser, January 5, 1987 2:05:44 pm PST 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 nextRecord must be page-aligned. ensure that first store into page clears valid bit. Compute the total length of the block to be written, and touch all pages in it. b.base+offset now points to first word of page containing b.base 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. ! AlpineLog.Error[logFull] (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[LogRep.Header]), so this record starts on the current page. There must be room for the RecordID. 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. AlpineLog 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. LogBasic.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. If page is only partly full then terminate it with 0 word. Mark current page "valid". may raise LogFull 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œ1™<—Jšœ™šœ™Jšœ*™*K™%K™+—˜šÏk ˜ J˜J˜J˜ J˜ J˜ J˜J˜J˜J˜——šœž˜šž˜J˜J˜ J˜ J˜J˜ —šž˜J˜ —Jšž˜Jšœ žœ ˜0Jšœ žœ˜$Jšœžœ"˜8šÏnœžœžœžœžœžœžœžœžœ˜QJšžœžœ˜J˜—šœžœžœ˜%Jšœ9™9J˜J˜—Jšœ™J˜J˜$Jšœžœ˜*šœ žœžœžœ˜Jšœ,™,—šœ žœ˜Jšœ4™4—˜Jšœ'™'J˜—Jšœžœ˜šœžœ˜Jšœ™J˜J˜—š Ÿœžœžœžœžœ˜?Jšžœ7˜=J˜J˜—šŸ œžœžœžœ˜J˜LJšœ ™ šžœ2ž˜8Jšžœ˜—J˜J˜J˜˜J˜?—š žœ žœžœžœžœ˜4Jšœ3™3—J˜J˜—šŸ œžœžœžœ˜%J˜#Jšœ žœ˜J˜J˜—š Ÿœžœžœžœžœ˜>Jšžœ˜J˜——˜šŸœžœÏc œžœ˜Jšœžœ žœ˜2Jšžœ,˜3JšœO™OJšœ žœ˜šžœ'žœžœž˜:Jšœžœ ˜šžœ žœ˜šžœ žœžœ˜šœžœžœžœ"˜HJšžœ'žœ˜8Jšœ@™@—šžœž˜Jš œžœžœžœžœžœžœ˜GJ˜1Jšžœ˜—J˜—J˜J˜—Jšžœ˜—Jšœ-™-šžœ žœžœ0ž˜FJšžœ˜—Jšœ/™/Jšœ,™,J˜IJšžœžœ<˜IJ˜——˜šŸœžœžœ˜Jšœ žœ žœ žœ˜FJšžœ,˜3Jšœžœžœ˜JšœR™RJšœK™KJšœX™XJšœ ™ J˜šžœ žœ˜Jšœ$™$šžœ/žœžœž˜PJšžœžœžœ˜)—šžœ ˜Jšžœžœžœ<˜K—J˜—šž˜Jšœ™šœžœ˜Jšžœžœ-˜C—Jšœžœ˜Jšœ$ *˜NJšœ!™!JšœD™D˜(Jšœžœ˜"J˜@Jšœžœ˜,—Jšœ$žœ˜8šž˜Jšœ%™%Jšœžœ˜1˜J˜I—J˜2Jšžœ žœžœ˜,JšœE™EJ˜.J˜Jšžœ˜—Jšœ8™8šžœžœ $˜;Jšœ'™'Jšœ™J˜J˜$J˜(Jšœžœ˜J˜—šžœ  ˜'Jšœ™JšœS™Sšžœžœ#žœž˜GJ˜—Jšžœ!˜'J˜—Jšžœ˜—J˜——˜šŸœžœžœ ˜2Jšœ™šŸ œžœžœ ˜5JšœK™KJšœ™šžœ>˜@Jšžœžœ˜ —JšœB™BšžœAž˜GJšžœžœžœ˜)—J˜J˜—J˜Jšœ,™,J˜*J˜J˜—šŸ œžœžœ˜!Jšœ:™:šžœ!žœ˜)J˜2Jš žœžœžœžœžœ ˜G—J˜"Jšœ™Jšœžœ˜ J˜šžœž˜J˜EJšœ™—šž˜J˜9—Jšœ™Jšœžœ˜!J˜@J˜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™—…—Â&Ò