(FILECREATED " 8-Jun-84 00:17:57" {ERIS}<LISPNEW>SOURCES>VOLUMEFILEMAP.;5 55573  

      changes to:  (FNS \DFSVFMInitMap)

      previous date: " 6-Jun-84 15:18:46" {ERIS}<LISPNEW>SOURCES>VOLUMEFILEMAP.;4)


(* Copyright (c) 1984 by Xerox Corporation)

(PRETTYCOMPRINT VOLUMEFILEMAPCOMS)

(RPAQQ VOLUMEFILEMAPCOMS ((* Implements {idun}<apilot100>pilot>private>VolFileMapImpl.mesa. Decided 
			     not to maintain a bufferPool (a cache of leaf BTree pages)
			     both to make things simpler and on the grounds that in a 1.5 MByte 
			     DLion, half the bufferPool will probably be swapped out anyway, thus 
			     erasing any speedup.)
	(DECLARE: EVAL@COMPILE DONTCOPY (COMS * VOLUMEFILEMAPCOMPILECOMS))
	(INITRECORDS PageGroup)
	(* The following are public entry points to the volume file map module)
	(FNS \DFSVFMClose \DFSVFMDeletePageGroup \DFSVFMGetNextFile \DFSVFMGetPageGroup 
	     \DFSVFMInsertPageGroup \DFSVFMInitMap \DFSVFMInit \DFSVFMGenerateFileIDs)
	(* The following are routines internal to the volume file map module.)
	(FNS \DFSVFMContextFlush \DFSVFMContextSet \DFSVFMInvalidateCache \DFSVFMGetBufferFor 
	     \DFSVFMCreateVPage \DFSVFMDelete \DFSVFMDelete1 \DFSVFMDelete2 \DFSVFMFind 
	     \DFSVFMFreeVPage \DFSVFMGet \DFSVFMGet1 \DFSVFMInsert \DFSVFMInsert1 \DFSVFMLower 
	     \DFSVFMMerge \DFSVFMMerge1 \DFSVFMMerge2 \DFSVFMPutNext \DFSVFMReadNext \DFSVFMSplit 
	     \DFSVFMSplit1 \DFSVFMSplit2 \DFSVFMXtra)
	(FNS \DFSSmartBLT \DFSPtrGEQ \DFSVFMAtLoad)
	(GLOBALVARS \DFSVFMmaxKey \DFSVFMnullKey \DFSVFMnullIntervals \DFSVFMcurrentID 
		    \DFSVFMvolumeHandle \DFSVFMbuffer \DFSVFMbufferVolumePage \DFSVFMxtraBuffer 
		    \DFSVFMinterval \DFSVFMold \DFSVFMlow \DFSVFMhigh \DFSVFMmonitor)
	(P (\DFSVFMAtLoad))))



(* Implements {idun}<apilot100>pilot>private>VolFileMapImpl.mesa. Decided not to maintain a 
bufferPool (a cache of leaf BTree pages) both to make things simpler and on the grounds that in
 a 1.5 MByte DLion, half the bufferPool will probably be swapped out anyway, thus erasing any 
speedup.)

