-- 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 PROCESS _ NIL; [] _ 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[]; transHandle _ AT.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]; universalFile _ refUniversalFile^; 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]]; list _ volumes; 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.UniversalFile _ transLogData.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 "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.