-- OldTransactionTestImpl.mesa
-- Last edited by
-- Kolling on May 13, 1983 1:42 pm


DIRECTORY

AlpineEnvironment
USING[bytesPerPage, FileID, FileStore, nullFileID, nullTransID, nullVolumeGroupID,
nullVolumeID, OwnerName, OwnerPropertyValuePair, PageCount, PageNumber,
PageRun, Principal, PropertyValuePair, TransID, UniversalFile, VolumeGroupID,
VolumeID, wordsPerPage],
AlpFile
USING[Close, Create, Delete, GetAccessRights, GetLockOption,
GetRecoveryOption, GetReferencePattern, GetSize, Handle,
IncrementVersion, Open, ReadPages, ReadProperties, SetLockOption,
SetReferencePattern, SetSize, UnlockPages, UnlockVersion, VALUEPageBuffer,
WritePages, WriteProperties],
AlpInstance
USING[Create, Handle, OperationFailed, Unknown],
AlpTransaction
USING[AssertAlpineWheel, Create, CreateOwner, DestroyOwner, Finish,
GetEnclosingVolumeGroup, GetNextVolumeGroup, GetVolumeGroup, Handle,
ReadNextOwner, ReadOwnerDBProperties, ReadOwnerProperties,
ReorganizeOwnerDB, WriteOwnerProperties],
AlpineInterimDirectory
USING[OpenUnderTrans],
Process
USING[Detach],
RandomCard
USING[Choose, Init, Next],
Rope
USING[Cat, Equal, ROPE],
RPC
USING[CallFailed, EncryptionKey, MakeKey],
System
USING
[GetGreenwichMeanTime, SecondsSinceEpoch],
UserCredentials
USING[GetUserCredentials];


OldTransactionTestImpl: MONITOR
IMPORTS AF: AlpFile, AI: AlpInstance, AT: AlpTransaction,
AlpineInterimDirectory, Process, RandomCard, RPC, Rope, System, UserCredentials =


BEGIN OPEN AE: AlpineEnvironment;


NullUniversalFile: AE.UniversalFile = [AE.nullVolumeID, AE.nullFileID];

TransLogData: TYPE = MACHINE DEPENDENT RECORD[
transID(0): AE.TransID,
timeStamp(SIZE[AE.TransID]): LONG CARDINAL,
nFileStates(SIZE[AE.TransID] + SIZE[LONG CARDINAL]): CARDINAL,
fileStates(SIZE[AE.TransID] + SIZE[LONG CARDINAL] + SIZE[CARDINAL]):
ARRAY [0..MaxFilesPerTransaction) OF FileState,
padding(SIZE[AE.TransID] + SIZE[LONG CARDINAL] + SIZE[CARDINAL] + SIZE[ARRAY
[0..MaxFilesPerTransaction) OF FileState]):
ARRAY [SIZE[AE.TransID] + SIZE[LONG CARDINAL] + SIZE[CARDINAL]
+ SIZE[ARRAY[0..MaxFilesPerTransaction) OF FileState]..AE.wordsPerPage) OF UNSPECIFIED
];

FileState
: TYPE = RECORD[
universalFile: AE.UniversalFile,
fileHandle: AF.Handle, -- for convenience.
fileSize: AE.PageCount,
nPageRunStates: NAT,
pageRunStates: ARRAY [0..MaxPageRunStatesPerFile) OF PageRunState];

PageRunState: TYPE = RECORD[
pageRun: AE.PageRun ← [0, 0],
seed: CARDINAL ← 0];

CompileTimeCheck: [AE.wordsPerPage..AE.wordsPerPage] = SIZE[TransLogData];


TransRunningData: TYPE = RECORD[transHandle: AT.Handle, historyFileHandle: AF.Handle,
pageNumber: AE.PageNumber, refTransLogData: REF TransLogData];

ListTransRunningDataSet
: TYPE = LIST OF TransRunningData;


DoTest: PROCEDURE[seed: CARDINAL] =
BEGIN

processes: LIST OF PROCESSNIL;
[] ← RandomCard.Init[seed];
-- if we error out of here, call CheckConsistency.
FOR
index: NAT IN [0..nNormalTransactionsThisTest)
DO

processes ← CONS[FORK DoTransSet[StartNewTransactionSet[1], RandomCard.Next[]],
processes];
Process.Detach[processes.first];
ENDLOOP;
FOR index: NAT IN [0..nSharingTransactionSetsThisTest)
DO

processes ← CONS[FORK DoTransSet[StartNewTransactionSet[
nTransPerSharingSetThisTest], RandomCard.Next[]]];
Process.Detach[processes.first];
ENDLOOP;
CheckConsistency[alreadyChecked: FALSE];
END;



StartNewTransactionSet: PROCEDURE[nTrans: NAT] RETURNS[listTransRunningDataSet:
ListTransRunningDataSet] =
BEGIN
pageNumber: AE.PageNumber;
transHandle: AT.Handle;
historyFileHandle: AF.Handle;
listTransRunningDataSet ← NIL;
FOR
index: CARDINAL IN [0..nTrans)
DO pageNumber ← GetNewPageInHistoryLog[];
transHandleAT.Create[instHandle, TRUE
! AI.OperationFailed => RETRY;
RPC.CallFailed => IF why = busy THEN RETRY;];
historyFileHandle ← AF.Open[transHandle: transHandle, universalFile:
historyUniversalFile, access: readWrite, lock: [intendWrite, wait], recoveryOption:
log, referencePattern: random
! RPC.CallFailed => IF why = busy THEN RETRY;].handle;
listTransRunningDataSet ← CONS[[transHandle: transHandle, historyFileHandle:
historyFileHandle, pageNumber: pageNumber,
refTransLogData: NEW[TransLogData ← [transID: transHandle.transID,
timeStamp: 0, nFileStates: 0, fileStates: ALL[[ universalFile: NullUniversalFile,
fileHandle: NIL, fileSize: 0, nPageRunStates: 0, pageRunStates: ALL[[pageRun:
[0, 0], seed: 0]]]], padding: ]]], listTransRunningDataSet];
ENDLOOP;
END;



DoTransSet
: PROCEDURE[listTransRunningDataSet: ListTransRunningDataSet, seed: CARDINAL] =
BEGIN

SetUpTransFilesAndPageRuns[listTransRunningDataSet];
IF listTransRunningDataSet = NIL THEN RETURN;
FOR
list: ListTransRunningDataSet ← listTransRunningDataSet.rest, list.rest
UNTIL list = NIL
DO Process.Detach[FORK DoWrites[list, seed]];
ENDLOOP;
DoWrites[listTransRunningDataSet, seed];
END
;


SetUpTransFilesAndPageRuns
: PROCEDURE[listTransRunningDataSet:
ListTransRunningDataSet] =
BEGIN

listTransRunningDataSet.first.refTransLogData.nFileStates ← nFilesPerTransactionThisTest;
FOR fileIndex: INT IN [0..listTransRunningDataSet.first.refTransLogData.nFileStates)
DO
fileSize: AE.PageCount ← RandomCard.Choose[0, MaxSizeOfFile];
fileHandle: AF.Handle;
universalFile: AE.UniversalFile;
refUniversalFile: REF AE.UniversalFile;
IF listTransRunningDataSet.rest = NIL
THEN BEGIN
[fileHandle, refUniversalFile] ←
AF.Create[listTransRunningDataSet.first.transHandle, volumeID, caller, fileSize, ,
log, random];
universalFilerefUniversalFile^;
END

ELSE BEGIN
scratchTransHandle: AT.Handle AT.Create[instHandle, TRUE ];
[fileHandle, refUniversalFile] ← AF.Create[scratchTransHandle, volumeID, caller,
fileSize, , log, random];
fileHandle.WriteProperties[LIST[[highWaterMark[fileSize]]], [write, wait]];
SELECT
scratchTransHandle.Finish[commit, FALSE] FROM
abort, unknown => ERROR;
ENDCASE;
universalFile ← refUniversalFile^;
fileHandle ← AF.Open[listTransRunningDataSet.first.transHandle,
universalFile, readWrite, [intendWrite, wait], log, random].handle;
END;
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex] ← [
universalFile: universalFile,
fileHandle: fileHandle,
fileSize: fileSize,
nPageRunStates: 0,
pageRunStates: ALL[[pageRun: [0, 0], seed: 0]]];
ENDLOOP
;
SetUpPageRuns[listTransRunningDataSet];
FOR
list: ListTransRunningDataSet ← listTransRunningDataSet.rest, list.rest
UNTIL list = NIL
DO
list.first.refTransLogData.nFileStates ← nFilesPerTransactionThisTest;
FOR fileIndex: INT IN [0..list.first.refTransLogData.nFileStates)
DO
universalFile: AE.UniversalFile ←
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].universalFile;
list.first.refTransLogData.fileStates[fileIndex] ← [
universalFile: universalFile,
fileHandle: AF.Open[list.first.transHandle, universalFile,
readWrite, [intendWrite, wait], log, random].handle,
fileSize: listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].fileSize,
nPageRunStates: 0,
pageRunStates: ALL[[pageRun: [0, 0], seed: 0]]];
ENDLOOP
;
SetUpPageRuns[list];
ENDLOOP;
END
;



SetUpPageRuns
: PROCEDURE[listTransRunningDataSet: ListTransRunningDataSet] =
BEGIN

FOR fileIndex: INT IN [0..listTransRunningDataSet.first.refTransLogData.nFileStates)
DO -- for each file.
nPageRunStates: INT ← RandomCard.Choose[1, nPageRunStatesPerFileThisTest];
lastPageOfFile: AE.PageNumber ←
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].fileSize - 1;
firstPage, lastPage, oldFirstPage, oldLastPage: AE.PageNumber;
pageBeforeFirstPage, pageContigBeforeFirstPage, pageContigAfterLastPage,
pageAfterLastPage: AE.PageNumber;
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].nPageRunStates ←
nPageRunStates;
DO
oldFirstPage ← RandomCard.Choose[0, lastPageOfFile];
oldLastPage ← RandomCard.Choose[oldFirstPage, lastPageOfFile];
IF oldLastPage - oldFirstPage < MaxPageRunSizePerTransaction THEN EXIT;
ENDLOOP;

listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].pageRunStates[0] ←
[[oldFirstPage, oldLastPage - oldFirstPage + 1], RandomCard.Next[]];
FOR
pageRunIndex: INT IN [1..nPageRunStates)
DO
whatToDo: WhatToDo;
DO
pageContigBeforeFirstPage ← IF oldFirstPage = 0 THEN 0 ELSE oldFirstPage - 1;
pageContigAfterLastPage ← IF oldLastPage = lastPageOfFile THEN lastPageOfFile ELSE
oldLastPage + 1;
pageBeforeFirstPage ← IF pageContigBeforeFirstPage = 0 THEN 0 ELSE
pageContigBeforeFirstPage - 1;
pageAfterLastPage ← IF pageContigAfterLastPage = lastPageOfFile THEN
lastPageOfFile ELSE pageContigAfterLastPage + 1;
SELECT
RandomCard.Choose[0, whatToDoCount] FROM
0 => --overlapBefore--
BEGIN firstPage ← RandomCard.Choose[0, pageContigBeforeFirstPage];
lastPage ← RandomCard.Choose[oldFirstPage, oldLastPage];
whatToDo ← overlapBefore;
END;
1 => --overlapAfter--
BEGIN firstPage ← RandomCard.Choose[oldFirstPage, oldLastPage];
lastPage ← RandomCard.Choose[pageContigAfterLastPage, lastPageOfFile];
whatToDo ← overlapAfter;
END;
2 => --subset--
BEGIN firstPage ← RandomCard.Choose[oldFirstPage, oldLastPage];
lastPage ← RandomCard.Choose[firstPage, oldLastPage];
whatToDo ← subset;
END
;
3 => --contiguousBefore--
BEGIN firstPage ← RandomCard.Choose[0, pageContigBeforeFirstPage];
lastPage ← pageContigBeforeFirstPage;
whatToDo ← contiguousBefore;
END
;
4 => --contiguousAfter--
BEGIN firstPage ← pageContigAfterLastPage;
lastPage ← RandomCard.Choose[pageContigAfterLastPage, lastPageOfFile];
whatToDo ← contiguousAfter;
END;
5 => --separateBefore--
BEGIN firstPage ← RandomCard.Choose[0, pageBeforeFirstPage];
lastPage ← RandomCard.Choose[firstPage, pageBeforeFirstPage];
whatToDo ← separateBefore;
END;
6 => --separateAfter--
BEGIN firstPage ← RandomCard.Choose[pageAfterLastPage, lastPageOfFile];
lastPage ← RandomCard.Choose[firstPage, lastPageOfFile];
whatToDo ← separateAfter;
END;
7 => --same--
BEGIN firstPage ← oldFirstPage;
lastPage ← oldLastPage;
whatToDo ← same;
END
;
8 => --random--
BEGIN firstPage ← RandomCard.Choose[0, lastPageOfFile];
lastPage ← RandomCard.Choose[firstPage, lastPageOfFile];
whatToDo ← random;
END
;
9 => --superset--
BEGIN firstPage ← RandomCard.Choose[0, pageContigBeforeFirstPage];
lastPage ← RandomCard.Choose[pageContigAfterLastPage, lastPageOfFile];
whatToDo ← superset;
END;
10 => --completeOverlapBefore--
BEGIN firstPage ← RandomCard.Choose[0, pageContigBeforeFirstPage];
lastPage ← oldLastPage;
whatToDo ← completeOverlapBefore;
END;
11 => --completeOverlapAfter--
BEGIN firstPage ← oldFirstPage;
lastPage ← RandomCard.Choose[pageContigAfterLastPage, lastPageOfFile];
whatToDo ← completeOverlapAfter;
END;
ENDCASE => ERROR;
IF lastPage - firstPage < MaxPageRunSizePerTransaction THEN EXIT;
ENDLOOP
;
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].pageRunStates[
pageRunIndex] ← [[firstPage, lastPage - firstPage + 1], RandomCard.Next[]];
oldFirstPage ← firstPage;
oldLastPage ← lastPage;
ENDLOOP;
ENDLOOP; -- end of for each file.
END
;



