Multi - User EOF() Problem 
Author Message
 Multi - User EOF() Problem

Can any one out there help me with a problem that I have had with our
clipper applications for a long time.

All our applications use standard routines (that have been developed
in-house) to paint input screens for adding or editing data.

For adding data the routine goes to the bottom of the table to get a
blank structure.

The code used is

GO BOTTOM
SKIP
and then in the next few lines of code the program grabs the empty
field values.

The problem is that in a multiuser environment sometime it does not
point to the EOF() record but to a record that another user has just
added to the bottom of the table which has overwritten the previous
EOF() record.

It seems that when the workstation does a go bottom it does not
synchronise with the server to determine the current EOF() record. The
skip  must also assume the EOF() record.

Before any go bottom or skip past the last reord I would have thought
that it would check what the current EOF() record is.

I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
a comix issue because the problem occurred with ntx.

Has any one experienced this problem?

Mark Goodwin

Analyst Programmer




Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem
Mark Goodwin a crit:

Quote:
> Can any one out there help me with a problem that I have had with our
> clipper applications for a long time.

> All our applications use standard routines (that have been developed
> in-house) to paint input screens for adding or editing data.

> For adding data the routine goes to the bottom of the table to get a
> blank structure.

> The code used is

> GO BOTTOM
> SKIP
> and then in the next few lines of code the program grabs the empty
> field values.

Hi Mark,

Why don't you use the DBSTRUCT() function to get your structure ? You'll
get an array with {{field_name,field_type,field_len,field_dec}}

HTH

Philippe

--

Philippe Morchain

See also : http://www.stack.nl/~lamping/bgevents.htm
    Lista TodoClipper :
http://www.geocities.com/SiliconValley/Horizon/1132/
    http://www.chez.com/todoclipper



Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:

> GO BOTTOM
> SKIP
> and then in the next few lines of code the program grabs the empty
> field values.

> The problem is that in a multiuser environment sometime it does not point
> to the EOF() record but to a record that another user has just added to
> the bottom of the table which has overwritten the previous EOF() record.

> It seems that when the workstation does a go bottom it does not
> synchronise with the server to determine the current EOF() record. The
> skip must also assume the EOF() record.

It is worth remembering that the above might not be the cause. Don't forget
that, in theory, it would be possible that the "GO BOTTOM" *did* go to the
last record and then as the SKIP is issued another record is added. I'm not
saying this is the case, only that in theory it is possible.

You really need to do one of two things, either re-think your method of
finding eof() or don't use eof() to get blank values. In the first case you
might want to try something like:

  dbgobottom()
  Do While !eof()
     dbskip()
  EndDo

but I wouldn't recommend it (there is the distant possibility that the loop
would never exit).

Personally I've found that:

  dbgoto( 0 )

gets me to eof() without any hassle. You might want to test that in your
environment and see if it makes any difference.

The (probably better) option is to not actually rely on the eof() record for
blank values but create the blank values from code. This is pretty trivial:

----------------------------------------------------------------------------
  cSurname := AsBlank( Cust->Surname )
  dDOB     := AsBlank( Cust->DOB )
  ...

  Function AsBlank( xValue )

     Do Case
        Case ISCHARACTER( xValue )
           xValue := space( len( xValue ) )
        Case ISNUMBER( xValue )
           xValue := 0
        Case ISDATE( xValue )
           xValue := ctod( "" )
        Case ISLOGICAL( xValue )
           xValue := .F.
        ...etc...
     EndCase

  Return( xValue )
----------------------------------------------------------------------------

Also, if you use a scatter/gather system you can use a variation on the
above.

--
Take a look in Hagbard's World: |   w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ |     eg - Norton Guide reader for Linux.
http://www.hagbard.demon.co.uk/ |    weg - Norton Guide reader for Windows.
Free software, including........| dgscan - DGROUP scanner for Clipper.



Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem
Mark;

I have found a relatively simple work-around for this phenomenon.  In my
apps I open(exclusive) a "semaphore" file before appending a record, then
close the semaphore file after the new record is completely written to
disk.  The app then goes into a "Waiting for append rights" loop until the
file can be opened.  E-mail me for specific sample code.

HTH!
--

