Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Speed tip needed
Message
 
To
08/06/2001 15:25:40
Walter Meester
HoogkarspelNetherlands
General information
Forum:
Visual FoxPro
Category:
COM/DCOM and OLE Automation
Miscellaneous
Thread ID:
00514404
Message ID:
00517352
Views:
15
>Hoi peter,
>
>Fijn om meer nederlanders te zien op de UT.
>
>
>>Whether the the DO WHILE RECCOUNT() works I'm not sure, but just an =RECCOUNT() is sufficient to work. Why ? simple (or logic) too :
>>
>>Whenever an Append is performed, your PC must know about the last record which is contained in the header. So underwater the reccount() is performed. If it didn't, recno()'s would get confused. So, this one is waterproof. Now since you always get the actual reccount(), you *must* get the data too, otherwise things would get inconsistent.
>
>It's not that simple unfortunately. Just try the following:
>1. open one instance of VFP use any table and SET REFRESH TO 0,0
>2. open another instance of VFP, open the same table and SET REFRESH TO 0,0
>3. In instance1 append one record, and ? RECCOUNT()
>4. Go to instance2 and ? RECOUNT() again.
>
>You'll see that instance2 did not catch the appended record.
>
>The problem is that the tableheader is chached in memory and only refreshes with a refresh (set by SET REFRESH) or a table or record lock.
>
>This is the reason why VFP locks the tableheader when appending records.
>In either way, one should wait until the global refresh occurs or lock (and unlock) a table, record or tableheader.
>
>Regards,
>
>Walter,

Okay Walter (hoi to you too !),

Like I said, there are many pages on this subject ...
Excuse me for doing too much by heart, and where I tried to use the experience on our transaction-processing module which does sort of the same things as Mike, and always needs the most actual data. And ... this works. But now how.

So, I was wrong, or anyway not complete;
Yes Walter, what you describe it true; the =Reccount() doesn't do the job. The next is the proper explanation, and this time I confirmed it by some tests ;)