Buffer
: TYPE = ARRAY [0..MaxPageRunSizePerTransaction) OF BufferPage;
BufferPage: TYPE = ARRAY [0..AE.wordsPerPage) OF WORD;
WhatToDo: TYPE = {overlapBefore, overlapAfter, subset, contiguousBefore, contiguousAfter, separateBefore, separateAfter, same, random, superset, completeOverlapBefore, completeOverlapAfter};

DoWrites
: PROCEDURE[listTransRunningDataSet: ListTransRunningDataSet, seed:
CARDINAL] =
BEGIN

buffer: REF Buffer ← NEW[Buffer];
FOR
fileIndex: INT IN [0..listTransRunningDataSet.first.refTransLogData.nFileStates)
DO -- for each file.
fileHandle: AF.Handle
listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].fileHandle;
FOR
pageRunIndex: INT IN
[0..listTransRunningDataSet.first.refTransLogData.fileStates[fileIndex].nPageRunStates)
DO
pageRun: AE.PageRun;
seed: CARDINAL;
[pageRun, seed] ← listTransRunningDataSet.first.refTransLogData.fileStates[
fileIndex].pageRunStates[pageRunIndex];
FOR offset: AE.PageNumber IN [0..pageRun.count)
DO buffer[offset][0] ← seed;
buffer[offset][1] ← seed + offset;
ENDLOOP;
fileHandle.WritePages[pageRun, DESCRIPTOR[buffer, pageRun.count*AE.wordsPerPage],
[write, wait]];
ENDLOOP;
UpdateHistoryLogPage[listTransRunningDataSet]; -- keep our trans alive, hopefully.
ENDLOOP;

UpdateHistoryLogPageAndCommitUs[listTransRunningDataSet];
END;




InitializeHistoryFileAndSetTestParams: PROCEDURE[fileStore:
AE.FileStore, nNormalTransactions, nSharingTransactionSets, nTransPerSharingSet: NAT,
nFilesPerTransaction: [1..MaxFilesPerTransaction], nPageRunStatesPerFile:
[1..MaxPageRunStatesPerFile]] =
BEGIN

