Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
BUG :VFP's Transactions are only corrected with bufferin
Message
De
13/12/2004 03:53:03
 
 
À
10/12/2004 06:14:58
Information générale
Forum:
Visual FoxPro
Catégorie:
Visual FoxPro Beta
Divers
Thread ID:
00968242
Message ID:
00968678
Vues:
9
Hi Fabio,

This behavior is not specific to TRANSACTIONs and doesn't make them incorrect, but putting "VFP's Transactions are only corrected with buffering=5" into title sure makes it very dramatic.

If you replace the following code:
  =CURSORSETPROP("Buffering",_BUFFERINGMODE,100)
with
  =CURSORSETPROP("Buffering",_BUFFERINGMODE,100)
  APPEND BLANK IN 100
  GO TOP IN 100
you'll see that even buffering=5 doesn't give you result you expect.

I admit, at first the behavior looks very strange, but there is an explanation for it.

The CURVAL() and OLDVAL() functions are designed for the specific scenario - update conflict management and resolution.

1) Here is how documentation describes the OLDVAL function: "Returns original field values for fields that have been modified but not updated." If record is not modified then it is expected to get the same value for TABLE_ON_SESSION_1.F1 and OLDVAL("F1",100).

2) Documentation for CURVAL() says the following: "CURVAL( ) and OLDVAL( ) can only return different values when optimistic row or table buffering is enabled." Therefore, for Buffering=2 or 4, it is expected to get the same value for OLDVAL("F1",100) and CURVAL("F1",100).

3) Because VFP uses file and record caching (do not confuse with row buffering), it is expected that TABLE_ON_SESSION_1.F1 doesn't return the most recent value from the record unless the record is locked.

4) If the record is not pessimistically/optimistically locked, it is expected that the record (TABLE_ON_SESSION_1.F1) might be refreshed with newer values, which might be not the most recent values.

What the TRANSACTION changes in this scenario? It changes whether and when one data session S1 "sees" changes made in another data session. It changes this by affecting how VFP caches the file and the record and, if the record is cached, when the record cache is refreshed/discarded. BEGIN/END TRANSACTION are not unique in this, many other commands might have similar side-effects. The record is not locked, the record is not modified, VFP is free to refresh record's content or not refresh it at any time. Developer shouldn't expect either because he is not in control. To get control, developer should pessimistically/optimistically lock the record.

Going back to the scenario, what can be expected?
- TABLE_ON_SESSION_1.F1 and OLDVAL("F1",100) should be the same because the record is not modified.
- For buffering 2 and 4, OLDVAL("F1",100) and CURVAL("F1",100) should be the same.
- For buffering 3 and 5, CURVAL("F1",100) should return value from disk.
- TABLE_ON_SESSION_1.F1 can't be expected to be refreshed nor it can be expected to stay the same, because the record isn't locked.

This is exactly how the result looks like.

Fabio, things don't always work the way you think they should. In this particular case, they are not designed to work that way, they are designed to work in a different way. I am not going to discuss whether it is a good or bad design, it doesn't make sense now, the design is many years old. The purpose of this reply is to explain how things work, what can be expected and what should not be expected. So that you and, more important, other developers could write reliable applications with predictable behavior.

Thanks,
Aleksey.

>Previous issue Thread #967998
>
>Bug/Issue : 28 of 49
>
>TITLE: BUG : the Transactions of VFP are only corrected with "optimistic table buffering"
>
>VERSION: 09.00.0000.1720 and previous
>
>EXPECTED: unchanged data must reflect the tables data
>
>OBSERVED:
>- within a transaction, with the buffering pessimistic, CURVAL() it is mistaken
>- with "optimistic table buffering" all it could be corrected
>
>REPRO:
>
>#DEFINE DBNAME SYS(2023)+'\DB______1'
>#DEFINE TABLENAME SYS(2023)+'\TABLE______1'
>
>* You changes the BUFFERINGMODE here
>#DEFINE _BUFFERINGMODE  2
>
>CLOSE ALL
>CLEAR
>ERASE FORCEEXT(DBNAME,'*')
>ERASE FORCEEXT(TABLENAME ,'*')
>* OPEN SESSION 1
>
>S1=CREATEOBJECT("SESSION")
>  SET DATASESSION TO S1.DATASESSIONID
>  * build a DBC for do the test
>  CREATE DATABASE DBNAME
>  * a table
>  CREATE TABLE TABLENAME ( F1 I)
>  * a row
>  APPEND BLANK
>  * relase exclusive access
>  CLOSE DATABASES
>  SET MULTILOCKS ON
>  * open share
>  USE TABLENAME IN 100 ALIAS TABLE_ON_SESSION_1 SHARE
>  =CURSORSETPROP("Buffering",_BUFFERINGMODE,100)
>  ? [BUFFERING's table :],CURSORGETPROP("Buffering",100)
>  ? "OPEN A FIRST TRANSACTION, BUT THIS DON'T DO ANYTHING"
>  ? ALIAS(100),TABLE_ON_SESSION_1.F1,OLDVAL("F1",100),CURVAL("F1",100)
>  BEGIN TRANSACTION
>    ********************************************************
>    * NOW SIMULATE ANOTHER SESSION, THIS WRITE ON THE TABLE NOW
>    =anotherSession('transaction_X')
>    ********************************************************
>  SET DATASESSION TO S1.DATASESSIONID
>  ?
>  ? "MINOR BUG 1: THE SESSION 1 WORKAREA IS NOT TOUCHED, THEN"
>  ? "EXPECTED 0|2 ,0|2 ,2 because field value on disk it is 2"
>  ? ALIAS(100),TABLE_ON_SESSION_1.F1,OLDVAL("F1",100),CURVAL("F1",100)
>  ?
>  ? "CLOSE THE FIRST TRANSACTION"
>  END TRANSACTION
>  ? "SERIOS BUG 2: I have not written into the record, IT'S STATUS IT IS :",GETFLDSTATE(-1,100)
>  ? "THEN EXPECTED 2,2,2 because field value on disk it is 2"
>  DO CASE
>    CASE CURSORGETPROP("Buffering",100)=2
>      ? "OBSERVED 0,0,0 !!!"
>      ? "WORKAROUND : exec a TABLEREVERT() on all the tables with Row buffering"
>    CASE CURSORGETPROP("Buffering",100)=3
>      ? "OBSERVED 0,0,2 !!!"
>      ? "WORKAROUND : exec a TABLEREVERT() on all the tables with Row buffering"
>    CASE CURSORGETPROP("Buffering",100)=4
>      ? "OBSERVED 2,2,2"
>    CASE CURSORGETPROP("Buffering",100)=5
>      ? "OBSERVED 2,2,2"
>  ENDCASE
>  ? ALIAS(100),TABLE_ON_SESSION_1.F1,OLDVAL("F1",100),CURVAL("F1",100)
>  RELEASE S1
>CLOSE ALL
>ERASE FORCEEXT(TABLENAME ,'*')
>ERASE FORCEEXT(DBNAME,'*')
>
>PROCEDURE anotherSession(_alias)
>  ?
>  ? CHR(9),"SIMULATE ANOTHER TRANSACTION, THIS ADD 2 TO THE FIELD VALUE"
>  WITH CREATEOBJECT("SESSION")
>    SET DATASESSION TO .DATASESSIONID
>    USE TABLENAME ALIAS (m._alias) SHARED
>    BEGIN TRANSACTION
>      REPLACE F1 WITH F1+2
>    END TRANSACTION
>    ? CHR(9),ALIAS(),F1
>  ENDWITH
>endproc
>
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform