<> <> <<>> <> <> <> <> <<>> <<>> <> <<1. Do VolumeGroup locks need to be recovered?>> <<>> DIRECTORY AlpineEnvironment, AlpineInternal, FileInstance, FileLock, FileLockFormat, FileLog, Lock, SkiPatrolHooks USING[TransIDFromTransHandle], SkiPatrolLog USING[LockConflictInfo, notice], TransactionMap; FileLockImpl: MONITOR <> IMPORTS FileInstance, Lock, SkiPatrolHooks, SkiPatrolLog EXPORTS FileLock, FileLog = BEGIN OPEN FileLock, FileLockFormat; VolumeID: TYPE = AlpineEnvironment.VolumeID; FileID: TYPE = AlpineEnvironment.FileID; LockIDRep: TYPE = RECORD [v: VolumeID, f: INT, fSub: FileLockSubID]; MakeLockID: PROC [file: AlpineInternal.FileInstanceHandle, fileLockSubID: FileLockSubID] RETURNS [lockID: AlpineInternal.LockID] = { vID: VolumeID; fID: FileID; [vID, fID] _ FileInstance.GetVolumeIDAndFileID[file]; RETURN [[LOOPHOLE[vID], LOOPHOLE[fID.id], LOOPHOLE[fileLockSubID]]] }; TransIDFromFileInstance: PROC [fileInstance: FileInstance.Handle] RETURNS [AlpineEnvironment.TransID] = { RETURN [SkiPatrolHooks.TransIDFromTransHandle[FileInstance.GetTransHandle[fileInstance]]] }; <> AcquireFileLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, requested: LockOption, minimum: LockMode] = BEGIN newFileMode: LockMode; requested.mode _ Lock.Sup[requested.mode][minimum]; <> newFileMode _ Lock.Set[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [file[]]], mode: requested.mode, wait: requested.ifConflict=wait ! Lock.Failed => { -- Log the error and let the error propagate. logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.AcquireFileLock", transID: TransIDFromFileInstance[fileInstance], mode: requested.mode, message: "" ]] } ]; SetLockMode[fileInstance, newFileMode]; END; ReleaseFileLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle] = BEGIN <> UnlockAndSetResultingLockMode[ fileInstance: fileInstance, lockID: MakeLockID[fileInstance, [file[]]], releasable: ALL[yes]]; END; AcquirePageLocks: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, pageRun: PageRun, requested: LockOption, minimum: AssertedPageLock] = BEGIN existingFileMode: LockMode = FileInstance.GetLockMode[fileInstance]; IF requested.mode NOT IN AssertedPageLock THEN requested.mode _ minimum; requested.mode _ Lock.Sup[requested.mode][minimum]; <> IF Lock.Sup[requested.mode][existingFileMode] # existingFileMode THEN BEGIN minFileMode: LockMode = minIntention[requested.mode]; IF Lock.Sup[minFileMode][existingFileMode] # existingFileMode THEN <> AcquireFileLock[fileInstance: fileInstance, requested: [minFileMode, requested.ifConflict], minimum: minFileMode]; <> FOR page: PageNumber IN [pageRun.firstPage .. pageRun.firstPage+pageRun.count) DO [] _ Lock.Set[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [page[page]]], mode: requested.mode, wait: requested.ifConflict=wait ! Lock.Failed => { <> logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.AcquirePageLocks", transID: TransIDFromFileInstance[fileInstance], mode: requested.mode, message: "trying to lock a run of pages" ]]; IF page#pageRun.firstPage THEN ReleasePageLocks[fileInstance: fileInstance, pageRun: [firstPage: pageRun.firstPage, count: page-pageRun.firstPage], mode: requested.mode] } ]; ENDLOOP; END; END; ReleasePageLocks: PUBLIC PROCEDURE [ fileInstance: FileInstance.Handle, pageRun: PageRun, mode: LockMode _ read] = BEGIN releasable: Lock.ModeReleasableSet _ ALL [no]; releasable[mode] _ yes; FOR page: PageNumber IN [pageRun.firstPage .. pageRun.firstPage+pageRun.count) DO [] _ Lock.Release[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [page[page]]], releasable: releasable ! Lock.Error => CONTINUE]; ENDLOOP; END; AcquirePropertyLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, property: Property, requested: LockOption, minimum: AssertedPageLock] = BEGIN existingFileMode: LockMode = FileInstance.GetLockMode[fileInstance]; IF requested.mode NOT IN AssertedPageLock THEN requested.mode _ minimum; requested.mode _ Lock.Sup[requested.mode][minimum]; <> IF Lock.Sup[requested.mode][existingFileMode] # existingFileMode THEN BEGIN minFileMode: LockMode = minIntention[requested.mode]; IF Lock.Sup[minFileMode][existingFileMode] # existingFileMode THEN <> AcquireFileLock[fileInstance: fileInstance, requested: [minFileMode, requested.ifConflict], minimum: minFileMode]; <> [] _ Lock.Set[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [property[property: IF property=version THEN version ELSE other]]], mode: requested.mode, wait: requested.ifConflict=wait ! Lock.Failed => { -- Log the error and let the error propagate. logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.AcquirePropertyLock", transID: TransIDFromFileInstance[fileInstance], mode: requested.mode, message: "" ]] } ]; END; END; ReleasePropertyLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, property: Property, mode: LockMode _ read] = BEGIN releasable: Lock.ModeReleasableSet _ ALL [no]; releasable[mode] _ yes; [] _ Lock.Release[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [property[property: IF property=version THEN version ELSE other]]], releasable: releasable ! Lock.Error => CONTINUE]; END; AcquireSizeLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, requested: LockOption, minimum: AssertedPageLock] = BEGIN existingFileMode: LockMode = FileInstance.GetLockMode[fileInstance]; IF requested.mode NOT IN AssertedPageLock THEN requested.mode _ minimum; requested.mode _ Lock.Sup[requested.mode][minimum]; <> IF Lock.Sup[requested.mode][existingFileMode] # existingFileMode THEN BEGIN minFileMode: LockMode = minIntention[requested.mode]; IF Lock.Sup[minFileMode][existingFileMode] # existingFileMode THEN <> AcquireFileLock[fileInstance: fileInstance, requested: [minFileMode, requested.ifConflict], minimum: minFileMode]; <> [] _ Lock.Set[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, [size[]]], mode: requested.mode, wait: requested.ifConflict=wait ! Lock.Failed => { -- Log the error and let the error propagate. logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.AcquireSizeLock", transID: TransIDFromFileInstance[fileInstance], mode: requested.mode, message: "" ]] } ]; END; END; AcquireVolumeGroupLock: PUBLIC PROCEDURE [volumeGroupID: AlpineEnvironment.VolumeGroupID, trans: TransactionMap.Handle, requested: LockOption, minimum: AssertedPageLock] = BEGIN subID: FileLockSubID _ [volumeGroup[]]; IF requested.mode NOT IN AssertedPageLock THEN requested.mode _ minimum; requested.mode _ Lock.Sup[requested.mode][minimum]; [] _ Lock.Set[ trans: trans, lock: [LOOPHOLE[volumeGroupID], LOOPHOLE[LONG[0]], LOOPHOLE[subID]], mode: requested.mode, wait: requested.ifConflict=wait ! Lock.Failed => { -- Log the error and let the error propagate. logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.AcquireVolumeGroupLock", transID: SkiPatrolHooks.TransIDFromTransHandle[trans], mode: requested.mode, message: "" ]] } ]; END; <> RecoverLock: PUBLIC PROCEDURE [fileInstance: FileInstance.Handle, lockSubID: AlpineInternal.LockSubID, outcome: AlpineInternal.TransState] = BEGIN IF outcome=ready THEN BEGIN mode: LockMode _ Lock.Set[ trans: FileInstance.GetTransHandle[fileInstance], lock: MakeLockID[fileInstance, LOOPHOLE[lockSubID]], mode: write, wait: FALSE ! Lock.Failed => { -- Log the error and let the error propagate. logProc: PROC [SkiPatrolLog.LockConflictInfo]; IF (logProc _ SkiPatrolLog.notice.lockConflict) # NIL THEN logProc[[ what: why, -- (conflict or timeout) where: "FileLockImpl.RecoverLock", transID: TransIDFromFileInstance[fileInstance], mode: write, message: "" ]] } ]; SetLockMode[fileInstance, mode]; END; END; <> minIntention: PACKED ARRAY LockMode[none..write] OF LockMode = [none: none, read: intendRead, write: intendWrite, update: intendUpdate]; -- minIntention[r] is the minimum file intention mode for page lock mode r <> <<1. Setting a lock can only raise the lock's strength or leave it the same; it can never weaken it.>> <<2. It is not harmful for the FileInstance.LockMode to record a lock mode weaker than the one which is actually set on the file.>> <<3. Any given caller will release only those locks which it has set; i.e., it will not call Release more times than it has previously called Acquire.>> SetLockMode: ENTRY PROCEDURE [fileInstance: FileInstance.Handle, mode: LockMode] = INLINE BEGIN FileInstance.SetLockMode[fileInstance, mode]; END; UnlockAndSetResultingLockMode: ENTRY PROCEDURE [fileInstance: FileInstance.Handle, lockID: AlpineInternal.LockID, releasable: Lock.ModeReleasableSet] = <> BEGIN ENABLE UNWIND => NULL; FileInstance.SetLockMode[fileInstance, Lock.Release[trans: FileInstance.GetTransHandle[fileInstance], lock: lockID, releasable: releasable]]; END; END. <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> CHANGE LOG <> <> <> <> <> <> <<>>