home *** CD-ROM | disk | FTP | other *** search
- (* TBTree13 Copyright (c) 1988 Dean H. Farwell II *)
-
- unit Logical;
-
- (*****************************************************************************)
- (* *)
- (* L O G I C A L R E C O R D R O U T I N E S *)
- (* *)
- (*****************************************************************************)
-
-
- (* This unit is used to manipulate logical records. A logical record is made
- some number of bytes. The minimum logical record size is one byte. The
- maximum size is MAXDATASIZE (MAXWORD = 65535). Depending on the size of
- logical and physical records, many logical records could reside in a single
- physical record or a logical record could use many physical records. In the
- later case contiguous physical records are used. Since fixed logical and
- physical record sizes are used the physical records used for a logical
- record can easily be calculated. *)
-
-
- (* Version Information
-
- Version 1.1 - Added GetValidLogicalRecords routine
-
- Version 1.2 - Removed several types which were not used
-
- - Removed CalculateRecordSize routine
- This routine was not used and was for future enhancements
-
- Version 1.3 - Changed MAXDATASIZE to 65520 which is the maximum
- number of bytes for a structued type in Turbo Pascal 4.0
-
- - Added StoreNewLogicalRecord routine *)
-
- (*\*)
- (*////////////////////////// I N T E R F A C E //////////////////////////////*)
-
- interface
-
- uses
- Compare,
- FileDecs,
- Files,
- LRecList,
- Numbers,
- Page;
-
- const
- MAXDATASIZE = 65520; (* max number of bytes for a logical record *)
-
- type
- DataSizeRange = 1 .. MAXDATASIZE; (* range for size of a field
- (attribute. Also maximum number of
- bytes in a logical record *)
-
- (*\*)
- (* This routine will get a logical record from a given data file and will put
- the record into a memory location. The location will be destination. Size
- is used to pass the number of bytes contained in the logical record. The
- BITMAP will be checked to ensure that the record is in use (that it exists).
- If it is in use then it is fetched. Otherwise, nothing will be returned in
- destination. Before calling this routine, you can check to see if the
- logical record exists. If it was retrieved from an index then it exists
- (unless the record was deleted and it wasn't deleted from the index. You
- can use RecordUsed(fName,lrNum) to check for the existence of the record
- before calling this if there is a possibility thet the record doesn't
- exist. *)
-
- procedure GetALogicalRecord(fName : FnString;
- lrNum : LrNumber;
- var destination;
- size : DataSizeRange);
-
-
- (* This routine will store a logical record for a given DATA file. The routine
- will set the logical record to used and will create the appropriate physical
- record(s) if required (StorePage will do this automatically). The logical
- record size is size and the data must reside in source. This routine is
- only used if the logical record number is known. If a new record is to be
- stored use StoreNewLogicalRecord rather than this routine *)
-
- procedure StoreALogicalRecord(fName : FnString;
- lrNum : LrNumber;
- var source;
- size : DataSizeRange);
-
-
- (* This routine will store a new logical record for a given DATA file. The
- routine will set the logical record to used and will create the appropriate physical
- record(s) if required (StorePage will do this automatically). The logical
- record size is size and the data must reside in source. Normally, when
- inserting new records, you will not know the next unused logical record
- number. This routine will assign the appropriate logical record number so
- that you won't have to worry about it. The routine will return the logical
- record number which will be associated with this record upon return. You
- will need this returned logical record number if there are any indexes
- associated with this DATA file. *)
-
- function StoreNewLogicalRecord(fName : FnString;
- var source;
- size : DataSizeRange) : LrNumber;
-
-
- (* This routine will return a list of logical records which are currently in
- use (contain valid data) for a given data file. This routine is necessary
- to be able to process all records which have not been deleted without
- using an index. *)
-
- procedure GetValidLogicalRecords(fName : FnString;
- var lrLst : LrList);
-
- (*\*)
- (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
-
- implementation
-
-
- (* This routine will calculate the physical record number and the byte location
- within the physical record for a given logical record. The logical record
- and the logical record sizes are passed as parameters. *)
-
- procedure ConvertLogicalToPhysical(lrNum : LrNumber;
- lrSize : DataSizeRange;
- var prNum : PrNumber;
- var firstByte : PageRange);
-
- var
- bf : DataSizeRange; (* blocking factor *)
-
- begin
- if lrSize < PAGESIZE then
- begin
- bf := Trunc(PAGESIZE / lrSize);
- prNum := Trunc((lrNum - 1) / bf) + 1;
- firstByte := ((lrNum - ((bf * (prNum - 1)) + 1)) * lrSize) + 1;
- end
- else
- begin
- bf := Trunc((lrSize - 1) / PAGESIZE) + 1;
- prNum := ((lrNum - 1) * bf) + 1;
- firstByte := 1;
- end;
- end; (* end of ConvertLogicalToPhysical routine *)
-
- (*\*)
- (* This routine will get a logical record from a given data file and will put
- the record into a memory location. The location will be destination. Size
- is used to pass the number of bytes contained in the logical record. The
- BITMAP will be checked to ensure that the record is in use (that it exists).
- If it is in use then it is fetched. Otherwise, nothing will be returned in
- destination. Before calling this routine, you can check to see if the
- logical record exists. If it was retrieved from an index then it exists
- (unless the record was deleted and it wasn't deleted from the index. You
- can use RecordUsed(fName,lrNum) to check for the existence of the record
- before calling this if there is a possibility thet the record doesn't
- exist. *)
-
- procedure GetALogicalRecord(fName : FnString;
- lrNum : LrNumber;
- var destination;
- size : DataSizeRange);
-
- type
- MemoryArray = array [DataSizeRange] of byte;
-
- var
- prNum : PrNumber;
- firstByte : PageRange;
- page : SinglePage;
- byteCnt : DataSizeRange;
- memory : MemoryArray absolute destination;
- done : Boolean;
-
- begin
- if RecordUsed(fName,lrNum) then
- begin
- ConvertLogicalToPhysical(lrNum,size,prNum,firstByte);
- if size <= PAGESIZE then
- begin
- FetchPage(fName,prNum,page);
- Move(page[firstByte],destination,size);
- end
- else
- begin
- byteCnt := 1;
- done := FALSE;
- while not done do
- begin
- FetchPage(fName,prNum,page);
- if size > PAGESIZE then
- begin
- Move(page[firstByte],memory[byteCnt],PAGESIZE);
- byteCnt := byteCnt + PAGESIZE;
- size := size - PAGESIZE;
- end
- else
- begin (* last time thru loop *)
- Move(page[firstByte],memory[byteCnt],size);
- done := TRUE;
- end;
- end;
- end;
- end;
- end; (* end of GetALogicalRecord routine *)
-
- (*\*)
- (* This routine will store a logical record for a given DATA file. The routine
- will set the logical record to used and will create the appropriate physical
- record(s) if required (StorePage will do this automatically). The logical
- record size is size and the data must reside in source. This routine is
- only used if the logical record number is known. If a new record is to be
- stored use StoreNewLogicalRecord rather than this routine *)
-
- procedure StoreALogicalRecord(fName : FnString;
- lrNum : LrNumber;
- var source;
- size : DataSizeRange);
-
- type
- MemoryArray = array [DataSizeRange] of byte;
-
- var
- prNum : PrNumber;
- firstByte : PageRange;
- page : SinglePage;
- byteCnt : DataSizeRange;
- memory : MemoryArray absolute source;
- done : Boolean;
-
- begin
- ConvertLogicalToPhysical(lrNum,size,prNum,firstByte);
- SetRecordUsed(fName,lrNum); (* it may be already be marked as used.
- This doesn't matter and its faster not
- to check. *)
- if size <= PAGESIZE then
- begin
- if PageExists(fName,prNum) then (* if it exists get it *)
- begin
- FetchPage(fName,prNum,page);
- end
- else (* if it doesn't exist make a new one *)
- begin
- FillChar(page,PAGESIZE,0);
- end;
- Move(source,page[firstByte],size);
- StorePage(fName,prNum,page);
- end
- else
- begin
- byteCnt := 1;
- done := FALSE;
- while not done do
- begin
- if size > PAGESIZE then
- begin
- Move(memory[byteCnt],page[firstByte],PAGESIZE);
- StorePage(fName,prNum,page);
- prNum := prNum + 1;
- byteCnt := byteCnt + PAGESIZE;
- size := size - PAGESIZE;
- end
- else
- begin (* last time thru loop *)
- FillChar(page,PAGESIZE,0);
- Move(memory[byteCnt],page[firstByte],size);
- StorePage(fName,prNum,page);
- done := TRUE;
- end;
- end;
- end;
- end; (* end of StoreALogicalRecord routine *)
-
- (*\*)
- (* This routine will store a new logical record for a given DATA file. The
- routine will set the logical record to used and will create the appropriate physical
- record(s) if required (StorePage will do this automatically). The logical
- record size is size and the data must reside in source. Normally, when
- inserting new records, you will not know the next unused logical record
- number. This routine will assign the appropriate logical record number so
- that you won't have to worry about it. The routine will return the logical
- record number which will be associated with this record upon return. You
- will need this returned logical record number if there are any indexes
- associated with this DATA file. *)
-
- function StoreNewLogicalRecord(fName : FnString;
- var source;
- size : DataSizeRange) : LrNumber;
-
- var
- lrNum : LrNumber;
-
- begin
- lrNum := FirstUnUsedRecord(fName);
- StoreALogicalRecord(fName,lrNum,source,size);
- StoreNewLogicalRecord := lrNum;
- end; (* end of StoreNewLogicalRecord routine *)
-
- (*\*)
- (* This routine will return a list of logical records which are currently in
- use (contain valid data) for a given data file. This routine is necessary
- to be able to process all records which have not been deleted without
- using an index. *)
-
- procedure GetValidLogicalRecords(fName : FnString;
- var lrLst : LrList);
-
- var
- lrNum : LrNumber;
-
- begin
- CreateLrList(lrLst);
- for lrNum := 1 to LastUsedRecord(fName) do
- begin
- if RecordUsed(fName,lrNum) then
- begin
- AddToLrList(lrNum,lrLst);
- end;
- end;
- end; (* end of GetValidLogicalRecords routine *)
-
-
- end. (* end of Logical unit *)