
.*
.pm 5
:gdoc sec=''
:frontm
:titlep
:title.FASTOPEN UTILITY HIGH LEVEL DESIGN
:date.
:author.J. K.
:ETITLEP
:toc
:body
.DH NUM
.*.pa
&SYSDATE.
.*:H1.INTRODUCTION
.*:H1.ARCHITECTURE OVERVIEW

:H1.FASTOPEN DESIGN
:H2.FASTOPEN UTILITY
:H3.FASTOPEN Overview
FASTOPEN is a utility that allows DOS to maintain the information about
files that have been opened.  The purpose is to reduce the number of times DOS
has to look into the directory area of the disk for information on the file once
the information is stored by FASTOPEN.	In real life, many application
programs, especially current database systems on the market, tend to open the
same file repeatedly and every open operation needs an access to the disk if the
information does not exist in the DOS buffer.  The FASTOPEN utility will
eliminate these disk accesses, and hence will increase the efficiency of DOS
performance.


:H3.FASTOPEN Operational Description
Conceptually FASTOPEN itself is a database maintained by DOS.  The data will
be stored and maintained in the system RAM.

FASTOPEN is a user-installable, stay resident utility loaded by entering a
command
.fo off
	1). FASTOPEN D:{=L} ...

where	"..." means a possible repetition.

	"D:" is a drive letter for a non_removable media.

	"L" is the maxium number of files and subdirectories that can be
	stored in the drive cache. The default value is 34, minimum
	value, 10.  The total number for all the drives is less
	than 1000.

.fo on

:H4.Name Caching
FASTOPEN will keep the history of the accessed subdirectory and file
information in LRU fashion.  The data are stored in a partial tree
structure that represents all the recently accessed files and
subdirectories of that drive.  The number of entries entered by the
user, or the default number of 34, represents the maximum number of
nodes and leaves of the tree.	As it suggests, the bigger the
number is, the more the efficient it will be.  Currently each additional
increase of the entry will take 36 bytes, which is the fixed length of
a node.

The number entered by the user should be bigger than the deepest nesting
of path entries in the drive.

The operation on this name cache is similar to the operation on the
physical drive.
With the look up request, FASTOPEN will traverse the name cache tree from the
root to the bottom to find the requested path, filename.  If found, then the
pointer to the file or subdirectory information packet will be returned, else FASTOPEN
will return the string pointer that points up to the matching subdirectory name.
In this case, if DOS wants to insert the rest of the subdirectory/file information
an insert operation should be requested for every subdirectory/file.  FASTOPEN
will use the information from the previous Look_up operation for a sequence of Insert operations.

At this moment, if there are any free entries left, then it will be used.
Otherwise, FASTOPEN will delete the least recently used leaf.  Any node cannot
be deleted until the node becomes an empty leaf, i.e., without children.
If a file or a directory has been removed, then DOS will update the name
cache tree with the Delete request.  The path, file will be looked up
first, and if found, then the corresponding entries will be free to the
free entry chain.  If not found, then still it is O.K. since the matching file
entries had been removed by the LRU scheme.


:H3.Fastopen Interface
When installed, by the nature of the functionality, FASTOPEN becomes
a part of DOS and a private communication mechanism will be
established.
Inside DOS, vector pointers are established for FASTOPEN and will be
initialized by the call "CALLinstall" macro by the FASTOPEN initialization.
The structure of the FASTOPEN entry will look like;

.fo off
FASTOPEN_ENTRY	struc
FASTOPEN_ENTRY_SIZE		dw	4    ;size of the following
FASTOPEN_NAME_CACHING		dd	?
;FASTOPEN_FATCHAIN_CACHING	 dd	 ?     ;not for DOS 3.3
;NUMBER_OF_SFTS 		 dw	 ?     ;# of files - 3
FASTOPEN_ENTRY	ends
.fo on

The initial vector pointer for FASTOPEN_NAME_CACHING
points to a dummy routine in DOS which simply set the carry flag and set AX to 0FFFFh.

When FASTOPEN is installed, then this vectors table will be established to
point to the matching procedures in FASTOPEN module.

The register AL will contain subfunction value on entry to FASTOPEN.

.fo off
;FASTOPEN NAME CACHING	Subfunctions
fastopen_name_look_up	equ	1
fastopen_name_insert	equ	2
fastopen_name_delete	equ	3
;fastopen_name_purge	equ	4	;Not for DOS 3.3