MicroData Systems, Ltd.   http://www.sturec.com

Quote:

> Can any one out there help me with a problem that I have had with our
> clipper applications for a long time.

> All our applications use standard routines (that have been developed
> in-house) to paint input screens for adding or editing data.

> For adding data the routine goes to the bottom of the table to get a
> blank structure.

> The code used is

> GO BOTTOM
> SKIP
> and then in the next few lines of code the program grabs the empty
> field values.

> The problem is that in a multiuser environment sometime it does not
> point to the EOF() record but to a record that another user has just
> added to the bottom of the table which has overwritten the previous
> EOF() record.

> It seems that when the workstation does a go bottom it does not
> synchronise with the server to determine the current EOF() record. The
> skip  must also assume the EOF() record.

> Before any go bottom or skip past the last reord I would have thought
> that it would check what the current EOF() record is.

> I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
> a comix issue because the problem occurred with ntx.

> Has any one experienced this problem?

> Mark Goodwin

> Analyst Programmer





Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem
Assuming you use an array to edit.

#include 'dbstruct.ch'

function EmptyFlds(aStruct)
local aValues := Array(Len(aStruct))
local xVal := ''
for nFld := 1 to Len(aStruct)
  do case
    case aStruct[nFld, DBS_TYPE] $ 'CM'
      xVal := ''
    case aStruct[nFld, DBS_TYPE] $ 'N'
      xVal := 0
    case aStruct[nFld, DBS_TYPE] $ 'D'
      xVal := Date()
    case aStruct[nFld, DBS_TYPE] $ 'L'
      xVal := .f.
  endcase
  aValues[nFld] := xVal
next
return( aValues )

--
Johan Nel
Project Manager:Forestry Systems, SAFCOL, South Africa

Tel: +27-12-4813683
Fax: +27-12-8043716



Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:
> #include 'dbstruct.ch'

> function EmptyFlds(aStruct)

Considering the name of this function...

Quote:
> local aValues := Array(Len(aStruct))
> local xVal := ''
> for nFld := 1 to Len(aStruct)
>   do case
>     case aStruct[nFld, DBS_TYPE] $ 'CM'
>       xVal := ''

...this should read:

      Case aStruct[ nFld ][ DBS_TYPE ] == "C"
        xVal := space( aStruct[ nFld ][ DBS_LEN ] )
      Case aStruct[ nFld ][ DBS_TYPE ] == "M"
        xVal := ""

and...

Quote:
>     case aStruct[nFld, DBS_TYPE] $ 'N'
>       xVal := 0
>     case aStruct[nFld, DBS_TYPE] $ 'D'
>       xVal := Date()

...this should read:

        xVal := ctod( "" )

Quote:
>     case aStruct[nFld, DBS_TYPE] $ 'L'
>       xVal := .f.
>   endcase
>   aValues[nFld] := xVal
> next
> return( aValues )

--
Take a look in Hagbard's World: |   w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ |     eg - Norton Guide reader for Linux.
http://www.hagbard.demon.co.uk/ |    weg - Norton Guide reader for Windows.
Free software, including........| dgscan - DGROUP scanner for Clipper.


Tue, 20 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:

>Can any one out there help me with a problem that I have had with our
>clipper applications for a long time.

>All our applications use standard routines (that have been developed
>in-house) to paint input screens for adding or editing data.

>For adding data the routine goes to the bottom of the table to get a
>blank structure.

>The code used is

>GO BOTTOM
>SKIP
>and then in the next few lines of code the program grabs the empty
>field values.

>The problem is that in a multiuser environment sometime it does not
>point to the EOF() record but to a record that another user has just
>added to the bottom of the table which has overwritten the previous
>EOF() record.

>It seems that when the workstation does a go bottom it does not
>synchronise with the server to determine the current EOF() record. The
>skip  must also assume the EOF() record.

>Before any go bottom or skip past the last reord I would have thought
>that it would check what the current EOF() record is.

>I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
>a comix issue because the problem occurred with ntx.

Mark,

I've read about 5 replies to this, all of which have suggested clever
ways to circumvent this problem, but IMHO they are all missing an
important point :-

