<> <> <> <> <> <> <> <> DIRECTORY Basics USING [bytesPerWord], CardTab USING [Create, Fetch, Ref, Store], SymTab USING [Create, Fetch, Ref, Store], YggEnvironment, YggDID, YggLog, YggOpenDoc, YggFileLockFormat, YggOpenDocLog, YggDIDMap, YggFilePageMgr, YggLogControl, Rope USING [InlineFlatten, ROPE, Text]; YggOpenDocLogImpl: MONITOR IMPORTS CardTab, SymTab, YggEnvironment, YggOpenDoc, YggOpenDocLog, YggDIDMap, YggFilePageMgr, YggLog, YggLogControl, Rope EXPORTS YggDID, YggOpenDocLog SHARES Rope = BEGIN OPEN YggOpenDocLog; <<>> <> LogCreate: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc, initialSize: PageCount, owner: YggEnvironment.OwnerName] = BEGIN textOwner: Rope.Text = Rope.InlineFlatten[owner]; did: YggEnvironment.DID; length: CARDINAL = textOwner.length; textBlock: YggLog.Block _ [ base: BASE[DESCRIPTOR[textOwner.text]], length: (length+Basics.bytesPerWord-1)/Basics.bytesPerWord]; record: FileLogRecord[create] _ [ fileID: 0, specifics: create [initialSize: initialSize, owner: [length: length, text: NULL]]]; did _ YggOpenDoc.GetDID[openDoc]; record.fileID _ StoreDIDInMaps[did: did, id: 0]; [] _ YggLog.Write[trans: YggOpenDoc.GetTransHandle[openDoc], logRecordPhaseType: redo, recordType: create, recordData: [base: @record, length: SIZE[FileLogRecord[create]], rest: @textBlock], force: TRUE]; END; LogDelete: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc] = BEGIN did: YggEnvironment.DID; record: FileLogRecord[delete] _ [fileID: NULL, specifics: delete []]; record.fileID _ LookupIDInMap[did: YggOpenDoc.GetDID[openDoc]]; IF record.fileID = 0 THEN record.fileID _ StoreDIDInMaps[did: did, id: 0]; [] _ YggLog.Write[trans: YggOpenDoc.GetTransHandle[openDoc], logRecordPhaseType: redo, recordType: delete, recordData: [base: @record, length: SIZE[FileLogRecord[delete]]]]; END; LogSetSize: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc, old, new: PageCount] = BEGIN did: YggEnvironment.DID; record: FileLogRecord[setSize] _ [fileID: NULL, specifics: setSize [old: old, new: new]]; record.fileID _ LookupIDInMap[did: YggOpenDoc.GetDID[openDoc]]; IF record.fileID = 0 THEN record.fileID _ StoreDIDInMaps[did: did, id: 0]; [] _ YggLog.Write[trans: YggOpenDoc.GetTransHandle[openDoc], logRecordPhaseType: redo, recordType: setSize, recordData: [base: @record, length: SIZE[FileLogRecord[setSize]]]]; END; LogWritePages: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc, where: LONG POINTER, pageRun: PageRun, referencePattern: ReferencePattern] RETURNS [recordID: LogRecordID] = BEGIN did: YggEnvironment.DID; dataBlock: YggLog.Block _ [base: where, length: pageRun.count*YggEnvironment.wordsPerPage]; record: FileLogRecord[writePages] _ [fileID: NULL, specifics: writePages [pageRun: pageRun, referencePattern: referencePattern, data: NULL]]; record.fileID _ LookupIDInMap[did: YggOpenDoc.GetDID[openDoc]]; IF record.fileID = 0 THEN record.fileID _ StoreDIDInMaps[did: did, id: 0]; [thisRecord: recordID] _ YggLog.Write[trans: YggOpenDoc.GetTransHandle[openDoc], logRecordPhaseType: redo, recordType: writePages, recordData: [base: @record, length: SIZE[FileLogRecord[writePages]], rest: @dataBlock]]; END; LogReadPages: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc, where: LONG POINTER, pageRun: PageRun, recordID: LogRecordID] RETURNS [referencePattern: ReferencePattern] = BEGIN did: YggEnvironment.DID; header: FileLogRecord[writePages]; status: YggLog.ReadProcStatus; [status: status] _ YggLog.Read[thisRecord: recordID, to: [base: @header, length: SIZE[FileLogRecord[writePages]]]]; IF status=sourceExhausted THEN ERROR; -- wrong length log record did _ YggOpenDoc.GetDID[openDoc]; IF LookupIDInMap[did: did] # header.fileID THEN ERROR; -- wrong file IF pageRun.firstPageheader.pageRun.firstPage+header.pageRun.count THEN ERROR; -- pageRun is not a subinterval of the one contained in the log record [status: status] _ YggLog.Read[thisRecord: recordID, wordsToSkip: SIZE[FileLogRecord[writePages]] + CARDINAL[pageRun.firstPage-header.pageRun.firstPage] * YggEnvironment.wordsPerPage, to: [base: where, length: pageRun.count * YggEnvironment.wordsPerPage]]; IF status=sourceExhausted THEN ERROR; -- log record not as long as it says it is RETURN [header.referencePattern]; END; LogFileLock: PUBLIC PROCEDURE [openDoc: YggOpenDoc.OpenDoc] = BEGIN did: YggEnvironment.DID; lockSubID: YggFileLockFormat.FileLockSubID = [file[]]; record: FileLogRecord[lock] _ [fileID: NULL, specifics: lock [lockSubID: LOOPHOLE[lockSubID]]]; record.fileID _ LookupIDInMap[did: YggOpenDoc.GetDID[openDoc]]; IF record.fileID = 0 THEN record.fileID _ StoreDIDInMaps[did: did, id: 0]; [] _ YggLog.Write[trans: YggOpenDoc.GetTransHandle[openDoc], logRecordPhaseType: redo, recordType: lock, recordData: [base: @record, length: SIZE[FileLogRecord[lock]]]]; END; <> FileAnalysisProc: YggLogControl.AnalysisProc --[record, type, trans]-- = TRUSTED BEGIN header: FileLogRecord; wordsRead: CARDINAL; exists: BOOLEAN _ TRUE; status: YggLog.ReadProcStatus; IF type NOT IN DefinedFileRecord THEN ERROR; <> [status, wordsRead] _ YggLog.ReadForRecovery[ thisRecord: record, to: [base: @header, length: SIZE[FileLogRecord]]]; IF status = destinationFull THEN ERROR; IF wordsRead BEGIN fileHandle: YggDIDMap.Document _ YggDIDMap.Register[did: LookupDIDInMap[header.fileID]]; ssl: SetSizeList _ CONS[[r.old, r.new, trans, record, fileHandle], NARROW[YggDIDMap.GetRecoveryData[fileHandle]]]; IF wordsRead NULL; END; FileRecoveryProc: YggLog.RecoveryProc --[record, type, trans, outcome]-- = TRUSTED BEGIN openDoc: YggOpenDoc.OpenDoc; header: FileLogRecord; wordsRead: CARDINAL; exists: BOOLEAN _ TRUE; IF type NOT IN DefinedFileRecord THEN ERROR; <> [wordsRead: wordsRead] _ YggLog.ReadForRecovery[thisRecord: record, to: [base: @header, length: SIZE[FileLogRecord]]]; IF wordsRead> <<[] _ YggFilePageMgr.GetSize[YggOpenDoc.GetDocHandle[openDoc] !>> < {exists _ FALSE; CONTINUE};>> <> < {IF type=delete THEN {exists _ FALSE; CONTINUE} ELSE REJECT}>> <<];>> IF exists THEN WITH r: header SELECT type FROM create => BEGIN <> <> <> <<{c _ r.owner.text[index]; index _ index+1};>> <> IF wordsRead> RecoverCreate[openDoc: openDoc, initialSize: r.initialSize, outcome: outcome]; END; delete => BEGIN IF wordsRead BEGIN IF wordsRead BEGIN IF wordsRead BEGIN IF wordsRead ERROR; <> YggOpenDoc.SetMaxDeltaVersion[openDoc, 1]; YggOpenDoc.Unregister[openDoc]; END; < log ID mapping.>> <> <<>> <<>> ROPE: TYPE ~ Rope.ROPE; DID: PUBLIC TYPE ~ REF DIDRep; DIDRep: PUBLIC TYPE ~ ROPE; <> didToIDMap: SymTab.Ref _ NIL; idToDIDMap: CardTab.Ref _ NIL; nextID: CARD _ 1000; LookupIDInMap: ENTRY PROC [did: DID] RETURNS [id: CARD _ 0] ~ { <> found: BOOL; val: REF; DO [found, val] _ SymTab.Fetch[x: didToIDMap, key: did^]; IF found THEN { entry: REF CARD; entry _ NARROW[val]; RETURN[entry^]; }; ENDLOOP; }; <<>> <<>> LookupDIDInMap: ENTRY PROC [id: CARD] RETURNS [did: DID _ NIL] ~ { <> found: BOOL; val: REF; DO [found, val] _ CardTab.Fetch[x: idToDIDMap, key: id]; IF found THEN { entry: DIDRep; entry _ NARROW[val]; did _ NEW[DIDRep]; did^ _ entry; }; ENDLOOP; }; <<>> <<>> StoreDIDInMaps: ENTRY PROC [did: DID, id: CARD] RETURNS [idUsed: CARD]~ { <> IF id = 0 THEN {idUsed _ nextID; nextID _ nextID + 1;} ELSE idUsed _ id; [] _ SymTab.Store[x: didToIDMap, key: did^, val: NEW[CARD _ idUsed]]; [] _ CardTab.Store[x: idToDIDMap, key: idUsed, val: NEW[ROPE _ did^]]; }; <<>> <<>> <<>> <> FOR type: DefinedFileRecord IN DefinedFileRecord DO YggLog.RegisterRecoveryProc[type, FileRecoveryProc]; ENDLOOP; YggLogControl.RegisterAnalysisProc[setSize, FileAnalysisProc]; didToIDMap _ SymTab.Create[mod: 129, case: TRUE]; idToDIDMap _ CardTab.Create[mod: 129]; END. <> <> <> <> <<>> <<>>