.fo off
1. Name Caching

 a. Look up
   IN)	DS:SI -> d:path
	ES:DI -> DIR_INFO buffer in DOS to be filled by FASTOPEN
	ES:CX -> Extended_Info buffer in DOS to be filled by FASTOPEN
   OUT)
	if found, DS:SI -> the last character of the path, i.e., 0.
		  ES:DI -> DIR INFO
		  ES:CX -> Extended INFO (explained in the data structure)
   else if there exist the name cache for the drive, but could not
	completely find the matching path,
		  DS:SI -> "\" following the directory that FASTOPEN can
			   find the match,
			   Will points to "\" after "d:" if no matching
			   root directory is found.
		  ES:DI -> Compct_Dir_Info of the subdirectory FASTOPEN
			   can find the match.
		  ES:CX -> the matching directory's Extended INFO
		  If cannot find the matching root directory entry, then
		  ES:DI, ES:CX are undetermined.
   else carry flag set and AX = 0FFFFh.

 b. Insert
   IN)	DS:DI -> DIR info
	ES:BX -> Extended info

   OUT)
	If failed, then carry flag set and AX = 0FFFFh.
	Insert operation handles only one file or subdirectory at a time.
	So, usually insert operations are performed in a sequential manner.
	A look up operation should be performed before any new sequential
	insert operation.
	FASTOPEN will keep the information of the pervious look up
	operation in CURRENT_NODE.  The CURRENT_NODE points to the matching
	directory node of the previous Look up operation.  The next insert
	operation will use this CURRENT_NODE information to insert the
	directory or file information.	So, DOS will call only one Look_
	up operation and possibly several Insert operation to insert the
	path.

	For example, suppose DOS wants to look up C:\DIR1\DIR2\FILE1 and
	FASTOPEN only has the inforamtion up to C:DIR1.  After the
	look up operation, FASTOPEN will return with DS:SI points "\"
	following C:\DIR1.
	At this moment, if DOS decides to insert this information,then
	it sets DS:DI to DIR_INFO, and ES:BX to EXTENDED_INFO of the
	subdirectory DIR2, and will request an insert operation.
	When control returned back to DOS, then it will set this time
	DS:DI and ES:BX to those of FILE1, and will call an another
	insert operation.
	At the first insert operation, FASTOPEN automatically knows
	that those informaton given by DOS belong to the child of
	C:\DIR1, and will install it as a child.  In the second operation,
	again FASTOPEN knows that it is for the child of C:\DIR1\DIR2
	and will accordingly install the information for FILE1.

 c. Delete
   IN)	DS:SI -> d:path

   OUT)
	If failed, then carry flag set and AX = 0FFFFh.

.fo on

:H3.FASTOPEN Special Considerations
FASTOPEN uses the following DOS function calls in its initialization
rouitine.  No DOS or BIOS function calls are allowed inside the
main routine that is resident once installed.
:ul
:li.AH = 40h, Int 21h; Write to device for the messages,
:li.AH = 31h, Int 21h; Terminate Process and Remain Resident,
:li.AH = 48h, AH = 49h, AH = 4Ah, Int 21h;  Allocate, free and
modify memory block.
:eul
:p.

To prevent the corruption of any DOS operation, once FASTOPEN is
loaded it cannot be reloaded.


:H4.FASTOPEN Top Level Design

:H5.Data Structure

The structures of the records in FASTOPEN are:

.fo off
NAME_record struc
	LRU_pointer	dw	-1
	Child_pointer	dw	-1
	Sibling_pointer dw	-1
	MRU_pointer	dw	-1
	Compct_Dir_info db	22 dup (?)
	Extended_Info	db	 5 dup (?)
NAME_record ends

Extended_Info	struc
dirpos	db	0
dirsec	dw	0
clusnum dw	0
Extended_Info	ends

Drive_cache_header	struc
LRU_ROOT	dw	0	 ;Start of LRU chain for this Name cache
Child_ptr	dw     -1	 ;points to the name cache
Sibling_ptr	dw     -1	 ;points to the next drive header
MRU_ROOT	dw	0	 ;set to the end of LRU chain
Drive_letter	db     'C'
Num_Entries	dw	0
Name_Cache_start dw	0	 ;Start of name cache for this drive
Drive_cache_header	ends