Base : SET REFRESH TO 0,0
No FLock is used.

  • The Writer can't influence what the Reader sees in any way. Note that many commands and/or Help implies differently; it's all not true. Not the Flush, not the Unlock (for sure) not the Refresh, and not even closing the table. Notice also that all the logic of commands imply that this *can* be influenced, and this is exactly why we all get confused on this.

  • Where I state that the Reader can get the actual data at will, from the above follows that all must be done at the Reader's site.

  • The above has one exception : If the writer has locked the record and replaced it with some (new) data, the Reader will never be able to see this new data. This says nothing about the possible retrieval of a new record being there !

  • No matter what I state below, locking should always be used in the proper way, because else your data get's corrupted (overwrite another's data). Remember that locking is a convention. However, Fox does it's best to deal with all the best it can. But : If one Writer performs an Append Blank immedeately followed by an Rlock(), another writer can get in between these two lines, and perform a Replace in the other's Append. Therefore in a decent system, Append and Replace should never be used, and a Insert SQL should be used instead; nothing can get in between that.

    Now next points are all methods of retrieving the actual number of records. This says nothing about the actuality of the data in them !
    Basis : A Writer appends a record and Reccount() has become 10;
    A Reader can perform :


  • Go Bottom followed by Skip 1. Reccount() now shows 10;
    This Skip refuses to show EOF(), which in fact wouldn't be true.

  • An Rlock() in any record. Reccount() now shows 10;
    Any Rlock() refreshes the cache in the PC, gets the header updated in the PC, but take care, because because this slows things down.

  • A Replace in any record. Reccount() now shows 10;
    Because the Replace performs an internal Rlock(), it's the same as the previous.

  • Go 10.
    The 10 is just there, and you'll get it ! Of course one must now it's there, but with a sneaky error-handler this may be a method (??).

  • Set Refresh to 1,1. Reccount() shows 10 after the elapse of the one second.
    This is not any way to do, because it 'll slow down all significantly. A temporary Set Refresh to 1,1 and back to f.e. 60,60 may be a way to go for.

  • Append blank. Reccount() now shows 11 (so the other's Append is included).
    In fact the same Rlock()-topic, but when this would show 10, things would get corrupted indeed.

    Next code is about getting the actual data of a new appended record.
    Please note that my testing of today is on one NT4 with two VFP-tasks running a MS-client. I expect things may be different in a real network !
    *** Get the actual data of any new record with Set Refresh to 0,0. ***
    
    Go Bottom
    Skip 1
    
    *** Reccount() is actual now;
    *** One would say this is enough, and yes, at one try it is. However, this
    *** gets your hairs out if you try it twice. So, Append on the Writer, do
    *** a Replace overthere, and the above subsequently performed -> 
    *** the second time you think you don't see the data. However :
    *** this second time you are at EOF() because somehow the second time works
    *** relatively on the first time and I didn't even start to think on why.
    *** There seems not any other command to get it right (f.e. Skip -1 
    *** followed by Skip +1 etc.) but to Go to the record.
    *** Note that a Go Reccount() does the trick, and which anticipates for
    *** this example on getting the very last new record only. Thus, by 
    *** comparing Reccount() with Recno() before the above was done, one can get
    *** all the new records when needed. This is not in the example !
    
    Go Reccount()
    
    *** So now we are there ? No !!
    *** This works only when the Writer didn't explicitly Rlock the record 
    *** after the Append Blank. When he did and we perform the above 
    *** right at the moment the record is locked, we will never get hold of
    *** the data anymore. I mean, even not when the Writer Unlocks. This is
    *** because the data is not given by the server due to the record being
    *** Locked (so Locking is not a convention only !!), though we do receive
    *** the record in it's last stage, which is being blank.
    *** In order to get the actual data, we have to enforce the server to 
    *** present the data again, and which is done by an Rlock of any record
    *** in the table. However, since we have to know whether the record just
    *** appended is locked or not, of course we Rlock the record itself.
    *** Now note that this is exactly why proper locking-logic always gets
    *** the right results.
    
    = Rlock()
    
    *** Pfff, we now have the actual data. Of course if the record is locked
    *** we have to deal with this.
    *** Now note that when we wish to have a speedy app, we have to adjust
    *** the concerning params like Set Reprocess which is not allowed to let
    *** us wait for any fraction of a second. In stead we have to use a 
    *** proper error-routine.
    *** I note that there is some unknown logic within VFP which I determined 
    *** as follows :
    *** Use Set Reprocess to 1 (no seconds !);
    *** This one attempt takes 0.05 seconds which may be far too long, depending
    *** on what you do. I mean, for any normal situation this will be okay, but
    *** when you have to skip through a table of which all records are locked
    *** and you know it (f.e. contains entries for active users), this will 
    *** take too long. now note :
    *** With an On Error in effect, the time decreases to 0.001 second, and
    *** that's okay for all of us. I quote that with an On Error in effect,
    *** the Set Reprocess is even overruled. I mean, we have it at 0 which
    *** implies indefinite trying, but instead the Error-routine is invoked 
    *** immmedeately !  The Help isn't quite clear about this and says something
    *** about "when a function attempt to place the lock ..." which indeed 
    *** influences things, so beware not to make things unnessecary slow;
    *** Just note that the 0.001 is reachable. But :
    *** This 0.001 was tested on local VFP-tasks, and will be slower on a 
    *** real network. Now beware, 'cause the before-mentioned 0.05 will have
    *** more attempts anyhow (though this is not promised by the "one attempt"
    *** of the Help), this just consumes this time. I mean, on a slower network
    *** the 0.05 will remain 0.05, but the 0.001 may increase towards the 0.05 too
    *** because of a package sent to the server, the server's attempt, and the
    *** package sent back to the PC with the result.
    *** When an On Error is in effect, there is really only one attempt.
    *** Note the difference on records locked and not locked, where the latter
    *** always gives the 0.001 and the first the 0.05 (without On Error); this
    *** can only be due to more attempts.
    *** So test this properly and always have an On Error. Even if you don't need
    *** it !
    I think that from the above can be derived how to get the actual data of just any existing record, and at optimum speed.

    I think I have prooven that any system with proper locking-logic just can work with a Set Refresh of higher than 1,1 (or even 0,0), getting the actual data anyhow.
    Please note (again) that all of the above account for the data, and not for the index; With some tricks and and additional "pages" this can be overcome too.
    Also note that all is nothing to just build in an existing app, and needs to be in the framework somewhere.

    If you like, now just start thinking of how to implement this properly within Views, where in there it's all the same but less visible, but, with great impact.

    Getting systems fast, needs inside knowledge of the kernels of the tools used.

    Sure HTH,
  • Previous
    Reply
    Map
    View

    Click here to load this message in the networking platform