-- File: DBStorageFieldImpl.mesa -- Last edited by MBrown on 18-Jun-81 14:40:28 -- Last Edited by: Willie-Sue, January 10, 1983 2:50 pm -- Last Edited by: Cattell, January 16, 1983 11:41 am DIRECTORY DBCache USING[CacheHandle], DBCommon USING[DBPage, NullDBPage, WordsPerPage], DBEnvironment USING[InternalError, Fatal], DBHeapStorage USING[Node --GetTheMDSZone--], DBSegment USING[SegmentIDFromDBPage, UnlockPage, WriteLockedPage], DBStorage USING[FieldDescriptor, FieldHandle, TuplesetHandle, FieldObjectSize, TuplesetObjectSize, IndexObjectSize, SystemTupleID, MaxSystemTupleID], DBStorageConcrete USING[SystemTuplesetObject, FieldObject, FieldType], DBStorageExtTuple USING[SizeOfNullTuple], DBStorageField USING[], DBStoragePrivate USING[GetNWordBase], DBStorageTID USING[TID, DecomposeTID], DBStorageTupleset USING[TuplesetObject], DBStorageTuple USING[TIDOfTuple], SafeStorage USING [GetSystemZone]; DBStorageFieldImpl: PROGRAM IMPORTS DBEnvironment, DBHeapStorage, DBSegment, DBStoragePrivate, DBStorageTID, DBStorageTuple, SafeStorage EXPORTS DBStorage, DBStorageField = BEGIN OPEN DBCommon, DBStorageTID; -- This module exports the following procedures of DBStorage: -- CreateTupleset, CreateSystemTupleset, DestroyTupleset, AddField, AddSystemField, DeleteField. -- This module exports all of DBStorageField. -- PROBLEMS, THINGS YET TO BE DONE: -- postponed: DestroyTupleset, DeleteField. -- AddField will only work on an empty tupleset; otherwise it SIGNALs BadOperation. -- Types exported to DBStorage FieldObject: PUBLIC TYPE = DBStorageConcrete.FieldObject; FieldHandle: TYPE = POINTER TO FieldObject; ListofFieldHandle: TYPE = DESCRIPTOR FOR ARRAY OF FieldHandle; SystemTuplesetObject: PUBLIC TYPE = DBStorageConcrete.SystemTuplesetObject; SystemTuplesetHandle: TYPE = REF SystemTuplesetObject; -- z: MDSZone = DBHeapStorage.GetTheMDSZone[]; systemTuplesetObjectZone: ZONE = SafeStorage.GetSystemZone[]; -- Procs exported to DBStorageField CopyFieldObject: PUBLIC PROC[fh: FieldHandle] RETURNS[FieldHandle] = { result: FieldHandle ← Alloc[]; result↑ ← fh↑; RETURN[result]; };--CopyFieldObject FreeFieldObject: PUBLIC PROC[fh: FieldHandle] = { IF fh # NIL THEN Free[fh]; };--FreeFieldObject tuplesetFieldHandle: FieldHandle; indexFieldHandle: FieldHandle; TuplesetFieldHandle: PUBLIC PROC RETURNS[FieldHandle] = { RETURN[tuplesetFieldHandle] };--TuplesetFieldHandle IndexFieldHandle: PUBLIC PROC RETURNS[FieldHandle] = { RETURN[indexFieldHandle] };--IndexFieldHandle CheckFieldHandleType: PUBLIC PROC[fh: FieldHandle, t: DBStorageConcrete.FieldType] = { -- Generates an ERROR if fh's fieldType is not t. IF fh.fieldType # t THEN ERROR DBEnvironment.InternalError; -- [Unknown]; };--CheckFieldHandleType FieldOffset: PUBLIC PROC[fh: FieldHandle] RETURNS[CARDINAL] = { RETURN[fh.offset]; };--FieldOffset NWordsInField: PUBLIC PROC[fh: FieldHandle] RETURNS[CARDINAL] = { RETURN[fh.nWords]; };--NWordsInField GroupIDOfField: PUBLIC PROC[fh: FieldHandle] RETURNS[TID] = { IF fh.fieldType # Group THEN ERROR DBEnvironment.InternalError; -- [Unknown]; RETURN[fh.groupID]; };--GroupIDOfField -- grubby details of FieldObject storage management. LOOPHOLEs below assume that a FieldObject --is large enough to hold a FieldHandle. freeFieldObjectList: FieldHandle ← NIL; Alloc: PROC[] RETURNS[FieldHandle] = --INLINE-- { result: FieldHandle; IF freeFieldObjectList#NIL THEN BEGIN result ← freeFieldObjectList; freeFieldObjectList ← LOOPHOLE[freeFieldObjectList,POINTER TO FieldHandle]↑; RETURN[result]; END ELSE -- RETURN[z.NEW[FieldObject]]; RETURN[DBHeapStorage.Node[SIZE[FieldObject]]]; };--Alloc Free: PROC[f: FieldHandle] = INLINE { LOOPHOLE[f,POINTER TO FieldHandle]↑ ← freeFieldObjectList; freeFieldObjectList ← f; };--Free -- Procs exported to DBStorage CreateTupleset: PUBLIC PROC[x: DBStorage.TuplesetHandle, expectedNGroups: CARDINAL] = { -- Creates a new tupleset whose tuples have no fields. The parameter x is an --existing tuple whose first-created field is an NWord field, TuplesetObjectLength --words long. Information describing the new tupleset is placed in this field, and --tuples in the new tupleset are placed in the same segment as tuple x . Tuple x is --returned by a ReadTuplesetID call on any tuple in this tupleset. -- Note that the TuplesetHandle is used primarily by CreateTuple, but is also --modified by AddField/DeleteField. tsObjPtr: LONG POINTER TO DBStorageTupleset.TuplesetObject; cacheHint: DBCache.CacheHandle; dbPage: DBPage; [dbPage,] ← DecomposeTID[DBStorageTuple.TIDOfTuple[x]]; [tsObjPtr, cacheHint] ← DBStoragePrivate.GetNWordBase[x, TuplesetFieldHandle[]]; DBSegment.WriteLockedPage[cacheHint]; tsObjPtr↑ ← [ wordsForTupleFields: 0, nVarFields: 0, expectedNGroups: expectedNGroups, searchList: [tuplesetID: DBStorageTuple.TIDOfTuple[x], next: NullDBPage, prev: NullDBPage], pageAllocator: [segmentID: DBSegment.SegmentIDFromDBPage[dbPage]] ]; DBSegment.UnlockPage[cacheHint]; };--CreateTupleset CreateSystemTupleset: PUBLIC PROC[x: DBStorage.SystemTupleID] RETURNS[SystemTuplesetHandle] = { -- Creates a new system tupleset (system tuplesets do not live in a single segment --and the pages containing their tuples are not chained together by the storage --level). IF x NOT IN [1..DBStorage.MaxSystemTupleID] THEN ERROR DBEnvironment.InternalError; -- [Unknown]; RETURN[systemTuplesetObjectZone.NEW[SystemTuplesetObject ← [ tuplesetID: x, wordsForTupleFields: 0]]]; };--CreateSystemTupleset DestroyTupleset: PUBLIC PROC[x: DBStorage.TuplesetHandle] = { -- In effect this procedure performs DestroyTuple on every tuple of the set --described by x, and undoes whatever was done by the CreateTupleset call that --created the tupleset. Any further user of TuplesetHandle x is an error. --(DestroyTupleset has no effect on system tuplesets). ERROR; };--DestroyTupleset MaxWordsPerTuple: CARDINAL = 3*(DBCommon.WordsPerPage/4); -- If AddField would make a tuple type with more than this many words per tuple, BadOperation is --raised. MakeFieldHandle: PROC[y: DBStorage.FieldDescriptor, wordsForTupleFields: CARDINAL] RETURNS[--fh-- FieldHandle, --newWordsInTuple-- CARDINAL] = { -- Creates a new field handle, for a tupleset whose tuples contain wordsInTuple words, in fh --based on the description of the field in y. Returns the new number of words in a tuple. --If this number of words is uncomfortably large (see MaxWordsPerTuple above), raise --BadOperation. -- Called from: AddField, AddSystemField, module init code. fh: FieldHandle ← Alloc[]; fieldInfo: RECORD[code: DBStorageConcrete.FieldType, length: CARDINAL] ← WITH fd: y SELECT FROM OneWord => [OneWord, 1], TwoWord => [TwoWord, 2], NWord => [NWord, fd.length], VarWord => [VarWord, 1 + fd.lengthHint], VarByte => [VarByte, 1 + (fd.lengthHint+1)/2], Group => [Group, 3*SIZE[TID]], ENDCASE => ERROR DBEnvironment.InternalError; -- [Unknown]; fh.fieldType ← fieldInfo.code; fh.offset ← DBStorageExtTuple.SizeOfNullTuple + wordsForTupleFields; fh.nWords ← fieldInfo.length; WITH fd: y SELECT FROM Group => fh.groupID ← DBStorageTuple.TIDOfTuple[fd.groupID]; ENDCASE => fh.fill1 ← 0; IF wordsForTupleFields + fieldInfo.length > MaxWordsPerTuple THEN ERROR DBEnvironment.Fatal[TupleTooLong]; RETURN[fh, wordsForTupleFields + fieldInfo.length]; };--MakeFieldHandle AddField: PUBLIC PROC[x: DBStorage.TuplesetHandle, y: DBStorage.FieldDescriptor] RETURNS[FieldHandle] = { -- In effect this procedure modifies each tuple of set x, adding a new field of --type y. It returns a FieldHandle for the new field. fh: FieldHandle; tsObjPtr: LONG POINTER TO DBStorageTupleset.TuplesetObject; cacheHint: DBCache.CacheHandle; [tsObjPtr, cacheHint] ← DBStoragePrivate.GetNWordBase[x, TuplesetFieldHandle[]]; -- For now, die if user tries to add a field after a tuple has been created. IF tsObjPtr.allocList#NullDBPage OR tsObjPtr.searchList.next#NullDBPage THEN ERROR DBEnvironment.InternalError; -- [AddFieldToExistingTupleset]; DBSegment.WriteLockedPage[cacheHint]; [fh, tsObjPtr.wordsForTupleFields] ← MakeFieldHandle[y, tsObjPtr.wordsForTupleFields]; SELECT fh.fieldType FROM VarWord, VarByte => {tsObjPtr.nVarFields ← tsObjPtr.nVarFields + 1; }; ENDCASE => {}; DBSegment.UnlockPage[cacheHint]; RETURN[fh]; };--AddField AddSystemField: PUBLIC PROC[x: SystemTuplesetHandle, y: DBStorage.FieldDescriptor] RETURNS[FieldHandle] = { -- This procedure adds to x the length of y. It returns a FieldHandle for the new --field. fh: FieldHandle; [fh, x.wordsForTupleFields] ← MakeFieldHandle[y, x.wordsForTupleFields]; RETURN[fh]; };--AddSystemField DeleteField: PUBLIC PROC [x: DBStorage.TuplesetHandle, z: ListofFieldHandle, i: INTEGER] RETURNS[ListofFieldHandle] = { -- In effect this procedure modifies each tuple of set x, deleting the i-th field --in list z. Parameter z describes all of the fields of tuples in x, and the result --gives new handles for the undeleted fields, in the same order (handles will change --due to deletion). -- Note: will the field handles be presented in order of creation? this would --avoid a sort. (This procedure will NOT be implemented in the first system). ERROR; };--DeleteField -- mainline code (start trap on first TuplesetFieldHandle[] or IndexFieldHandle[] will do this --required initialization) IF DBStorage.FieldObjectSize < SIZE[DBStorageConcrete.FieldObject] OR DBStorage.TuplesetObjectSize < SIZE[DBStorageTupleset.TuplesetObject] THEN ERROR DBEnvironment.InternalError; -- [Unknown]; [tuplesetFieldHandle,] ← MakeFieldHandle[[NWord[DBStorage.TuplesetObjectSize]], 0]; [indexFieldHandle,] ← MakeFieldHandle[[NWord[DBStorage.IndexObjectSize]], 0]; END.--DBStorageFieldImpl CHANGE LOG Created by MBrown on 2-Feb-80 16:07 -- AllocVec, CompactPage, and related inlines {~1 to paper-sketch AllocVec, 3:15 to --code, :10 to compile}. Changed by MBrown on February 3, 1980 3:07 PM -- CreateTupleset, CreateSystemTupleset, AddField, AddSystemField, FreeTupleHandle. Changed by MBrown on February 10, 1980 11:41 PM -- Read1Word, Read2Word, ReadNWord (except overflow page reads). Changed by MBrown on February 16, 1980 12:15 AM -- Major restructuring of storage impl. Moved everything but tupleset creation/field --creation out of this module. Changed by MBrown on February 16, 1980 9:11 PM -- Moved heap storage allocation to DBStorageHeap. Changed by MBrown on February 16, 1980 11:04 PM -- Invented MakeFieldHandle to reduce some duplication. Changed by MBrown on 17-Feb-80 13:59 -- Eliminated use of @ from CreateTupleset. Added checks for inconsistent sizes of --objects, making the "true" size be the one in DBStorage. (This can be larger than --the actual size with no ill effect, but smaller is a no-no). Changed length to --wordsPerTuple in SystemTuplesetObject. Changed by MBrown on February 25, 1980 7:45 PM -- Added procs exported to DBStoragePrivateA (TuplesetFieldHandle, IndexFieldHandle). --Made tupleset creation and field creation consistent with DBStoragePrivateB's TupleBody --structure. Changed by MBrown on April 9, 1980 10:11 AM -- Made CreateTupleset convert the TSID to a DBPage before converting THAT to a segmentID. Changed by MBrown on April 17, 1980 11:02 PM -- Changed SystemTuplesetID to SystemTupleID. Changed by MBrown on June 8, 1980 9:25 PM -- Scattered minor changes in introducing FieldObject as an opaque type. The module now contains --only 2 LOOPHOLEs. Changed MakeFieldHandle to do storage allocation for the field handle it --produces. Changed by MBrown on June 8, 1980 10:19 PM -- Compiler insists on an exported version of DBStorage.ListofFieldHandle. Changed by MBrown on June 10, 1980 8:39 PM -- Renamed to be StorageFieldImpl from StorageImplA. Changed by MBrown on June 24, 1980 11:26 AM -- Made SystemTuplesetObject be opaque in DBStorage. Changed by MBrown on July 31, 1980 3:11 PM -- Added expectedNGroups to CreateTupleset. Changed by MBrown on August 13, 1980 11:59 AM -- DBStoragePrivateB.SizeOfNullTuple became DBStorageExtTuple.SizeOfNullTuple. Changed by MBrown on August 25, 1980 1:37 PM -- Added nVarFields to TuplesetObject. Changed by MBrown on September 26, 1980 12:28 PM -- Converted to new DBException. Changed by MBrown on February 27, 1981 3:58 PM -- Use zone for storage allocation. Changed by MBrown on 18-Jun-81 14:47:11 -- Use counted zone for allocation of system tupleset objects.