Cmpct_Dir_Info	struc
CD_File_name		db	11 dup (0)
CD_File_attr		db	?
CD_time 		dw	?
CD_date 		dw	?
CD_cluster		dw	?
CD_Filesize		dd	?
Cmpct_Dir_Info	ends

Dir_Info	struc		;= full directory entry information.
DI_head 		db	12 dup (?)
DI_skip 		db	10 dup (0) ;reserved area. All the time 0.
DI_tail 		db	10 dup (?)
Dir_Info	ends

.fo


:H5.FASTOPEN Hierarch
:H6.FASTOPEN Components

.fo off

		      Ŀ
		        FASTOPEN    
		      
			     
			     
	  Ŀ
	  					
	  V					V
Ŀ			 Ŀ
  INIT				   MAIN	
			 
						
						V
			    Ŀ
			    					   
			    	LOOK_UP, INSERT, DELETE, INIT_TREE 
			    					   
			      (SUPPORTING MODULES)		   
			    					   
			    	GET_FREE_NODE, PRE_LRU_STACK,	   
			    	SET_LRU,  MAKE_NAME_RECORD,	   
			    	UNFOLD_NAME_RECORD, PACK_DIR_NAME, 
			    	REMOVEFROMLRUCHAIN		   
			    

.fo

:H6.FASTOPEN Memory Structure

.fo off
  Lo_memory   Ŀ 
	            LOOK_UP,		     
	            INSERT,		     M
	            DELETE,		     A
	          & Supporting Routines     I
	       			     N
	       Ĵ  
	             INIT_TREE 	     
	       Ĵ 
	           DRIVE_CACHE_HEADER	     I
	           (After Init, this	     N
	            area will be used	     I
	            for name caches.)	     T
	           SHOW_ERR_MESSAGE	     
	        

  High_memory
.fo

.pa
:H5.FASTOPEN Component Interfaces

.fo off
;*************************************************************************
;
;SUBROUTINE: INIT
;
;INPUT:
;
;OUTPUT:
;
;DESCRIPTION:
;
;      1:(Installation check)
;	{ Get the entry pointer of FASTOPEN from DOS.
;	  Check the signature ($FASTOPEN01$)
;	  If already installed,
;	   then Show 'FASTOPEN already installed'; Exit
;	}
;
;      2:(Parse the command line)
;	 Input: User input
;
;	 Output: Total_Entry_Num.
;		 Drive_Cache_Headers set.
;		 End_Cache_Header.
;
;	{ For every drive entered
;	  { Drive sanity check;
;	    Get_Num;
;	    if success and Total_Entry_Num < 1000, then
;	       Set Drive_Cache_Header;
;	  }
;	 }
;
;	3:(Check the system memory) - Check if the system has enough
;				      memory for the Name caches.
;				      Name cache will start from the
;				      End_Cache_Header.
;
;	 Input: Total_Entry_Num, End_Cache_Header, End_Init,
;	 Output: End_Caches
;	{
;	  Needed_space = size of (Name_Record) * Total_Entry_Num;
;	  Needed_space = Needed_space - (End_Init - End_Cache_Header);
;	  Free allocated memory from End_Init (AH = 4Ah);
;	  Set memory block from End_Init to Needed_Space (AH = 48h);
;	  if fail, Show 'Insufficient memory for FASTOPEN cache';
;	  Set End_Caches;
;	}
;
;	4: jmp to INIT_TREE
;
;*************************************************************************


.pa
.fo off
;*************************************************************************
;
;SUBROUTINE: INIT_TREE
;
;INPUT: Drive_cache_header, End_Caches
;
;OUTPUT:Name_cache entries installed for every drive requested.
;	LRU chain established for every drive.
;	FASTOPEN entry pointer set in DOS.
;	Terminate & stay resident. (Up to End_Caches)
;
;DESCRIPTION:
;
;	1:(Install_Name_Cache)
;	 Input: Drive cache header, End_cache_header (= Name cache start)
;	 Output:According to the information in the header,
;		the name cache entries will be established.
;		Also, LRU chain, MRU_pointer are established.
;
;	{ Buffer_start = End_cache_header;
;	  For every drive header
;	  { LRU_ROOT = Buffer_start;
;	    For (i=1;i=Num_Entries;i++)
;	    { MRU_pointer = Buffer_start;
;	      Buffer_start= Buffer_start + size_of (Name_record);
;	      if i = Num_Entries then LRU_pointer = -1
;				 else LRU_pointer = Buffer_start;
;	    }
;	  }
;	}
;
;	2:(Set FASTOPEN entry pointer in DOS)
;	 Use CALL INSTALL macro.
;
;	3: Terminate and stay resident up to Buffer_start;
;
;*************************************************************************


