Multiusuário sem mistério

Foto de Anderson
aprendendoMultiusuário sem mistério

Para os iniciantes, lembrem que o Clipper só trabalha em rede com unidades mapeadas, isto é, transforme "\\servidor\diretorio\" para "F:", por exemplo. No Windows Explorer, clique com o botão direito do mouse sobre o diretório onde está o sistema no servidor, escolha "Mapear unidade", então associe uma letra de unidade ao diretório. Faça o link apontando para a unidade mapeada, funcionando nela.

Um dos tópicos que "endoidam o cabeção" de muita gente é aprender a programar em modo multiusuário, aprender a usar aliases e abandonar o select, bloquear registros e arquivos etc.

Lembre-se que tudo é muito fácil e simples quando se sabe, então acalme-se: você saberá! (palavra de quem já passou por isso).

Na programação multiusuário é fundamental o conhecimento de funções do clipper, primeira dica: para todo comando do clipper existe uma função equivalente, qualquer dúvida consulte o arquivo de include padrão do clipper /include/STD.CH, é lá onde todos os comandos se tornam operacionais devido a um tipo de tradução tipo "quando ver este comando, traduza para esta função".

Por que o enfoque nas funções? Porque você a partir de agora abandonará o comando select e trabalhará com aliases e os aliases só trabalham com funções.

Exemplo:

CLI->(DBSEEK(nCODIGO))

Isto quer dizer: No arquivo de apelido (alias) CLI, pesquise (seek=dbseek()) o valor de nCODIGO, usando o arquivo de indice em uso.

A sintaxe da abertura de um arquivo em modo compartilhado (multiusuario) com a atribuição de um alias, seria o seguinte:

USE CLIENTE ALIAS CLI SHARED NEW

Onde CLIENTE é o nome do arquivo DBF e CLI é o alias (apelido dado a CLIENTE com o parâmetro ALIAS após o nome do arquivo). O resto (SHARED NEW) é sempre igual, é o que faz abrir em modo compartilhado.

Para usar o arquivo aberto em modo compartilhado você precisa usar o alias. Para usar o alias digite o alias -> e ação a ser realizada no arquivo entre parênteses.

Sintaxe:

alias->( funcao() )

Note que a função vem sempre entre parênteses.

  Não quero dizer que não se pode usar o vetusto SELECT, é claro que sim, mas você perde bastante objetividade e torna o programa menos legível. Veja um exemplo:

Gravar os campos VALOR, DATA, HORA do arquivo MOVIMENTO e os campos UTILIZADO, ULTCOMPRA e MAIORCOMP do arquivo CLIENTE:

SELECT A
USE MOVIMENTO SHARED NEW
SELECT B
USE CLIENTE SHARED NEW
* [...]
SELECT A
BLOQREG()  // Funcao p/ bloqueio de registro. Explicada a seguir.
REPLACE VALOR WITH nVALOR, DATA WITH dDATA, HORA WITH TIME()
SELECT B
BLOQREG()
REPLACE UTILIZADO WITH nUTILIZADO, ULTCOMPRA WITH DATE(), MAIORCOMP WITH nMAIORCOMP
UNLOCK ALL

VEJA AGORA COMO FICA FÁCIL COM O USO DE ALIASES:

USE MOVIMENTO ALIASES MOV SHARED NEW
USE CLIENTE ALIASES CLI SHARED NEW
*[...]
MOV->(BLOQREG())  // Função p/ bloqueio de registro. Explicada a seguir.
MOV->VALOR := nVALOR
MOV->DATA  := dDATA
MOV->HORA  := TIME()
MOV->(DBUNLOCK())
CLI->(BLOQREG())
CLI->UTILIZADO := nUTILIZADO
CLI->ULTCOMP   := DATE()
CLI->MAIORCOMP := nMAIORCOMP
CLI->(DBUNLOCK())

* AMBOS OS CÓDIGOS ACIMA PRODUZEM O MESMO EFEITO

RLOCK()

