Alaska Software Inc. - DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
Username: Password:
AuthorTopic: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
Jose Manuel Acevedo GalvaDbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Mon, 11 Apr 2016 12:40:39 -0500
Hi, recently I discovered this error with the next scenario:

First, you've opened a DBF "TEST" and you try to lock the Phantom 
Record(LastRec() + 1)  and everything is fine, you get a TRUE as result 
and DbRLockList() will report you the recocord as locked. Ok, up to here 
no problem. But, if you try to lock the Phantom Record(LastRec()+ 1) 
again(remeber that Phantom Record remains locked) you will get a TRUE as 
result and DbRLockList() will report the record on the list, the same 
record being locked previously and this is wrong, you should be 
receiving a FALSE as result and this record out of the list.

Additional information about the work environment:

Operating Systems: 	Windows 7 Professional - 64bits - SP1
			Windows 10 Professional - 64bits
Compiler:		Alaska Xbase v1.90.335
DBE: 			FOXCDX

You'll find here a ready to compile an run sample of code I've used to 
test. You can run the exe twice for a simple locking test.

Any kind of help or sharing experiences about similar cases will be 
apreciated.

Regards,
---
José Manuel Acevedo Galván
macevedo@compuks.com


testLock.rar
Peter AlderliestenRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Wed, 13 Apr 2016 16:43:11 +0200
Jose,

> Hi, recently I discovered this error with the next scenario:
> 
> First, you've opened a DBF "TEST" and you try to lock the Phantom 
> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result 
> and DbRLockList() will report you the recocord as locked. Ok, up to here 
> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1) 
> again(remeber that Phantom Record remains locked) you will get a TRUE as 
> result and DbRLockList() will report the record on the list, the same 
> record being locked previously and this is wrong, you should be 
> receiving a FALSE as result and this record out of the list.

I don't know if this should be called an error. 
IMHO you shouldn't be locking the phantom record, at least not as a valid
(and to be checked) option.

Peter
Clifford WiernikRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Wed, 13 Apr 2016 18:51:34 -0500
On 4/13/2016 9:43 AM, Peter Alderliesten wrote:
> Jose,
>
>> Hi, recently I discovered this error with the next scenario:
>>
>> First, you've opened a DBF "TEST" and you try to lock the Phantom
>> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result
>> and DbRLockList() will report you the recocord as locked. Ok, up to here
>> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1)
>> again(remeber that Phantom Record remains locked) you will get a TRUE as
>> result and DbRLockList() will report the record on the list, the same
>> record being locked previously and this is wrong, you should be
>> receiving a FALSE as result and this record out of the list.
>
> I don't know if this should be called an error.
> IMHO you shouldn't be locking the phantom record, at least not as a valid
> (and to be checked) option.
>
> Peter
>
Are you looking the record the same time from the same thread, same 
workarea. If you are, even it is the phantom record, the 2nd lock 
releases the first lock first. Same would be on a real record. We use 
ADS and you can not lock the eof() record. We test if eof() so that you 
cannot lock it.
Jose Manuel Acevedo GalvaRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Thu, 14 Apr 2016 09:29:13 -0500
El 13/04/2016 a las 06:51 p.m., Clifford Wiernik escribió:
> On 4/13/2016 9:43 AM, Peter Alderliesten wrote:
>> Jose,
>>
>>> Hi, recently I discovered this error with the next scenario:
>>>
>>> First, you've opened a DBF "TEST" and you try to lock the Phantom
>>> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result
>>> and DbRLockList() will report you the recocord as locked. Ok, up to here
>>> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1)
>>> again(remeber that Phantom Record remains locked) you will get a TRUE as
>>> result and DbRLockList() will report the record on the list, the same
>>> record being locked previously and this is wrong, you should be
>>> receiving a FALSE as result and this record out of the list.
>>
>> I don't know if this should be called an error.
>> IMHO you shouldn't be locking the phantom record, at least not as a valid
>> (and to be checked) option.
>>
>> Peter
>>
> Are you looking the record the same time from the same thread, same
> workarea. If you are, even it is the phantom record, the 2nd lock
> releases the first lock first. Same would be on a real record. We use
> ADS and you can not lock the eof() record. We test if eof() so that you
> cannot lock it.
Hi Clifford,

