Looking at Locking

A long time I believed like so many others that Visual FoxPro uses the area beyond 2 GB for locking purposes. wOOdy was the first to point out to me that this isn't the case. He said that this fact further reduces the number of records in a table. So how does locking really work in Visual FoxPro?
As far as locking is concerned, Visual FoxPro treats the header as record number 0. This allows for using the same code for locking records as well as the header. Whenever Visual FoxPro updates the table header, it locks this byte first. Locking the header is required for adding a record. You can manually lock the header using


Lock("0",Alias())

The record lock bytes start at position 2,147,483,645 for record number 1 and go down from there. Hence, record number 2 is locked at 2,147,483,644, and so on. When Visual FoxPro locks a single record or the header, it only locks the corresponding byte.

FLOCK() locks the entire table. Technically, locking the table is identically to locking all records and the table header. If Visual FoxPro would only lock existing records this could lead to a raise condition. On one machine, Visual FoxPro would read the current number of records to determine which part of the locking area needs to be locked. After performing this calculation but before actually requesting the lock, another machine could add a new record. As a result, Visual FoxPro would either have to extent the locking area afterwards, or lock the table header before locking records.

Because that impacts performance, Visual FoxPro locks the highest possible number of records instead. The following expression returns the maximum number of records for any given table:


Int((2^31-Header()-2)/(Recsize()+1))

If you add more records than this to a table, you should either get an error message, or you would suffer from serious problems accessing the last records as they overlap with their own locking area. I haven't yet tested what happens in this case. Visual FoxPro starts locking at position:


2^31 - 1 - Int((2^31-Header()-2)/(Recsize()+1))