-- AlpineFile.mesa -- Last edited by -- Taft on January 25, 1983 11:15 am -- MBrown on January 21, 1983 10:39 pm -- Kolling on February 18, 1983 5:40 pm DIRECTORY AlpineEnvironment, File USING [Type], FileTypes USING [tUntypedFile]; AlpineFile: DEFINITIONS = BEGIN AccessList: TYPE = AlpineEnvironment.AccessList; AccessRights: TYPE = AlpineEnvironment.AccessRights; Conversation: TYPE = AlpineEnvironment.Conversation; FileID: TYPE = AlpineEnvironment.FileID; LockOption: TYPE = AlpineEnvironment.LockOption; OpenFileID: TYPE = AlpineEnvironment.OpenFileID; OwnerName: TYPE = AlpineEnvironment.OwnerName; PageCount: TYPE = AlpineEnvironment.PageCount; PageNumber: TYPE = AlpineEnvironment.PageNumber; RecoveryOption: TYPE = AlpineEnvironment.RecoveryOption; ReferencePattern: TYPE = AlpineEnvironment.ReferencePattern; String: TYPE = AlpineEnvironment.String; TransID: TYPE = AlpineEnvironment.TransID; VolOrVolGroupID: TYPE = AlpineEnvironment.VolOrVolGroupID; VolumeID: TYPE = AlpineEnvironment.VolumeID; -- Procedures which create OpenFileIDs Open: PROCEDURE [ conversation: Conversation, transID: TransID, volumeID: VolumeID, fileID: FileID, access: AccessRights ← readOnly, lock: LockOption ← [intendRead, wait], recoveryOption: RecoveryOption ← log, referencePattern: ReferencePattern ← random] RETURNS [openFileID: OpenFileID]; --! AccessFailed {fileRead, fileModify}, LockFailed, OperationFailed {damagedLeaderPage}, -- PossiblyDamaged, StaticallyInvalid, Unknown {volumeID, fileID, transID}; -- Opens an existing file described by volume and file for access under trans, and -- returns an OpenFileID which designates the open file. -- The client is required to be a member of the access control list implied by access -- (readAccess or modifyAccess); and if access=readOnly, the client is restricted to -- read-only operations on that OpenFileID. -- The entire file is locked in lock.mode (a wait or a Lock.Failed can result). -- lock.ifConflict is also remembered and is used when performing certain file actions -- (e.g., Delete) which do not take a LockMode as an argument. standardFile: File.Type = FileTypes.tUntypedFile; Create: PROCEDURE [ conversation: Conversation, transID: TransID, volumeID: VolOrVolGroupID, owner: OwnerName, initialSize: PageCount, type: File.Type ← standardFile, recoveryOption: RecoveryOption ← log, referencePattern: ReferencePattern ← random] RETURNS [openFileID: OpenFileID]; --! AccessFailed {ownerCreate, spaceQuota}, -- OperationFailed {insufficientSpace, reservedType}, StaticallyInvalid, -- Unknown {volumeID, transID, owner}; -- Creates and opens a new file under trans. volumeID may be either a specific -- VolumeID or a VolumeGroupID; in the latter case, the server will choose among -- the volumes of the group. -- The initial size of the file is specified by initialSize; note that this specifies -- the number of data pages, and does not include any file overhead (e.g., leader page). -- The space is charged against owner in the owner data base; the client is required -- to be a member of owner's create access control list, and the allocation must not -- exceed owner's quota. -- The file is created with a Pilot FileType of type, and with Pilot attributes -- immutable=FALSE and temporary=FALSE. All file properties are set to default values, -- which are: byteLength, highWaterMark: 0; createTime: now; readAccess: "World"; -- modifyAccess: "Owner" + owner's create access control list; -- owner: owner specified in call; stringName: empty string; version: 1. -- If the call is successful, returns an OpenFileID with accessRights=readWrite and -- lockOption = [write, fail]. -- Note: for all remaining operations, Unknown[openFileID] may be raised if: -- 1. The OpenFileID is no longer known to Alpine because it has been closed (either -- explicitly or as a result of committing or aborting the transaction). -- 2. The file it refers to has been deleted by this transaction, perhaps using -- a different OpenFileID. -- Procedures which destroy OpenFileIDs Close: PROCEDURE [conversation: Conversation, openFileID: OpenFileID]; --! Unknown {openFileID, transID}; -- Breaks the association between openFileID and its file. The number of simultaneous -- open files permitted on one FileStore is large but not unlimited; clients are -- encouraged to close files which are no longer needed, particularly when referencing -- many files under one transaction. Note that closing a file does not terminate -- the enclosing transaction and does not release any locks on the file; nor does it -- restrict the client's ability to later re-open the file under the same transaction. Delete: PROCEDURE [conversation: Conversation, openFileID: OpenFileID]; --! AccessFailed {handleReadWrite}, LockFailed, Unknown {openFileID, transID}; -- First locks the entire file in update mode; then deletes the file. The file -- must have been opened with access=readWrite. The OpenFileID is made invalid -- by this procedure. Note that, like all destructive update actions, the deletion -- does not occur until the transaction is committed; however, subsequent attempts -- to access the file under this transaction will fail with Unknown[openFileID]. -- The owner's allocation is not credited with the deleted pages until commit time. -- Procedures which access open file state GetVolumeID: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [volumeID: VolumeID]; --! Unknown {openFileID, transID}; GetFileID: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [fileID: FileID]; --! Unknown {openFileID, transID}; GetTransID: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [transID: TransID]; --! Unknown {openFileID, transID}; GetAccessRights: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [access: AccessRights]; --! Unknown {openFileID, transID}; GetLockOption: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [lock: LockOption]; --! Unknown {openFileID, transID}; -- This may return a lock mode stronger than the one with which the file was -- originally opened if operations have been performed which upgrade the lock. -- Such operations may have been performed on either this OpenFileID or some -- other OpenFileID referring to the same file under the same transaction. SetLockOption: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, lock: LockOption]; --! LockFailed, StaticallyInvalid, Unknown {openFileID, transID}; -- This actually changes the file lock, so it may wait or fail according to -- lock.ifConflict. File locks may only be upgraded by this means; attempts -- to downgrade a lock are ignored. GetRecoveryOption: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [recoveryOption: RecoveryOption]; --! Unknown {openFileID, transID}; GetReferencePattern: PROCEDURE [conversation: Conversation, openFileID: OpenFileID] RETURNS [referencePattern: ReferencePattern]; --! Unknown {openFileID, transID}; SetReferencePattern: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, referencePattern: ReferencePattern]; --! StaticallyInvalid, Unknown {openFileID, transID}; -- Note: for operations which reference the contents of a file (data or properties), -- it is possible that several clients may be accessing the file concurrently under -- the same transaction (using the same or different OpenFileIDs). Alpine makes no -- attempt to prevent or adjudicate conflicting access to the same data in this situation, -- except to assure that reads and writes of single individual file pages and properties -- are atomic with respect to each other. -- Procedures which access pages of the file PageRun: TYPE = AlpineEnvironment.PageRun; PageBuffer: TYPE = LONG DESCRIPTOR FOR ARRAY OF WORD; VALUEPageBuffer: TYPE = PageBuffer; RESULTPageBuffer: TYPE = PageBuffer; maxPagesPerRun: CARDINAL = LAST[CARDINAL]/AlpineEnvironment.wordsPerPage; -- This is all that can be described with a DESCRIPTOR (PageBuffer). -- This restriction applies only to ReadPages and WritePages. ReadPages: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, pageRun: PageRun, pageBuffer: RESULTPageBuffer, lock: LockOption ← [read, wait]]; --! OperationFailed {inconsistentDescriptor, nonexistentFilePage}, LockFailed, -- StaticallyInvalid, Unknown {openFileID, transID}; -- Reads data from the pages described by pageRun of the file associated with -- openFileID, and puts it contiguously into client memory in the block described -- by pageBuffer (whose length must be consistent with pageRun.count or else -- OperationFailed[inconsistentDescriptor] is raised). If the entire file is not -- already locked in at least the mode specified by lock, sets locks in that mode -- on the individual pages, and upgrades the file lock to the corresponding -- intention mode if necessary. WritePages: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, pageRun: PageRun, pageBuffer: VALUEPageBuffer, lock: LockOption ← [write, wait]]; --! AccessFailed {handleReadWrite}, LockFailed, -- OperationFailed {nonexistentFilePage}, StaticallyInvalid, Unknown {openFileID, transID}; -- Writes data from client memory in the block described by pageBuffer to the pages -- described by pageRun of the file associated with openFileID. If the entire file -- is not already locked in at least the mode specified by lock, sets locks in that -- mode on the individual pages, and upgrades the file lock to the corresponding -- intention mode if necessary. The file must have been opened with access=readWrite. LockPages: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, pageRun: PageRun, lock: LockOption ← [read, wait]]; --! LockFailed, StaticallyInvalid, Unknown {openFileID, transID}; -- Explicitly sets locks on the specified pages of the file. UnlockPages: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, pageRun: PageRun]; --! StaticallyInvalid, Unknown {openFileID, transID}; -- If the specified pages of the file are locked in a mode no stronger than read, -- then removes those locks. It is the client's responsibility to assure consistency -- of any subsequent operations whose behavior depends on the data which was read -- under those locks. Note that locks are reference-counted and are not -- removed until one UnlockPages has been done for each LockPages or ReadPages -- previously performed on the same pages. Attempts to remove nonexistent locks -- or locks stronger than read are ignored without error indication. File intention -- locks that were set while acquiring the page locks are not released. -- Procedures which access properties of the file Property: TYPE = AlpineEnvironment.Property; PropertyValuePair: TYPE = AlpineEnvironment.PropertyValuePair; PropertySet: TYPE = PACKED ARRAY Property OF FalseBool; FalseBool: TYPE = BOOLEAN ← FALSE; allProperties: PropertySet = ALL [TRUE]; ByteCount: TYPE = AlpineEnvironment.ByteCount; FileVersion: TYPE = AlpineEnvironment.FileVersion; ReadProperties: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, desiredProperties: PropertySet ← allProperties, lock: LockOption ← [read, wait]] RETURNS [properties: LIST OF PropertyValuePair]; --! LockFailed, StaticallyInvalid, Unknown {openFileID, transID}; -- Reads the properties specified by desiredProperties, ordered as in the declaration -- of Property. Locks those properties as specified by lock. Currently, all properties -- with the exception of version are treated together with respect to locking; -- the version has a separate lock. Note that reading the version will prevent -- any other transaction which updates the file from committing, unless the version -- lock is later removed (by UnlockVersion). WriteProperties: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, properties: LIST OF PropertyValuePair, lock: LockOption ← [write, wait]]; --! AccessFailed {handleReadWrite, ownerCreate, spaceQuota}, LockFailed, -- OperationFailed {insufficientSpace, unwritableProperty}, StaticallyInvalid, -- Unknown {openFileID, owner}; -- Writes the supplied properties, after first locking them in the specified mode. -- The type and version properties may not be written by this means. -- To write the byteLength, createTime, highWaterMark, and stringName properties -- requires that the OpenFileID be open with access=readWrite. To write readAccess -- or modifyAccess additionally requires that the client be the file's owner or a -- member of the create access control list for the file's owner. To write owner -- additionally requires that the client be a member of the create access control -- list for the new owner; and the disk space occupied by the file is credited to -- the old owner and charged to the new one. -- If there is insufficient space in the leader page to represent the new properties, -- OperationFailed[insufficientSpace] is raised. Note that if multiple properties -- are written by one call and an error occurs, some of the properties may nevertheless -- have been written successfully. UnlockVersion: PROCEDURE [conversation: Conversation, openFileID: OpenFileID]; --! Unknown {openFileID, transID}; -- Unlocks a read lock previously set on the version property. All comments on -- UnlockPages apply here also. IncrementVersion: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, increment: LONG INTEGER]; --! AccessFailed {handleReadWrite}, StaticallyInvalid, Unknown {openFileID, transID}; -- Arranges that at transaction commit time, increment will be added to the version -- property, instead of 1 or 0 (depending on whether or not the transaction has -- performed any updates to the file). Note that the change in version number -- is not visible, even to the transaction that incremented it, until commit time. GetSize: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, lock: LockOption ← [read, wait]] RETURNS [size: PageCount]; --! LockFailed, Unknown {openFileID, transID}; -- Returns the file's size, after setting a lock on the size property. Note that -- the returned value is the number of data pages, and does not include any file -- overhead (e.g., leader page). SetSize: PROCEDURE [ conversation: Conversation, openFileID: OpenFileID, size: PageCount, lock: LockOption ← [write, wait]]; --! AccessFailed {handleReadWrite, spaceQuota}, LockFailed, -- OperationFailed {insufficientSpace}, StaticallyInvalid, Unknown {openFileID, transID}; -- Changes the file's size to the new size specified, after setting an update or write -- lock on it. Additionally, decreasing the file's size locks the entire file in the -- same mode. Note that the size is the number of data pages, and does not include -- any file overhead (e.g., leader page). If the new size is less than the file's -- high water mark, sets the high water mark equal to size. -- Requires that the OpenFileID be open with access=readWrite. Appropriately adjusts -- the disk space charged to the file's owner; however, it is not required that -- the client be a member of the owner's create access control list. -- Note that allocation is consumed immediately when a file's size is increased; -- but when the size is decreased, the allocation is not credited with the freed -- pages until transaction commit time. -- Exceptions AccessFailed: ERROR [missingAccess: AlpineEnvironment.NeededAccess]; LockFailed: ERROR [why: AlpineEnvironment.LockFailure]; -- See AlpineEnvironment for a description of LockFailure. OperationFailed: ERROR [why: AlpineEnvironment.OperationFailure]; StaticallyInvalid: ERROR; -- Raised by any operation if passed unreasonable arguments, where unreasonableness -- may be determined statically and does not depend on the state of the file system. -- The most common cause is an enumerated or subrange argument out of bounds, which -- can generally occur only if the client passed it through a LOOPHOLE. Unknown: ERROR [what: AlpineEnvironment.UnknownType]; PossiblyDamaged: SIGNAL; END.