transHandle: AT.Handle;
historyFileHandle: AF.Handle;
createdHistoryFile: BOOLEAN;
nNormalTransactionsThisTest ← nNormalTransactions;
nSharingTransactionSetsThisTest ← nSharingTransactionSets;
nTransPerSharingSetThisTest ← nTransPerSharingSet;
nFilesPerTransactionThisTest ← nFilesPerTransaction;
nPageRunStatesPerFileThisTest ← nPageRunStatesPerFile;
historyLogNextPageNumber ← 0;
historyLogMaxPageNumber ← nNormalTransactionsThisTest +
(nSharingTransactionSetsThisTest*nTransPerSharingSetThisTest);
IF caller = NIL THEN
BEGIN password: Rope.ROPE;
[caller, password] ← UserCredentials.GetUserCredentials[];
key ← RPC.MakeKey[password];
END;
instHandle ← AI.Create[fileStore, caller, key];
transHandle ← AT.Create[instHandle, TRUE];
transHandle.AssertAlpineWheel[TRUE];
volumeGroupID ← transHandle.GetNextVolumeGroup[AE.nullVolumeGroupID, [none, wait]];
[] ← transHandle.CreateOwner[volumeGroupID: volumeGroupID, owner:
caller, properties: LIST[[quota[1000]]], enforceTotalQuota: TRUE
! AI.OperationFailed => IF why = duplicateOwner THEN CONTINUE];
[historyUniversalFile, createdHistoryFile] ←
AlpineInterimDirectory.OpenUnderTrans[transHandle,
Rope.Cat["[", fileStore, "]<", caller, ">", "TransactionTest.HistoryFile"], none,
(historyLogMaxPageNumber*AE.bytesPerPage)];
volumeID ← historyUniversalFile.volumeID;
historyFileHandle ← AF.Open[transHandle: transHandle, universalFile:
historyUniversalFile, access: readWrite, lock:
[write, wait], recoveryOption: log, referencePattern: random].handle;
IF (NOT createdHistoryFile)
THEN historyFileHandle.SetSize[historyLogMaxPageNumber, [write, wait]];
EraseHistoryFile[historyFileHandle];
-- test a bunch of stuff in the alppackage:
BEGIN
volumes: LIST OF AE.VolumeID ← NIL;
list: LIST OF AE.VolumeID ← NIL;
owner: AE.OwnerName ← NIL;
ownerProperties: LIST OF AE.OwnerPropertyValuePair;
nOwners, nEntriesUsed, nEntries: NAT;
totalQuota, totalSpaceInUse, volumeGroupSize: AE.PageCount;
properties: LIST OF AE.PropertyValuePair;
IF Rope.Equal[fileStore, "local.alpine", FALSE]
THEN transHandle.ReorganizeOwnerDB[volumeGroupID, 20];
ownerProperties ← transHandle.ReadOwnerProperties[volumeGroupID, caller, ];
transHandle.WriteOwnerProperties[volumeGroupID, caller, FALSE, NIL];
[nOwners, nEntriesUsed, nEntries, totalQuota, totalSpaceInUse, volumeGroupSize] ←
transHandle.ReadOwnerDBProperties[volumeGroupID];
--IF (nOwners < 1) OR (nEntriesUsed < 1) OR (nEntries < 1) THEN ERROR;
DO
[owner, ownerProperties] ← transHandle.ReadNextOwner[volumeGroupID, owner, ];
IF owner = NIL THEN ERROR;
IF
Rope.Equal[owner, caller, FALSE] THEN EXIT;
ENDLOOP
;
IF historyLogMaxPageNumber # historyFileHandle.GetSize[] THEN ERROR;
IF historyFileHandle.GetAccessRights # readWrite THEN ERROR;
--IF
historyFileHandle.GetLockOption # [write, wait] THEN ERROR;
IF
historyFileHandle.GetRecoveryOption # log THEN ERROR;
IF
historyFileHandle.GetReferencePattern # random THEN ERROR;
properties ← historyFileHandle.ReadProperties[[owner: TRUE]];
owner ← NARROW[properties.first, AE.PropertyValuePair.owner].owner;
IF NOT
Rope.Equal[owner, caller, FALSE] THEN ERROR;
historyFileHandle.SetReferencePattern[sequential];
IF
historyFileHandle.GetReferencePattern # sequential THEN ERROR;
historyFileHandle.UnlockPages[[0, 1]];
historyFileHandle.SetLockOption[[read, wait]];
IF
historyFileHandle.GetLockOption # [write, wait] THEN ERROR;
historyFileHandle.IncrementVersion[2];
historyFileHandle.UnlockPages[[0, 1]];
historyFileHandle.UnlockVersion;
BEGIN

