Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Automatic Record Locking in FoxPro 2.x 2

Status
Not open for further replies.

michel392

Programmer
Dec 17, 2001
54
BR
To turn my FoxPro 2.0 (I have the LAN version for development of application) application in a multi-user application I just put the following commands in the main program:
SET EXCLUSIVE OFF
SET REPROCESS TO AUTOMATIC
Of course, if a routine opens a file to pack it, it is opened with the command EXCLUSIVE set to ON in the program.
The .EXE file is set to Read Only in the server machine.
The DOS application runs under Windows 95/98 without problems in a multi-user environment.
I understood that I don't have to worry about putting RLOCKs in the programs ( do not use FLOCK or RLOCK), I just used the commands above. Am I correct or am I missing something important?
Thank you very much
Michel
 
It is always better to retain control of your app. FoxPro only unlocks a record if the UNLOCK statement is issued, or the record pointer is moved.
For example, suppose a customer calls and wants to order something. A user changes their record and saves it, then goes to lunch. The customer calls back and tells another user they want to add something to their order. Since the first person saved the record, but didn't move to another record, the customers' record is still locked. The second user is forced to wait until the first user unlocks the record. You should always test for the record already being locked by another user before attempting to update it by using something like:

IF RLOCK()
*... update record
UNLOCK
ELSE
WAIT WINDO "Record is in use." TIMEOUT 3
ENDIF

Check the documentation for the commands:
RLOCK()
UNLOCK
UNLOCK ALL
SET REPROCESS TO

Dave S.
 
Hi there,

How did you go about using Record locking? Do you have any code snippets at all?

Thanks,

Steve Harris
 
Here are a couple of functions I use for record locking.
Use the SET REPROCESS statement in you initialization area of your main program. 5 SECONDS will attempt a record lock, pause for 5 seconds, retry, and so on:

SET REPROCESS TO 5 SECONDS
SET PROCEDURE TO proc_lib &&... or whatever it is named

When it comes time to attempt a record lock, you can do something like:

Code:
SELECT table1
IF rec_lock()
   SELECT table2
   IF rec_lock()
      IF *... any other locks that need to be made
         *... update record(s)
      ENDIF
   ENDIF
ENDIF
UNLOCK ALL

Then place the following two finctions within your procedure library (proc_lib.prg):

Code:
*!********************************************************
*!       Function: REC_LOCK
*!
*!          Calls: ABORTRLOCK         
*!
*!*******************************************************
FUNCTION rec_lock
   
   PUBLIC abort_rlock
   
   STORE 0 TO retries
   STORE .F. TO islocked
   STORE .F. TO abort_rlock
   SET ESCAPE ON
   ON ESCAPE DO abortrlock
   
   DO WHILE retries <= 10 .AND. !abort_rlock
      IF RLOCK()
         STORE .T. TO islocked
         EXIT
      ELSE
         retries = retries + 1
         WAIT WINDOW 'Attempting to lock record...' + LTRIM(STR(retries)) + '/10'NOWAIT
         STORE .F. TO islocked
      ENDIF ( RLOCK() )
   ENDDO ( retries <= 10 .AND. !abort_rlock )

   IF !islocked
      WAIT WINDOW &quot;Unable to lock record' TIMEOUT 3
   ENDIF

   SET ESCAPE OFF
   RETURN islocked
*: end proc 
   
*!*********************************************************
*!      Procedure: ABORTRLOCK
*!
*!      Called by: REC_LOCK()         (function  in STRATPRC.PRG)
*!
*!*********************************************************
PROCEDURE abortrlock
   
   ON ESCAPE
   SET ESCAPE OFF
   abort_rlock = .T.
   WAIT WINDOW &quot;Lock request aborted.&quot; TIMEOUT 2
   RETURN

*: end proc

Dave S.

 
Hi Steve,

Dave has some very good suggestions ; at our firm we used a different approach to locking when you're simply updating one field (for example the balance field when one user is changing the address and another user is making a payment for the same customer).

- try to lock the record.
- if after 5 tries no lock, we create a record in a table called fUpdate, containing a refrence to what record we wanted to update, which field and the delta-value, and get on with our business.
- when a program is about to unlock a record again, it will first check the fUpdate table to see if there are pending changes ; if so, it will execute them and check again.
- if there are no pending changes, the record is unlocked.

This mixture of pessimistic/optimistic locking in one program has been working just fine as a strategy for us.

Best regards,

Jan Schenkel.

&quot;As we grow older, we grow both wiser and more foolish at the same time.&quot; (De Rochefoucald)
 
Thank you very much to all of you who is helping me.

Dave S.:

Reading your helpful answer made me understand that I must issue an UNLOCK command every time an user finishes replacing fields in a record.
About testing if a record is in use by another I already use the ON ERROR DO ErrorHandler (a routine in a procedure), that manages errors (It displays the message &quot;Record is in use by another&quot; if an user is trying to manipulate fields of a that is already locked by other user) and then return to the main program). But is this error routine a necessity if I use the SET REPROCESS TO AUTOMATIC ?