The behaviour you describe is very likely being caused by the
workstation's network client cacheing file writes - very common on
Wintel boxes these days to improve network performance, and very
Clipper unfriendly.  

What happens is this: when you ask Clipper to go to EOF, especially if
an index is used, it can happen that the index hasn't been updated to
the server yet and so it can point to the wrong physical record
because the updated data is still residing in the cache of the
workstation which just added the new record.  

I suggest that you make sure that you are doing a dbCommit() after all
your updates (appends, deletes & writes) to files to force the data to
be written back to the server.  I have even resorted to doing this:

nRec := recno()
dbCommit()
dbGoTop()
dbGoBottom()
dbGoTo(nRec)

to ensure data is flushed by forcing client cache updates.  That said,
this is an extreme example.

<aside>
A common error I have seen is NOT doing a dbCommit() immediately after
a dbAppend() and waiting until the user has finished filling the
record in.
</aside>

In my experience, a properly written network-aware Clipper app should
always return the correct number of records in a file at the instant
it checks. (Assuming a properly configured network environment, of
course).

HTH
--
Nick Ramsay




Thu, 22 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:

>Mark;

>I have found a relatively simple work-around for this phenomenon.  In my
>apps I open(exclusive) a "semaphore" file before appending a record, then
>close the semaphore file after the new record is completely written to
>disk.  The app then goes into a "Waiting for append rights" loop until the
>file can be opened.  E-mail me for specific sample code.

>HTH!
>--

>MicroData Systems, Ltd.   http://www.sturec.com


>> Can any one out there help me with a problem that I have had with our
>> clipper applications for a long time.

>> All our applications use standard routines (that have been developed
>> in-house) to paint input screens for adding or editing data.

>> For adding data the routine goes to the bottom of the table to get a
>> blank structure.

>> The code used is

>> GO BOTTOM
>> SKIP
>> and then in the next few lines of code the program grabs the empty
>> field values.

>> The problem is that in a multiuser environment sometime it does not
>> point to the EOF() record but to a record that another user has just
>> added to the bottom of the table which has overwritten the previous
>> EOF() record.

>> It seems that when the workstation does a go bottom it does not
>> synchronise with the server to determine the current EOF() record. The
>> skip  must also assume the EOF() record.

>> Before any go bottom or skip past the last reord I would have thought
>> that it would check what the current EOF() record is.

>> I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
>> a comix issue because the problem occurred with ntx.

>> Has any one experienced this problem?

>> Mark Goodwin

>> Analyst Programmer



What's wrong with

alias_name->(dbappend())

Provides a blank record, which is automatically locked and available to the
caller, while others can do the same simultaneously. Obviously the ghost
record does not cut it. And the idea to prevent others from appending may be
frowned upon as well.

Jacob
Toronto



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:


>>Mark;

>>I have found a relatively simple work-around for this phenomenon.  In my
>>apps I open(exclusive) a "semaphore" file before appending a record, then
>>close the semaphore file after the new record is completely written to
>>disk.  The app then goes into a "Waiting for append rights" loop until the
>>file can be opened.  E-mail me for specific sample code.

>>HTH!
>>--

>>MicroData Systems, Ltd.   http://www.sturec.com


>>> Can any one out there help me with a problem that I have had with our
>>> clipper applications for a long time.

>>> All our applications use standard routines (that have been developed
>>> in-house) to paint input screens for adding or editing data.

>>> For adding data the routine goes to the bottom of the table to get a
>>> blank structure.

>>> The code used is

>>> GO BOTTOM
>>> SKIP
>>> and then in the next few lines of code the program grabs the empty
>>> field values.

>>> The problem is that in a multiuser environment sometime it does not
>>> point to the EOF() record but to a record that another user has just
>>> added to the bottom of the table which has overwritten the previous
>>> EOF() record.

>>> It seems that when the workstation does a go bottom it does not
>>> synchronise with the server to determine the current EOF() record. The
>>> skip  must also assume the EOF() record.

>>> Before any go bottom or skip past the last reord I would have thought
>>> that it would check what the current EOF() record is.

>>> I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
>>> a comix issue because the problem occurred with ntx.

>>> Has any one experienced this problem?

>>> Mark Goodwin

>>> Analyst Programmer


>What's wrong with

