BackupLogImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Carl Hauser, March 12, 1986 4:16:42 pm PST
DIRECTORY
AlpineEnvironment,
AlpineLog,
BackupLog,
Basics,
FS,
IO,
LogBasic,
LogInline,
LogRep,
Rope,
Worker;
BackupLogImpl: CEDAR MONITOR
IMPORTS
FS,
IO,
LogInline
EXPORTS
BackupLog
= BEGIN
OPEN
BackupLog;
VolumeID: TYPE = AlpineEnvironment.VolumeID;
FileID: TYPE = AlpineEnvironment.FileID;
FileStore: TYPE = AlpineEnvironment.FileStore;
TransID: TYPE = AlpineEnvironment.TransID;
nullTransID: TransID = AlpineEnvironment.nullTransID;
PageNumber: TYPE = AlpineEnvironment.PageNumber;
PageCount: TYPE = AlpineEnvironment.PageCount;
WordNumber: TYPE = LogBasic.WordNumber;
WordCount: TYPE = LogBasic.WordCount;
RecordID: TYPE = AlpineLog.RecordID;
nullRecordID: RecordID = AlpineLog.nullRecordID;
Block: TYPE = AlpineLog.Block;
RecordType: TYPE = AlpineLog.RecordType;
wordsPerPage: CARDINAL = AlpineEnvironment.wordsPerPage;
ClientProgrammingError: ERROR = CODE;
InternalProgrammingError: ERROR = CODE;
backupLog: IO.STREAM;
startBackupID: RecordID;
logStreamOptions: FS.StreamOptions = [
tiogaRead: FALSE,
commitAndReopenTransOnFlush: FALSE,
truncatePagesOnClose: FALSE,
finishTransOnClose: FALSE,
closeFSOpenFileOnClose: TRUE
];
RecordIDRecord: TYPE = MACHINE DEPENDENT RECORD [
pad: [0..1] ← 0,
type: RecordType ← logRecordID,
recordID: RecordID ← TRASH
];
OpenForNormalOperation: PUBLIC PROC [backupLogName: Rope.ROPE, initialPosition: RecordID] ~ TRUSTED {
recordIDRecord: RecordIDRecord;
backupLog ← FS.StreamOpen[ fileName: backupLogName, accessOptions: $write, streamOptions: logStreamOptions, streamBufferParms: [vmPagesPerBuffer: 64, nBuffers: 2], remoteCheck: FALSE];
Check the first record to see that it really is a RecordIDRecord.
IF backupLog.UnsafeGetBlock[block: MakeBlock[@recordIDRecord, (RecordIDRecord.SIZE)*2]] # (RecordIDRecord.SIZE)*2 THEN ERROR InternalProgrammingError;
IF recordIDRecord.type # logRecordID THEN ERROR InternalProgrammingError;
startBackupID ← recordIDRecord.recordID;
Now position as requested.
backupLog.SetIndex[LogInline.WordsFromSubtract[initialPosition, startBackupID]*2];
};
MakeBlock: PROC [base: LONG POINTER, count: CARDINAL] RETURNS [Basics.UnsafeBlock] ~
TRUSTED INLINE {
RETURN[ [base: LOOPHOLE[base, LONG POINTER TO Basics.RawBytes], count: count] ];
};
BackupLog.Format
Format: PUBLIC PROC [backupLogName: Rope.ROPE, pages: INT, firstRecordID: RecordID] RETURNS[firstUsableRecordID: RecordID] = TRUSTED {
recordIDRecord: RecordIDRecord ← [recordID: firstRecordID];
openFile: FS.OpenFile;
openFile ← FS.Create[name: backupLogName, pages: pages, setKeep: TRUE, keep: 1];
backupLog ← FS.StreamFromOpenFile[ openFile: openFile, accessRights: $write, streamOptions: logStreamOptions, streamBufferParms: [vmPagesPerBuffer: 64, nBuffers: 2]];
[] ← Write[recordData: [base: @recordIDRecord, length: RecordIDRecord.SIZE], force: TRUE];
Force[];
backupLog.Close[];
RETURN[LogInline.AddLC[firstRecordID, RecordIDRecord.SIZE]];
};
Force: PUBLIC PROC [] = {
backupLog.Flush[];
};
BackupLog.Write
Write: PUBLIC UNSAFE PROC [continuation: BOOLFALSE, recordData: BackupLog.Block, force: BOOL] RETURNS [followingRecord: RecordID] = TRUSTED {
FOR b: LONG POINTER TO BackupLog.Block ← @recordData, b.rest WHILE b # NIL DO
backupLog.UnsafePutBlock[block: MakeBlock[b.base, b.length*2]];
ENDLOOP;
followingRecord ← LogInline.AddLC[startBackupID, backupLog.GetIndex/2];
};
RecordIDOfNextWrite: PUBLIC PROC [] RETURNS [RecordID] = TRUSTED {
RETURN [LogInline.AddLC[startBackupID, backupLog.GetIndex/2]];
};
recoveryLog: IO.STREAM;
startRecoveryID: RecordID;
OpenForRecovery: PUBLIC PROC [backupLogName: Rope.ROPE] RETURNS [firstRecord: RecordID] ~ TRUSTED {
recordIDRecord: RecordIDRecord;
recoveryLog ← FS.StreamOpen[ fileName: backupLogName, accessOptions: $read, streamOptions: logStreamOptions, streamBufferParms: [vmPagesPerBuffer: 64, nBuffers: 2], remoteCheck: FALSE];
Check the first record to see that it really is a RecordIDRecord.
IF recoveryLog.UnsafeGetBlock[block: MakeBlock[@recordIDRecord, 2*(RecordIDRecord.SIZE)]] # 2*(RecordIDRecord.SIZE) THEN ERROR InternalProgrammingError;
IF recordIDRecord.type # logRecordID THEN ERROR InternalProgrammingError;
Read the first record to find the starting RecordID in this backup log file
startRecoveryID ← recordIDRecord.recordID;
firstRecord ← LogInline.AddLC[startRecoveryID, RecordIDRecord.SIZE];
};
BackupLog.Read
Read: PUBLIC ReadProc = TRUSTED {
bytesRead: INT;
recoveryLog.SetIndex[
LogInline.WordsFromSubtract[thisRecord, startRecoveryID]*2 + 2*wordsToSkip];
bytesRead ← recoveryLog.UnsafeGetBlock[
block: MakeBlock[ to.base, to.length*2]];
wordsRead ← bytesRead / 2;
status ← SELECT TRUE FROM
wordsRead = to.length => normal,
wordsRead < to.length => sourceExhausted,
ENDCASE => destinationFull; -- shouldn't occur;
};
Close: PUBLIC PROC [] RETURNS [] ~ {
IF recoveryLog # NIL THEN recoveryLog.Close[];
IF backupLog # NIL THEN {
Force[];
backupLog.Close[];
backupLog ← NIL;
};
};
END.
CHANGE LOG