Bienvenidos a Iseries Venezuela

Las mejores prácticas, recursos, tips, enlaces, videos y artículos para informáticos relacionados con el Iseries y el As/400 lenguajes de programación RPG, ILE RPG y SQL.

The best practices, resources, tips, links, videoes and articles for computer related to the Iseries and the As/400 languages of programming RPG, ILE RPG and SQL.

Wednesday, February 25, 2009

Ahora si es en serio: Error de Dispositivo.










El mensaje de Error de Dispositivo puede generarse por varias razones.

Vamos a enumerar algunas de ellas.

1.-En el programa realizas un Exfmt del registro de control de un subfile y los indicadores que permiten mostrar el registro de control y/o el subfile están apagados.

2.-En el programa realizas un Exfmt del registro de control de un subfile y los indicadores para mostrar el registro de control y el subfile están encendidos pero el subfile no contiene ningún registro grabado.



Este problema suele suceder cuando leemos un archivo en el programa y a medida que leemos el archivo vamos grabando un registro respectivo en el subfile con la información que nos interesa.
Finalmente al salir del lazo de lectura del archivo, encendemos los indicadores y hacemos un Exfmt del registro de control del subfile. Si el archivo de lectura no tenía data, nunca llenamos el subfile y por ende, a la hora de mostrarlo no hay nada que mostrar. Por esta razón el programa Rpg nos muestra un Error de Dispositivo. Podemos controlar con un indicador o con una pregunta si el archivo de lectura tenía o no registros para leer. Dependiendo si el archivo estaba vacío o no, apagamos o encendemos los indicadores para desplegar el subfile o impedir que sea mostrado.

Un subfile lo podemos definir a través de su registro de control (en el SDA) de dos maneras:

1.-Inicializado en forma automática: SFLINZ

Si elegimos que sea inicializado en forma automática no nos ocurre el problema que acabamos de describir. Sin embargo esta practica no es muy utilizada porque el tamaño del archivo de lectura pudiera ser menor que el numero de líneas definidos para el subfile. Para evitar que esas cantidad de lineas en blanco sean mostradas en la pantalla los programadores deben activar en el SDA un indicador de nondisplay ND a todos los campos del subfile y luego hacer update a los registros que quedaron en blanco (los campos con valores en cero o blanco) con el indicador asociado al ND = *ON.

Pseudo-Código para el caso SFLINZ
Fuente Del SDA

A R SFLR SFL
A nombre 15 A 2 10
A direccion 30 A 2 34
A*
A*
A*
A R SFLCTLR SFLCTL(SFLR)
A SFLPAG(17)
A SFLSIZ(17)
A 01 SFLDSP
A SFLDSPCTL
A 02 SFLINZ
A 2 10'NAME'
A 2 34'ADDRESS'
A

Este tipo de subfile resiste perfectamente este tipo de programación:

C* Inicializa Subfile generando 17 registros con valores 0 o blanco en sus campos.
C seton 02
C write SFLCTLR
C setoff 02
C*
C Línea = Línea +1 (contador de linea del subfile declarado en hoja F)
C Read archivo 99
C Dow not *in99
C UPDATE SFLR
C Linea = Línea + 1
C Read archivo
C Enddo

Si el archivo esta vacío y realizamos esta operación:
C seton 01
C EXFMT SFLCTLR

No se produce un error de dispositivo pero nos muestra 17 líneas en blanco en la
Pantalla. Para eliminar las líneas en blanco, tendríamos que recorrernos el subfile desde el principio prendiendo el indicador de ND (no display) y haciendo update a cada registro del subfile.

2.-Inicializado el subfile con un clear: SFLCLR.

Pseudo-Código para el caso SFLCLR
Fuente Del SDA

A R SFLR SFL
A nombre 15 A 2 10
A direccion 30 A 2 34
A*
A*
A*
A R SFLCTLR SFLCTL(SFLR)
A SFLPAG(17)
A SFLSIZ(17)
A 01 SFLDSP
A SFLDSPCTL
A 02 SFLCLR
A 2 10'NAME'
A 2 34'ADDRESS'
A

Este tipo de subfile resiste perfectamente este tipo de programación:

C* Inicializa Subfile generando un subfile vacío.
C seton 02
C write SFLCTLR
C setoff 02
C*
C Línea = Línea +1 (contador de linea del subfile declarado en hoja F)
C Read archivo 99
C Dow not *in99
C WRITE SFLR
C Linea = Línea + 1
C Read archivo
C Enddo

Si el archivo esta vacío y realizamos esta operación:
C seton 01
C EXFMT SFLCTLR

Se produce un error de dispositivo
A menos que luego del Enddo del lazo de lectura coloquemos el siguiente código:
C* seton 01
C If Linea = 1
C Setoff 01
C Endif
C EXFMT SFLCTLR


De esta manera nos evitamos el error de dispositivo.

3.-Otra causa de error es el tratar de grabar una línea del subfile dos veces. Me refiero al segundo caso (SFLCLR) Por ejemplo: si en el lazo de lectura nos olvidamos de incrementar el contador de línea, cuando hagamos el segundo write SFLR estamos tratando de sobreescribir un registro del subfile que ya estaba escrito previamente. (En realidad nos da un intento de grabar registro duplicado, aunque me ha pasado que el mensaje de primer nivel me dice error de dispositivo; luego en el detalle del mensaje me especifica registro duplicado)


