martes, 19 de junio de 2018

El paradigma del Factor de Bloqueo en COBOL

COBOL es muy considerado no solamente por su sencillez en la programación, sino también, y fundamentalmente, por la altísima performance de sus archivos indexados, tanto en escritura como en lectura. Como se sabe, los archivos indexados son indispensables para la rápida ubicación de registros, en forma lo más inmediata posible de estos, ya que para el usuario final no son admisibles las esperas de tiempos extensos (en algunos casos varios segundos) para recuperar la información necesaria. Entonces, los archivos indexados son insustituibles. Así se implementa hoy día, tanto en archivos ISAM y VSAM, como en bases de datos relaciones, y alguna más de otro tipo que para este informe no vienen al caso.

Antiguamente, cuando las únicas opciones eran la grabación de archivos en cintas magnéticas o discos duros de poca capacidad (no más de 5 MB), la considerción de ahorro de espacio era un parámetro siempre crítico a tener en cuenta. Sin embargo, hoy día, con discos que se establecen ya en terabytes frente a las antiguas velocidades de acceso, esto es despreciable; ahora los archivos solo se limitan a la capacidad de manipulación entregada por los lenguajes y no por el hardware. En virtud de esto, antiguamente, cuantas más opciones de ahorro de espacio en almacenamiento se lograra, era muy bien recibido. Por tanto, el "pegar" fìsicamente un registro a otro cuando se estaba grabando, era fundamental, sin desperdicio de espacio. Para ello, por ejemplo, COBOL incluía (e incluye) lo que se conoce como Factor de Bloqueo (FB); esto es, considerando que el tamaño del sector (también llamado "bloque", y no confundir con "clúster", que es un conjunto de sectores contiguos), una clásula que permite "pegar" los registros en un mismo sector. Esto se logra, por parte del programador, dividiendo el tamaño del bloque de Windows (que puede ser 512, 1024, 2048 o 4096 bytes por bloque, dependiendo de la FAT de Windows) entre la cantidad de bytes del registro.

Por ejemplo, si el bloque (o sector) de Windows fuera de 1024 KB, y el tamaño del registro del archivo es de 10 bytes, la cuenta daría 102,4 registros en el bloque, donde esa fracción de 4 se perdería, pero es desestimable pero no inútil, ya que sería utilizada por alguna otra aplicación distinta (Excel, etc.) si es que es suficiente para alojar algo.

Hoy día, con los descomunales tamaños de los discos duros, cuando se graba un registro, es indiferente el ahorro de espacio. He intentado dejar esto en claro realizando un benchmark entre dos archivos con el mismo tamaño: un campo numérico de 10 bytes como clave primaria:

           Select OutputFile    assign to random, "OutputFile.BM"
                                organization is indexed
                                access mode  is dynamic
                                record key   is Of-Count
                                file status  is Fs-Gral.

           Select OutputFileBlk assign to random, "OutputFileBlk.BM"
                                organization is indexed
                                access mode  is dynamic
                                record key   is OfBlk-Count
                                file status  is Fs-Gral.

La declaración para el archivo sin FB de registros es la siguiente:

       Fd  OutputFile.
       01  Reg-OutputFile.
           03 Of-Count   pic 9(10).

Y esta es la declaración del archivo con FB, considerando un bloque de 1024 KB:

       Fd  OutputFileBlk block contains 102 records
                         record contains 10 characters
                         label record is standard.
       01  Reg-OutputFileBlk.
           03 OfBlk-Count pic 9(10).

La finalidad de este ejercicio es comprobar si Windows 10 da curso al FB. Como se comprobó con el benchmark, sí le da curso, pero sus resultados son, en principio (quedan más cosas para chequear, como el armado de la tabla de índices hash), algo indefinidos, pero se puede concluir que no vale la pena establecer un FB en los archivos. Veamos en estos ejemplos por qué.

En esta instancia, se grabaron 500.000 registros sin FB en un archivo, y los mismos con FB en el otro archivo. Los tamaños de los archivos quedaron de la siguiente manera:

500.000 registros s/FB

OutputFileBlk    10,108,928 MB    FB: 1024
OutputFile       10,264,576 MB    FB: 1024

Luego se aumentó el tamaño del bloque a 4096 bytes, dando por resultado 409 registros por bloque, y el resultado fue el siguiente:

500.000 registros c/FB

OutputFileBlk    17,199,104 MB    FB: 4096
OutputFile       10,264,576 MB    FB: 4096

Ahora veamos los tiempos de grabación y de lectura de cada archivo:

Grabacion 500.000 registros s/B inicia:    13:47:29:29
Fin grabacion s/B.....................:    13:50:28:53