.pa
.fo off
;*************************************************************************
;
;SUBROUTINE: MAIN
;
;INPUT: Called by DOS throught Look_up, Insert, Delete requests.
;
;OUTPUT:Request performed based on LRU scheme.
;	CX, DX, DS, ES, BP value saved.  Other register are destroyed.
;
;DESCRIPTION:
;	Call Pack_Dir_Name		;get the drive letter in BL
;	Call Get_Drive_Cache_Header	;find the matching drive header
;	if not found, then AX = 0ffffh, Carry set
;  else if AL = Look_up then Call Look_up
;  else if AL = Insert	then Call Insert
;  else if AL = Delete	then Call Delete
;  else AX = 0ffffh, Carry set.
;
;	MAJOR SUBROUTINES:
;	(Look_up) - Refer to Look_up subroutine.
;	(Delete)  - Refer to Delete subroutine.
;	(Insert)  - Refer to Insert subroutine.
;
;	SUPPORTING SUBROUTINES:
;	1:(Get_Free_Node) - Get the entry from the LRU_ROOT,
;			    Set LRU_ROOT to the next entry of the
;			    LRU chain
;	 Input: none
;	 Output:Entry address. LRU_ROOT updated to the next entry.
;
;	2:(Pre_LRU_Stack) - This is needed to implement LRU scheme in
;	  a tree structure.  Since the order of traversing a tree is
;	  from the root to bottom and from left to right, the direct
;	  implementation of LRU will result the parent the least mostly
;	  used one instead of the child.  This is exactly in the reverse
;	  order to what had been expected.  This procedure will
;	  solve this problem without loss of any efficiency.  In the
;	  Look_up operation and found the match, the found entris will
;	  be saved with each of its LRU, MRU pointer modified to reflect
;	  the desired LRU order.
;	  These created mini LRU chain will be attached to the
;	  LRU chain again by SET_LRU.  SET_LRU and PRE_LRU_STACK
;	  should work in a synchronized fashion.  SET_LRU routine
;	  will be called in the beginning of every Look_up, Insert
;	  operation.  PRE_LRU_Stack will be called whenever a matching
;	  entry is found in a Look_up operation, or whenever a new
;	  entry is inserted by the Insert operation.
;	 Input: Current_Drive,Target node.
;	 Output:Depth, Top, Bottom set
;
;	3:(SET_LRU)
;	 Input: Depth, Top, Bottom, Current_Drive
;	 Output:Mini LRU chain created by Pre_LRU_Stack will be
;		placed at the end of LRU chain.
;
;	4:(MAKE_NAME_RECORD) - At Insert time, BOS will give
;	 two types of information. DS:DI -> Dir_Info, ES:BX -> Extended_
;	 Info.	The Name_Record is composed of Cmpct_Dir_Info and
;	 Extend_Info.  MAKE_NAME_RECORD will simply make a Name_Record
;	 from the informations from DOS.
;	 Input: Dir_Info, Extended_Info
;	 Output:Name_Record
;
;	5:(UNFOLD_NAME_RECORD) - Inverse function of above. When Look_up
;	 operation finishes,  then unfold the Name_Record of the current_
;	 node for DOS.  If the Current_Node is a drive_cache_header,
;	 then will just return.
;	 Input: CS:Current_Node, ES, DI, BX set for the buffer
;	 Output:ES:DI->Dir_Info, ES:BX->Extended_Info buffer in DOS.
;
;	6:(PACK_DIR_NAME) - At Look_up or Delete operation, DS:SI points
;	 to the requested full path, for ex., "C:\DIR1.EXT\DIR2\FILE.EXT",
;	 0.  This routine is smart enough to recognize ":","\" and 0 as
;	 a delimeter and will parse until the next delimeter and leave
;	 SI to the next delimeter found.  Also, if it is a drive name
;	 it will  set SI to the "\" after ":" for consistency and
;	 it will set BL to the drive letter.
;	 The main function of this routine is "pack" the given directory
;	 name into 11 bytes format.  PACKED_NAME will be filled with
;	 the result.  For example, when it is called the first time,
;	 DL =  "C" and SI will point to "\" before DIR1.EXT.
;	 The second time, PACKED_NAME will be filled with
;	"DIR1     EXT" and SI will points to "\" before "DIR2".
;	 Likewize, if this routine is called the fourth time,
;	 FILE.EXT has been parsed and DS:SI will points to 0.
;	 When this routine is called again, then it will return
;	 with carry signaling that it has reached the end.
;	 The user is required to call this routine consequtively
;	 until it returns with carry.
;	 Input:
;	 Output:
;
;*************************************************************************


