FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Programación en Red Local
Posts: 610
Joined: Wed Oct 19, 2005 08:20 PM
Programación en Red Local
Posted: Fri Jan 13, 2012 09:33 PM
Desde hace muchos años (Desde Clipper) vengo arrastrando la siguiente función para modificar/añadir registros a un fichero en red local. La verdad es que siempre ha funcionado correctamente sin ningún problema en programas clipper y programas clipper/fivewin con nueve o diez usuarios trabajando simultáneamente. Sin embargo con fivewin+xHarbour estoy teniendo algún problema de duplicidad de registros y desaparición de uno que otro registro cuando se trabaja en red local sin explicación aparente, y sólo con dos o tres usuarios como mucho. No sé por donde tirar ni si el problema es esta función, la red local (me pasa en varias redes distintas) u otra causa, pero lo cierto es que este asunto me tiene bastante preocupado pues es un problema bastante grave y desconcertante.
Cualquier ayuda o sugerencia será bien recibida.

Code (fw): Select all Collapse
.........................
.........................
      // 
      IF TRABAJA->(!RecLock(5))
         TONE(400,2)
         TONE(200,2)
         //
         IF lNuevo
            MsgStop("No es posible añadir el registro;inténtelo más tarde, por favor.")
         ELSE
            MsgStop("No es posible la modificación;inténtelo más tarde, por favor.")
         ENDIF
         //
      ELSE
         //
         TRABAJA->NOMTRA    = cNomTra         
         TRABAJA->POSTAL    = cPostal
         TRABAJA->LOCA      = cLoca
         TRABAJA->PROVIN    = cProvin
         TRABAJA->TELEFONO  = cTelefono
         //
         TRABAJA->(DbRunLock())
         TRABAJA->(DbCommit())
         //
      ENDIF
      //
.............................
.............................
#include "Common.ch"
#define NET_WAIT     0.5   // Seconds to wait between between retries
#define NET_SECS     2     // Number of seconds to continue retry
    
**********************************************      
FUNCTION RecLock( nSeconds )
**********************************************
   LOCAL lForever          // Retry forever?
   DEFAULT nSeconds TO NET_SECS
   //
   IF RLOCK()
      RETURN ( .T. )       // NOTE
   ENDIF
   //
   lForever := ( nSeconds == 0 )
   //
   DO WHILE ( lForever .OR. ( nSeconds > 0 ) )
      //
      IF RLOCK()
         RETURN ( .T. )    // NOTE
      ENDIF
      //
      INKEY( NET_WAIT )    // Wait 1/2 second
      nSeconds -= NET_WAIT
      //
   ENDDO
   //
   RETURN ( .F. )
Un saludo,

Manuel



xH 1.2.3, FWH 23.07 32 bits, BC++ 7.4, xVerce CW 1.0, PellesC
Posts: 1445
Joined: Mon Oct 10, 2005 02:38 PM
Re: Programación en Red Local
Posted: Fri Jan 13, 2012 11:12 PM
Manuel Aranda wrote:
Code (fw): Select all Collapse
.........................
.........................
      // 
      IF TRABAJA->(!RecLock(5))
         TONE(400,2)
         TONE(200,2)
         //
         IF lNuevo
            MsgStop("No es posible añadir el registro;inténtelo más tarde, por favor.")
         ELSE
            MsgStop("No es posible la modificación;inténtelo más tarde, por favor.")
         ENDIF
         //
      ELSE
         //
         TRABAJA->NOMTRA    = cNomTra         
         TRABAJA->POSTAL    = cPostal
         TRABAJA->LOCA      = cLoca
         TRABAJA->PROVIN    = cProvin
         TRABAJA->TELEFONO  = cTelefono
         //
         TRABAJA->(DbRunLock())
         TRABAJA->(DbCommit())
         //
      ENDIF
      //
.............................
.............................
#include "Common.ch"
#define NET_WAIT     0.5   // Seconds to wait between between retries
#define NET_SECS     2     // Number of seconds to continue retry
    
**********************************************      
FUNCTION RecLock( nSeconds )
**********************************************
   LOCAL lForever          // Retry forever?
   DEFAULT nSeconds TO NET_SECS
   //
   IF RLOCK()
      RETURN ( .T. )       // NOTE
   ENDIF
   //
   lForever := ( nSeconds == 0 )
   //
   DO WHILE ( lForever .OR. ( nSeconds > 0 ) )
      //
      IF RLOCK()
         RETURN ( .T. )    // NOTE
      ENDIF
      //
      INKEY( NET_WAIT )    // Wait 1/2 second
      nSeconds -= NET_WAIT
      //
   ENDDO
   //
   RETURN ( .F. )