It is a classic scenario where you have a shared database and you have 
several users trying to get a unique data on a sequenced field like a 
Invoice or an Order Number.

So, is a different thread and a different workarea.

 > We use ADS and you can not lock the eof() record. We test if eof() so 
 > that you cannot lock it.
I have not experienced using ADS yet.

Regards,
---
José Manuel Acevedo Galván
macevedo@compuks.com
Carlos A Beling Re: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Thu, 14 Apr 2016 15:57:10 -0300
Good afternoon.
To lock the phantom record has not sense because the phantom record is 
only an empty record that is "placed" in the work area until the record 
pointer being moved, a record is appended or the file is closed. This 
way many workstations may to have phantom records without to modify the 
database; then to lock a phantom record has not effect.
Also if you update the phantom record and want inserting the new one 
record in the database, you will have to DbAppend() a record and then 
this will erase the updates that you did.
Any way I agree that to lock the phantom record might always to return 
.t. and unlock should to do nothing.

Fraternally
Beling


On 14/4/2016 11:29, Jose Manuel Acevedo Galva wrote:
> El 13/04/2016 a las 06:51 p.m., Clifford Wiernik escribió:
>> On 4/13/2016 9:43 AM, Peter Alderliesten wrote:
>>> Jose,
>>>
>>>> Hi, recently I discovered this error with the next scenario:
>>>>
>>>> First, you've opened a DBF "TEST" and you try to lock the Phantom
>>>> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result
>>>> and DbRLockList() will report you the recocord as locked. Ok, up to
>>>> here
>>>> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1)
>>>> again(remeber that Phantom Record remains locked) you will get a
>>>> TRUE as
>>>> result and DbRLockList() will report the record on the list, the same
>>>> record being locked previously and this is wrong, you should be
>>>> receiving a FALSE as result and this record out of the list.
>>>
>>> I don't know if this should be called an error.
>>> IMHO you shouldn't be locking the phantom record, at least not as a
>>> valid
>>> (and to be checked) option.
>>>
>>> Peter
>>>
>> Are you looking the record the same time from the same thread, same
>> workarea. If you are, even it is the phantom record, the 2nd lock
>> releases the first lock first. Same would be on a real record. We use
>> ADS and you can not lock the eof() record. We test if eof() so that you
>> cannot lock it.
> Hi Clifford,
>
> It is a classic scenario where you have a shared database and you have
> several users trying to get a unique data on a sequenced field like a
> Invoice or an Order Number.
>
> So, is a different thread and a different workarea.
>
>> We use ADS and you can not lock the eof() record. We test if eof() so
>> that you cannot lock it.
> I have not experienced using ADS yet.
>
Jorge LRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Fri, 15 Apr 2016 15:06:14 -0300
Hi José, I have in the register No. 1 (or anyone) a record fill with chr 
(33)

then i use register 1like a phantom record

regards

"Carlos A Beling"  escribió en el mensaje de 
noticias:7c9bbe0c$77831b4$4b671@news.alaska-software.com...

Good afternoon.
To lock the phantom record has not sense because the phantom record is
only an empty record that is "placed" in the work area until the record
pointer being moved, a record is appended or the file is closed. This
way many workstations may to have phantom records without to modify the
database; then to lock a phantom record has not effect.
Also if you update the phantom record and want inserting the new one
record in the database, you will have to DbAppend() a record and then
this will erase the updates that you did.
Any way I agree that to lock the phantom record might always to return
.t. and unlock should to do nothing.

Fraternally
Beling


