Record Lock problem

Record Lock problem

Postby Wanderson » Wed Aug 07, 2013 11:01 pm

Hi, I have many problems with duplicated records, how the best way to block a record in network.

I use this to control a field name CODIGO, but in lan enviroment I have problem with records with the same CODIGO

oArqUlt:GoTop()

While ! oArqUlt:RecLock()
MsgBeep()
MsgStop("Registro bloqueado, tente novamente","Informação")
Loop
Enddo

...

oArqUlt:Load()
oArqCto:CONHEC := Strzero(oArqUlt:PROXCTO,6,0)
oArqUlt:PROXCTO := oArqUlt:PROXCTO + 1
oArqUlt:Save()
oArqUlt:Commit()
oArqUlt:RecUnlock()

Thanks in advance.
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm

Re: Record Lock problem

Postby James Bott » Thu Aug 08, 2013 2:13 pm

Wanderson,

I don't understand exactly what you are saying. Is CODIGO the primary key field? How are you setting it (your sample code does not show the field CODIGO)?

I have found that you cannot use the database to keep track of the last used ID as you will get duplicates due to index problems (corruption, not the current index, etc). I use a separate database to keep track of the last used ID.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby Wanderson » Thu Aug 08, 2013 6:53 pm

James Bott wrote:Wanderson,

I don't understand exactly what you are saying. Is CODIGO the primary key field? How are you setting it (your sample code does not show the field CODIGO)?

I have found that you cannot use the database to keep track of the last used ID as you will get duplicates due to index problems (corruption, not the current index, etc). I use a separate database to keep track of the last used ID.

James


Hi Jame, thanks for your answer. I explain

I have a customer table with many fields, the first field is name CODIGO Type Numeric and lenght 6.
I have another table with one field named NEXTCUS Type Numeric and lenght 6, i use this field to control the inserts. All the time that i insert one registry in customer table i lock this field and add +1 to NEXTCUS, save and unlock. I use this because dbf do not have a auto increment field. But in some cases i see duplicated datas in table customer with equal CODIGO. My question is how the best way (i use tdatabase) to lock and unlock my table NEXTCUS in network situation.
Sorry about my terrible english.

Thanks in advance.
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm

Re: Record Lock problem

Postby avista » Thu Aug 08, 2013 8:43 pm

HI You must detect next valye for CODIGO in moment of writing data

try this example

Code: Select all  Expand view
SELECT customer
APPEND BLANK
REPLACE CODIGO WITH NextCODIGO() ,;
        Field2 WITH ???          ,;
        Field3 WITH ???
        ...

FUNCTION NextGODOGO()

Local SelectedFile  := SELECT()
Local SelectedIndex := INDEXORD()

Local nGODIGO := 0

SELECT anothertable
GO BOTTOM
IF EOF()
   nGODIGO := 1
 ELSE
   nGODIGO := GODIGO + 1
ENDIF

APPEND BLANK
REPLACE GODIGO WITH nGODIGO

SELECT( SelectedFile )
SET ORDER TO SelectedIndex

RETURN nGODIGO

User avatar
avista
 
Posts: 301
Joined: Fri Jun 01, 2007 9:07 am
Location: Macedonia

Re: Record Lock problem

Postby James Bott » Thu Aug 08, 2013 9:25 pm

Wanderson,

I have a customer table with many fields, the first field is name CODIGO Type Numeric and lenght 6.

I have another table with one field named NEXTCUS Type Numeric and lenght 6, i use this field to control the inserts. All the time that i insert one registry in customer table i lock this field and add +1 to NEXTCUS, save and unlock.

OK, remember that locking a record does not prevent reading. So, when you read the record, you need to make sure it is not locked before reading. If it is locked, then you need to keep checking until it is unlocked before reading it.

Note that there is a fairly new FWH function isLocked(). We didn't have this in Clipper.

James
Last edited by James Bott on Thu Aug 08, 2013 9:34 pm, edited 1 time in total.
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby James Bott » Thu Aug 08, 2013 9:33 pm

