-- 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.