On 14/4/2016 11:29, Jose Manuel Acevedo Galva wrote:
> El 13/04/2016 a las 06:51 p.m., Clifford Wiernik escribió:
>> On 4/13/2016 9:43 AM, Peter Alderliesten wrote:
>>> Jose,
>>>
>>>> Hi, recently I discovered this error with the next scenario:
>>>>
>>>> First, you've opened a DBF "TEST" and you try to lock the Phantom
>>>> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result
>>>> and DbRLockList() will report you the recocord as locked. Ok, up to
>>>> here
>>>> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1)
>>>> again(remeber that Phantom Record remains locked) you will get a
>>>> TRUE as
>>>> result and DbRLockList() will report the record on the list, the same
>>>> record being locked previously and this is wrong, you should be
>>>> receiving a FALSE as result and this record out of the list.
>>>
>>> I don't know if this should be called an error.
>>> IMHO you shouldn't be locking the phantom record, at least not as a
>>> valid
>>> (and to be checked) option.
>>>
>>> Peter
>>>
>> Are you looking the record the same time from the same thread, same
>> workarea. If you are, even it is the phantom record, the 2nd lock
>> releases the first lock first. Same would be on a real record. We use
>> ADS and you can not lock the eof() record. We test if eof() so that you
>> cannot lock it.
> Hi Clifford,
>
> It is a classic scenario where you have a shared database and you have
> several users trying to get a unique data on a sequenced field like a
> Invoice or an Order Number.
>
> So, is a different thread and a different workarea.
>
>> We use ADS and you can not lock the eof() record. We test if eof() so
>> that you cannot lock it.
> I have not experienced using ADS yet.
>
Jose Manuel Acevedo GalvaRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Thu, 14 Apr 2016 09:15:29 -0500
El 13/04/2016 a las 09:43 a.m., Peter Alderliesten escribió:
> Jose,
>
>> Hi, recently I discovered this error with the next scenario:
>>
>> First, you've opened a DBF "TEST" and you try to lock the Phantom
>> Record(LastRec() + 1)  and everything is fine, you get a TRUE as result
>> and DbRLockList() will report you the recocord as locked. Ok, up to here
>> no problem. But, if you try to lock the Phantom Record(LastRec()+ 1)
>> again(remeber that Phantom Record remains locked) you will get a TRUE as
>> result and DbRLockList() will report the record on the list, the same
>> record being locked previously and this is wrong, you should be
>> receiving a FALSE as result and this record out of the list.
>
> I don't know if this should be called an error.
> IMHO you shouldn't be locking the phantom record, at least not as a valid
> (and to be checked) option.
>
> Peter
>

Hi Peter,

 > I don't know if this should be called an error.
I agree, may be it should be called a bug.

 > IMHO you shouldn't be locking the phantom record, at least not as a valid
 > (and to be checked) option.
Thanks for the advise, but no matter if it is a good option or a good 
programming practice it is working bad. If the Phantom Record cannot be 
locked it must return a FALSE.

In my case locking Phantom Record is a good option(if it were possible) 
because while the phantom record is locked nobody can append, so 
meanwhile you can perform several tasks to ensure avoid data corruption 
like duplicate keys.

I would like to know the point of view or a clarification about this 
from the Alaska Software Development Team.

Regards,
---
José Manuel Acevedo
macevedo@compuks.com
Andreas Gehrs-Pahl
Re: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Thu, 14 Apr 2016 01:10:13 -0400
José

The only reason I can imagine why you would want to lock the ghost record, 
is to prevent a different process to a add a new record to the table. For 
this, you should instead use FLock(), even though this prevents write access 
to any record of the table.

Up to Build 1.30.212, locking the ghost record could result in DbAppend() 
running into an endless loop, hanging the application. This was apparently 
fixed with PDR 109-3545:

http://www.Alaska-Software.com/scripts/waa001.dll?WAA_PACKAGE=PUBLICDTS&WAA_FORM=DISPLAYPDR&PDRID=3545

The original solution/workaround for this PDR was to simply not to lock the 
ghost record. It looks like the final solution for the PDR was to allow 
locking of the ghost record, but without having an actual record lock -- as 
there really isn't a real record to lock.

So you now will always get .T. if you try to lock the ghost record, even it 
was already locked. This will apparently allow DbAppend() to work, even if 
the ghost record has been (supposedly) locked. But this will also no longer 
prevent a different process to append a new record.