.pa
.fo off
;*************************************************************************
;
;SUBROUTINE: LOOK_UP
;
;INPUT: DS:SI -> path
;	ES:DI -> DIR_INFO buffer in DOS to be filled by FASTOPEN
;	ES:CX -> Extended_Info buffer in DOS to be filled by FASTOPEN
;	CS:BP -> Matching Drive_cache_header
;
;OUTPUT:if found, DS:SI -> the last character of the path, i.e., 0.
;		  ES:DI -> DIR_INFO
;		  ES:CX -> Extended_INFO (explained in the data structure)
;  else if there exist the name cache for the drive, but could not
;	completely find the matching path,
;		  DS:SI -> "\" following the directory that FASTOPEN can
;			   find the match,
;			   Will points to "\" after "d:" if no matching
;			   root directory is found.
;		  ES:DI -> Dir_Info of the subdirectory FASTOPEN
;			   can find the match.
;		  ES:CX -> the matching directory's Extended INFO
;		  If cannot find the matching root directory entry, then
;		  ES:DI, ES:BX are undetermined.
;		  If the requested path is "D:\,0" then FASTOPEN will
;		  return with carry flag set and, AX = 0ffffh.
;  else carry flag set and AX = 0FFFFh.
;
;GLOBAL VARIABLES:
;	CURRENT_NODE,
;	CURRENT_SIBLING,
;
;DESCRIPTION:
;	   Save Dir_Info, Extended_Info buffer address in DOS.
;	   Set ES to Name_Cache_Seg
;	   SET_LRU;
;      1:
;	   Current_Node = BP
;	   Current_Sibling = 0
;	   PACK_DIR_NAME (from the path);
;	   if CX = 0, then jmp to 3 /*Found*/;
;	   Find_child (from the current_node);
;	   if not found then jmp to 3
;      2:  Compare Packed_name with Child_pointer.CD_filename
;	   if yes, then PRE_LRU_STACK; JMP to 1
;	   else Find_Sibling;Current_sibling=Sibling_pointer
;		if found a sibling, then Current_Node = Current_Sibling
;					 jmp to 2
;		   else jmp to 3;
;      3:  UNFOLD_NAME_RECORD	/*for the info packet to DOS */
;	   Exit
;
;*************************************************************************


.pa
.fo off
;*************************************************************************
;
;SUBROUTINE: INSERT
;
;INPUT: DS:DI -> DIR info
;	ES:BX -> Extended info
;
;OUTPUT:Automatic insertion based on CURRENT_NODE, CURRENT_SIBLING
;	If failed, then carry flag set and AX = 0FFFFh.
;	Insert operation handles only one file or subdirectory at a time.
;	So, usually insert operations are performed in a sequential manner.
;	A look up operation should be performed before any new sequential
;	insert operation.
;
;GLOBAL VARIABLES:
;	CURRENT_NODE,
;	CURRENT_SIBLING,
;
;DESCRIPTION:
;
;	Make_Name_Record	;Make Name Record from the input
;	Get_Free_Node
;	Set_LRU 		;(from TEMP_LRU_STACK)
;	if current_sibling <> 0 (or current_sibling=0FFh)
;		then Install as a sibling of Current_Node
;	   else Install as a child under Current_Node;
;	Pre_LRU_stack		;(pre operation for LRU)
;	Exit
;
;*************************************************************************


.pa
.fo off
;*************************************************************************
;
;SUBROUTINE: Delete
;
;INPUT: DS:SI -> d:path
;
;OUTPUT: If found, then remove the item from the Tree and from the
;	 LRU chain.  Move that slot to the Top of the LRU chain.
;
;GLOBAL VARIABLES:
;
;DESCRIPTION:
;	Look_Up
;	If ds:si -> 0, then Remove that entry from Tree, LRU chain,
;			    Put that entry to the top of LRU chain
;	else AX = 0FFFFh, Carry set,
;	Exit
;
;*************************************************************************


.fo
:egdoc.