transHandle.DestroyOwner[volumeGroupID, "badname"
! AI.Unknown => IF what = owner THEN GOTO okay];
ERROR;
EXITS
okay => NULL;
END;
volumes ← transHandle.GetVolumeGroup[volumeGroupID, [none, wait]];
listvolumes;
DO
IF
list = NIL THEN ERROR;
IF
list.first = volumeID THEN EXIT;
list ← list.rest;
ENDLOOP;
IF
volumeGroupID # transHandle.GetEnclosingVolumeGroup[volumeID, ] THEN ERROR;
END
;
-- end of extra alppackage test.
SELECT transHandle.Finish[commit, FALSE] FROM
abort, unknown => ERROR;
ENDCASE;
END;


EraseHistoryFile: PROCEDURE[historyFileHandle: AF.Handle] =
BEGIN

nullTransLogData: TransLogData ← [transID: AE.nullTransID, timeStamp: 0,
nFileStates: 0, fileStates: ALL[[universalFile: NullUniversalFile,
fileHandle: NIL, fileSize: 0, nPageRunStates: 0, pageRunStates: ALL[[pageRun: [0, 0], seed:
0]]]], padding: ];
FOR pageNumber: AE.PageNumber IN [0..historyLogMaxPageNumber)
DO historyFileHandle.WritePages[[pageNumber, 1], DESCRIPTOR[@nullTransLogData,
AE.wordsPerPage], [write, wait]];
ENDLOOP;
END;


CheckConsistency: PROCEDURE[alreadyChecked: BOOLEAN] =
BEGIN

transHandle: AT.Handle;
historyFileHandle: AF.Handle;
buffer: BufferPage;
transLogData: TransLogData;
BEGIN
ENABLE
AI.Unknown => IF ((what = transID) OR (what = openFileID)) THEN RETRY;
transHandle ← AT.Create[instHandle, TRUE
! AI.OperationFailed => IF why = busy THEN RETRY;
RPC.CallFailed => IF why = busy THEN RETRY;];
historyFileHandle ← AF.Open[transHandle: transHandle, universalFile: historyUniversalFile,
access: readWrite, lock: [write, wait], recoveryOption: log, referencePattern: random
! RPC.CallFailed => IF why = busy THEN RETRY].handle;
regFiles ← NIL;
FOR historyPageNumber: AE.PageNumber IN [0..historyLogMaxPageNumber)
DO
historyFileHandle.ReadPages[[historyPageNumber, 1], DESCRIPTOR[@transLogData,
AE.wordsPerPage], [write, wait]
! RPC.CallFailed => IF why = busy THEN RETRY];
IF transLogData.transID = AE.nullTransID THEN LOOP;
IF
transLogData.timeStamp = 0 THEN ERROR;
FOR
fileIndex: INT DECREASING IN [0..transLogData.nFileStates)
DO
universalFile: AE.UniversalFiletransLogData.fileStates[fileIndex].universalFile;
fileHandle: AF.Handle;
IF NOT alreadyChecked
THEN
fileHandle ← AF.Open[transHandle: transHandle, universalFile: universalFile,
access: readWrite, lock: [write, wait], recoveryOption: log, referencePattern:
random
! RPC.CallFailed => IF why = busy THEN RETRY].handle;
FOR
pageRunIndex: INT DECREASING IN
[0..transLogData.fileStates[fileIndex].nPageRunStates)
DO
pageRun: AE.PageRun ←
transLogData.fileStates[fileIndex].pageRunStates[pageRunIndex].pageRun;
seed: CARDINAL ← transLogData.fileStates[fileIndex].pageRunStates[pageRunIndex].seed;
FOR pageIndex: AE.PageNumber IN [pageRun.firstPage..pageRun.firstPage +
pageRun.count)
DO
IF NOT alreadyChecked THEN fileHandle.ReadPages[[pageIndex, 1],
DESCRIPTOR[@buffer, AE.wordsPerPage], [write, wait]
! RPC.CallFailed => IF why = busy THEN RETRY];
Register[transLogData.transID, universalFile, pageIndex, transLogData.timeStamp,
((alreadyChecked) OR
((buffer[0] = seed) AND (buffer[1] = (seed + pageIndex - pageRun.firstPage))))];
ENDLOOP;
ENDLOOP;
IF NOT alreadyChecked THEN fileHandle.Close[
! RPC.CallFailed => IF why = busy THEN RETRY];
ENDLOOP;
ENDLOOP
;
historyFileHandle.Close[!
RPC.CallFailed => IF why = busy THEN RETRY;
AI.Unknown => CONTINUE;];
END;