Thanks
Michel



Steve:
I didn't understand your answer (I'm Brazilian and I'm not very good in English). But I feel I am missing something that could be helpful. Could you or any colleague please explain the following:
&quot;How did you go about using Record locking? Do you have any code snippets at all?&quot;

Thanks
Michel



Jan:
Your approach is a good idea, but for now, as I am new to multi-user environment in FoxPro (I have experience in locking routines in another language), I would like to simplify my work, for I'm afraid of commiting errors (my applications are in use in a some firms, and they want to use the same systems in more than one machine). So I want to, at least for now (in order to put the applications in a multi-user environment) to do minor changes in programs.


Thanks
Michel
 
Hi Michel,

I was asking for an example of the code you used to enable multi-user access to your FoxPro2.6 applications.

Could you post some code examples on the forum ? - Thanks

As an aside, you do need to use lock() which is the same as rlock(). SET REPROCESS merely retries the locking procedure if the record was locked by someone else the first time you tried.

Exclusive needs to be OFF to do this, of course.

Best regards,

Steve Harris
 
Michel:
Regarding SET REPROCESS. If you don't use it, the application will try to lock the record indefinitely, which could cause the app to hang for an undetermined length of time, until the other user releases the record. If the network client software is acting flakey, it may not release the record lock properly and the machine waiting for the lock would hang forcing a reboot. Reprocess also forces the app to attempt a record lock as long as you want it to rather than producing an error message after one failed record lock attempt, giving sufficient time for the other user to commit changes and release the record. By setting reprocess to a value such as 5 seconds, I give the user some visual feedback as to what is happening with the application, giving them a sort of comfort level knowing the app is trying to do its job but is waiting on another user. Also, this gives them the opportuninty to cancel the update and retry later if unable to obtain a lock immedietly on that record.

Steve:
There are no special commands to 'enable' record locking or multi-user access as FoxPro is inherently multi-user. The only required statement is SET EXCLUSIVE OFF, which is placed at the beginning of your 'main' program, or somewhere prior to USEing and tables. If you don't issue the SET EXCLUSIVE OFF statement, you must remember to USE all tables SHARED or you will get a 'File is in use' error every time you attempt to open it on another computer. From there, all you need to do is use LOCK() or RLOCK() to test for the availability of a record prior to attempting and update, and UNLOCK after completing the update. Using LOCK() or RLOCK() along with REPROCESS is highly recommended over using nothing at all as I mentioned earlier in this post, because it allows the programmer more control over how the app performs and allows the app to interract with the data more gracefully.

Dave S.
 
Steve,

Here is a piece of code of my program.
For the use of this program in a multi-user environment, I put the 2 commands below(marked with <<<<===============)
According to Dave S., I must put UNLOCK after putting the record in the file (REPLACE command). I have just put it there (marked with <<<<=*=*=*=*=*=*=*=*=*=*=*=*=*=)

SET etc
SET EXCLUSIVE OFF && <<<<===============
SET REPROCESS TO AUTOMATIC && <<<<===============

USE CUSTOMERS INDEX INDCCODI
PP=1
DO WHILE PP<>0
CLEAR
@ 1,23 SAY &quot;* NEW CUSTOMER *&quot;

YCCODI=0
YCNOME=SPACE(34)
YCCIDA=SPACE(20)

@ 3, 1 SAY &quot;CUSTOMER CODE&quot; GET YCCODI PICTURE '9999'
READ
IF YCCODI=0
PP=0
LOOP
ENDIF

SEEK YCCODI
IF .NOT. EOF()
@20,30 SAY &quot;CODE ALREADY EXISTS &quot;
WAIT &quot; &quot; TIMEOUT 3
@20,30 SAY &quot; &quot;
LOOP
ENDIF

@ 5, 1 SAY &quot;NAME ............ &quot; GET YCNOME
@10, 1 SAY &quot;CITY ............ &quot; GET YCCIDA
READ

OK=&quot; &quot;
DO WHILE OK<> &quot;Y&quot; .AND. OK<> &quot;N&quot;
@23,30 SAY &quot;IS RECORD OK Y/N&quot; GET OK PICTURE '!'
READ
ENDDO
IF OK=&quot;Y&quot;
APPEND BLANK
REPLACE CCODI WITH YCCODI
REPLACE CNOME WITH YCNOME
REPLACE CCIDA WITH YCCIDA
UNLOCK && <<<<=*=*=*=*=*=*=*=*=*=*=*=*=*=
ENDIF
ENDDO
USE

RETURN




If there was a SEEK YCCODI (in the case of updating an existing record) I would use:
@ 3, 1 SAY &quot;CUSTOMER'S CODE &quot; GET YCCODI PICTURE '9999'
READ
SEEK YCCODI && record that contains customers'code
IF FOUND() && customer's code was found !
IF RLOCK() && <<<<=*=*=*=*=*=*=*=*=*=*=*=*=*=
updates record ...

Thanks to all of you who are helping me. Happy new Year !
:) Michel
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top