Manuel,

Reclok() a mi modo de ver creo que está bien. Lo que no veo claro que esté bien es el código donde se está usando, me explico.

Segun el código que veo (no se si faltan trozos), no estás haciendo ningun DbAppend() ni ningún LOCATE, y además desde que se intenta bloquear el registro hasta que se consigue grabarlo no se ha actualizado ninguna variable de las que grabas, es decir: puedes estar intentanto boquear un registro (desde el puesto A) que en otro puesto de trabajo (B) se está actualizando. Con lo cual cuando desde el otro puesto (B) se actualiza y se libera el registro, entra en acción (A) sobreescribiendo el registro actualizado por (B).

Yo por ejemplo, uso referencias únicas guardadas en una DBF del sistema, cuando consigo bloquear el registro de la DBF de trabajo, es cuando obtengo la nueva referfencia; eso para las altas. Para las modificaciones, antes de editar miro si está borrado, en caso contrario una vez bloqueado busco el código que quiero 'updatear' por si existe en otro registro y finalmente el último puesto que graba es lo que queda.

Pero todo esto sin ver toda la rutina que usas para modifidcar/añadir registros.

Un Saludo

Carlos G.



FiveWin 25.12 + Harbour 3.2.0dev (r2502110321), BCC 7.7 Windows 11 Home

Posts: 652
Joined: Wed Oct 19, 2005 12:03 PM
Re: Programación en Red Local
Posted: Sat Jan 14, 2012 10:49 AM
Hola Manuel mira desde que aprendi algo de esto uso unos programas de Rick Spencer y nunca me dieron problemas fijate si te sirven:

Code (fw): Select all Collapse
******************************************************************************
/***
* NetTryUI.prg
*
* Una versi¢n de NetTry() que permite pasar un segundo codeblock
* y usarlo para preguntar si se desea continuar o no. Esta versi¢n
* lo reintenta hasta que este segundo codeblock devuelve .T.
*/

FUNCTION NetTryUI(nSeconds, bAction, bRetryUI)

LOCAL lSuccess, lRetry

  REPEAT
    IF !(lSuccess := NetTry(nSeconds, bAction))
      lRetry := Eval(bRetryUI)
    ENDIF
  UNTIL lSuccess .OR. !lRetry

RETURN lSuccess


*****************************************************************************
FUNCTION NetTry( nSeconds, bAction )

LOCAL lForever, lSuccess

  lForever := (nSeconds == NIL .OR. nSeconds == 0)
  DO WHILE !(lSuccess := Eval(bAction)) .AND. ;
            (lForever .OR. nSeconds > 0)

    InKey(.5)           // Esperar medio segundo
    nSeconds := nSeconds - .5
  ENDDO

RETURN lSuccess
*****************************************************************************
.