Avista,

Using GO BOTTOM is risky since records may get deleted (unless the app doesn't allow it). If there were records created with that ID (invoices printed, etc.) then that record is deleted, it would get reused for a new customer. Not good.

I have also had a corrupted file cause a problem with this method. GO BOTTOM did not actually go to the bottom but to the middle and I ended up with lots of duplicates.

I have been using a separate file with just one last used ID field (as Wanderson is doing) for many years without any problems.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby Rick Lipkin » Thu Aug 08, 2013 10:31 pm

Wanderson

I would write a function to create the next unique number and before I append it to the database .. I would test for its existence in the customer database... if I don't find it I would update the nextcus table and return that number to your CUstomer add routine and

Something like this

Rick Lipkin
Code: Select all  Expand view


// customer add routine

nID := _GenId()
Select Customer
append blank

customer->Codigo := nId
..
...
dbCOmmit()

//------------------
Static Func _GenId()

Local nNext

Select CUstomer
set order to tag CustomerID // indexed on codigo

Select nextcus
nNext := nextcus->codigo
DO WHile .t.
     
     nNext++
     select customer
     seek nNext
     if .not. found()
        select nextcus
        nextcus->codigo := nNext
        exit
     endif

Enddo

CLose nectcus
select CUstomer
set order to last tag  // set index back

return( nNext )  
 
User avatar
Rick Lipkin
 
Posts: 2665
Joined: Fri Oct 07, 2005 1:50 pm
Location: Columbia, South Carolina USA

Re: Record Lock problem

Postby Wanderson » Thu Aug 08, 2013 11:35 pm

James Bott wrote:Wanderson,

I have a customer table with many fields, the first field is name CODIGO Type Numeric and lenght 6.

I have another table with one field named NEXTCUS Type Numeric and lenght 6, i use this field to control the inserts. All the time that i insert one registry in customer table i lock this field and add +1 to NEXTCUS, save and unlock.

OK, remember that locking a record does not prevent reading. So, when you read the record, you need to make sure it is not locked before reading. If it is locked, then you need to keep checking until it is unlocked before reading it.

Note that there is a fairly new FWH function isLocked(). We didn't have this in Clipper.

James


Hi James I understand but in my case I dont read the record before a

oArqUlt:GoTop()
While ! oArqUlt:RecLock()
MsgBeep()
MsgStop("Registro bloqueado, tente novamente","Informação")
Loop
Enddo

In this case if I locked the record first other user see the message "Record Lock"

Thanks.
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm

Re: Record Lock problem

Postby Wanderson » Thu Aug 08, 2013 11:38 pm

avista wrote:HI You must detect next valye for CODIGO in moment of writing data

try this example

Code: Select all  Expand view
SELECT customer
APPEND BLANK
REPLACE CODIGO WITH NextCODIGO() ,;
        Field2 WITH ???          ,;
        Field3 WITH ???
        ...

FUNCTION NextGODOGO()

Local SelectedFile  := SELECT()
Local SelectedIndex := INDEXORD()

Local nGODIGO := 0

SELECT anothertable
GO BOTTOM
IF EOF()
   nGODIGO := 1
 ELSE
   nGODIGO := GODIGO + 1
ENDIF

APPEND BLANK
REPLACE GODIGO WITH nGODIGO

SELECT( SelectedFile )
SET ORDER TO SelectedIndex

RETURN nGODIGO



Thanks avista but I had many insues with this solutions
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm

Re: Record Lock problem

Postby RAMESHBABU » Fri Aug 09, 2013 12:29 am

Hello Friends,

Try this

Code: Select all  Expand view

#include "fivewin.ch"

STATIC nCodeRef
REQUEST DBFCDX

********************

FUNCTION Main()

LOCAL nOldCode, nNewCode

FIELD party_code

IF .NOT. FILE("UNIQUEID.DBF")
   Create_Dbf()
ELSE
   USE UniqueId SHARED NEW
ENDIF
 
INDEX ON party_code TAG party_code TEMPORARY
GO BOTTOM

nOldCode := party_code
nCodeRef := party_code-RECNO()

APPEND BLANK

nNewCode := (UniqueId->(RecCount()) + nCodeRef)

IF RLock()
   REPLACE Party_Code WITH nNewCode
   DbUnLock()
ENDIF

MsgInfo("New Party Code "+LTRIM(STR(Party_Code)), "Old Code : "+LTRIM(STR(nOldCode)))

RETURN nil

**********

FUNCTION Create_Dbf()

LOCAL aStruct := { { "PARTY_CODE","N", 5, 0 } }

DbCreate( "UniqueId", aStruct, "DBFCDX", .T., "UniqueId" )

RETURN nil

**********
 


- RAMESH BABU
User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Re: Record Lock problem

Postby James Bott » Fri Aug 09, 2013 1:43 am

Wanderson,

OK, I have studied your code some more. I was confused, because in your description you said the fieldname of the primary key was CONDIGO, but it seems it is CONHEC (oArq:CONHEC). Also the fieldname you said was NEXTCUS is really PROXTO (oArqUlt:PROXTO).

I am assuming oArqUlt is the database that you keep the NEXT UNUSED primary key in.

If my assumptions are true, then you are doing just what I suggested--locking the record, incrementing the number and saving it, then unlocking. And nobody else can read the next key while the record is locked. I don't see how this can fail.

So I have to assume there is some other code that is causing the problem. What is the missing code "..." doing? Is there code somewhere else in your program that is reading the next key without using this routine?

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby James Bott » Mon Aug 12, 2013 2:03 pm

Wanderson,

May I also suggest writing a small sample program that just adds new records to the customer file. Then run two or more copies of this program across the LAN for a few minutes, then check for duplicates.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby Wanderson » Tue Aug 13, 2013 5:24 pm

James Bott wrote:Wanderson,

May I also suggest writing a small sample program that just adds new records to the customer file. Then run two or more copies of this program across the LAN for a few minutes, then check for duplicates.

James


Thanks James. In my pc with 2 copies of my program runs ok, not duplicated but the case occurs in my customer with windows xp and lan mapped unit. I think is some windows xp bug.
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm

Re: Record Lock problem

Postby James Bott » Thu Aug 15, 2013 2:18 pm

Wanderson,

I think is some windows xp bug.


I do remember some issues with COMMITs because the OS doesn't necessarily flush the buffers when a COMMIT is issued.

In this case I guess the best solution is to check for the existence for a duplicate record before saving a new record. If the same primary key already exists, then go back and generate another key and try saving again.

Another possibility might be to add a slight delay after locking the primary key record, and actually reading it. I.E. lock it, wait, read it using oDBF:load().

Or use both ideas.

You can build all this logic into a subclass of TDatabase. Create a new Append method that automatically increments the primary key field and saves it to the newly appended record, then calls the load() method (to get the primary key into the buffer).

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Record Lock problem

Postby Wanderson » Fri Aug 16, 2013 3:29 pm

James Bott wrote:Wanderson,

I think is some windows xp bug.


I do remember some issues with COMMITs because the OS doesn't necessarily flush the buffers when a COMMIT is issued.

In this case I guess the best solution is to check for the existence for a duplicate record before saving a new record. If the same primary key already exists, then go back and generate another key and try saving again.

Another possibility might be to add a slight delay after locking the primary key record, and actually reading it. I.E. lock it, wait, read it using oDBF:load().

Or use both ideas.

You can build all this logic into a subclass of TDatabase. Create a new Append method that automatically increments the primary key field and saves it to the newly appended record, then calls the load() method (to get the primary key into the buffer).

Regards,
James


Thanks James.
Wanderson
 
Posts: 332
Joined: Thu Nov 17, 2005 9:11 pm


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 100 guests