IF NOT alreadyChecked THEN FindBadInRegistry[];
alreadyChecked ← TRUE;

-- deleteFiles.
DO
fileHandle: AF.Handle;
BEGIN
ENABLE
AI.Unknown => IF ((what = transID) OR (what = openFileID)) THEN
BEGIN
transHandle ← AT.Create[instHandle, TRUE
! AI.OperationFailed => IF why = busy THEN RETRY;
RPC.CallFailed => IF why = busy THEN RETRY];
RETRY;
END;
FOR
file: LIST OF RegFile ← regFiles, file.rest
UNTIL
file = NIL
DO

fileHandle ← AF.Open[transHandle: transHandle, universalFile: file.first.universalFile,
access: readWrite, lock: [write, wait], recoveryOption: log, referencePattern:
random].handle;
fileHandle.Delete;
ENDLOOP;

IF transHandle.Finish[commit, FALSE] = commit THEN EXIT;
END;
ENDLOOP;

END;



Register: PROCEDURE[transID: AE.TransID, universalFile: AE.UniversalFile,
pageNumber: AE.PageNumber, timeStamp: LONG CARDINAL, okay: BOOLEAN] =
BEGIN
FOR file: LIST OF RegFile ← regFiles, file.rest
UNTIL
file = NIL
DO

IF universalFile = file.first.universalFile
THEN BEGIN -- found file.
FOR pages: LIST OF RegPages ← file.first.pages, pages.rest
UNTIL pages = NIL
DO
IF pages.first.pageNumber = pageNumber
THEN BEGIN -- found pages.
SELECT TRUE FROM
pages.first.timeStamp > timeStamp => NULL; -- reg better.
pages.first.timeStamp < timeStamp => -- we're better.
pages.first ← [transID, pageNumber, timeStamp, okay];
pages.first.transID = transID => NULL; -- time stamps =; either this
ENDCASE => ERROR; -- is same trans and okay due to
order of calling,
-- or not same trans and not determinable.
RETURN;
END;
ENDLOOP;
file.first.pages ← CONS[[transID, pageNumber, timeStamp, okay], file.first.pages];
RETURN;
END;
ENDLOOP
;
regFiles ← CONS[[universalFile, LIST[[transID, pageNumber, timeStamp, okay]]], regFiles];
END;


FindBadInRegistry: PROCEDURE =
BEGIN
FOR file: LIST OF RegFile ← regFiles, file.rest
UNTIL
file = NIL
DO

FOR pages: LIST OF RegPages ← file.first.pages, pages.rest
UNTIL pages = NIL
DO
IF (NOT pages.first.okay) THEN ERROR;
ENDLOOP;
ENDLOOP;
END;




regFiles: LIST OF RegFile ← NIL;
RegFile: TYPE = RECORD[universalFile: AE.UniversalFile, pages: LIST OF RegPages];
RegPages: TYPE = RECORD[transID: AE.TransID, pageNumber: AE.PageNumber, timeStamp:
LONG CARDINAL, okay: BOOLEAN];