Esta função é usada para bloquear o registro ao ser editado alguma informação no arquivo. Já pensou se dois usuários da rede quisessem editar um mesmo registro ao mesmo tempo??? Para evitar isso, o a linguagem simplesmente não permite isso. Para se editar um registro aberto em modo compartilhado (modo multiusuario) é necessário bloqueá-lo.

A chamada a RLOCK() retorna .T. se a função conseguiu bloquear o registro e .F., caso contrário. Assim, você irá querer fazer uma função para bloquear o registro com certeza de sucesso, por mais simples que seja, como por exemplo:

FUNCTION BLOQREG() 
DO WHILE !RLOCK() 
ENDDO 
RETURN

  Veja este outro exemplo mais implementado que você pode ainda adequar às suas necessidades. Neste caso você deve ter um arquivo DBF de usuários do sistema sempre aberto e em todos os seus arquivos DBF, sem exceção, devem ter o campo LAST_USER para armazenar o código do usuário. Vamos ao exemplo:

FUNCTION BLOQREG()
CURAL := ALIAS() // ALIAS/DBF CORRENTE
lBLOQ := RLOCK()
nTRY := 1
DO WHILE !lBLOQ
    lBLOQ := RLOCK()
   nTRY++
   IF nTRY = 5
      US->(DBSEEK( (CURAL)->LAST_USER) ) // US = ALIAS DO ARQUIVO USUARIOS.DBF
      ALERT("O registro nao pode ser alterado enquanto o usuario ";
            +US->CODIGO+"-"+US->NOME+;
            " estiver usando-o. Espere ele terminar e entao volte!" )
      nTRY := 0
      INKEY(5)
      IF LASTKEY()=27
         EXIT
      ELSE
         LOOP
      ENDIF
   ENDIF
ENDDO
IF lBLOQ = .T.
   (CURAL)->LAST_USER := US->CODIGO // GRAVA O CODIGO DO USUARIO QUE ESTA BLOQUEANDO O REGISTRO
ENDIF
RETURN (lBLOQ)

 Neste novo exemplo, o usuário tomará consciência de quem está usando o registro e poderá entrar em contato com a pessoa, se desejar, e não ficará sem saber o que aconteceu com o sistema paralizado. Eu uso essa função nos meus sistemas com sucesso.

Assim, use BLOQREG() antes de gravar no registro e depois use DBUNLOCK() para liberar o registro para uso. Não esqueça do DBCOMMIT() para descarregar o "CACHE" do disco depois do DBUNLOCK().

 Outra dica importante caso você esteja usando os índices do RDD DBFNTX, o padrão do Clipper:

 Sempre abra todos os índices do arquivo na mesma ordem quando você for gravar dados no arquivo DBF.

 Por exemplo, mesmo que o índice FOCIDADE seja o que você precise para trabalhar primeiro, você usará sempre esse mesmo esquema:

USE FORNECEDORES ALIAS FO SHARED NEW
SET INDEX TO FOCOD, FONOME, FOCIDADE, FOMACOMP
FO->( DBSETORDER(3) ) // Aqui voce diz a ordem que voce quer
*[...]


E nunca em um programa:
USE FORNECEDORES ALIAS FO SHARED NEW
SET INDEX TO FOCIDADE, FOCOD, FONOME, FOMACOMP
*[...]

E em outro:
USE FORNECEDORES ALIAS FO SHARED NEW
SET INDEX TO FOCOD, FONOME, FOCIDADE, FOMACOMP
*[...]

Porque se dois ou mais usuários inserirem um registro em um mesmo momento, os arquivos podem se corromper.

 Nos próximos tópicos você se tornará mais íntimo destes procedimentos.

 Um problema com arquivos em rede é a integridade dos arquivos, principalmente dos índices, portanto, em todo sistema que criar faça uma rotina de recriação de todos os índices usados, para que caso haja problemas, sejam resolvidos na hora. Lembre-se que para reindexar os índices ninguém na rede poderá estar usando o sistema, ou seja, ter em sua estação algum DBF aberto, assim este procedimento seria desejável todos os dias antes do início de cada jornada de trabalho, como prevenção. Para saber mais sobre problemas dos arquivos de índice, entre na página de KNOW-HOW.

Total votes: 0