>alias_name->(dbappend())

>Provides a blank record, which is automatically locked and available to the
>caller, while others can do the same simultaneously. Obviously the ghost
>record does not cut it. And the idea to prevent others from appending may
be
>frowned upon as well.

>Jacob
>Toronto

But then again, with my following function, you don't have to create a blank
record yet, nor do you have to go to the ghost record, just call the
'blank() ' function.

#include "SIXCDX.CH"
#include "MACHSIX2.CH"
#include "INKEY.CH"
function BLANK(var,blankit) // Fri  05-22-1992  06:39:14 JA
  /*
     This function returns a field of any type with its contents set to
     empty(), or, if blankit is any expression, empties the field as well.

     This differs from Clipper Tools in that a string is returned as an
     empty string of the same length and in that a field can be set to
     empty with this function.

  */
   do case
     case VAR=NIL
return nil
     case BLANKIT#NIL
       ent(blank(var),var)
return .t.
     case valtype(var)='M'
return ""
     case valtype(var)='C'
return spac(len(var))
     case valtype(var)='D'
return ctod('        ')
     case valtype(var)='N'
return 0
     case valtype(var)='L'
return .f.
   end
return .f.
**********************

Some other ideas:
To blank a record in a multi-user environment where packing is a pain:

  for nCount = 1 to fcount()
    fieldput(nCount, blank(FieldGet(nCount)))
  next

In my programs, I will then also mark this record for deletion, and then the
record is available instead of the append blank command. This snippet is
part of that action, again using the blank() function. The
 gath() function I wrote to emulate the Foxpro gather() function, and yes of
course I have a scat() to match.

   if len(saveblan)#0
     dbseek(blank(indexkey()))
     gath(saveblan)
     saveblan[1]:=NIL
   endi

Another gem:

function COPYREC(restore)
  // Copies a record
  // With a parameter restores the record
  static saveblan:={}
  if restore=NIL
    saveblan:=scat()
    tone(1620,2)
  else
    if saveblan#{}.and.dbseek(blank(indexkey()))
      gath(saveblan)
      saveblan:={}
    else
      tone()
    endi
  endi
return .t.

Jacob Abas

also: Analyst, programmer, but also the boss, the floor sweeper

- Show quoted text -



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:



>>Can any one out there help me with a problem that I have had with our
>>clipper applications for a long time.

>>All our applications use standard routines (that have been developed
>>in-house) to paint input screens for adding or editing data.

>>For adding data the routine goes to the bottom of the table to get a
>>blank structure.

>>The code used is

>>GO BOTTOM
>>SKIP
>>and then in the next few lines of code the program grabs the empty
>>field values.

>>The problem is that in a multiuser environment sometime it does not
>>point to the EOF() record but to a record that another user has just
>>added to the bottom of the table which has overwritten the previous
>>EOF() record.

>>It seems that when the workstation does a go bottom it does not
>>synchronise with the server to determine the current EOF() record. The
>>skip  must also assume the EOF() record.

>>Before any go bottom or skip past the last reord I would have thought
>>that it would check what the current EOF() record is.

>>I am using clipper 5.2e and comix 3.0 (cdx\fpt). I do not think it is
>>a comix issue because the problem occurred with ntx.

>Mark,

>I've read about 5 replies to this, all of which have suggested clever
>ways to circumvent this problem, but IMHO they are all missing an
>important point :-

>The behaviour you describe is very likely being caused by the
>workstation's network client cacheing file writes - very common on
>Wintel boxes these days to improve network performance, and very
>Clipper unfriendly.

>What happens is this: when you ask Clipper to go to EOF, especially if
>an index is used, it can happen that the index hasn't been updated to
>the server yet and so it can point to the wrong physical record
>because the updated data is still residing in the cache of the
>workstation which just added the new record.

>I suggest that you make sure that you are doing a dbCommit() after all
>your updates (appends, deletes & writes) to files to force the data to
>be written back to the server.  I have even resorted to doing this:

>nRec := recno()
>dbCommit()
>dbGoTop()
>dbGoBottom()
>dbGoTo(nRec)

>to ensure data is flushed by forcing client cache updates.  That said,
>this is an extreme example.