GetNewPageInHistoryLog: ENTRY PROCEDURE RETURNS[pageNumber: AE.PageNumber] =
BEGIN
IF historyLogNextPageNumber >= historyLogMaxPageNumber THEN ERROR;
pageNumber ← historyLogNextPageNumber;
historyLogNextPageNumber ← historyLogNextPageNumber + 1;
RETURN
[pageNumber];
END;


ProbablyTransAborted: ERROR = CODE;


UpdateHistoryLogPage: ENTRY PROCEDURE [listTransRunningDataSet:
ListTransRunningDataSet] =
BEGIN
ENABLE BEGIN
AI.Unknown => IF ((what = openFileID) OR (what = transID))
THEN GOTO transAborted;
RPC.CallFailed => IF why = busy THEN RETRY;
END;
listTransRunningDataSet.first.historyFileHandle.WritePages[[
listTransRunningDataSet.first.pageNumber, 1],
DESCRIPTOR
[@listTransRunningDataSet.first.refTransLogData^, AE.wordsPerPage],
[write, wait]];
EXITS transAborted => RETURN WITH ERROR ProbablyTransAborted;
END
;



UpdateHistoryLogPageAndCommitUs
: ENTRY PROCEDURE [listTransRunningDataSet:
ListTransRunningDataSet] =
BEGIN ENABLE BEGIN
AI.Unknown => IF ((what = openFileID) OR (what = transID))
THEN GOTO transAborted;
RPC.CallFailed => IF why = busy THEN RETRY;
END;
listTransRunningDataSet.first.refTransLogData.timeStamp ←
System.SecondsSinceEpoch[System.GetGreenwichMeanTime[]];
listTransRunningDataSet.first.historyFileHandle.WritePages[[
listTransRunningDataSet.first.pageNumber, 1],
DESCRIPTOR
[@listTransRunningDataSet.first.refTransLogData^, AE.wordsPerPage], [write,
wait]];
listTransRunningDataSet.first.historyFileHandle.Close[];
[] ← listTransRunningDataSet.first.transHandle.Finish[commit, FALSE];
EXITS
transAborted => ERROR ProbablyTransAborted;
END
;




-- starting up: the history file is "<caller>TransactionTest.HistoryFile".

StartTestFromScratch: PROCEDURE[newCaller: AE.Principal ← NIL, --newKey: RPC.EncryptionKey
--ALL[0], -- fileStore: AE.FileStore, nNormalTransactions, nSharingTransactionSets,
nTransPerSharingSet: NAT, nFilesPerTransaction: [1..MaxFilesPerTransaction],
nPageRunStatesPerFile: [1..MaxPageRunStatesPerFile], initialSeed:
INT] =
BEGIN

caller ← newCaller;
--key ← newKey;
InitializeHistoryFileAndSetTestParams[fileStore, nNormalTransactions,
nSharingTransactionSets, nTransPerSharingSet, nFilesPerTransaction,
nPageRunStatesPerFile];
DoTest[initialSeed];
END
;



volumeID: AE.VolumeID;
volumeGroupID: AE.VolumeGroupID;
caller: AE.Principal;
key:
RPC.EncryptionKey;
historyUniversalFile
: AE.UniversalFile;

instHandle: AI.Handle;

nNormalTransactionsThisTest: NAT ← 1;
nSharingTransactionSetsThisTest: NAT ← 1;
nTransPerSharingSetThisTest: NAT ← 3;
nFilesPerTransactionThisTest: [1..MaxFilesPerTransaction] ← 4;
nPageRunStatesPerFileThisTest: [1..MaxPageRunStatesPerFile] ← 8;

MaxFilesPerTransaction: NAT = 4;
MaxPageRunStatesPerFile
: NAT = 8;
MaxPageRunSizePerTransaction
: NAT = 15;
MaxSizeOfFile: NAT = 300;


historyLogNextPageNumber: AE.PageNumber ← 0;
historyLogMaxPageNumber: AE.PageNumber ← 0;

whatToDoCount: NAT ← 0;

FOR whatToDo: WhatToDo IN [WhatToDo.FIRST..WhatToDo.LAST)
DO
whatToDoCount ← whatToDoCount + 1;
ENDLOOP;



END.


Edit Log

Initial: Kolling: March 28, 1983 2:26 pm: test for Alpine.