Y la forma de llamarla usando database (reemplazar un dato existente

Code (fw): Select all Collapse
FUNCTION reviso(odbf)                               &&bloquear registro en un objeto database
local exito
if exito:= NetTryUI(2,                                             ;
               {||odbf:reclock(), !neterr()  },;
               {||alert("Registro bloqueado ¨REINTENTAMOS?",{"SI","NO"}) == 1})
endif
return exito


agregar

Code (fw): Select all Collapse
FUNCTION yapar(odbf)
local exito
if exito := NetTryUI(2,                                             ;
               {||odbf:blank(),odbf:append(), !neterr()  },;
               {||alert("¨REINTENTAMOS?",{"SI","NO"}) == 1})
endif
return exito


y para uso directo de bases dbf

Code (fw): Select all Collapse
*funcion que trabaja sobre la base*/
FUNCTION revbase()                            &&bloquear registro de una base de datos directamente
local exito
if exito:= NetTryUI(2,                                             ;
               {||rlock(), !neterr()  },;
               {||alert("Registro bloqueado ¨REINTENTAMOS?",{"SI","NO"}) == 1})
endif
return exito


Espero sea de utilidad

Luis
Posts: 652
Joined: Wed Oct 19, 2005 12:03 PM
Re: Programación en Red Local
Posted: Sat Jan 14, 2012 10:54 AM

Un ejemplo con database

IF lNuevo
odata:append()
ENDIF
if reviso(odata)
odata:save()
odata:commit()
odata:unlock()
endif

Luis

Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Programación en Red Local
Posted: Sat Jan 14, 2012 12:07 PM

Manuel,

Yo tambien herede un rec_lock() desde clipper y sin problemas: creo que es igual al tuyo.
Lo que yo nunca hago es poner tiempo al "intento" de bloqueo: siempre pongo 0: se debe bloquear si o si.

Creo que tu problema sea otro y no tenga qaue ver con el reclock(): algun seek con el order erroneo o algo asi.

Saludos

Posts: 610
Joined: Wed Oct 19, 2005 08:20 PM
Re: Programación en Red Local
Posted: Sat Jan 14, 2012 01:16 PM

Primero que nada agradeceros a los tres vuestras respuestas, pues ya tengo material por donde empezar a mirar.
Carlos, voy a empezar a probar con la pista que me has dado. Me explico. Tengo una misma rutina para modificar/añadir un registro y dependiendo si es un registro a añadir o modificar hago el DbAppend():
//
IF lNuevo
TRABAJA->(DbAppend())
ENDIF
//
Pues bien, resulta que DbAppend() lo estaba haciendo con anteoridad, sin bloquear el fichero (Abriendo el fichero como Shared te permite añadir el registro sin bloquearlo, no así el modificarlo). Creo que por ahí puede venir el problema. He modificado la rutina y voy a observar el comportamiento.

Muchas gracias a todos.

Un saludo,

Manuel



xH 1.2.3, FWH 23.07 32 bits, BC++ 7.4, xVerce CW 1.0, PellesC
Posts: 1710
Joined: Tue Oct 28, 2008 06:26 PM
Re: Programación en Red Local
Posted: Sat Jan 14, 2012 01:46 PM
Manuel yo lo hago asi:
Code (fw): Select all Collapse
Function Aumenta(oDBF)
   Do While .T.
     IF oDBF:Lock()
        oDBF:Load()
        oDBF:CORRELATIVO+=1
        oDBF:Save()
        oDBF:COMMIT()
        oDBF:Lock()
        Exit
     Else
        Inkey(0.4)
     EndIf
   EndDo
Return Ni

*Luego que retorna de la funcion
 oDBF:unLock()


Funciona perfecto.

Espero te sirva

Saludos,

Adhemar
Saludos,



Adhemar C.
Posts: 610
Joined: Wed Oct 19, 2005 08:20 PM
Re: Programación en Red Local
Posted: Sun Jan 15, 2012 08:43 AM

Adhemar, muchas gracias.

Un saludo,

Manuel



xH 1.2.3, FWH 23.07 32 bits, BC++ 7.4, xVerce CW 1.0, PellesC
Posts: 3358
Joined: Fri Oct 07, 2005 08:20 PM
Re: Programación en Red Local
Posted: Sun Jan 15, 2012 05:02 PM
Adhemar:

Solo para salir de mi duda !

acuellar wrote:Manuel yo lo hago asi:
Code (fw): Select all Collapse
Function Aumenta(oDBF)
   Do While .T.
     IF oDBF:Lock()
        oDBF:Load()
        oDBF:CORRELATIVO+=1
        oDBF:Save()
        oDBF:COMMIT()
        oDBF:Lock()
        Exit
     Else
        Inkey(0.4)
     EndIf
   EndDo
Return Ni

*Luego que retorna de la funcion
 oDBF:unLock()

Adhemar


Qué caso tiene la línea oDbf:Lock dentro de un IF donde
la línea en cuestión se ejecuta cuando la DBF esta bloqueda?

En mi opinión la línea oDbf:COMMIT() hace lento el proceso y no siempre es necesaria
la línea para que se salve la información.

Saludos
SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
Posts: 989
Joined: Thu Nov 24, 2005 03:01 PM
Re: Programación en Red Local
Posted: Fri Jan 20, 2012 01:37 PM
Manuel,

veo que en tu código tienes
Code (fw): Select all Collapse
         TRABAJA->(DbRunLock())
         TRABAJA->(DbCommit())


lo que creo que debe ser
Code (fw): Select all Collapse
         TRABAJA->(DbCommit())
         TRABAJA->(DbRunLock())

Estás liberando el bloqueo ANTES DE ACTUALIZAR, lo que probablemente esté ocasionando los problemas. Puede que el commit no pueda actualizar porque ya se haya interpuesto otro lock.

UN saludo
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Posts: 610
Joined: Wed Oct 19, 2005 08:20 PM
Re: Programación en Red Local
Posted: Fri Jan 20, 2012 08:07 PM

Muchíiiisimas gracias, Carlos, puede que sea eso. No sé como no me he dado cuenta antes, con la de vueltas que le he dado.

Un saludo,

Manuel



xH 1.2.3, FWH 23.07 32 bits, BC++ 7.4, xVerce CW 1.0, PellesC

Continue the discussion