4.-También el uso de palabras claves que requieren el uso de variables “escondidas” en el SDA puede originar error de dispositivo.

Un ejemplo de este caso es el uso de la palabra clave CSRLOC en el SDA. Esta palabra clave utilizada para posicionar en la pantalla el cursor en una fila y columna especifica, requiere de dos variables
CSRLOC(FILA COLUMNA) para este ejemplo, llamamos a las variables FILA Y COLUMNA.
Si las variables FILA y COLUMNA están en cero al momento de mostrar la pantalla: EXFMT también da error de dispositivo a menos que coloquemos un indicador en el SDA que condicione la activación del CSRLOC.

Encendemos el indicador solamente cuando queremos que el cursor se mueva a las posiciones contenidas en las variables FILA y COLUMNA si el indicador está apagado, el cursor se mueve por omisión tal y como lo maneja el SDA para los campos de entrada, salida e I/O.

Revisa las palabras claves de tu pantalla y verifica que al momento de hacer un EXFMT las variables asociadas a los keywords contienen valores válidos.




Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Monday, February 23, 2009

Mejorando los Tiempos de Respuesta













Supongamos que tienes un archivo muy grande que es el lazo principal del programa y que dentro de este lazo haces chain a una tabla constantemente de la cual extraes información de un código que a su vez lo usas para actualizar el archivo grande.

El siguiente pseudo-código fuente como ejemplo para ilustrar de lo que se trata:

FArchivoGrande U K Disk
FTabla I K Disk

C Read Archivo Grande 99
C Dow not *in99
C Clave Chain Tabla 98
c*
c Eval Campog = campot
c update ArchivoGrander (la r al final: nombre de registro)
c*
c Read Archivo Grande 99
c Enddo
c Seton LR
c*


Si el "ArchivoGrande" tiene un total de 5.000.0000 de registros, esto
significa que en la ejecucion del programa se realizan un total de accesos
al disco relacionado como sigue:

Total lecturas:

Sobre el Archivo grande: 5.000.000
Sobre la tabla: 5.000.000
----------
10.000.000

Hay que añadir a esta cifra los accesos al disco que se hacen por cada update al archivo grande que son 5.000.000 puesto que se realiza un update por cada registro leído en el archivogrande.

En un ejercicio de imaginación supongamos que cada acceso a disco "cuesta" un milisegundo. Un milisegundo es 0,001 segundos. 15.000.000 accesos x 0,001 segundos
representa 15.000 segundos que traducidos a minutos son 250. Llevados a horas son 4,16 horas. (aproximandamente 4 horas, 9 minutos, 36 segundos)

Son 15.000.000 de acceso al disco lo cual representan 15.000.000 de operaciones de I/O.
La operaciones de I/O son las mas lentas que procesa cualquier sistema operativo.


Si queremos reducir el tiempo de respuesta es necesario reducir la cantidad de lecturas y grabaciones al disco.


Vamos a generar un código fuente mas efectivo en cuanto a tiempo de respuesta.

FArchivoGrande U K Disk
FTabla I K Disk

D*
DTclave 5 S dim(1000) *Arreglo que guarda clave de la tabla*
DTdata 10 A dim(1000) *Arreglo guarda la data de la tabla*
Dindice 4 S 0 *Indice de acceso al arreglo*
D*

c* Lectura de la tabla y se guarda en un arreglo.
C*
C Eval Indice = 1
C Read Tabla 01
c Dow not *in01
C eval Tclave(indice) = Clave
c eval Tdata(indice) = Campot
c Eval Indice = Indice + 1
c Read Tabla 01
c Enddo


C*
C Read Archivo Grande 99
C Dow not *in99
c Eval Indice = 1
C Clave Lookup,Indice Tclave 98
c*
c Eval Campog = Tdata(indice)
c update ArchivoGrander (la r al final: nombre de registro)
c*
c Read Archivo Grande 99
c Enddo
c Seton LR
c*

El uso de arreglos ( o matrices) reduce los tiempos de respuesta porque los accesos a un arreglo NO SON accesos al disco.
vamos a contabilizar el número de I/O que tenemos en esta versión:

Lecturas:
Sobre el ArchivoGrande: 5.000.000
Sobre la tabla : 1.000
---------
5.001.000
Updates:

Sobre el ArchivoGrande: 5.000.000

Un total de 10.001.000 accesos a disco. Esto representa: 10.001.000 x 0,001 segundos = 10001 segundos consumidos en acceso a disco que traducidos a minutos son: 166,683 y llevados a horas son: 2,77805 horas. (esto es aproximadamante 2 horas, 46 minutos, 41 segundos), reduciendose en un 33% el tiempo de respuesta. ¿Impresionante no?



Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Sunday, February 22, 2009

Mejores Practicas en RPG: Uso de Constantes e Indicadores



Uso de constantes en un programa RPG:


Por ejemplo:

Si status = 1 es Activo y Status = 2 es Inactivo,
es recomendable declarar dos contantes:

D ACTIVO const(1)
D INACTIVO const(2).


Al preguntar en el programa por el status no es lo mismo decir:

C If Status = 1

que decir

C If Status = Activo,

De esta manera se autodocumenta el programa y se hace mas legible para un nuevo programador que deba darle mantenimiento.

----------------------------------