(DECLARE: EVAL@COMPILE DONTCOPY 

(RPAQQ VOLUMEFILEMAPCOMPILECOMS ((CONSTANTS (indexInBuffer 25)
					    (tUnassigned 0)
					    (tPhysicalVolumeRootPage 1)
					    (tSubVolumeMarkerPage 4)
					    (tLogicalVolumeRootPage 5)
					    (tFreePage 6)
					    (tVolumeAllocationMap 7)
					    (tVolumeFileMap 8)
					    (tRootDirectory 18)
					    (nullVolumePage 0)
					    (maxPagesPerFile 8388607)
					    (lastPageNumber (SUB1 maxPagesPerFile))
					    (* maxPagesPerFile = 2↑23 - 1))
	(RECORDS ID Key Index Interval Intervals PageGroup BufferArray Buffer Label FileDescriptor 
		 DiskFileID LVBootFiles RootFileArray LogicalVolumeDescriptor PVBootFiles 
		 PhysicalVolumeDescriptor LogicalSubVolumeMarker SubVolumeMarkerPage)
	[CONSTANTS (maxReadPtr (SUB1 (MESASIZE Buffer]
	(MACROS Vfm)))
(DECLARE: EVAL@COMPILE 

(RPAQQ indexInBuffer 25)

(RPAQQ tUnassigned 0)

(RPAQQ tPhysicalVolumeRootPage 1)

(RPAQQ tSubVolumeMarkerPage 4)

(RPAQQ tLogicalVolumeRootPage 5)

(RPAQQ tFreePage 6)

(RPAQQ tVolumeAllocationMap 7)

(RPAQQ tVolumeFileMap 8)

(RPAQQ tRootDirectory 18)

(RPAQQ nullVolumePage 0)

(RPAQQ maxPagesPerFile 8388607)

(RPAQ lastPageNumber (SUB1 maxPagesPerFile))

(RPAQ * maxPagesPerFile = 2↑23 - 1)

(CONSTANTS (indexInBuffer 25)
	   (tUnassigned 0)
	   (tPhysicalVolumeRootPage 1)
	   (tSubVolumeMarkerPage 4)
	   (tLogicalVolumeRootPage 5)
	   (tFreePage 6)
	   (tVolumeAllocationMap 7)
	   (tVolumeFileMap 8)
	   (tRootDirectory 18)
	   (nullVolumePage 0)
	   (maxPagesPerFile 8388607)
	   (lastPageNumber (SUB1 maxPagesPerFile))
	   (* maxPagesPerFile = 2↑23 - 1))
)
[DECLARE: EVAL@COMPILE 

(MESATYPE ID (5 WORD))

(MESARECORD Key ((fileID ID)
		 (filePage SWAPPEDFIXP)))

(MESARECORD Index ((key Key)
		   (volumePage SWAPPEDFIXP)
		   (ptr WORD)))

(MESARECORD Interval ((key Key)
		      (volumePage SWAPPEDFIXP)
		      (nextKey Key)))

(MESAARRAY Intervals ((0 5))
		     Interval)

(DATATYPE PageGroup ((filePage SWAPPEDFIXP)
		     (volumePage SWAPPEDFIXP)
		     (nextFilePage SWAPPEDFIXP)))

(MESAARRAY BufferArray ((0 (SUB1 indexInBuffer)))
		       Index)

(MESARECORD Buffer ((data BufferArray)
		    (used WORD))                             (* This is the structure for a BTree page)
		   (CREATE (NCREATE (QUOTE VMEMPAGEP))))

(MESARECORD Label ((fileID ID)                               (* valid in label of every page)
		   (filePageLo WORD)
		   (filePageHi BITS 7)                       (* 23 bit page number, valid in label of every page)
		   (NIL BITS 6)                              (* always zero)
		   (immutable FLAG)                          (* valid only in label of page 0)
		   (temporary FLAG)                          (* valid only in label of page 0)
		   (zeroSize FLAG)                           (* valid only in label of page 0)
		   (type WORD)                               (* valid in label of every page)
		   bootChainLink                             (* valid in label of every page)
		   )
		  (ACCESSFNS (filePage (\MAKENUMBER (fetch (Label filePageHi) of DATUM)
						    (fetch (Label filePageLo) of DATUM))
				       (PROGN (replace (Label filePageHi) of DATUM
						 with (\HINUM NEWVALUE))
					      (replace (Label filePageLo) of DATUM
						 with (\LONUM NEWVALUE))
					      NEWVALUE))))

(MESARECORD FileDescriptor ((fileID ID)
			    (volumeID ID)
			    location immutable temporary (size SWAPPEDFIXP)
			    (type WORD)))

(MESARECORD DiskFileID ((fID ID)
			(firstPage SWAPPEDFIXP)
			(da SWAPPEDFIXP))                    (* Booting information)
		       )

(MESAARRAY LVBootFiles ((0 5))
		       DiskFileID                            (* Booting information)
		       )

(MESAARRAY RootFileArray ((6 14))
			 ID)

(MESARECORD LogicalVolumeDescriptor ((seal WORD)             (* Validation ; absolutely must be first field)
				     (version WORD)          (* must be 2nd field)
				     (vID ID)                (* ID of This Volume)
				     (labelLength WORD)      (* Length of th ASCII name of this volume)
				     (label 20 WORD)         (* Volume name in AScII)
				     (type WORD)
				     (volumeSize SWAPPEDFIXP)
                                                             (* Number of pages in this volume)
				     (bootingInfo LVBootFiles)
                                                             (* Defines 6 PILOT file types)
                                                             (* Reorder from here on only)
				     (treeLevel WORD)
				     (changing WORD)         (* boolean ← T)
				     (freePageCount SWAPPEDFIXP)
                                                             (* Number of free pages remaining)
				     (vamStart SWAPPEDFIXP)
				     (vfmStart SWAPPEDFIXP)
                                                             (* Relative address of the start of the volume file map)
				     (lowerBound SWAPPEDFIXP)
				     (rootFileID RootFileArray)
				     (volumeRootDirectory ID)
				     (NIL WORD)              (* This is inserted for compatibility)
				     (interval Intervals)    (* One entry for each level of the B-Tree)
				     (NIL 13 WORD)
				     (checksum WORD)         (* Must be the last field)
				     )
				    (CREATE (NCREATE (QUOTE VMEMPAGEP))))

(MESAARRAY PVBootFiles ((0 3))
		       DiskFileID)

(MESARECORD PhysicalVolumeDescriptor ((seal WORD)            (* Validation)
				      (version WORD)
				      (labelLength WORD)
				      (pvID ID)
				      (bootingInfo PVBootFiles)
                                                             (* Defines 4 PILOT file types)
				      (label 20 WORD)        (* Ascii name of the volume)
				      (subVolumeCount WORD)
				      (subVolumeMarkerID ID)
                                                             (* Marker pages belong to this Pseudo File)
				      (badPageCount SWAPPEDFIXP)
				      (maxBadPages SWAPPEDFIXP)
				      (onLineCount WORD)
				      (subVolumes 78 WORD)   (* See SubVolumeDscr record for description of each of 
							     six entries stored here)
				      (NIL 99 WORD)
				      (localTimeParametersValid WORD)
				      (localTimeParameters 2 WORD)
				      (checksum WORD)))

(MESARECORD LogicalSubVolumeMarker ((seal WORD)
				    (version WORD)
				    (labelLength BITS 6)
				    (type BITS 2)
				    (NIL BITS 8)
				    (label 20 WORD)
				    (bootingInfo LVBootFiles)
				    (volumeRootDirectory ID)
				    (NIL WORD)))

(MESARECORD SubVolumeMarkerPage ((logical LogicalSubVolumeMarker)
                                                             (* Incomplete)
				 ))
]
(/DECLAREDATATYPE (QUOTE PageGroup)
		  (QUOTE (SWAPPEDFIXP SWAPPEDFIXP SWAPPEDFIXP)))
(DECLARE: EVAL@COMPILE 

(RPAQ maxReadPtr (SUB1 (MESASIZE Buffer)))

[CONSTANTS (maxReadPtr (SUB1 (MESASIZE Buffer]
)
(DECLARE: EVAL@COMPILE 

(PUTPROPS Vfm MACRO ((\DFSVFMvolumeHandle)
		     (PROGN                                  (* Returns the file ID of the volume file map)

          (* Watch it! This would be disastrous if the result of Vfm were (a) written into or (b) held onto longer than the 
	  logical volume page)


			    (FMESAELT (fetch (LogicalVolumeDescriptor rootFileID) of 
									      \DFSVFMvolumeHandle)
				      RootFileArray tVolumeFileMap))))
)
)
(/DECLAREDATATYPE (QUOTE PageGroup)
		  (QUOTE (SWAPPEDFIXP SWAPPEDFIXP SWAPPEDFIXP)))



(* The following are public entry points to the volume file map module)

(DEFINEQ

(\DFSVFMClose
  [LAMBDA (final)                                            (* hts: "14-May-84 16:28")
                                                             (* final: BOOLEAN)
                                                             (* Public)
    (WITH.MONITOR \DFSVFMmonitor (UNINTERRUPTABLY
                                     (\DFSVFMContextFlush final))])

(\DFSVFMDeletePageGroup
  [LAMBDA (vol filePtr groupPtr)                             (* hts: "14-May-84 16:31")
                                                             (* vol: LogicalVolumeDescriptor, filePtr: 
							     FileDescriptor, groupPtr: PageGroup)

          (* Deletes all or part of a single page group from the volume file map. The page group requested to be deleted 
	  need not correspond to a single run of pages on the disk. It can be part of a single run of pages or stretch over 
	  several runs of pages. In particular it is possible to delete a page or pages out of the middle of a run of pages 
	  (the scavenger uses this capability). The actual page group deleted is returned in the group pointed to by 
	  GroupPtr. Thus GroupPtr points to a modifiable hint. Care must be taken by the caller to insure that the page 
	  group to be deleted exists. If it doesn't, Bug (pageGroupNotFound) is raised. This procedure implements the 
	  following funny features:)



          (* 1.0 If the page group to be deleted includes parts of more than one run of pages on the disk, only the last run
	  (or that part of the last run requested to be deleted) will be deleted.)



          (* 2.0 If the page group to be deleted is the last page group left for the file and includes page zero of the file
	  and at least one following page, page zero will not be deleted. This is a special case that facilitates shrinking 
	  a file to a zero-length file. VolAllocMapImpl has special case code in FreePageGroup for this also.
	  You can delete this last page of the file by specifying page group "[0..0)".)



          (* 3.0 A hole at the beginning of a file is represented as follows: if file F is missing pages 
	  (0..n) and the preceding file in the lexicographic ordering is file E of size m, then the interval in the file map
	  representing the hole looks like this: (key: (E, m), volumePage: nullVolumePage, nextKey: 
	  (F, n)).)



          (* 4.0 A hole in the middle of the file (e.g. missing pages (m..n)) looks like this: (key: 
	  (F, m), volumePage: nullVolumePage, nextKey: (F, n)).)



          (* 5.0 This procedure does not care whether the page group being deleted corresponds to a hole in a file or to a 
	  real run of pages on the volume, with the exception of a hole at the beginning of a file. If the page group to be 
	  deleted is fully contained in a hole at the beginning of the file, Bug (pageGroupNotFound) is raised.)


    (WITH.MONITOR \DFSVFMmonitor
		  (UNINTERRUPTABLY
                      (PROG ([key (create Key
					  fileID ←(fetch (FileDescriptor fileID) of filePtr)
					  filePage ←(IDIFFERENCE (fetch (PageGroup nextFilePage)
								    of groupPtr)
								 (if (EQP (fetch (PageGroup 
										     nextFilePage)
									     of groupPtr)
									  0)
								     then 0
								   else 1]
			     (interval (create Interval))
			     fileSize)
			    (with FileDescriptor filePtr (if (EQ location (QUOTE local))
							     then (SETQ fileSize size)
							   else (ERROR "remoteFile")))
			    (if (IGREATERP (fetch (PageGroup nextFilePage) of groupPtr)
					   fileSize)
				then (SHOULDNT "conflictingFileSize&PageGroup"))
			    (\DFSVFMContextSet vol)
			    (MESASETQ interval (\DFSVFMGet key 0)
				      Interval)              (* get interval containing last page of group)
			    (if (OR (NOT (MESAEQUAL (fetch (Key fileID) of (fetch (Interval key)
									      of interval))
						    (fetch (FileDescriptor fileID) of filePtr)
						    ID))
				    (AND (NOT (MESAEQUAL (fetch (Key fileID)
							    of (fetch (Interval nextKey)
								  of interval))
							 (fetch (FileDescriptor fileID) of filePtr)
							 ID))
					 (EQP (fetch (Interval volumePage) of interval)
					      nullVolumePage)))
				then (SHOULDNT "pageGroupNotFound"))
                                                             (* for a zero-length file, interval.nextKey.fileID # 
							     filePtr.fileID BUT interval.volumePage # nullVolumePage)
			    [replace (PageGroup filePage) of groupPtr
			       with (replace (Key filePage) of key
				       with (MAX (fetch (Key filePage) of (fetch (Interval key)
									     of interval))
						 (fetch (PageGroup filePage) of groupPtr]
			    [replace (PageGroup volumePage) of groupPtr
			       with (if (EQP (fetch (Interval volumePage) of interval)
					     nullVolumePage)
					then nullVolumePage
				      else (IPLUS (fetch (Interval volumePage) of interval)
						  (IDIFFERENCE (fetch (PageGroup filePage)
								  of groupPtr)
							       (fetch (Key filePage)
								  of (fetch (Interval key)
									of interval]
			    (replace (PageGroup nextFilePage) of groupPtr
			       with (MIN (fetch (Key filePage) of (fetch (Interval nextKey)
								     of interval))
					 (fetch (PageGroup nextFilePage) of groupPtr)))
                                                             (* deal with the starting page of the page group first)
			    (if [AND (MESAEQUAL key (fetch (Interval key) of interval)
						Key)
				     (OR (NOT (EQP (fetch (PageGroup nextFilePage) of groupPtr)
						   fileSize))
					 (NOT (ZEROP (fetch (Key filePage) of key]
				then (\DFSVFMDelete key 0))
			    [if (NOT (ZEROP (fetch (Key filePage) of key)))
				then (PROG [(previousKey (create Key
								 fileID ←(fetch (FileDescriptor
										  fileID)
									    of filePtr)
								 filePage ←(SUB1 (fetch (Key filePage)
										    of key]
				           (if (MESAEQUAL (fetch (Key fileID)
							     of (fetch (Interval key)
								   of (\DFSVFMGet previousKey 0)))
							  (fetch (FileDescriptor fileID)
							     of filePtr)
							  ID)
					       then          (* key.filePage is not the first 
							     (existing) page of the file)
						    (\DFSVFMInsert key nullVolumePage 0]
                                                             (* now deal with the ending page of the page group)
			    (replace (Key filePage) of key with (fetch (PageGroup nextFilePage)
								   of groupPtr))
			    (if (EQP (fetch (Key filePage) of key)
				     fileSize)
				then (\DFSVFMDelete key 0))
			    (if (AND [NOT (EQP (fetch (Key filePage) of key)
					       (fetch (Key filePage) of (fetch (Interval nextKey)
									   of interval]
				     (MESAEQUAL (fetch (Key fileID) of key)
						(fetch (Key fileID) of (fetch (Interval nextKey)
									  of interval))
						ID))
				then (\DFSVFMInsert key [if (EQP (fetch (PageGroup volumePage)
								    of groupPtr)
								 nullVolumePage)
							    then nullVolumePage
							  else (IPLUS (fetch (PageGroup volumePage)
									 of groupPtr)
								      (IDIFFERENCE
									(fetch (PageGroup 
										     nextFilePage)
									   of groupPtr)
									(fetch (PageGroup filePage)
									   of groupPtr]
						    0)))
		      (PROGN                                 (* This block is not part of the Mesa 10.0 code)
			     (\LvPutPage \DFSVFMvolumeHandle \DFSVFMbufferVolumePage \DFSVFMbuffer)
                                                             (* Write out \DFSVFMbuffer in case it is dirty)
			     (\LvPutPage \DFSVFMvolumeHandle 0 \DFSVFMvolumeHandle)
                                                             (* Write out logical volume page to keep interval finger
							     (intervals field) up to date)
			     ))])

(\DFSVFMGetNextFile
  [LAMBDA (volume file)                                      (* hts: "14-May-84 16:32")
    (SHOULDNT (QUOTE functionNotImplemented])

(\DFSVFMGetPageGroup
  [LAMBDA (vol filePtr filePage)                             (* hts: "14-May-84 16:33")
                                                             (* vol: LogicalVolumeDescriptor, filePtr: 
							     FileDescriptor, filePage: SWAPPEDFIXP)
                                                             (* RETURNS (BOOLEAN, PageGroup))
                                                             (* Public)
                                                             (* finds page group containing key 
							     ((filePage = nextFilePage = size) when off end of file))
    (WITH.MONITOR \DFSVFMmonitor
		  (UNINTERRUPTABLY
                      (PROG ((key (create Key
					  fileID ←(fetch (FileDescriptor fileID) of filePtr)
					  filePage ← filePage))
			     (interval (create Interval)))
			    (\DFSVFMContextSet vol)
			    (MESASETQ interval (\DFSVFMGet key 0)
				      Interval)
			    [RETURN (CONS (MESAEQUAL (fetch (Key fileID) of (fetch (Interval key)
									       of interval))
						     (fetch (FileDescriptor fileID) of filePtr)
						     ID)
					  (create PageGroup
						  filePage ←(fetch (Key filePage)
							       of (fetch (Interval key) of interval))
						  volumePage ←(fetch (Interval volumePage)
								 of interval)
						  nextFilePage ←(fetch (Key filePage)
								   of
								    (if
								      (MESAEQUAL
									(fetch (Key fileID)
									   of (fetch (Interval 
											  nextKey)
										 of interval))
									(fetch (FileDescriptor fileID)
									   of filePtr)
									ID)
									then (fetch (Interval nextKey)
										of interval)
								      else (fetch (Interval key)
									      of interval]
                                                             (* covers page zero and size requests)
			))])

(\DFSVFMInsertPageGroup
  [LAMBDA (vol filePtr groupPtr)                             (* hts: "14-May-84 16:34")
                                                             (* vol: LogicalVolumeDescriptor, filePtr: 
							     FileDescriptor, groupPtr: PageGroup)
                                                             (* public)
                                                             (* inserts a pageGroup into B-tree 
							     (unordered inserts are merged for rebuild))
    (WITH.MONITOR \DFSVFMmonitor
		  (UNINTERRUPTABLY
                      (PROG ((key (create Key
					  fileID ←(fetch (FileDescriptor fileID) of filePtr)
					  filePage ←(fetch (PageGroup filePage) of groupPtr)))
			     (interval (create Interval)))
			    (\DFSVFMContextSet vol)
			    (MESASETQ interval (\DFSVFMGet key 0)
				      Interval)
			    (if (MESAEQUAL (fetch (Interval key) of interval)
					   key Key)
				then (\DFSVFMDelete key 0)
				     (MESASETQ interval (\DFSVFMGet key 0)
					       Interval))
			    (if (OR [NOT (EQP (IDIFFERENCE (fetch (Key filePage) of key)
							   (fetch (Key filePage)
							      of (fetch (Interval key) of interval)))
					      (IDIFFERENCE (fetch (PageGroup volumePage)
							      of groupPtr)
							   (fetch (Interval volumePage) of interval]
				    (NOT (MESAEQUAL (fetch (Key fileID) of key)
						    (fetch (Key fileID) of (fetch (Interval key)
									      of interval))
						    ID)))
				then                         (* don't merge with previous)
				     (\DFSVFMInsert key (fetch (PageGroup volumePage) of groupPtr)
						    0)
				     (MESASETQ interval (\DFSVFMGet key 0)
					       Interval))
			    (replace (Key filePage) of key with (fetch (PageGroup nextFilePage)
								   of groupPtr))
			    (if [AND (NOT (MESAEQUAL (fetch (Interval nextKey) of interval)
						     key Key))
				     (NOT (EQP (fetch (PageGroup filePage) of groupPtr)
					       (fetch (PageGroup nextFilePage) of groupPtr]
				then (\DFSVFMInsert key nullVolumePage 0))
			    (if [AND (MESAEQUAL (fetch (Interval nextKey) of interval)
						key Key)
				     (EQP (fetch (Interval volumePage) of (\DFSVFMGet key 0))
					  (IPLUS (fetch (Interval volumePage) of interval)
						 (IDIFFERENCE (fetch (Key filePage)
								 of (fetch (Interval nextKey)
								       of interval))
							      (fetch (Key filePage)
								 of (fetch (Interval key)
								       of interval]
				then (\DFSVFMDelete key 0) 
                                                             (* merge with following)))
		      (PROGN                                 (* This block is not part of the Mesa 10.0 code)
			     (\LvPutPage \DFSVFMvolumeHandle \DFSVFMbufferVolumePage \DFSVFMbuffer)
                                                             (* Write out \DFSVFMbuffer in case it is dirty)
			     (\LvPutPage \DFSVFMvolumeHandle 0 \DFSVFMvolumeHandle)
                                                             (* Write out logical volume page to keep interval finger
							     (intervals field) up to date)
			     ))])

(\DFSVFMInitMap
  [LAMBDA (vol)                                              (* edited: " 8-Jun-84 00:11")
                                                             (* vol: LogicalVolumeDescriptor)
                                                             (* Public)
    (WITH.MONITOR \DFSVFMmonitor (UNINTERRUPTABLY
                                     (PROG (level)
				           (replace (LogicalVolumeDescriptor interval) of vol
					      with \DFSVFMnullIntervals)
				           (\DFSVFMContextSet vol)
				           (replace (LogicalVolumeDescriptor vfmStart) of vol
					      with (\DFSVFMCreateVPage))
				           (for level from (SUB1 (fetch (LogicalVolumeDescriptor
									  treeLevel)
								    of vol))
					      to 0 by -1
					      do             (* init the tree)
						 (\DFSVFMInsert \DFSVFMnullKey (if (ZEROP level)
										   then 
										   nullVolumePage
										 else (
\DFSVFMCreateVPage))
								level)))
				     (PROGN                  (* This block is not part of the Mesa 10.0 code)
					    (\LvPutPage \DFSVFMvolumeHandle \DFSVFMbufferVolumePage 
							\DFSVFMbuffer)
                                                             (* Write out \DFSVFMbuffer in case it is dirty)
					    (\LvPutPage \DFSVFMvolumeHandle 0 \DFSVFMvolumeHandle)
                                                             (* Write out logical volume page to keep interval finger
							     (intervals field) up to date)
					    ))])

(\DFSVFMInit
  [LAMBDA NIL                                                (* hts: "21-May-84 17:41")
    (SETQ \DFSVFMbufferVolumePage)                           (* if bufferVolumePage is NIL, then GetBufferFor will 
							     not try to flush the last buffer page)
    ])

(\DFSVFMGenerateFileIDs
  [LAMBDA (vol)                                              (* hts: "22-May-84 18:17")
                                                             (* vol: LogicalVolumeDescriptor)
                                                             (* Returns all the fileIDs currently in the BTree)
    (WITH.MONITOR \DFSVFMmonitor (UNINTERRUPTABLY
                                     (\DFSVFMContextSet vol)
				     (bind (currentKey ←(create Key))
					until (PROGN (replace (Key filePage) of currentKey
							with MAX.FIXP)
						     (MESASETQ currentKey (fetch (Interval nextKey)
									     of (\DFSVFMGet 
										       currentKey 0))
							       Key)
						     (MESAEQUAL (fetch (Key fileID) of currentKey)
								\DFSVFMmaxKey ID))
					collect (MESASETQ (create ID)
							  (fetch (Key fileID) of currentKey)
							  ID)))])
)



(* The following are routines internal to the volume file map module.)

(DEFINEQ

(\DFSVFMContextFlush
  [LAMBDA (final)                                            (* hts: "10-May-84 12:30")
                                                             (* final: BOOLEAN)
                                                             (* Internal)
                                                             (* Omitted a pile of bufferPool manipulation)
    (if final
	then (MESASETQ \DFSVFMcurrentID \DFSVFMnullID ID])

(\DFSVFMContextSet
  [LAMBDA (vol)                                              (* hts: "15-Apr-84 01:07")
                                                             (* vol: LogicalVolumeDescriptor)
                                                             (* Internal)
    (MESASETQ \DFSVFMcurrentID (fetch (LogicalVolumeDescriptor vID) of vol)
	      ID)
    (SETQ \DFSVFMvolumeHandle vol])

(\DFSVFMInvalidateCache
  [LAMBDA (page)                                             (* hts: " 4-Apr-84 23:20")
                                                             (* Internal)

          (* Look for a \DFSVFMbuffer in the pool that's mapped to page and remove it from the cache as someone is either 
	  going to write into it through a non-cache mechanism or is about to delete the VFM page)

                                                             (* Body of this function all bufferPool stuff, so 
							     omitted.)
    ])

(\DFSVFMGetBufferFor
  [LAMBDA (page)                                             (* hts: "18-May-84 22:00")
                                                             (* page: SWAPPEDFIXP)
                                                             (* Internal)
                                                             (* Most of this routine is bufferPool management stuff 
							     and so is omitted.)
    (if (NOT (AND (LVEqual \DFSVFMvolumeHandle \DFSVFMbufferVolume)
		  (EQP page \DFSVFMbufferVolumePage)))
	then (if \DFSVFMbufferVolumePage
		 then (\LvPutPage \DFSVFMbufferVolume \DFSVFMbufferVolumePage \DFSVFMbuffer))
                                                             (* Write out old \DFSVFMbuffer page in case it is 
							     dirty.)
	     (UNINTERRUPTABLY
                 (SETQ \DFSVFMbufferVolume \DFSVFMvolumeHandle)
                                                             (* Record what volume the buffer comes from)
		 (SETQ \DFSVFMbufferVolumePage page)         (* Remember what page the \DFSVFMbuffer came from)
		 (\LvGetPage \DFSVFMvolumeHandle \DFSVFMbufferVolumePage \DFSVFMbuffer)) 
                                                             (* and read it in)])

(\DFSVFMCreateVPage
  [LAMBDA NIL                                                (* hts: " 6-Apr-84 15:51")
                                                             (* Returns SWAPPEDFIXP)
                                                             (* Internal)
                                                             (* Calls VolAllocMap.AllocPageGroup to get a new page 
							     for the vfm B-tree. Returns its volume-relative page 
							     number.)
    (with LogicalVolumeDescriptor \DFSVFMvolumeHandle
	  (PROG ((group (create PageGroup
				filePage ← 0
				volumePage ← 0
				nextFilePage ← 1))
		 (vfmFileD (create FileDescriptor
				   fileID ←(Vfm \DFSVFMvolumeHandle)
				   volumeID ← vID
				   location ←(QUOTE local)
				   immutable ← NIL
				   temporary ← NIL
				   type ← tVolumeFileMap)))
	        (\DFSVAMAllocPageGroup \DFSVFMvolumeHandle vfmFileD group T)
	        (RETURN (fetch (PageGroup volumePage) of group])

(\DFSVFMDelete
  [LAMBDA (deleteKey deleteLevel)                            (* hts: " 6-Jun-84 14:19")
                                                             (* key: Key, level: SMALLP)
                                                             (* Internal)
                                                             (* Deletes the index = key, error if no such index 
							     (Merge is called from \DFSVFMFind))
    (PROG (firstFlag lastFlag volumePage (nextKey (create Key)))
                                                             (* volumePage is the page holding the key 
							     (delete if firstFlag AND lastFlag))
                                                             (* nextKey is the following key;
							     must be slid down over deleted key)
          (DECLARE: (SPECVARS deleteKey deleteLevel firstFlag lastFlag volumePage nextKey))
          (\DFSVFMFind deleteKey deleteLevel (FUNCTION \DFSVFMDelete1))
                                                             (* Get the preceding index)
          [if firstFlag
	      then (\DFSVFMDelete deleteKey (ADD1 deleteLevel))
		   (if lastFlag
		       then (\DFSVFMFreeVPage volumePage)
		     else (\DFSVFMInsert nextKey volumePage (ADD1 deleteLevel]
          (\DFSVFMFind deleteKey deleteLevel (FUNCTION \DFSVFMDelete2)))
                                                             (* Get the preceding index)
    ])

(\DFSVFMDelete1
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 14:19")
                                                             (* Internal)
    (SETQ firstFlag (EQP (fetch (Index ptr) of \DFSVFMlow)
			 0))
    (SETQ lastFlag (EQP (fetch (Index ptr) of \DFSVFMhigh)
			(fetch (Buffer used) of \DFSVFMbuffer)))
    (SETQ volumePage (fetch (Interval volumePage) of \DFSVFMinterval))
    (MESASETQ nextKey (fetch (Index key) of \DFSVFMhigh)
	      Key)
    (if (NOT (MESAEQUAL (fetch (Index key) of \DFSVFMlow)
			deleteKey Key))
	then (SHOULDNT "DeleteError"))
    (if (AND firstFlag (NOT lastFlag))
	then (\DFSSmartBLT \DFSVFMbuffer (\ADDBASE \DFSVFMbuffer (fetch (Index ptr) of \DFSVFMhigh))
			   (replace (Buffer used) of \DFSVFMbuffer with (IDIFFERENCE
									  (fetch (Buffer used)
									     of \DFSVFMbuffer)
									  (fetch (Index ptr)
									     of \DFSVFMhigh])

(\DFSVFMDelete2
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 14:19")
                                                             (* Internal)
    (replace (Index key) of \DFSVFMhigh with nextKey)
    (replace (Index volumePage) of \DFSVFMhigh with (fetch (Index volumePage) of \DFSVFMlow))
    (MESASETQ \DFSVFMlow \DFSVFMold Index)
    (\DFSSmartBLT (\ADDBASE \DFSVFMbuffer (IPLUS (fetch (Index ptr) of \DFSVFMlow)
						 (MESASIZE Index)))
		  (\ADDBASE \DFSVFMbuffer (fetch (Index ptr) of \DFSVFMhigh))
		  (IDIFFERENCE (fetch (Buffer used) of \DFSVFMbuffer)
			       (fetch (Index ptr) of \DFSVFMhigh)))
    (\DFSVFMPutNext (fetch (Index key) of \DFSVFMhigh)
		    (fetch (Index volumePage) of \DFSVFMhigh)
		    deleteLevel)
    (replace (Buffer used) of \DFSVFMbuffer with (IDIFFERENCE (IPLUS (fetch (Index ptr) of \DFSVFMlow)
								     (fetch (Buffer used)
									of \DFSVFMbuffer))
							      (fetch (Index ptr) of \DFSVFMhigh])

(\DFSVFMFind
  [LAMBDA (key level proc)                                   (* hts: " 6-Jun-84 13:42")
                                                             (* key: Key, level: SMALLP, proc: FUNCTION)
                                                             (* Internal)
                                                             (* executes proc with context 
							     (buffer, low, \DFSVFMhigh) surrounding key 
							     (merges too))
    (MESASETQ \DFSVFMinterval (\DFSVFMGet key (ADD1 level))
	      Interval)
    (\DFSVFMGetBufferFor (fetch (Interval volumePage) of \DFSVFMinterval))
    (replace (Index key) of \DFSVFMold with (fetch (Interval key) of \DFSVFMinterval))
    (replace (Index volumePage) of \DFSVFMold with nullVolumePage)
    (replace (Index ptr) of \DFSVFMold with 0)
    (MESASETQ \DFSVFMlow \DFSVFMold Index)
    (MESASETQ \DFSVFMhigh \DFSVFMlow Index)                  (* Initialize reader)
    (repeatuntil (\DFSVFMLower key (fetch (Index key) of \DFSVFMhigh)) do (\DFSVFMReadNext))
                                                             (* Scan this page till key is passed)
    (APPLY proc)
    (if (AND (ILEQ (fetch (Buffer used) of \DFSVFMbuffer)
		   (IQUOTIENT (MESASIZE Buffer)
			      3))
	     (NOT (MESAEQUAL (fetch (Interval nextKey) of \DFSVFMinterval)
			     \DFSVFMmaxKey Key)))
	then (\DFSVFMMerge (fetch (Index key) of \DFSVFMold)
			   level])

(\DFSVFMFreeVPage
  [LAMBDA (volumePage)                                       (* hts: " 6-Apr-84 15:56")
                                                             (* volumePage: SWAPPEDFIXP)
                                                             (* Internal)
                                                             (* calls VolAllocMap.FreePageGroup to free a page of the
							     vfm BTree)
    (with LogicalVolumeDescriptor \DFSVFMvolumeHandle
	  (PROG ((group (create PageGroup
				filePage ← volumePage
				volumePage ← volumePage
				nextFilePage ←(ADD1 volumePage)))
		 (vfmFileD (create FileDescriptor
				   fileID ←(Vfm \DFSVFMvolumeHandle)
				   volumeID ← vID
				   location ←(QUOTE local)
				   immutable ← NIL
				   temporary ← NIL
				   type ← tVolumeFileMap)))
	        (\DFSVFMInvalidateCache volumePage)
	        (\DFSVAMFreePageGroup \DFSVFMvolumeHandle vfmFileD group T])

(\DFSVFMGet
  [LAMBDA (getKey getLevel)                                  (* hts: " 6-Jun-84 14:15")
                                                             (* key: Key, level: SMALLP; returns Interval)
                                                             (* Internal)
    (PROG NIL
          (DECLARE: (SPECVARS getKey getLevel))
          (if (OR (IGREATERP getLevel (fetch (LogicalVolumeDescriptor treeLevel) of 
									      \DFSVFMvolumeHandle))
		  (IGREATERP getLevel 6))
	      then (ERROR "ManThisHereIntervalCacheItBeFuckedUp"))
          (if (EQP getLevel (fetch (LogicalVolumeDescriptor treeLevel) of \DFSVFMvolumeHandle))
	      then (RETURN (create Interval
				   key ← \DFSVFMnullKey
				   volumePage ←(fetch (LogicalVolumeDescriptor vfmStart)
						  of \DFSVFMvolumeHandle)
				   nextKey ← \DFSVFMmaxKey)))
          (MESASETQ \DFSVFMinterval (FMESAELT (fetch (LogicalVolumeDescriptor interval) of 
									      \DFSVFMvolumeHandle)
					      Intervals getLevel)
		    Interval)
          (if [OR (\DFSVFMLower getKey (fetch (Interval key) of \DFSVFMinterval))
		  (NOT (\DFSVFMLower getKey (fetch (Interval nextKey) of \DFSVFMinterval]
	      then (\DFSVFMFind getKey getLevel (FUNCTION \DFSVFMGet1)))
          (RETURN (FMESAELT (fetch (LogicalVolumeDescriptor interval) of \DFSVFMvolumeHandle)
			    Intervals getLevel))

          (* Watch it! This would be disastrous if the result of Get were (a) written into or (b) held onto longer than the 
	  logical volume page)


      ])

(\DFSVFMGet1
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 14:14")
                                                             (* Internal)
    (MESASETA (fetch (LogicalVolumeDescriptor interval) of \DFSVFMvolumeHandle)
	      Intervals getLevel (create Interval
					 key ←(fetch (Interval key) of \DFSVFMlow)
					 volumePage ←(fetch (Interval volumePage) of \DFSVFMhigh)
					 nextKey ←(fetch (Interval key) of \DFSVFMhigh])

(\DFSVFMInsert
  [LAMBDA (insertKey insertVolumePage insertLevel)           (* hts: " 6-Jun-84 14:24")
                                                             (* key: Key, volumePage: PageNumber, level: Level)
                                                             (* Internal)
                                                             (* Inserts insertKey into insertVolumePage 
							     (including duplicates) calling split if necessary)
    (PROG (splitFlag)
          (DECLARE: (SPECVARS insertKey insertVolumePage insertLevel splitFlag))
          (\DFSVFMFind insertKey insertLevel (FUNCTION \DFSVFMInsert1))
          (if splitFlag
	      then (\DFSVFMSplit insertKey insertLevel)
		   (\DFSVFMFind insertKey insertLevel (FUNCTION \DFSVFMInsert1])

(\DFSVFMInsert1
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 15:15")
                                                             (* Internal)
    (PROG NIL
          (if [SETQ splitFlag (IGREATERP (fetch (Buffer used) of \DFSVFMbuffer)
					 (IDIFFERENCE maxReadPtr (MESASIZE Index]
	      then (RETURN))
          [if (ILESSP (fetch (Index ptr) of \DFSVFMlow)
		      (fetch (Buffer used) of \DFSVFMbuffer))
	      then (\DFSSmartBLT (\ADDBASE \DFSVFMbuffer (IPLUS (fetch (Index ptr) of \DFSVFMlow)
								(ITIMES (MESASIZE Index)
									2)))
				 (\ADDBASE \DFSVFMbuffer (fetch (Index ptr) of \DFSVFMhigh))
				 (IDIFFERENCE (fetch (Buffer used) of \DFSVFMbuffer)
					      (fetch (Index ptr) of \DFSVFMhigh)))
		   (\DFSVFMPutNext insertKey (fetch (Index volumePage) of \DFSVFMhigh)
				   insertLevel)
	    else (\DFSSmartBLT (\ADDBASE \DFSVFMbuffer (IPLUS (fetch (Index ptr) of \DFSVFMlow)
							      (MESASIZE Index)))
			       (\ADDBASE \DFSVFMbuffer (fetch (Index ptr) of \DFSVFMhigh))
			       (IDIFFERENCE (fetch (Buffer used) of \DFSVFMbuffer)
					    (fetch (Index ptr) of \DFSVFMhigh]
          (\DFSVFMPutNext (fetch (Index key) of \DFSVFMhigh)
			  insertVolumePage insertLevel)
          (replace (Buffer used) of \DFSVFMbuffer with (IDIFFERENCE (IPLUS (fetch (Index ptr)
									      of \DFSVFMlow)
									   (fetch (Buffer used)
									      of \DFSVFMbuffer))
								    (fetch (Index ptr) of \DFSVFMhigh]
)

(\DFSVFMLower
  [LAMBDA (a b)                                              (* hts: " 4-Apr-84 23:06")
                                                             (* a: Key, b: Key; returns BOOLEAN)
                                                             (* Internal)
                                                             (* Compares two keys for ordering)
    (PROG ((i 0))
      loop(if (ILESSP (\GETBASE (fetch (Key fileID) of a)
				i)
		      (\GETBASE (fetch (Key fileID) of b)
				i))
	      then (RETURN T))
          (if (IGREATERP (\GETBASE (fetch (Key fileID) of a)
				   i)
			 (\GETBASE (fetch (Key fileID) of b)
				   i))
	      then (RETURN NIL))
          (add i 1)
          (if (ILESSP i (MESASIZE ID))
	      then (GO loop))
          (RETURN (OR (ILESSP (fetch (Key filePage) of a)
			      (fetch (Key filePage) of b))
		      (MESAEQUAL b \DFSVFMmaxKey Key)))      (* \DFSVFMmaxKey < maxKey, to close key space)
      ])

(\DFSVFMMerge
  [LAMBDA (mergeKey mergeLevel)                              (* hts: " 6-Jun-84 14:39")
                                                             (* key: Key, level: SMALLP)
                                                             (* Internal)
                                                             (* Tries to merge page of oldIntervalwith next page at 
							     same mergeLevel or with root;
							     cannot merge last page of any mergeLevel except 
							     rootlevel)
    (PROG (mergeFlag (leftInterval (create Interval))
		     (rightInterval (create Interval)))
          (DECLARE: (SPECVARS mergeKey mergeLevel mergeFlag leftInterval rightInterval))
          (MESASETQ leftInterval (\DFSVFMGet mergeKey (ADD1 mergeLevel))
		    Interval)                                (* so as to get a valid volumePage)
          (\DFSVFMFind (fetch (Interval nextKey) of leftInterval)
		       mergeLevel
		       (FUNCTION \DFSVFMMerge1))             (* beware the merging)
          (\DFSVFMDelete (fetch (Interval nextKey) of leftInterval)
			 (ADD1 mergeLevel))
          (if mergeFlag
	      then (\DFSVFMFreeVPage (fetch (Interval volumePage) of rightInterval))
	    else (\DFSVFMInsert (fetch (Interval key) of rightInterval)
				(fetch (Interval volumePage) of rightInterval)
				(ADD1 mergeLevel)))          (* insert new index)
      ])

(\DFSVFMMerge1
  [LAMBDA NIL                                                (* hts: " 5-Apr-84 00:58")
                                                             (* Internal)
    (MESASETQ rightInterval \DFSVFMinterval Interval)
    (\DFSVFMXtra (fetch (Interval volumePage) of leftInterval)
		 (FUNCTION \DFSVFMMerge2])

(\DFSVFMMerge2
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 14:39")
                                                             (* Internal)
    (PROG ((xtraBufferUsed (fetch (Buffer used) of \DFSVFMxtraBuffer)))
                                                             (* xtraBufferUsed used to solve stack modeling error)
          (if (EQP mergeLevel (SUB1 (fetch (LogicalVolumeDescriptor treeLevel) of \DFSVFMvolumeHandle)
				    ))
	      then (replace (Buffer used) of \DFSVFMxtraBuffer with 0))
                                                             (* clear now instead of deleteing later)
          (if (SETQ mergeFlag (ILESSP (IPLUS (fetch (Buffer used) of \DFSVFMbuffer)
					     (fetch (Buffer used) of \DFSVFMxtraBuffer))
				      (MESASIZE Buffer)))
	      then                                           (* If merging possible then merge pages)
		   (\DFSSmartBLT (\ADDBASE \DFSVFMxtraBuffer xtraBufferUsed)
				 \DFSVFMbuffer
				 (fetch (Buffer used) of \DFSVFMbuffer))
                                                             (* merge \DFSVFMbuffer with xtra)
		   (replace (Buffer used) of \DFSVFMxtraBuffer with (IPLUS (fetch (Buffer used)
									      of \DFSVFMxtraBuffer)
									   (fetch (Buffer used)
									      of \DFSVFMbuffer)))
                                                             (* buffer.used remains to prevent Find from attempting a
							     merge)
		   
	    else                                             (* balance pages simply to provide hysteresis against 
							     futile merge attempts)
		 (while (ILESSP (fetch (Index ptr) of \DFSVFMlow)
				(IQUOTIENT (IDIFFERENCE (fetch (Buffer used) of \DFSVFMbuffer)
							(fetch (Buffer used) of \DFSVFMxtraBuffer))
					   2))
		    do (\DFSVFMReadNext))                    (* find middle)
		 (\DFSSmartBLT (\ADDBASE \DFSVFMxtraBuffer xtraBufferUsed)
			       \DFSVFMbuffer
			       (fetch (Index ptr) of \DFSVFMlow))
                                                             (* move first of \DFSVFMbuffer to xtra)
		 (\DFSSmartBLT \DFSVFMbuffer (\ADDBASE \DFSVFMbuffer (fetch (Index ptr) of \DFSVFMlow)
						       )
			       (IDIFFERENCE (fetch (Buffer used) of \DFSVFMbuffer)
					    (fetch (Index ptr) of \DFSVFMlow)))
                                                             (* slide down the rest of \DFSVFMbuffer)
		 (replace (Buffer used) of \DFSVFMxtraBuffer with (IPLUS (fetch (Buffer used)
									    of \DFSVFMxtraBuffer)
									 (fetch (Index ptr)
									    of \DFSVFMlow)))
		 (replace (Buffer used) of \DFSVFMbuffer with (IDIFFERENCE (fetch (Buffer used)
									      of \DFSVFMbuffer)
									   (fetch (Index ptr)
									      of \DFSVFMlow)))
                                                             (* use \DFSVFMlow to insert while it is still valid)
		 (replace (Interval key) of rightInterval with (fetch (Index key) of \DFSVFMlow])

(\DFSVFMPutNext
  [LAMBDA (key volumePage level)                             (* hts: "20-Apr-84 22:29")
                                                             (* key: Key, volumePage: SWAPPEDFIXP, level: SMALLP)
                                                             (* Internal)

          (* Compresses item in the context of low. Note the side effect on \DFSVFMlow but not on high!! No compression is 
	  implemented in this version, but useful one would include: front compression (especially to shrink page groups 
	  back to 2 fields))


    (MESASETQ \DFSVFMold \DFSVFMlow Index)
    (PROG ((lowPtr (fetch (Index ptr) of \DFSVFMlow)))
          (MESASETQ \DFSVFMlow (create Index
				       key ← key
				       volumePage ← volumePage
				       ptr ←(MESASIZE Index))
		    Index)
          (MESASETQ (\ADDBASE (fetch (Buffer data) of \DFSVFMbuffer)
			      lowPtr)
		    \DFSVFMlow Index))
    (replace (Index ptr) of \DFSVFMlow with (IPLUS (fetch (Index ptr) of \DFSVFMlow)
						   (fetch (Index ptr) of \DFSVFMold)))
                                                             (* ptr is just an increment)
                                                             (* low:Index.ptr was just an increment)
    (MESASETA (fetch (LogicalVolumeDescriptor interval) of \DFSVFMvolumeHandle)
	      Intervals level (create Interval
				      key ←(fetch (Index key) of \DFSVFMold)
				      volumePage ←(fetch (Index volumePage) of \DFSVFMlow)
				      nextKey ←(fetch (Index key) of \DFSVFMlow)))
                                                             (* keep cache up to date in the face of changes)
    ])

(\DFSVFMReadNext
  [LAMBDA NIL                                                (* hts: "20-Apr-84 22:07")
                                                             (* Internal)

          (* Decompresses item at \DFSVFMhigh to become \DFSVFMlow & bumps high. Note the side effect on \DFSVFMlow and 
	  high!! No compression is implemented in this version)


    (if (IGREATERP (fetch (Index ptr) of \DFSVFMhigh)
		   (fetch (Buffer used) of \DFSVFMbuffer))
	then (ERROR "Attempt to access nonexistent interval on B-tree page"))
    (MESASETQ \DFSVFMold \DFSVFMlow Index)
    (MESASETQ \DFSVFMlow \DFSVFMhigh Index)
    (MESASETQ \DFSVFMhigh (if (ILESSP (fetch (Index ptr) of \DFSVFMhigh)
				      (fetch (Buffer used) of \DFSVFMbuffer))
			      then                           (* Loophole)
				   (\ADDBASE (fetch (Buffer data) of \DFSVFMbuffer)
					     (fetch (Index ptr) of \DFSVFMhigh))
			    else (create Index
					 key ← \DFSVFMmaxKey
					 volumePage ← nullVolumePage
					 ptr ← 0))
	      Index)
    (replace (Index ptr) of \DFSVFMhigh with (IPLUS (fetch (Index ptr) of \DFSVFMhigh)
						    (fetch (Index ptr) of \DFSVFMlow)))
                                                             (* high:Index.ptr was just an increment)
    ])

(\DFSVFMSplit
  [LAMBDA (splitKey splitLevel)                              (* hts: " 6-Jun-84 14:46")
                                                             (* key: Key, level: SMALLP)
                                                             (* Internal)
                                                             (* moves half of \DFSVFMbuffer 
							     (or root) to xtraBuffer, creating new page of tree)
    (PROG ((keyStone (create Key))
	   (page (\DFSVFMCreateVPage)))                      (* keyStone is the half way mark)
          (DECLARE: (SPECVARS splitKey splitLevel keyStone page))
          (\DFSVFMFind splitKey splitLevel (FUNCTION \DFSVFMSplit1))
          (\DFSVFMInsert keyStone page (ADD1 splitLevel])

(\DFSVFMSplit1
  [LAMBDA NIL                                                (* hts: " 5-Apr-84 00:58")
                                                             (* Internal)
    (\DFSVFMXtra page (FUNCTION \DFSVFMSplit2])

(\DFSVFMSplit2
  [LAMBDA NIL                                                (* hts: " 6-Jun-84 14:46")
                                                             (* Internal)
    (MESASETQ \DFSVFMhigh (create Index
				  key ←(fetch (Interval key) of \DFSVFMinterval)
				  volumePage ← nullVolumePage
				  ptr ← 0)
	      Index)                                         (* quick readReset)
    (repeatuntil (IGREATERP (fetch (Index ptr) of \DFSVFMhigh)
			    (IQUOTIENT (fetch (Buffer used) of \DFSVFMbuffer)
				       2))
       do (\DFSVFMReadNext))
    [\BLT \DFSVFMxtraBuffer (\ADDBASE (fetch (Buffer data) of \DFSVFMbuffer)
				      (fetch (Index ptr) of \DFSVFMlow))
	  (replace (Buffer used) of \DFSVFMxtraBuffer with (IDIFFERENCE (fetch (Buffer used)
									   of \DFSVFMbuffer)
									(fetch (Index ptr)
									   of \DFSVFMlow]
                                                             (* split)
    (replace (Buffer used) of \DFSVFMbuffer with (fetch (Index ptr) of \DFSVFMlow))
    (MESASETQ keyStone (fetch (Index key) of \DFSVFMlow)
	      Key])

(\DFSVFMXtra
  [LAMBDA (page proc)                                        (* hts: " 6-Jun-84 14:38")
                                                             (* page: SWAPPEDFIXP, proc: FUNCTION)
                                                             (* Internal)
                                                             (* maps, operates, unmaps \DFSVFMxtraBuffer)
    (\DFSVFMInvalidateCache page)
    (\LvGetPage \DFSVFMvolumeHandle page \DFSVFMxtraBuffer)
    (APPLY proc)
    (\LvPutPage \DFSVFMvolumeHandle page \DFSVFMxtraBuffer])
)
(DEFINEQ

(\DFSSmartBLT
  [LAMBDA (DBASE SBASE NWORDS)                               (* hts: " 5-Apr-84 01:03")

          (* This is necessary because \BLT will not copy overlapping intervals correctly in one direction.
	  Might be nice if this routine checked first to see if the intervals were actually overlapping.)


    (if (\DFSPtrGEQ SBASE DBASE)
	then (for i from 0 to (SUB1 NWORDS) do (\PUTBASE DBASE i (\GETBASE SBASE i)))
	     DBASE
      else (\BLT DBASE SBASE NWORDS])

(\DFSPtrGEQ
  [LAMBDA (P1 P2)                                            (* lmm "28-Mar-84 17:02")
    (OR (IGREATERP (\HILOC P1)
		   (\HILOC P2))
	(AND (EQ (\HILOC P1)
		 (\HILOC P2))
	     (IGEQ (\LOLOC P1)
		   (\LOLOC P2])

(\DFSVFMAtLoad
  [LAMBDA NIL                                                (* hts: "15-May-84 09:32")
                                                             (* Initialize global variables for the volume file map)
    (SETQ \DFSVFMmaxKey (create Key
				filePage ← lastPageNumber))
    (for i from 0 to 4 do (\PUTBASE (fetch (Key fileID) of \DFSVFMmaxKey)
				    i 65535))                (* Initialize maxKey)
    (SETQ \DFSVFMnullKey (create Key))
    (SETQ \DFSVFMnullIntervals (create Intervals))
    (SETQ \DFSVFMcurrentID (create ID))
    (SETQ \DFSVFMvolumeHandle)
    (SETQ \DFSVFMbuffer (create Buffer))
    (SETQ \DFSVFMbufferVolume)
    (SETQ \DFSVFMbufferVolumePage)
    (SETQ \DFSVFMxtraBuffer (create Buffer))
    (SETQ \DFSVFMinterval (create Interval))
    (SETQ \DFSVFMold (create Index))
    (SETQ \DFSVFMlow (create Index))
    (SETQ \DFSVFMhigh (create Index))
    (SETQ \DFSVFMmonitor (CREATE.MONITORLOCK (QUOTE \DFSVFMmonitor])
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \DFSVFMmaxKey \DFSVFMnullKey \DFSVFMnullIntervals \DFSVFMcurrentID 
	  \DFSVFMvolumeHandle \DFSVFMbuffer \DFSVFMbufferVolumePage \DFSVFMxtraBuffer \DFSVFMinterval 
	  \DFSVFMold \DFSVFMlow \DFSVFMhigh \DFSVFMmonitor)
)
(\DFSVFMAtLoad)
(PUTPROPS VOLUMEFILEMAP COPYRIGHT ("Xerox Corporation" 1984))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (9761 26585 (\DFSVFMClose 9771 . 10162) (\DFSVFMDeletePageGroup 10164 . 18207) (
\DFSVFMGetNextFile 18209 . 18370) (\DFSVFMGetPageGroup 18372 . 20350) (\DFSVFMInsertPageGroup 20352 . 
23751) (\DFSVFMInitMap 23753 . 25342) (\DFSVFMInit 25344 . 25634) (\DFSVFMGenerateFileIDs 25636 . 
26583)) (26665 53390 (\DFSVFMContextFlush 26675 . 27138) (\DFSVFMContextSet 27140 . 27561) (
\DFSVFMInvalidateCache 27563 . 28134) (\DFSVFMGetBufferFor 28136 . 29414) (\DFSVFMCreateVPage 29416 . 
30417) (\DFSVFMDelete 30419 . 31930) (\DFSVFMDelete1 31932 . 32966) (\DFSVFMDelete2 32968 . 34084) (
\DFSVFMFind 34086 . 35653) (\DFSVFMFreeVPage 35655 . 36608) (\DFSVFMGet 36610 . 38256) (\DFSVFMGet1 
38258 . 38768) (\DFSVFMInsert 38770 . 39589) (\DFSVFMInsert1 39591 . 41257) (\DFSVFMLower 41259 . 
42315) (\DFSVFMMerge 42317 . 43821) (\DFSVFMMerge1 43823 . 44169) (\DFSVFMMerge2 44171 . 47429) (
\DFSVFMPutNext 47431 . 49192) (\DFSVFMReadNext 49194 . 50574) (\DFSVFMSplit 50576 . 51361) (
\DFSVFMSplit1 51363 . 51603) (\DFSVFMSplit2 51605 . 52811) (\DFSVFMXtra 52813 . 53388)) (53391 55198 (
\DFSSmartBLT 53401 . 53922) (\DFSPtrGEQ 53924 . 54159) (\DFSVFMAtLoad 54161 . 55196)))))
STOP