home *** CD-ROM | disk | FTP | other *** search
- program FixDel;
-
- {$I+}
-
- { Fix the deleted record chain in a Database Toolbox data file.
-
- Scott Bussinger
- Professional Practice Systems
- 110 South 131st Street
- Tacoma, WA 98444
- (206)531-8944
- Compuserve 72247,2671
-
- Version 4.01 - 10/14/1988 - Refixed bug with reading one too many records
- 4.00 - 6/28/1988 - Converted for use with version 4
- 1.00 - 9/22/1987 - First release
-
- The Database Toolbox uses the first four bytes of a DataFile as a marker
- that a record has been deleted. By convention, if the first four bytes
- (considered as an longint) are 0, then the record is in use. Otherwise the
- record is deleted. AddRec will reuse deleted records before allocating new
- records at the end of the DataFile. This keeps the DataFile as small as
- possible.
- Normally this happens invisibly to your program as DeleteRec and AddRec
- are called and you don't need to do anything except make the first field in
- the data type for all of your DataFiles look like:
- DeletedRec: longint;
- Internally, the Database Toolbox keeps two variables pertaining to the
- deleted record chain. The first is FirstFree and is the record number of
- the next deleted record to be reused when AddRec is next called. The other
- variable is NumberFree and is the number of deleted records available in
- the DataFile. This value is used only in the calculations for UsedRecs so
- that you can find out how many records are in use without actually scanning
- the file. When a record is deleted, current value in FirstFree is written
- into the deleted record and FirstFree is set to deleted record's record
- number. This creates a chain of deleted records.
- When AddRec is called, FirstFree is checked to see if there are any
- deleted records to be reused. If FirstFree is -1 then there are no deleted
- records and the file is made larger. Otherwise AddRec uses the value of
- FirstFree as the record number, reads in that record and sets FirstFree to
- the value saved in the deleted record. This goes back down the deleted
- record chain.
- Everything works fine as long as nothing goes wrong. If a DataFile gets
- messed up though power failure, media problems or programming bugs, then
- this deleted record chain can be trashed and all sorts of strange things
- can happen. For example, lets say that the header record in a file takes a
- hit and FirstFree ends up pointing at a record that is really a record in
- use. In this case the next time AddRec is called, the previous contents
- of the record are overwritten by the new record. If you are using index
- files, you will probably have two keys pointing at this record (one for the
- record just added and one for the original record). Even worse, FirstFree
- takes its new value from that record and will be set to 0 (since the record
- wasn't deleted). Now, the next AddRec will write its record on top of the
- header record! At this point things get progressively worse and all kinds
- of bizarre behaviour is common.
- Just as it is good practice to reindex files occasionally, it is a good
- idea to rebuild the deleted record chain of DataFiles. This program will
- rebuild the deleted record chain of any DataFile and can also serve as a
- guideline for writing your own programs.
- To use this program, compile it to disk with Turbo Pascal 4. Then from
- the DOS prompt, type
- FIXDEL filename recsize
- where 'filename' is the name of a DataFile and 'recsize' is the number of
- bytes in a record. This record size is the same number passed to the
- OpenFile routine. }
-
-
- type DBoxHeaderRec = record { Layout the a header record }
- FirstFree: longint;
- NumberFree: longint;
- Int1: longint;
- RecLen: word
- end;
-
- var Buffer: ^longint; { Pointer to deleted record flag }
- ErrorCode: integer;
- Fyle: file;
- Header: DBoxHeaderRec;
- RecNum: longint;
- RecSize: word;
-
- begin
- case paramcount of
- 0: writeln('Usage: FIXDEL filename recsize');
- 1: writeln('Not enough parameters.');
- 2: begin
- val(paramstr(2),RecSize,ErrorCode);
- if (ErrorCode<>0) or (RecSize<14)
- then
- writeln('Record size out of range.'^G)
- else
- begin
- getmem(Buffer,RecSize); { Get enough memory to hold a record }
- assign(Fyle,paramstr(1));
- {$I-}
- reset(Fyle,RecSize); { Open the data file }
- {$I+}
- if ioresult <> 0
- then
- writeln(paramstr(1),' not found.'^G)
- else
- begin
- blockread(Fyle,Buffer^,1); { Get the header record }
- move(Buffer^,Header,sizeof(Header));
- with Header do
- begin
- FirstFree := -1; { Initialize deleted record chain }
- NumberFree := 0; { Deleted record chain now empty }
- Int1 := 0; { Zap the index root page }
- RecLen := RecSize { Reset the record length }
- end;
- for RecNum := 1 to filesize(Fyle)-1 do { Go through all records }
- begin
- seek(Fyle,RecNum);
- blockread(Fyle,Buffer^,1); { Get data record }
- if Buffer^ <> 0 then { Is this a deleted record? }
- begin
- Buffer^ := Header.FirstFree; { Put record in chain }
- Header.FirstFree := RecNum; { New head of list }
- inc(Header.NumberFree); { One more deleted }
- seek(Fyle,RecNum); { Put file position back }
- blockwrite(Fyle,Buffer^,1){ Put deleted record back }
- end
- end;
- seek(Fyle,0); { Put fixed header back in file }
- blockwrite(Fyle,Header,1);
- close(Fyle) { We're done }
- end
- end
- end
- else writeln('Too many parameters.')
- end
- end.