La grabación de los 500.000 registros del archivo sin FB insumió 3 minutos.

Grabacion 500.000 registros c/B inicia:    13:50:28:53
Fin grabacion c/B.....................:    13:56:47:34

La grabación de los 500.000 registros del archivo con FB insumió más de 6 minutos.

Esto indica claramente que la "performance" entre uno y otro da por mejor al que no tiene FB, y esto se explica de la siguiente manera: Windows sí aplica el FB, pero ello le consume más tiempo a COBOL dado que tiene "que tomarse un tiempo" para establecer la estructura del árbol de índices, según donde vayan cayendo los registros en un disco particionado. Esto es, determinar en las páginas del índice el bloque y la posición del registro en el mismo (tarea nada sencilla, pero infalible en exactitud para COBOL). Cuando no establecemos FB, para Windows es mucho más sencillo, pues pone los registros donde puede y le tira a COBOL la información de dónde se encuentra el registro, y COBOL arma sin estrés el árbol-B.

Ahora veamos los tiempos de lectura de los 500.000 registros de esos archivos, en el mismo bechmark:

Inicio lectura s/B....................:    13:56:47:35
Fin lectura s/B.......................:    13:57:13:72  26"

Inicio lectura c/B....................:    13:57:13:72
Fin lectura c/B.......................:    13:57:38:87  25"

La diferencia es de apenas un segundo.

Ahora, la cosa cambia un poco cuando declaramos archivos con múltiples claves con duplicados. Veamos esta.

Select optional StkLinFac assign to random, NombreStkLinFac
                          organization is indexed
                          access mode  is dynamic
                          record key   is SLF-Clave01 = SLF-Fecha,  SLF-NroCli,   SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave02 = SLF-NroCli, SLF-Fecha,    SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave03 = SLF-NroArt, SLF-Fecha
                alternate record key   is SLF-Clave04 = SLF-Fecha,  SLF-NroArt                             with duplicates
                alternate record key   is SLF-Clave05 = SLF-Fecha,  SLF-Zona,     SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave06 = SLF-Zona,   SLF-Fecha,    SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave07 = SLF-Ramo,   SLF-Fecha,    SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave08 = SLF-Fecha,  SLF-Ramo,     SLF-NroArt               with duplicates
                alternate record key   is SLF-Clave09 = SLF-Grupo,  SLF-SubGrupo, SLF-NroArt    SLF-Fecha  with duplicates
                alternate record key   is SLF-Clave10 = SLF-Fecha,  SLF-Grupo,    SLF-SubGrupo, SLF-NroArt with duplicates
                alternate record key   is SLF-Clave11 = SLF-TipDoc, SLF-NroDoc                             with duplicates
                file status  is We-StFile.

Como se observa, el archivo está dotado de once claves, de las cuales solo una es sin duplicado (SLF-Clave03); esto es particularmente importante porque el árbol-B está compuesto, y COBOL ahora sí debe preocuparse por una clave única y otras diez sin inconvenientes en introducirlas en la página del índice que corresponda; necesariamente, deberá emplear más tiempo en ello.

Se efectuó el mismo test, o sea, sobre 500.000 registros, y el resultado fue el siguiente:

Grabación 500.000 registros s/B inicia:    19:36:25:04
Fin grabación s/B.....................:    19:58:37:50   22' 13"

Grabación 500.000 registros c/B inicia:    19:58:37:50
Fin grabación s/B.....................:    20:15:28:02   17'  9"

Hasta acá, el test varía muy poco, pues hay apenas 5' de diferencia a favor del archivo con FB. Veamos los tiempos de lectura:

Inicio lectura s/B....................:    20:15:28:02
Fin lectura s/B.......................:    20:16:06:53    0' 32"

Inicio lectura c/B....................:    20:16:06:53
Fin lectura c/B.......................:    20:16:36:58    0' 30"

Ahora veamos los tamaños de ambos archivos:

BlkStkLinfac    112,054 KB
StkLinfac       112,926 KB

Como puede comprobarse, tampoco es trascendente la diferencia, y estamos mencionando un archivo de 500.000 registros, un número importante para un test. Se podría incluir archivos de mayores extensiones, como 2 GB, límite en RM/COBOL bajo Windows (ver página 119 en el manual "RM/COBOL User's Guide" por más información), pero se puede suponer que, estableciendo una proporcionalidad, los valores no cambiarían demasiado.

En principio, y a menos que surja otro estudio semejante, como conclusión final, no veo necesario que se establezca un FB en los archivos indexados, puesto que las diferencias no son para nada dramáticas.