Hope that helps,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
Jose Manuel Acevedo GalvaRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Thu, 14 Apr 2016 18:19:13 -0500
El 14/04/2016 a las 12:10 a.m., Andreas Gehrs-Pahl escribió:
Hi Andreas,
> José
>
> The only reason I can imagine why you would want to lock the ghost record,
> is to prevent a different process to a add a new record to the table. For
> this, you should instead use FLock(), even though this prevents write access
> to any record of the table.
Yes, it is correct. But, regrettably FLock() will not work fine for me 
because this process requires concurrent locks of other processes/users 
and this is the reason why I were testing to lock the Phantom Record.

Let me tell you something, the problem is not really the Phantom Record 
Locking , initially I had a problem related to Data Corruption due to 
the SMB 2.0 and Oplocks issues and also work environments with a variety 
of operating systems(Win7/Win10 and WinServer 2012 specifically). Due to 
this problem I had to research into a new way to prevent data 
corruption(specifically duplicated keys) and the Phantom Record 
technique seems to be to me a good option/solution based on my 
experience with Clipp*r where this feature worked great.

Before this situation I never had a problem with data corruption. All 
the tools and code I had developed to manage dbfs and records were 
working fine.
>
> Up to Build 1.30.212, locking the ghost record could result in DbAppend()
> running into an endless loop, hanging the application. This was apparently
> fixed with PDR 109-3545:
>
> http://www.Alaska-Software.com/scripts/waa001.dll?WAA_PACKAGE=PUBLICDTS&WAA_FORM=DISPLAYPDR&PDRID=3545
>
> The original solution/workaround for this PDR was to simply not to lock the
> ghost record. It looks like the final solution for the PDR was to allow
> locking of the ghost record, but without having an actual record lock -- as
> there really isn't a real record to lock.
Thanks for letting me know it.

> So you now will always get .T. if you try to lock the ghost record, even it
> was already locked. This will apparently allow DbAppend() to work, even if
> the ghost record has been (supposedly) locked. But this will also no longer
> prevent a different process to append a new record.
IMHO, according to the policy of Alaska Software, related to emulate or 
preserve the Clipp*r behavior in many of its language features, it 
results disconcerting, specially if the documentation is not clear 
enough or there is not.

I really appreciate your help and your time.

Regards,
---
José Manuel Acevedo Galván
macevedo@compuks.com
Pascal BoivinRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Fri, 15 Apr 2016 15:02:36 +0200
An easy way to solve your initial problem (duplicate key) is to use a
small table with only two field:

LOCAL aStruct := {}

aAdd(aStruct, { "Number", "C", 10, 0} )
aAdd(aStruct, { "Value", "N", 15, 0} )
aAdd(aStruct, { "MaxValue", "N", 15, 0} )
DbCreate("Number.DBF", aStruct)

Then fill it with the unique number you want

Numer    Value  MaxValue
Invoice    1     9999999
Order      1     999999
Customer   1     999999


FUNCTION GetUniqueValue(cNumber)
LOCAL cAlias := Alias(), RetVal := "Record " + cNumber + " not found in
Number.dbf"

  USE Number NEW SHARED
  SET ORDER TO TAG Number
  SEEK cNumber
  IF FOUND()
    IF TryLock(5)
      IF Value < MaxValue
        REPLACE Value WITH Value + 1
        RetVal := Value
      ELSE
        RetVal := "Number of " + cNumber + " reach maximum value!"
      ENDIF
      DbrUnlock()
    ELSE
      RetVal := "Unable to lock record for " + cNumber
    ENDIF
  ENDIF
  USE
  
  IF !Empty(cAlias)
    SELECT (cAlias)
  ENDIF
RETURN RetVal


PROCEDURE AddInvoice()
LOCAL nID

  nID := GetUniqueValue("INVOICE")
  IF Valtype(nID) == "N"
    //Add invoice with unique id nID
  ELSE
    MsgBox(nID)
  ENDIF
RETURN
Jose Manuel Acevedo GalvaRe: DbRLock()/RLock() wrong behavior when locking Phantom Record(LastRec()+1) on Win 7/10.
on Fri, 15 Apr 2016 10:51:09 -0500
Hi Pascal, thanks for your response and for sharing your solution.

Regards,
---
José Manuel Acevedo
macevedo@compuks.com