(01/Abr) Segunda entrega :
Índices .NTX sólidos como la roca.
Bienvenidos a esta segunda entrega, me alegra de que
estén aquí ya que esto significa que les ha gustado la
primera.
Hoy, sin demasiadas vueltas hablaré sobre las RDD's y
los índices NTX.
Las Replaceable Database Drivers (RDDs) en español
Manejador reemplazable de bases de datos, son soportadas
por Clipper a partir de su versión 5.0
El objetivo de una RDD como su nombre lo indica
(reemplazable) es permitir el uso de varios manejadores
de bases de datos distintos y simultáneos si es
necesario.
Esto permite crear índices con formatos y
compatibilidades distintas, por ejemplo los .MDX
compatibles con dBase IV, los CDX compatibles con FoxPro
y los .DB compatibles con Paradox.
La RDD nativa de Clipper es la "DBFNTX", la
cual funciona en forma transparente al programador al
punto que ni siquiera hace falta incluir la librería en
tiempos de compilación.
Debido a su arquitectura requieren de ciertos métodos
especiales de uso cuando se utilicen en programas que
trabajan en una red, donde se abren y actualizan
simultáneamente por dos o mas estaciones de trabajo.
En la actualidad los índices .NTX tienen fama de
volverse inconsistentes con gran facilidad, esto en
realidad no es así, solo que hay que tomar ciertas
medidas que hasta hoy no figuran detalladas en ningún
manual de los que he leído.
En primer lugar voy a nombrar la incompatibilidad con los
viejos índices .NTX debido a varios cambios en su
estructura el nuevo RDD nativo de Clipper
"DBFNTX" no es compatible con los viejos
índices de Clipper .NTX a pesar de poseer la misma
extensión. El intento de abrir índices creados con
versiones anteriores de Clipper 5.0 provocará un error
irrecuperable en tiempo de ejecución y rara vez
indicará un mensaje relacionado a índices corruptos ó
RDD incompatible, por lo que será algo complicado
determinar donde se encuentra el problema.
El culpable del 99% de las inconsistencias de los
índices .NTX de trabajo en red es el diseño de la RDD
que compete al manejo del tiempo de vida de los bloqueos,
en pocas palabras a la manera en que se manejan los
tiempos de espera.
Es muy común que al tratar de abrir una base de datos en
red utilicemos algún control para determinar he informar
si esta está bloqueada, por ejemplo:
DbUseArea(.T., [...]
Whil NetErr()
@... Say "Base en uso exclusivo, reintentando apertura"
DbUseArea(.T., [...]
EndD
|
De esta manera
alentamos a los usuarios a esperar o dar aviso del
problema, también es común que al tratar de bloquear
una base de datos o un registro se haga algo similar como
muestra el siguiente ejemplo:
[...]
Whil !Flock()
@... Say "Base bloqueada, reintentando..."
EndD
[...]
Whil !Rlock()
@... Say "Registro #" + AllTrim(Str(RecNo())) + " bloqueado, reintentando..."
EndD
[...]
|
Este tipo de controles se realizan debido a que si un
ordenador que tiene un registro bloqueado se
"cuelga" este quedará bloqueado para todas las
demás estaciones, cosa que es común en las redes
ocupadas por varios usuarios y que también sucede cuando
el usuario deja la aplicación en un segundo plano en
sistemas multitarea sin suficientes recursos como para
mantener la conexión activa, en este caso la mayoría de
las redes termina por desconectar al usuario por tiempo
de espera agotado "Time Out".
Estos métodos adoptados por los programadores lo que
hacen es que el usuario no piense que su máquina se ha
colgado y la reinicie provocando así la corrupción de
bases de datos, en su lugar si ve que se ha extendido por
mucho tiempo el mensaje optan por llamar al administrador
de redes quien simplemente busca y desconecta la
estación que no está haciendo petición (Request).
Si no existiesen estos mensajes todas las PC's conectadas
a la red parecerían estar "colgadas".
Con los índices ocurre algo similar, hay que mostrar un
mensaje si se encuentra bloqueado por los mismos motivos,
ya que Clipper bloquea el índice después de escribir la
base y si lo encuentra bloqueado se queda en espera
infinitamente hasta que sea factible bloquearlo con lo
cual si el usuario supone que su estación ha dejado de
responder y la re inicia provocará sin lugar a dudas la
ruptura del índice en cuestión.
Como el bloqueo y desbloqueo de los índices se realiza
en forma transparente al programador, hay que determinar
la falla en bloqueo utilizando un manejador de errores
(errorhandler).
El manejador de errores original devuelve siempre
verdadero (.T.) a este error sin mostrar ningún mensaje,
cosa que está bien si trabajamos en sistemas
monousuarios, pero en redes esto es un verdadero horror.
A continuación muestro un ejemplo de cómo manejar estos
errores basándome en el archivo NTXERR.PRG que viene en los ejemplos de
Clipper.
Init Proc InitHandler()
LOCAL bDefError := ErrorBlock( { |err| LockErrHandler( err, bDefError ) } )
// Carga en la variable bDefError el manejador de errores actual.
Retu
Static Func LockErrHandler( oErr, bDefError ) // El nuevo manejador.
If ( oErr:genCode == 41) // corresponde al error de bloqueo de índices
@... Say "Índice bloqueado por otra estación, NO reinicie su PC"
@... Say "Si el error persiste informe a su administrador de sistemas"
Retu .T.
EndI
Retu ( eval( bDefError, oErr ) ) // Devuelve el control de errores al manejador original.
|
Si bien este
código viene con Clipper no es mencionado por el manual
con el énfasis necesario que creo merece, muchas veces
es mas fácil migrar a otros RDD's que no necesiten este
tipo de manejos pero como verán no es tan complicada la
cosa.
La semilla del problema se haya en el momento del
bloqueo, para los .NTX el driver bloquea el índice en el
momento de accederlo y después de haber escrito la base,
no se si esto puede ser llamado "bug" o
simplemente una manera de hacer las cosas, pero de lo que
si estoy seguro es de no haber encontrado manual, guía o
tutorial que lo mencione y siendo un tema tan delicado me
pareció coherente incluirlo en esta publicación.
|