><aside>
>A common error I have seen is NOT doing a dbCommit() immediately after
>a dbAppend() and waiting until the user has finished filling the
>record in.
></aside>

>In my experience, a properly written network-aware Clipper app should
>always return the correct number of records in a file at the instant
>it checks. (Assuming a properly configured network environment, of
>course).

>HTH
>--
>Nick Ramsay



The dbcommit() is only good for manually adding one record at a time. If you
do that quickly, programmatically, the time to do this work becomes
horrendous and you make your network quite busy.

Jacob
Toronto



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem
On Mon, 07 Sep 1998 15:31:34 GMT, "Jacob Abas"

Quote:

>The dbcommit() is only good for manually adding one record at a time. If you
>do that quickly, programmatically, the time to do this work becomes
>horrendous and you make your network quite busy.

The dbcommit() is necessary for ALL multiuser programming, and not
using it will cause lots of problems, like others not seeing your
already written records. The network is busy because it is writing
your data to the server. The lack of that means.....?

--

        Oasis WWW  http://www.iag.net/~philb/
 Oasis WWW Mirror  http://www.enterconnex.com/oasis/
         FTP Site  ftp://ftp.iag.net/pub/clipper

             Always remember you are unique...
               Just like everyone else!



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:

> What's wrong with

> alias_name->(dbappend())

There is one obvious problem with the above, appending a record *before* the
user as decided to save the record isn't a smart move, it can be a smarter
move if you use record recycling but it still isn't the smartest move.

--
Take a look in Hagbard's World: |   w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ |     eg - Norton Guide reader for Linux.
http://www.hagbard.demon.co.uk/ |    weg - Norton Guide reader for Windows.
Free software, including........| dgscan - DGROUP scanner for Clipper.



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem


Can you give me any clue on network configuration and workstation
caches.



Fri, 23 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem

Quote:



>Can you give me any clue on network configuration and workstation
>caches.

I'd be happy to, but first can you give me a clue - which NOS, client
OS & network client are you using?

Whole books have been written on this...
--
Nick Ramsay




Sat, 24 Feb 2001 03:00:00 GMT  
 Multi - User EOF() Problem
[snip]

Quote:

> >> Can any one out there help me with a problem that I have had with our
> >> clipper applications for a long time.
> >> All our applications use standard routines (that have been developed
> >> in-house) to paint input screens for adding or editing data.
> >> For adding data the routine goes to the bottom of the table to get a
> >> blank structure.
> >> The code used is
> >> GO BOTTOM
> >> SKIP
> >> and then in the next few lines of code the program grabs the empty
> >> field values.
> >> The problem is that in a multiuser environment sometime it does not
> >> point to the EOF() record but to a record that another user has just
> >> added to the bottom of the table which has overwritten the previous
> >> EOF() record.
> What's wrong with
> alias_name->(dbappend())
> Provides a blank record, which is automatically locked and available to the
> caller, while others can do the same simultaneously. Obviously the ghost
> record does not cut it. And the idea to prevent others from appending may be
> frowned upon as well.

Then again, why not just copy a record; _any_ record; and set all
the fields to empty? You know, or at least can find out, what types
the fields are; you know what the empty value of all these types is;
so you can create an empty record from any random record. This way
you don't even need to mess with the real database until the user
hits OK.
In fact, you could also COPY STRUCTURE to a dummy database and APPEND
BLANK in there, and throw it away if cancelled, or COPY FROM it if not.

So many solutions; this is starting to look like Perl!

Richard



Sat, 24 Feb 2001 03:00:00 GMT  
 
 [ 25 post ]  Go to page: [1] [2]

 Relevant Pages 

1. eof on channel, not eof on transform: [eof] returns true

2. Multi-tasking and Multi-user

3. Multi-tasking and Multi-user

4. Multi-tasking and Multi-user

5. Multi-tasking and Multi-user

6. Multi-tasking and Multi-user

7. Multi-tasking and Multi-user

8. Multi-tasking and Multi-user

9. Multi-tasking and Multi-user

10. Multi-tasking and Multi-user

11. Multi-tasking and Multi-user

12. Multi-User app, Problem with shared file access

 

 
Powered by phpBB® Forum Software