1 #LyX 1.3 created this file. For more info see http://www.lyx.org/
11 \paperpackage widemarginsa4
15 \use_numerical_citations 0
16 \paperorientation portrait
19 \paragraph_separation indent
21 \quotes_language english
25 \paperpagestyle default
29 Organización de Datos (75.06)
34 \begin_inset Formula $\mu$
44 Leandro Lucarella (77891)
46 Ricardo Markiewicz (78226)
49 Primera Entrega, 19 de Abril de 2004
53 \begin_inset LatexCommand \tableofcontents{}
63 Esta es la documentación correspondiente a las API`s para el manejo de tres
64 organizaciones de archivo diferentes.
65 A continuación se describe cada una de ellas y su modo de funcionamiento
66 y sus características principales.
67 De la correcta elección de la organización, dependerá la eficiencia de
68 la aplicación que la utilice.
72 EMUFS se presenta como un
80 , capaz de administrar datos almacenados en cualquiera de las tres organizacione
81 s de archivo previamente mencionadas, las cuales a saberse son:
84 Registros de Longitud Variable, Bloques de tamaño parametrizable
87 Registros de Longitud Variable, Sin Bloques
90 Registros de Longitud Fija, Bloques de tamaño parametrizables
93 A través de este trabajo, se podrán observar las diferencias entre distintos
94 tipos de organización de archivos, ventajas y desventajas de cada una de
95 ellas, y las situaciones particulares que deberá sortear un filesystem,
96 como la partición de registros en distintos bloques, manejo de espacio
97 libre, compactación de un archivo, etc.
100 A continuación, veremos que el manejo de los archivos en EMUFS se realiza
101 a través de una estructura de control común para cualquier tipo de archivo,
102 dándole flexibilidad y escalabilidad a nuestro sistema.
105 Hacia el final de esta presentación, se observaran las pruebas realizadas
106 con las distintas organizaciones de archivos, y las conclusiones obtenidos
116 Se detallan a continuación los tipos de datos definidos y utilizados en
117 las distintas implementaciones que conforman nuestro sistema, siendo el
118 más importante de ellos, la estructura
122 que actúa como interfaz común para el manejo de cualquier tipo de archivo
123 (no importa que tipo de organización física posea un archivo, esta estructura
124 proveerá una interfaz (funciones) para su manejo).
130 En la implementación de cada tipo de organización física, así como también
131 en las API de los archivos auxiliares comunes a ellas, se da la utilización
132 de tipo definidos para una clara interfaz entre las mismas, los cuales
133 son brevemente descriptos a continuación y pueden ser hallados en el archivo
145 : usado para representar un
156 : usado para representar el tamaño en bytes de un registro.
163 : usado para representar un número de bloque.
170 : usado para representar el tamaño en bytes de un bloque.
177 : usado para representar espacio libre en bytes.
184 : usado para representar un offset.
204 es la estructura principal que encapsula todas las funciones para el manejo
205 de un archivo de datos.
206 Posee punteros a funciones que dependiendo de la organización física por
207 la cual se opte dentro del sistema, serán asignados de acorde.
211 Su declaración puede ser observada en el archivo
215 y la misma cuenta con los siguiente campos:
222 que es un tipo enumerado que indica cual es la organización.
229 indica el tamaño del bloque para los tipos 1 y 3.
236 indica el tamaño del registro, para el tipo 3 que posee tamaño constante.
243 puntero a la función para leer un bloque.
248 void *leer_bloque_raw()
250 puntero a la función para leer un bloque, el anterior y el siguiente.
255 void **leer_registro()
257 puntero a la función para leer un registro.
262 void **leer_registro_raw()
264 puntero a la función para leer un registro con su encabezado.
269 EMUFS_REG_ID *grabar_registro()
271 puntero a la función para grabar un registro.
276 EMUFS_REG_ID *modificar_registro()
278 puntero a la función para modificar un registro.
283 int *borrar_registro()
285 puntero a la función para borrar un registro.
290 EMUFS_Estadisticas *leer_estadisticas()
292 puntero a la función para cargar una estructura con las estadísticas.
299 puntero a la función para compactar un archivo.
306 almacena el nombre del archivo sin extensión.
309 Esta estructura define los valores de sus punteros según el tipo de organización
310 que se desee manejar y esto se realiza a través del API emufs, implementado
315 , que se describirá posteriormente.
318 Por ejemplo si se desea crear un archivo de nombre
319 \begin_inset Quotes eld
323 \begin_inset Quotes erd
326 organizado de la forma 3, se invoca a la función:
331 emufs_crear(filename,tipo,tam_bloque,tam_reg),
337 es el nombre que tendrán los archivos de datos e índice,
341 es el tipo de organización - bloques parametrizados y registros constantes
346 es el tamaño del bloque, y
350 es el tamaño del registro.
353 Para las diferentes organizaciones puede ser que alguno de estos 2 últimos
354 valores no tengan sentido almacenarlas y tomaran un valor por defecto igual
358 Según el tipo de organización, se inicializan los punteros a las funciones.
365 emufs_tipo3_leer_bloque()
367 , y lo mismo sucede con los demás.
377 es un tipo de dato enum, el cual será utilizado en la cabecera de todo
382 ), para indicar los distintos tipos de organización física.
383 Su declaración puede verse en el archivo
388 A saberse los valores y significado correspondiente que puede tomar este
396 : Archivos con registros de longitud variable y bloques parametrizables.
403 : Archivos con registros de longitud variable sin bloques.
410 : Archivos con registros de longitud fija y bloques parametrizables.
420 es una estructura que almacenará los datos pertinentes a las estadísticas
421 de un archivo dado, y será utilizada para visualizar dichas observaciones
425 Su declaración puede ser observada en el archivo
429 y la misma cuenta con los siguiente campos:
440 : indica el tamaño del archivo de datos (.dat) en bytes.
451 : indica el tamaño de los archivos auxiliares sumados en bytes.
462 : indica la cantidad de bytes en información de control utilizados para
474 : promedio de espacio libre en el archivo de datos (por bloque o gap promedio
486 : total de espacio libre en el archivo de datos.
497 : máximo espacio libre en el archivo de datos (en un bloque o máximo gap
520 : cantidad de bloques en el archivo de datos (.
535 : cantidad de registros en el archivo de datos (
542 En base a la estructura descripta anteriormente y mediante la utilización
543 de la función de lectura de estadísticas
545 emufs_leer_estadisticas()
547 disponible en la estructura común
551 handler de cualquier tipo de archivo, podremos obtener una serie de estadística
552 s que pasamos a detallar (más allá de los datos básicos como cant registros,
553 cant bloques, tam archivo, etc):
556 Relación entre espacio libre y el tamaño del archivo de datos (
563 Relación entre el espacio ocupado por información de control y el tamaño
564 del archivo de datos (
571 Cantidad promedio de espacio libre (en bloque o gap promedio)
574 Desviaciones extremas de espacio libre (máximo/mínimo espacio libre en bloque
579 \begin_inset LatexCommand \label{sec:cabecera_gral}
583 Organización física general de un archivo E
584 \begin_inset Formula $\mu$
591 \begin_inset Formula $\mu$
594 FS está compuesto por 4 archivos a nivel de sistema operativo: archivo de
595 datos (con 3 formatos posibles, ver páginas
596 \begin_inset LatexCommand \pageref{cha:tipo1}
601 \begin_inset LatexCommand \pageref{cha:tipo2}
606 \begin_inset LatexCommand \pageref{cha:tipo3}
610 ), archivo de índice (ver página
611 \begin_inset LatexCommand \pageref{sec:idx}
615 ), archivo de control de espacio libre (ver página
616 \begin_inset LatexCommand \pageref{sec:fsc}
620 ) y archivo de índices recuperables (ver página
621 \begin_inset LatexCommand \pageref{sec:did}
628 El archivo de datos está compuesto por:
639 (4 bytes en plataformas Linux de 32 bits) que representa el tipo de archivo.
642 Datos dependientes del tipo de archivo.
649 es utilizada para poder detectar el formato de un archivo al abrirlo.
650 Los datos dependientes del tipo de archivo serán explicados en sus secciones
657 +-----------+--------------------------------------------//-+
660 | tipo | Datos dependientes del tipo de archivo ...
668 +-----------+--------------------------------------------//-+
674 Uso de la estructura EMUFS
677 Como fue mencionado anteriormente en la descripción de la estructura EMUFS,
678 la misma proporciona al usuario una interfaz a través de la cual puede
679 realizar el manejo de archivos en forma genérica, abstrayéndose del tipo
680 de organización física en particular que dicho archivo posea.
685 y las funciones que inicializan la estructura se encuentran en
690 Es decir que a través de esta estructura, podemos manejar cualquier tipo
691 de archivo, mediante una misma interfaz en común.
696 posee además de ciertos datos que describen la organización física de un
697 archivo dado como por ejemplo
715 , una serie de punteros a funciones para el manejo del archivo del cual
719 Entre dichos funciones se encuentran:
725 leer_bloque(), borrar_registro()
733 modificar_registro, leer_estadisticas()
740 Para entender mejor el uso de esta estructura para el manejo de los archivos,
741 mostraremos un ejemplo concreto.
742 Supongamos que tenemos el siguiente código:
745 EMUFS *efs = emufs_crear(¨articulos.dat¨,T3,200,50);
748 Esto hará que se cree el archivo de datos
752 , con la organización física tipo 3 con registros de longitud fija de 50
753 bytes y bloques de 200 bytes.
754 Al mismo tiempo, los se asignaran valores a los punteros a funciones que
755 posee dicha estructura, la cual de ahora en más estará en condiciones de
756 manejar un archivo del tipo 3.
757 Gráficamente lo que sucede es:
761 \begin_inset Float figure
768 Inicialización de estructura EMUFS para un caso Archivo Tipo 3
772 \begin_inset Graphics
773 filename graphics/Emufsinit.png
785 Así pues, cuando se utilice la estructura para por ejemplo leer un registro,
786 sucederá lo siguiente:
789 efs->leer_registro(params) -- calls --> emufs_tipo3_leer_registro(params)
792 Como se puede observar, la estructura
796 permitirá el manejo de cualquier tipo de archivo, a través del mismo código,
797 dándole gran flexibilidad a nuestro sistema, que podrá expandirse a más
798 tipos de archivos de ser necesario.
804 Acompañando al archivo de datos (
808 ) el cual es responsable de la contención de los registros, tendremos tres
809 archivos auxiliares (
821 ) cuya funcionalidad y propósito pasamos a describir a continuación, sin
822 antes remarcar que los tres archivos poseen una sola implementación para
823 las distintas formas de organización física que hemos implementado (tres
824 para ser mas exactos).
827 Entre las ventajas de poseer la misma implementación se encuentra el tener
828 un API común entre los tres tipos para el manejo de la localización de
829 sus registros, administración de espacio libre e Id's liberados, sin necesidad
830 de realizar n-implementaciones para un mismo objetivo final.
833 Además, la obtención de ciertos datos estadísticos como espacio libre, o
834 cantidad de registros, se realiza a través de la misma interfaz, y también
835 se ha facilitado en cierto grado la re-organización física de un archivo
836 (pasar de un tipo a otro), dado el uso de estos tres archivos auxiliares
837 en común para funciones tan predominantes como índexación, administración
838 de espacio libre y recuperación de Id's.
842 \begin_inset LatexCommand \label{sec:idx}
849 El archivo índice (.idx), permite la localización de los registros en el
850 .DAT de forma directa, mediante la obtención de su offset respecto del inicio
851 del .dat, o nro bloque (segun el tipo de organización física) en donde se
852 encuentra un registro dado, indicado por su
857 Los registros de este archivo se encuentran representados una estructura
858 que indica un número de registro y el bloque u offset en donde se encuentra
862 Es necesario que este archivo esté ordenado por
866 , ya que esto permitirá el acceso directo al mismo, para la rápida obtención
867 del nro de bloque u offset y posterior búsqueda de un registro en el archivo
874 Los registros de este archivo se encuentran representados a nivel código
875 por el siguiente tipo de dato interno (
882 typedef struct emufs_idx_t {
888 EMUFS_OFFSET location;
895 \begin_inset Float table
902 Ejemplo de registro en archivo índice (.idx), para un archivo de organización
908 <lyxtabular version="3" rows="2" columns="3">
910 <column alignment="center" valignment="top" leftline="true" width="0">
911 <column alignment="center" valignment="top" leftline="true" width="0">
912 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
913 <row topline="true" bottomline="true">
914 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
922 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
930 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
938 <row topline="true" bottomline="true">
939 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
947 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
955 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
960 Indica que el registro de id_reg = 5, se encuentra en el bloque 54
972 \begin_inset Float table
979 Ejemplo de registro en archivo índice (.idx), para un archivo de organización
985 <lyxtabular version="3" rows="2" columns="3">
987 <column alignment="center" valignment="top" leftline="true" width="0">
988 <column alignment="center" valignment="top" leftline="true" width="0">
989 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
990 <row topline="true" bottomline="true">
991 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
999 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1007 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1015 <row topline="true" bottomline="true">
1016 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1024 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1032 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1037 Indica que el registro de id_reg = 5, se encuentra en el bloque 54
1057 Como se puede observar, para distintas organizaciones el significado de
1058 los registros en este archivo es diferente y se utilizará de distinta manera
1065 Las declaraciones e implementación se pueden encontrar en
1079 \labelwidthstring 00.00.0000
1087 Los registros del archivo índice (
1091 ), poseen una correspondencia 1 a 1, con los Id's de los registros en el
1097 Con esto, queremos decir que el N-ésimo registro del archivo índice, será
1098 aquél que posea la información para localizar al registro cuyo
1102 es N, dentro del archivo de datos (
1112 Cabe aclarar que por si bien el índice se encuentra ordenado por
1116 , los registros en el archivo de datos, por lo general no lo estarán (ordenados
1122 emufs_idx_buscar_registro(), emufs_idx_get()
1124 \labelwidthstring 00.00.0000
1130 Ante la alta de un registro en el archivo de datos, se insetará un nuevo
1131 registro en el archivo índice, con el id_reg del registro en cuestión,
1132 y el offset u bloque donde se lo haya grabado en disco.
1138 \labelwidthstring 00.00.0000
1144 Ante el borrado de un registro del archivo de datos, se accederá el registro
1145 correspondiente en el índice, y se actualizara su LOCATION, estableciéndolo
1146 en el valor especial
1150 , el cual indica que ese registro ha sido eliminado y por ende no se lo
1151 podrá localizar en el futuro.
1152 Como se verá mas adelante, según el tipo de organización física, el registro
1153 puede ser borrado concretamente del .
1164 \labelwidthstring 00.00.0000
1170 Ante la modificación en la posición física de un registro dentro del archivo
1171 de datos (por ejemplo luego del proceso de re-compactación, se realizará
1172 la modificación respectiva del campo
1180 emufs_idx_actualizar()
1184 \begin_inset LatexCommand \label{sec:fsc}
1188 Archivo de control de espacio libre
1191 El archivo de espacio libre (
1195 ) (espacio por bloque o gaps en archivo, según el tipo de organización física),
1196 tiene como función la administración del espacio libre, generado por previas
1197 eliminaciones de registros en el archivo de datos.
1198 El mismo, nos indicará donde hay lugar para insertar un nuevo registro.
1201 Para el caso de una organización por bloque, nos dirá en que bloque o si
1202 se debe generar un nuevo bloque.
1203 En el caso de la organización sin bloques, nos indicará en que gap o si
1204 al final del archivo.
1207 Los registros de este archivo se encuentran representados una estructura
1208 que indica un número de bloque u offset y el espacio libre disponible en
1209 el mismo (o a partir del mismo en el caso del offset).
1216 : Por requerimiento del algoritmo de compactación el tipo de organización
1217 física con reg long var, sin bloques, los gaps se graban en forma ordenada
1219 (El orden se corresponde con lo que hay en el .dat).
1225 Los registros de este archivo se encuentran representados a nivel código
1226 por el siguiente tipo de dato interno (
1233 typedef struct emufs_fsc_t {
1236 EMUFS_BLOCK_ID marker;
1239 EMUFS_FREE freespace;
1249 \begin_inset Float table
1256 Ejemplo de registro en archivo de control de espacio libre para un archivo
1261 \begin_inset Tabular
1262 <lyxtabular version="3" rows="2" columns="3">
1264 <column alignment="center" valignment="top" leftline="true" width="0">
1265 <column alignment="center" valignment="top" leftline="true" width="0">
1266 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
1267 <row topline="true" bottomline="true">
1268 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1276 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1284 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1292 <row topline="true" bottomline="true">
1293 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1301 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1309 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1314 Indica que en el bloque 12, hay 120 bytes libres al final del mismo.
1326 \begin_inset Float table
1333 Ejemplo de registro en archivo de
1337 para un archivo sin bloques
1341 \begin_inset Tabular
1342 <lyxtabular version="3" rows="2" columns="3">
1344 <column alignment="center" valignment="top" leftline="true" width="0">
1345 <column alignment="center" valignment="top" leftline="true" width="0">
1346 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
1347 <row topline="true" bottomline="true">
1348 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1356 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1364 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1372 <row topline="true" bottomline="true">
1373 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1381 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
1389 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
1394 Indica que a partir del byte 12 del archivo de datos, hay 120 bytes libres.
1414 Como se puede observar, para distintas organizaciones el significado de
1415 los registros en este archivo es diferente y se utilizará de distinta manera
1419 Funciones principales
1422 Las declaraciones e implementación se pueden encontrar en
1436 \labelwidthstring 00.00.0000
1442 Ante la operación de alta de un registro en el archivo de datos, se realizará
1443 la búsqueda de espacio libre donde este podrá ser insertado.
1444 En el caso de organizaciones con bloques, se buscará en que
1448 se posee espacio suficiente para albergar el nuevo registro (o a partir
1457 bloques consecutivos libres).
1458 En el caso de organización sin bloque, se buscará un gap o espacio libre
1459 en el archivo, obteniéndose en consecuencia, el
1468 emufs_fsc_buscar_lugar(), emufs_fsc_buscar_n_lugares()
1470 \labelwidthstring 00.00.0000
1476 Luego de una operación de baja o alta de un registro en el archivo de datos
1481 ), incrementará o decrementará respectivamente el espacio libre en el archivo
1482 de datos, y esto deberá ser registrado, agregando un nuevo registro en
1483 el archivo de espacios libres (
1487 ) o bien modificándolo.
1491 En el caso de organizaciones con bloques, se actualizará el valor del espacio
1496 en el bloque (ya sea incrementándolo o decrementándolo) o bien se insertará
1497 un nuevo registro en caso de que se esté creando un nuevo bloque en el
1498 archivo de datos (en este caso no será debido a un alta o baja de registro
1499 como se mencionó al principio).
1503 Para el caso de organización sin bloques, en el caso de baja de un registro
1508 ) se insertará un nuevo registro en el
1512 dando cuenta de la aparición de un nuevo gap en el archivo de datos (
1516 ), y en caso de estar este lindante con otro gap, se realizará el merge
1518 (esto esta explicado más en profundidad en los casos particulares de organizaci
1519 ón física, registros variables sin bloques).
1520 Para el caso de una alta en el archivo de datos (
1524 ), el valor del gap donde se haya insertado se actualizará.
1529 emufs_fsc_agregar(), emufs_fsc_agregar_gap(), emufs_fsc_actualizar(), emufs_fsc_
1532 \labelwidthstring 00.00.0000
1538 : Únicamente para el caso de una organización que presente gaps en el archivo,
1539 se podrá dar a lugar la eliminación de un registro del archivo de espacios
1545 Esta situación tendrá efecto cuando se inserte un registro que entre perfecto
1546 en un gap disponible, y por ende el gap desaparecerá.
1550 emufs_fsc_borrar_gap()
1554 \begin_inset LatexCommand \label{sec:did}
1558 Archivo de id's recuperables
1561 El archivo de Id's liberado (
1565 ) llevará cuenta de aquellos Id's de registros (
1569 ) que ya no se encuentran siendo utilizados y fueron liberados por registros
1570 eliminados previamente.
1571 A través del mismo, se podrá realizar la reutilización de Id's ante la
1572 alta de nuevos registros.
1575 A nivel físico, este archivo poseerá una secuencia de datos del tipo EMUFS_REG_I
1576 D, y el comportamiento del sistema de recuperación de Id's será el de una
1578 Es decir, ante el requerimiento de un
1582 libre por una función del sistema como por ejemplo la alta de un nuevo
1583 registro, el API del archivo (
1587 ), obtendrá el último dato del mismo (el
1591 que fue liberado mas recientemente), y truncará el archivo eliminando el
1596 recuperado de la tabla.
1597 (LIFO, Last in First Out).
1603 Este archivo tiene registros de un solo campo,
1607 el cual simboliza al id que fue liberado en un proceso de baja de registros.
1610 Funciones principales
1613 Las declaraciones e implementación se pueden encontrar en
1627 \labelwidthstring 00.00.0000
1633 Ante la eliminación de un registro del archivo de datos (
1637 ) se procederá al agregado del correspondiente
1641 que fue liberado por dicha operación, al archivo
1655 \labelwidthstring 00.00.0000
1661 Cuando el sistema desee grabar un nuevo registro en el archivo de datos,
1666 disponible para el mismo.
1667 El sistema de administración de Id's libres, obtendrá el último
1671 que se guardó en el archivo (o se eliminó del archivo de datos), y truncará
1672 el archivo eliminándolo.
1680 emufs_did_get_last()
1684 \begin_inset LatexCommand \label{cha:tipo1}
1688 Archivo con bloques parametrizados y registros de longitud variable
1691 Este tipo de archivo tiene varias complicaciones, al tratarse de un punto
1693 \begin_inset LatexCommand \ref{cha:tipo2}
1698 \begin_inset LatexCommand \ref{cha:tipo3}
1702 (cuenta tanto con bloques como con registros variables), hereda los inconvenien
1703 tes (y ventajas) de ambos, más los propios.
1704 Al implementar este tipo de archivo se puso énfasis en la eficiencia mientras
1705 esta no comprometa la mantenibilidad del código, es por esto que en algunas
1706 circunstancias no se hace un uso óptimo del espacio.
1709 La implementación de este tipo de archivo puede ser encontrada en
1713 mientras que su interfaz pública está disponible en
1723 El archivo está compuesto por la
1728 \begin_inset LatexCommand \pageref{sec:cabecera_gral}
1733 El valor que toma en este tipo de archivo es 0 (o el valor simbólico
1742 Luego le sigue una cabecera propia del archivo (un
1746 , 4 bytes) que almacena el tamaño del bloque que usa el archivo.
1747 De esta manera, al abrir un archivo de este tipo no se necesita tener ninguna
1748 información sobre él.
1749 A esta cabecera le siguen cero o más bloques del tamaño fijo especificado
1750 en la cabecera antes mencionada.
1756 +-----------+-----------+------------------------//-+
1759 | tipo | tam_bloque| Cero o más bloques ...
1767 +-----------+-----------+------------------------//-+
1770 /- 4 bytes -/- 4 bytes -/
1773 Organización física de un bloque
1776 Cada bloque no guarda información en sí, sólo se comporta como un contenedor
1778 Esto no significa que un bloque no tenga utilidad, el bloque es utilizado
1779 para proveer un acceso semi-aleatorio a los registros.
1780 Para esto se utiliza el archivo de índice (ver página
1781 \begin_inset LatexCommand \ref{sec:idx}
1785 ), que almacena pares [identificador de registro, número de bloque].
1786 Para que sea suficiente este único índice para hallar un registro (siendo
1787 que puede haber más de un registro por bloque), es necesario
1789 alinear los registros a izquierda
1792 Esto significa que hay que asegurar que siempre los registros en un bloque
1793 se presenten de forma consecutiva, jamás permitiendo que haya un espacio
1794 libre entre registros (en un mismo bloque).
1797 Podemos ver un ejemplo de esto en forma gráfica:
1800 bloque N-1 | bloque N | bloque N+1
1803 /----------+------------+------------+---------------+-----------/
1808 | registro 1 | registro 2 | espacio libre |
1813 /----------+------------+------------+---------------+-----------/
1816 /------------- tamaño del bloque ---------/
1819 De esta forma, una vez obtenido el número de bloque, se pueda recorrer secuencia
1820 lmente hasta encontrar el registro deseado.
1821 A fin de llevar el conteo de espacio libre se utiliza el archivo de control
1822 de espacio libre (ver página
1823 \begin_inset LatexCommand \ref{sec:fsc}
1827 ), de forma tal que no sea necesario recorrer secuencialmente en busca de
1828 espacio libre al hacer una inserción.
1831 Puede darse un caso excepcional en el que un registro sea más grande que
1832 un bloque, en este caso el registro se almacenará en N bloques consecutivos
1833 (siendo N la cantidad de bloques que necesita el registro), ocupando completos
1834 los todos los bloques a excepción del último, en el que posteriormente
1835 se pueden agregar más registros.
1836 \layout Subsubsection
1839 \begin_inset LatexCommand \label{sub:tipo1_reg}
1843 Organización física de un registro.
1846 El registro es el que representa al dato realmente que se quiere almacenar.
1847 Para representar ese dato se necesita una determinada información de control,
1848 tanto para poder identificar el registro en un bloque (en búsquedas secuenciale
1849 s dentro del bloque) como para saber su longitud (dado que este tipo de
1850 archivo utiliza registros de tamaño variable).
1853 Siguiendo la metodología general de E
1854 \begin_inset Formula $\mu$
1857 FS, se optó por incluir esta información de control como una cabecera al
1858 comienzo del registro, siguiendo a esta los datos en sí.
1859 La cabecera está compuesta por un identificador (
1863 ) de registro (EMUFS_REG_ID, 4 bytes) seguido por el tamaño (
1867 ) del registros (EMUFS_REG_SIZE, 4 bytes).
1868 Podemos ver gráficamente como se se compone un registro:
1874 +-----------+-----------+------------------+
1877 | id | tamaño | datos ...
1881 +-----------+-----------+------------------+
1884 /- 4 bytes -/- 4 bytes -/- [tamaño] bytes -/
1885 \layout Subsubsection
1888 \begin_inset LatexCommand \label{sub:tipo1_reg_multi}
1892 Organización física de un registro más grande que un bloque (registro
1899 Puede darse el caso excepcional en que un registro sea de mayor longitud
1901 Al ser una situación excepcional, no siempre se resuelve de la forma más
1902 eficiente ni se minimiza el espacio ocupado por datos de control (como
1903 se dijo anteriormente, se prefirió conservar la simpleza del código, adoptando
1904 algoritmos generales aunque no sea de la forma más eficiente o maximizando
1905 el uso del espacio para no perjudicar la mantenibilidad).
1908 Para manejar un registro
1912 se optó por limitarlo a la siguiente estructura (suponiendo que el registro
1913 ocupa N bloques, con N > 1 y que un
1917 es una porción del registro que entra en un bloque):
1924 se almacenan en bloques completos consecutivos.
1927 El último fragmento se almacena al comienzo del bloque inmediatamente posterior
1931 Cada fragmento posee las cabeceras mencionadas en la sección
1932 \begin_inset LatexCommand \ref{sub:tipo1_reg}
1936 , cuyo contenido es el siguiente:
1944 se almacena el identificador único obtenido al hacer el alta.
1951 se almacena el tamaño del
1955 actual más los tamaños de los
1959 posteriores, quedando en el primer
1963 el tamaño completo del registro y en el último sólo el tamaño del
1971 Como puede observarse, la información de control en los
1975 intermedios puede ser redundante, pero se conserva para poder realizar
1976 algoritmos genéricos (que se basan en que al principio de un bloque, si
1977 no está vacío, hay una cabecera de un registro) y para facilitar chequeos
1978 de integridad del archivo.
1981 A continuación se presenta un ejemplo gráfico de un registro multibloque
1982 de 10 bytes (de contenido
1983 \begin_inset Quotes eld
1987 \begin_inset Quotes erd
1990 ) almacenado en un archivo con bloques de 12 bytes (4 para datos):
1993 | bloque 0 | bloque 1 | bloque 2
1996 +-------------------+-------------------+-------------------+-//-+
1999 | registro 0 - 1/3 | registro 0 - 2/3 | registro 0 - 3/3..|
2006 |+----+-----+------+|+----+-----+------+|+----+-----+----+..| // |
2009 || id | tam | datos||| id | tam | datos||| id | tam |dato|..|
2016 ||----+-----+------+||----+-----+------+||----+-----+----+..| // |
2019 || 0 | 10 | 1234 ||| 0 | 6 | 5678 ||| 0 | 2 | 90 |..|
2026 |+----+-----+------+|+----+-----+------+|+----+-----+----+..| // |
2029 +-------------------+-------------------+-------------------+-
2039 2 bytes libres al final del bloque 2
2042 Este es un ejemplo figurativo, ya que se puso como límite mínimo de tamaño
2043 de bloque 16 bytes (para que haya al menos la misma cantidad de espacio
2044 para datos que para información de control).
2045 Este límite mínimo ya roza lo absurdo (es muy ineficiente por la gran cantidad
2046 de accesos a disco que necesita).
2047 El límite físico es de 9 bytes (8 para información de control, 1 para datos).
2050 Funciones principales
2053 Las funciones principales son las necesarias para completar la estructura
2055 \begin_inset LatexCommand \pageref{sub:EMUFS}
2062 Lectura de registros
2065 Para leer un registro se hace uso del archivo de índice (ver página
2066 \begin_inset LatexCommand \pageref{sec:idx}
2070 ), obteniéndose el número de bloque en donde está almacenado el registro
2072 Una vez obtenido, se carga en memoria el bloque entero y se busca secuencialmen
2073 te en él (leyendo la cabecera de cada registro y salteando los datos) hasta
2074 encontrar el registro pedido.
2075 Una vez encontrado se lo copia y devuelve.
2078 Si se tratara de un registro
2083 \begin_inset LatexCommand \ref{sub:tipo1_reg_multi}
2087 ), se procede forma similar, sólo que se cargan en memoria uno a uno los
2088 bloques que componen el registro y se van copiando (y uniendo) los
2097 emufs_tipo1_leer_registro()
2103 Para realizar el alta de un registro, lo primero que se obtiene es un identifica
2104 dor, buscando primero en el archivo de identificadores recuperables (pág.
2106 \begin_inset LatexCommand \ref{sec:did}
2110 ) y de no haber ninguno, buscando el mayor identificador presente en el
2111 archivo de índice (pág.
2113 \begin_inset LatexCommand \ref{sec:idx}
2118 El paso siguiente es buscar un bloque con espacio libre suficiente como
2119 para almacenar el registro (y su cabecera) en el archivo de control de
2122 \begin_inset LatexCommand \ref{sec:fsc}
2126 ) y cargarlo completo en memoria.
2127 De no encontrarse, se crea un bloque nuevo al final de archivo.
2128 En el bloque cargado en memoria, se agrega el registro nuevo (con su cabecera)
2129 al comienzo del espacio libre (calculado a partir del tamaño del bloque
2130 y el espacio libre en bloque) y se lo graba en disco.
2131 Finalmente se agrega (o actualiza) el identificador al archivo índice y
2132 el espacio libre en el bloque.
2135 Si el registro ocupara más de un bloque (ver sección
2136 \begin_inset LatexCommand \ref{sub:tipo1_reg_multi}
2140 ), se buscan N bloques consecutivos (todos los que necesite el registro)
2141 absolutamente libres
2147 Incluso el último bloque debe estar absolutamente libre para cumplir con
2148 las condiciones presentadas en la sección
2149 \begin_inset LatexCommand \ref{sub:tipo1_reg_multi}
2156 y graba bloque a bloque cada
2160 del registro (con sus cabeceras intermedias), al último
2164 se lo trata de forma análoga a un registro
2169 Por cada bloque utilizado se actualiza el archivo de control de espacio
2175 emufs_tipo1_agregar_registro()
2181 Al eliminar un registro lo primero que se hace es actualizar los archivos
2182 de índice y de identificadores recuperables, poniendo como número de bloque
2187 y agregando el identificador del registro a borrar respectivamente.
2188 También se actualiza el archivo de control de espacio libre por cada bloque
2189 (en caso de ser más de uno, en registros
2193 , se actualizan todos los bloques) y se carga el bloque en memoria para
2196 alinear los datos a izquierda
2198 (en caso de ser un registro
2202 , esto se realiza sólo para el último bloque).
2203 Para alinear los datos, se recorre secuencialmente en bloque (leyendo la
2204 cabecera de cada registro y salteando los datos) hasta encontrar el registro
2206 Encontrado el registro, se copian todos los bytes que se encuentran entre
2207 el fin del registro a borrar y el fin del bloque, en el comienzo del bloque
2213 emufs_tipo1_borrar_registro()
2216 Modificación de registros
2219 Se optó por un algoritmo simple y general, que usa las funciones de alto
2220 nivel mencionadas hasta ahora.
2221 Simplemente borra el registro y vuelve a crearlo.
2222 Al recuperar el último identificador de registro borrado, nos aseguramos
2223 de que se mantenga el identificador del registro.
2228 emufs_tipo1_modificar_registro()
2231 Obtención de estadísticas
2234 Es una función bastante simple, con una única complicación que mencionaremos
2238 Para obtener las máximas desviaciones, cantidad total de espacio libre,
2239 cantidad de registros y tamaño de los archivos auxiliares se utilizan las
2240 funciones apropiadas de los archivos auxiliares (ver secciones
2241 \begin_inset LatexCommand \ref{sec:idx}
2246 \begin_inset LatexCommand \ref{sec:fsc}
2251 \begin_inset LatexCommand \ref{sec:did}
2258 Para obtener la cantidad de bloques se hace el siguiente calculo:
2261 cant_bloques = (tamaño_archivo_datos - tamaño_cabecera_archivo_datos)
2267 Hasta aquí no hay mayores inconvenientes.
2268 El problema se presenta para calcular el tamaño de la información de control
2269 utilizada por el archivo de datos; se utiliza el siguiente cálculo:
2272 tam_info_control_datos = tamaño_cabecera_archivo_datos
2275 + cant_registros * tamaño_cabecera_registro;
2278 Aunque a simple vista esto parece acertado, no contempla el caso de los
2284 \begin_inset LatexCommand \pageref{sub:tipo1_reg_multi}
2288 ), estos registros almacenan
2290 tamaño_cabecera_registro * N
2296 es la cantidad de bloques que ocupan.
2297 Salvar este caso sería muy costoso, porque habría que recorrer el archivo
2298 registro a registro,
2306 e ir contando todas las cabeceras de registro que aparecen (similar a lo
2307 que se hace en la compactación, ver sección
2308 \begin_inset LatexCommand \ref{sub:tipo1_compact}
2313 Al tratarse este de un caso excepcional, se optó por mantener la función
2314 simple ya que funciona bien en la mayoría de los casos.
2319 emufs_tipo1_leer_estadisticas()
2323 \begin_inset LatexCommand \label{sub:tipo1_compact}
2327 Compactación del archivo de datos
2330 Esta función es una de las más simples, porque se limita a un algoritmo
2331 muy simple que utiliza las funciones de
2335 antes nombradas para realizar su tarea.
2336 Básicamente recorre el archivo de índices de registros, de comienzo a fin,
2337 leyendo el registro, borrándolo y volviéndolo a insertar.
2338 Si había espacio libre en un bloque anterior al que estaba, será insertado
2339 en él, si no volverá a grabarse en el lugar en que estaba.
2340 De esta forma se aprovechan todos los espacios libres intermedios, concluyendo
2341 con un archivo igual o más pequeño que el original.
2344 Esta implementación no es la más eficiente, pero siendo que esta es una
2345 operación costosa y excepcional por naturaleza, se optó por mantener el
2346 algoritmo simple a costo de un poco de eficiencia.
2351 emufs_tipo1_compactar()
2354 Detalles de implementación (funciones internas, ver si lo ponemos o no)
2358 \begin_inset LatexCommand \label{cha:tipo2}
2362 Archivo sin bloques y registros de longitud variable
2365 Este tipo de archivo nos traerá a la mesa la particularidad de grabar registros
2366 de longitud variable sin realizar su agrupación en bloques, y como veremos
2367 en la siguiente sección, también permitirá la administración de gaps que
2368 queden en el archivo luego de operaciones de baja de registros.
2374 Este tipo de archivo realizará el almacenamiento de registros de longitud
2375 variable en disco, su borrado y modificación sin la utilización de bloques
2377 Su implementación se encuentra en los archivos fuente (
2388 Los archivos del tipo 2, presentarán al comienzo del mismo un header compuesto
2389 simplemente por un dato del tipo EMUFS_Tipo (int) el cual indicará el tipo
2390 de archivo en cuestión.
2393 Para poder entender mejor la organización física de este tipo de archivo,
2394 tomemos el caso hipotético en el que se encuentran grabados
2398 (comenzando desde registro 0) de
2407 Supongamos también que entre el registro 0 y 1 se encontraba un
2409 registro de 10 bytes
2424 Si miramos al archivo de datos (.dat) en el disco nos encontraremos con
2426 \begin_inset Float figure
2433 Organización física de los registros en disco
2437 \begin_inset Graphics
2438 filename graphics/Example1.png
2449 Como se puede observar, a nivel físico cada registro grabado esta compuesto
2450 por un Header cuyo tamaño total es de 8 bytes (
2458 ), y posteriormente el registro (bloque de datos) en sí.
2459 Luego se encuentra el espacio libre de 18 bytes dejado por el registro
2460 de 10 bytes eliminado (10 bytes de datos + header de 8 bytes) y finalmente
2461 el segundo registro mencionado.
2464 Comportamiento Particular de los Archivos Auxiliares
2467 Como fue explicado al inicio de la documentación, la implementación de cualquier
2468 a de las tres organizaciones físicas de archivos presenta la necesidad de
2469 poseer tres archivos auxiliares que actuarán como índice de direcciones
2474 ), administrador de espacio libre (
2478 ) y administrador de Id's liberados (
2485 No obstante, cada tipo de organización presentara sus particularidades respecto
2486 de estos tres archivos, las cuales describiremos a continuación en caso
2488 \layout Subsubsection
2490 Archivo índice o de posiciones relativas (.idx)
2497 ), permite la localización de los registros en el .DAT de forma directa,
2498 mediante la obtención de su offset o posición relativa respecto del inicio
2503 en donde se encuentra un registro dado, indicado por su ID.
2506 Así pues, si tomamos el ejemplo descripto al inicio de este capítulo, tendremos
2507 las siguientes entradas en el archivo índice
2512 \begin_inset Float table
2519 Organización física del archivo de índice o posiciones relativas.
2523 \begin_inset Tabular
2524 <lyxtabular version="3" rows="3" columns="3">
2526 <column alignment="center" valignment="top" leftline="true" width="0">
2527 <column alignment="center" valignment="top" leftline="true" width="0">
2528 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
2529 <row topline="true" bottomline="true">
2530 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2540 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2550 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
2558 <row topline="true">
2559 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2569 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2579 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
2584 El primer registro (reg0) comienza en el byte 4
2588 <row topline="true" bottomline="true">
2589 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2597 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2607 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
2612 El segundo registro (reg1) comienza en el byte 60
2632 LOCATION indica donde comienza el header del registro buscado, y por consiguien
2633 te luego del header tendremos el registro en sí (los datos).
2634 \layout Subsubsection
2636 Archivo de Gaps / Espacios Libres (.fsc)
2639 El archivo de espacios libres o gaps (.fsc), tiene como función la administración
2640 del espacio libre o gaps (agujeros), generados por previas eliminaciones
2641 de registros en el archivo de datos.
2642 El mismo, nos indicará donde hay lugar para insertar un nuevo registro
2643 (se podrán insertar en algún gap acorde, o bien al final del archivo).
2644 Este archivo será utilizado también para el proceso de compactación de
2645 un archivo, explicado luego.
2648 Así pues, si tomamos el ejemplo descripto al inicio del documento, tendremos
2649 las siguientes entradas en el archivo índice
2654 \begin_inset Float table
2661 Organización física del archivo de
2665 o control de espacio libre.
2669 \begin_inset Tabular
2670 <lyxtabular version="3" rows="2" columns="3">
2672 <column alignment="center" valignment="top" leftline="true" width="0">
2673 <column alignment="center" valignment="top" leftline="true" width="0">
2674 <column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
2675 <row topline="true" bottomline="true">
2676 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2686 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2696 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
2704 <row topline="true" bottomline="true">
2705 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2715 <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
2725 <cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
2730 18 bytes libres a partir del byte 42 del .dat
2750 Por requerimiento del algoritmo de compactación, los gaps se graban en
2751 forma ordenada en el (.fsc).
2752 (El orden se corresponde con lo que hay en el
2757 \layout Subsubsection*
2762 Si bien la utilización concreta de los GAPS será explicada posteriormente
2763 en la ALTA y BAJA de registros, debemos remarcar la funcionalidad de MERGING
2764 que posee nuestro sistema FSC.
2767 Ante la eliminación de un registro del archivo de datos, se generara por
2768 consiguiente un gap o espacio libre en alguna posición del archivo.
2769 Ese gap deberá ser registrado en el archivo de gaps (.fsc).
2770 Ahora bien, nuestro sistema de gaps, contemplará como es debido, la posibilidad
2771 de que se haya eliminado un registro que posee un GAP por delante, un GAP
2772 por detrás, o bien un GAP por delante y por detrás del mismo.
2775 Nuestro sistema actuará en consecuencia, realizando un merge de los espacios
2776 libres, y unificándolos en una ÚNICA entrada en el archivo .fsc, que contendrá
2777 como dato de freespace, la suma correspondiente de los espacios libres
2779 \layout Subsubsection
2781 Archivo de ID's liberados (.did)
2784 El archivo de ID's liberados no presenta ningún aspecto particular en este
2785 tipo de organización.
2786 Remitirse al capítulo correspondiente a los archivos auxiliares para consultar
2787 su estructura y funcionamiento.
2790 Funciones Principales
2805 se encuentran las cabeceras y la implementación de las funciones principales
2806 respectivamente, las cuales dan funcionalidad a esta organización.
2810 A continuación se comentará el funcionamiento algunas de las mas importantes.
2813 Lectura de registros
2816 Como se vio al comienzo, los registros en este tipo de archivo no se encuentran
2817 agrupados en bloques de ninguna índole y están dispersos a lo largo del
2818 archivo, con la particularidad de que pueden existir gaps o espacio libre,
2819 entre dos registros dados.
2822 Por ende la lectura de registros en este tipo de organización es muy simple
2823 y dada la inexistencia de bloques, el procedimiento será el siguiente:
2826 Se determina el offset en bytes, donde comienza el registro deseado, a través
2827 de su ID, buscando la misma en el archivo índice (
2834 Ya determinada la posición física del registro dentro del archivo de datos
2839 ), nos posicionamos en la misma, y leemos el header del registro (
2848 Contando así con el tamaño del registro, procedemos a leer el mismo (los
2849 datos), dando por finalizada la lectura.
2854 emufs_tipo2_leer_registro()
2860 En el proceso de alta de registros entrarán en juego dos archivos descriptos
2863 sección de archivos auxiliares
2865 , siendo estos el archivo índice (
2869 ), y el archivo de gaps / espacios libres (
2876 Así pues, a la hora de realizar una inserción de un registro en el archivo
2877 de datos, el procedimiento será el siguiente:
2880 Calculamos el espacio que necesitaremos para el registro: sizeof(
2888 ) + sizeof(registro).
2891 Determinamos donde debemos insertar el registro, ya sea un gap donde entre,
2892 o bien al final del archivo.
2895 Insertamos el registro e información de control (
2903 ), en la posición indicada en el paso 2.
2906 En caso de haber utilizado un GAP, actualizamos el espacio libre restante
2907 en el mismo y en caso de que se haya utilizado al totalidad del GAP, se
2908 lo elimina del archivo (
2915 Actualizamos la entrada correspondiente al registro ingresado (determinada
2916 por su RegID), en el archivo índice (
2920 ), indicando su offset donde podrá ser accedido luego.
2925 emufs_tipo2_agregar_registro()
2931 En el proceso de baja de registros entrarán en juego los tres archivos descripto
2934 sección de archivos auxiliares
2936 , siendo estos el archivo índice (
2940 ), el archivo de gaps / espacios libres (
2944 ) y el archivo de ID's liberados (
2951 Dado que en la implementación de este tipo de organización física contamos
2952 con los gaps o espacios libres entre registros, no se eliminará físicamente
2953 el registro del archivo de datos (
2957 ), pues entonces carecería de sentido el archivo anteriormente mencionado
2963 En cambio, se agrega el gap dejado por la eliminación a dicho archivo,
2964 y se marca físicamente en el archivo de datos la eliminación mediante un
2965 fill de los bytes correspondientes con un caracter nulo.
2966 (hexa 00 y con el propósito de probar fehacientemente que el sistema funciona).
2969 El proceso de baja o eliminación de un registro constará luego de los siguientes
2973 Se obtiene el offset o posición relativa en donde se encuentra grabado el
2974 registro dentro del archivo de datos.
2977 Se obtiene el tamaño del registro y se realiza un dummyfill del sector del
2978 archivo correspondiente al registro que se está dando de baja.
2979 (Se rellena la zona correspondiente a su header+data).
2982 Se agrega el GAP generado al archivo de gaps o espacios libres, y en caso
2983 de haberse generado un GAP lindante con otro GAP, se realizará un merge
2984 de los mismos y se los registrará bajo una única entrada en el archivo
2985 de espacios libres (.fsc).
2988 Se agrega el ID que fue liberado, al archivo de ID's liberados (
2992 ), al final del mismo (
2999 Se marca en el archivo índice (
3003 ) la eliminación, mediante el valor ¨-1¨ en el registro correspondiente
3004 al registro recién eliminado (se le cambia el valor al n-esimo registro,
3005 donde N = IDReg del reg eliminado).
3010 emufs_tipo2_borrar_registro()
3013 Modificación de registros
3016 Dada la naturaleza del archivo de ID's liberados, y el manejo de espacio
3017 libre del que consta esta organización de archivo, el proceso de modificación
3018 de un registro se limita a los siguientes pasos:
3021 Se realiza la lectura del registro, mediante el respectivo procedimiento
3022 ya desarrollado anteriormente.
3025 Una vez que se cuenta con los nuevos datos modificados, se procede a dar
3026 de baja el registro que ha sido modificado, e inmediatamente después se
3027 realiza una inserción con los nuevos datos.
3036 Como fue indicado, dada la naturaleza de PILA del subsistema de administración
3037 de ID liberados, es asegurado que la nueva inserción del registro modificado
3038 se realizará con el mismo RegID.
3043 emufs_tipo2_modificar_registro()
3046 Obtención de estadísticas
3049 Se puede tener acceso a las estadísticas generales del archivo, por ejemplo,
3050 cantidad de bloques, cantidad de registros, espacio libre total, espacio
3051 libre promedio, espacio libre máximo y mínimo, etc.
3054 Esta información es el resultado de ciertos cálculos realizados tanto en
3055 el archivo de datos como en los archivos índice.
3058 Completa una estructura del tipo EMUFS_Estadisticas con las estadísticas
3059 del archivo de datos, espacio libre total, cantidad de registros, cantidad
3060 de bloques, tamaño del archivo en bytes, relaciones entre tamaños y espacios
3066 emufs_tipo2_leer_estadisticas()
3069 Compactación del archivo de datos
3072 Así como los otros dos tipos de datos, el que nos compete también cuenta
3073 con la posibilidad de realizar la compactación de datos cuando el usuario
3074 lo desee, justificando todos los registros a izquierda, eliminando así
3075 los gaps existentes y decrementando el tamaño del archivo en disco (truncándolo
3079 Para poder comprender como hemos implementado el proceso de re-compactación
3080 en nuestro tipo de archivo 2, nos ayudaremos de esquemas a través de los
3081 cuales iremos describiendo el proceso.
3082 Notemos antes, que el proceso de compactación esta directamente ligado
3083 con el archivo de gaps o espacios libres (
3090 Comencemos con el siguiente cuadro situacional:
3091 \begin_inset Float figure
3098 Archivo con gaps entre registros previo a compactación
3102 \begin_inset Graphics
3103 filename graphics/Compact1.png
3115 Partiendo de esta base, el algoritmo de compactación tomará en su inicio
3116 al primer gap existente dentro del archivo de datos, en este caso llamado
3122 Luego, establecerá que el
3126 a partir de donde se quieren mover datos, sera:
3129 StartGap0 + SizeGap0 = EndGap0 = Source
3132 Lo cual no es nada más y nada menos que lo obvio, la fuente a partir de
3133 donde se mueven los datos, sera el fin del primer gap, donde comienzan
3139 ) del movimiento, se establece inicialmente, el inicio del gap, o sea
3141 StartGap0 = Destination
3146 Luego, el algoritmo entrara en un bucle while (mientras haya bucles por
3147 levantar), el cual trabajara hasta el final de la compactación de la siguiente
3158 Se levanta el próximo gap al levantado en una instancia previa.
3159 En este ejemplo, durante el primer loop del while, se levantará
3164 Luego, se calcula cuantos bytes hay que mover hacia el Destination de la
3188 Lo cual nuevamente es lógico pues querremos mover lo que se encuentra entre
3189 el final del primer gap levantado y el inicio del siguiente).
3192 Se realiza el movimiento de los datos, utilizando las direcciones
3200 , así como la variable
3204 que nos indica cuantos bytes transferir.
3210 La transferencia se hace de a chunks de 25 bytes + un resto segun el valor
3214 Se establece como gap de referencia, al ultimo gap leído (En este caso se
3227 ) y termina el código de repetición del bucle, dando lugar a la carga del
3228 siguiente gap en el inicio del mismo.
3236 Luego del primer bucle, el archivo se vera de la siguiente forma:
3237 \begin_inset Float figure
3244 Archivo con gaps en disco luego del primer bucle de compactación
3248 \begin_inset Graphics
3249 filename graphics/Compact2.png
3260 Notemos que al final de la porción de datos de los bytes movidos (donde
3265 ), hay basura que será pisada por el próximo movimiento.
3268 En el próximo loop, el bucle levantará un nuevo gap, y utilizando el gap
3269 anterior (En esta caso el Gap anterior será
3273 ) como referencia, realizará los mismos cálculos, desde donde transferir
3274 y cuantos bytes mover.
3275 (El destino es solo establecido inicialmente por código, y para el resto
3276 del algoritmo es el lugar donde quedo el puntero destination luego de la
3280 Una vez que se salga del bucle while, se realizará un último movimiento
3281 preprogramado, donde la fuente (
3285 ) será el final del ultimo gap, y la cantidad de bytes a mover será lo que
3286 se encuentre luego del mismo hasta el fin de archivo.
3289 Source = StartLastGap + SizeLastGap = EndLastGap
3292 Mustmove_bytes = Datsize - Source
3295 Damos por terminada así, la explicación del algoritmo de compresión el cual
3296 para el caso del tipo 2, es realmente bastante sencillo.
3301 emufs_tipo2_compactar()
3304 Consideraciones y Políticas de Diseño
3307 Se han tomado ciertas consideraciones para algunos casos particulares que
3308 se pueden presentar durante el uso/ejecución de la aplicación, así como
3309 también políticas respecto del diseño e implementación del sistema:
3312 En la organización física tipo 2 para los registros que se graban en disco
3313 hemos decidido utilizar como encabezado de cada uno de ellos, los datos
3314 [ID_REG][REG_SIZE], los cuales fueron detallados previamente.
3315 Si bien se podría haber descartado el grabado del ID del registro en el
3316 archivo de datos y puede parecer redundante, dado que poseemos el archivo
3317 índice con el offset directo, el mismo se lo graba por distintos motivos:
3321 A) En caso de la corrupción del archivo índice (.idx), podremos gracias a
3322 que poseemos en el archivo de datos, el ID de cada registro, recrear dicho
3323 índice, ayudándonos del archivo de espacios libres (
3327 ), para poder saltear los espacios libres y e ir recorriendo secuencialmente
3328 los registros, reconstruyendo así el índice en cuestión.
3329 (esta función de reconstrucción no pudo ser implementada para esta entrega,
3330 pero es una posibilidad real).
3334 B) Luego de un proceso de re-compactación, los espacios libres que pudieron
3335 haber existido en el archivo de datos (
3339 ), son eliminados y los registros han cambiado de posición.
3340 Por ello, recorriendo secuencialmente por única vez el archivo de datos,
3341 se procede a la actualización / reconstrucción del índice de direcciones
3349 Si se desea insertar un registro y no se puede hallar un gap o espacio libre
3350 donde quepa, se los inserta al final del archivo.
3353 Ante una operación de baja de un registro, el mismo no es físicamente borrado
3354 del archivo de datos (
3358 ), simplemente los bytes que ocupa son llenados con hexa (00).
3359 Paralelamente, se procede a actualiza el archivo índice, insertando como
3360 valor de OFFSET para el registro eliminado, el valor ¨-1¨, indicando así
3361 la inexistencia del registro para el futuro, y por otro lado se genera
3362 la entrada de espacio libre en el archivo de gaps (
3369 La reutilización de ID's liberados por previas operaciones de baja de registros,
3370 se ve implementada por el archivo de ID liberados (.did), y su comportamiento
3371 es el de una pila por lo que el último ID liberado, sera el próximo a ser
3375 Como fue explicado en la implementación del archivo índice, existe una correspon
3376 dencia 1 a 1 entre los registros allí presentes (en el .idx) y los ID's de
3377 los registros, por lo cual el registro N-ésimo del archivo índice, será
3378 el correspondiente al registro de datos cuyo ID es igual a N.
3381 El proceso de compactación de archivos, realiza los movimientos de información
3382 requeridos para dicho propósito de a chunks de 25 bytes por vez.
3383 Este valor es fijo, pero se lo podría hacer parametrizable mediante la
3384 GUI en próximas entregas.
3388 \begin_inset LatexCommand \label{cha:tipo3}
3392 Archivo con bloques parametrizados y registros de longitud constante
3395 Las distintas organizaciones de archivos buscan aprovechar al máximo el
3396 espacio del archivo.
3399 En este caso veremos que sucede luego de agregar y borrar una gran cantidad
3400 de registros del archivo, lo que provoca como consecuencia directa la fragmenta
3401 ción del archivo, es decir, quedan huecos entre un registro y otro, lo que
3402 produce un desperdicio de espacio.
3405 La implementación de este tipo de archivo puede ser encontrada en
3409 mientras que su interfaz pública está disponible en
3419 Esta organización guarda los registros pertenecientes al archivo en bloques
3420 de tamaño parametrizado, de modo que intentará guardar la mayor cantidad
3421 de registros que quepan en un bloque.
3425 Así como los graba, también tendrá la posibilidad de leer registros y borrarlos
3429 El archivo estará compuesto por una cabecera que da información sobre el
3430 tipo (2, o el valor T3 del tipo
3434 en este caso) de organización, el tamaño de los bloques y el tamaño de
3441 +-----------+-----------+-----------+------------------------//-+
3444 | tipo | tam_bloque| tam_reg | Cero o más bloques ...
3452 +-----------+-----------+-----------+------------------------//-+
3455 /- 4 bytes -/- 4 bytes -/- 4 bytes -/
3458 Organización Física de un Bloque
3461 Cada bloque será capaz de contener la cantidad de registros enteros que
3463 De esta manera un registro que no entre completamente en el bloque deberá
3464 almacenarse en un bloque diferente.
3467 Los bloques no contienen ninguna información adicional, solo se conoce su
3468 tamaño y se usa para delimitar
3469 \begin_inset Quotes eld
3473 \begin_inset Quotes erd
3476 zonas en el archivo y obtener de esta manera acceso semi-aleatorio a los
3480 bloque N-1 | bloque N | bloque N+1
3483 /----------+------------+------------+---------------+-----------/
3488 | registro 1 | registro 2 | espacio libre |
3493 /----------+------------+------------+---------------+-----------/
3496 /------------- tamaño del bloque ---------/
3499 Organización Física de Registros
3502 Cada registro se almacena en un bloque, y contiene una cabecera que indica
3507 por este motivo al realizar la búsqueda de espacio en un bloque se lo hará
3508 preguntando por el tamaño del registro más
3510 sizeof(EMUFS_REG_ID).
3516 +-----------+-------------------+
3523 +-----------+-------------------+
3526 /- 4 bytes -/- [tam_reg] bytes -/
3529 Organización Física de Registros
3534 Al ser los registros de longitud constante, se ha adoptado que un registro
3539 nunca podrá estar almacenado en algún lugar que no sea el comienzo de un
3541 De esta manera se puede calcular cuantos bloques ocupará un registro y
3542 se podrá solicitar lugar para almacenarlo con la ayuda de la función
3544 emufs_fsc_buscar_n_lugares(),
3546 que es muy importante para evitar el solapamiento de registros.
3547 Esta consideración acarrea como consecuencia directa un alto costo en términos
3548 del espacio desperdiciado.
3551 A continuación se presenta un ejemplo gráfico de un registro multibloque
3552 de 26 bytes (de contenido
3553 \begin_inset Quotes eld
3556 12345678901234567890123456
3557 \begin_inset Quotes erd
3560 ) almacenado en un archivo con bloques de bytes 14 bytes (10 para datos)
3561 y registros de 38 bytes:
3564 | bloque 0 | bloque 1 | bloque 2
3567 +-------------------+-------------------+-------------------+-//-+
3570 | registro 0 - 1/3 | registro 0 - 2/3 | registro 0 - 3/3..|
3577 |+----+------------+|+----+------------+|+----+--------+....| // |
3580 || id | datos ||| id | datos ||| id | datos |....|
3587 ||----+------------+||----+------------+||----+--------+....| // |
3590 || 0 | 1234567890 ||| 0 | 1234567890 ||| 0 | 123456 |....|
3597 |+----+------------+|+----+------------+|+----+--------+....| // |
3600 +-------------------+-------------------+-------------------+-
3610 4 bytes libres (e inutilizables) al final del bloque 2
3613 Funciones Principales
3624 se encuentran las cabeceras y la implementación de las funciones principales
3625 respectivamente, las cuales dan funcionalidad a esta organización.
3628 A continuación se comentará la descripción de algunas acciones importantes.
3631 Lectura de registros
3634 La lectura de un registro se realiza con la ayuda del archivo .
3638 el cual contiene la información de la posición del registro dentro del
3640 Una vez leída esta información, se recupera el bloque (en su totalidad)
3641 del archivo y se busca secuencialmente el registro con el
3650 emufs_tipo3_leer_registro()
3656 Graba un registro en un bloque donde haya espacio suficiente, y si no crea
3657 un nuevo bloque y lo agrega al final del archivo.
3660 Luego de grabar un registro, actualiza los archivos de índice .idx y .fsc
3661 para mantener la coherencia.
3664 Cuando nos encontramos con registros multibloque, se calcula cuantos bloques
3665 ocupará el registro de la siguiente manera:
3667 Cantidad de Bloques = 1 + Tamaño del Registro/(Tamaño del Bloque-Sizeof(EMUFS_RE
3671 Esta ecuación solo falla en el caso que el tamaño del registro y el tamaño
3672 del bloque sean iguales, en tal caso, se coloca el valor 1 en
3679 Y con esta información se realiza un ciclo
3683 que grabará tantas veces como sea necesario levantando y grabando los bloques
3689 emufs_tipo3_grabar_registro()
3695 Borra un registro del archivo de datos, para esto levanta el bloque al que
3696 pertenece el archivo y ajusta los demás registros justificándolos hacia
3700 Cabe destacar que para dar de baja un registro no hace falta borrarlo del
3701 archivo de datos, solo es necesario borrar las entradas en los archivos
3702 de índice, pero cuando se realiza el ajuste el algoritmo toma porciones
3703 del bloque del tamaño de un registro mas su encabezado - comenzando desde
3704 el siguiente al que fue borrado - y copia (sobreescribe) sobre el anterior.
3705 De esta manera, la información correspondiente al registro borrado no estará
3706 presente en el archivo de datos.
3707 Esto es una consecuencia del ajuste al borrar un registro, pudiendo no
3708 ser así, si no se realizara el mismo.
3711 En el caso de los registros multibloque, se eliminará la porción del registro
3712 contenida en el primer bloque y se actualizarán de manera conveniente los
3713 archivos índice, para restaurarlos a un valor verdadero.
3718 emufs_tipo3_borrar_registro()
3721 Obtención de estadísticas
3724 Se puede tener acceso a las estadísticas generales del archivo, por ejemplo,
3725 cantidad de bloques, cantidad de registros, espacio libre total, espacio
3726 libre promedio, espacio libre máximo y mínimo, etc.
3729 Esta información es el resultado de ciertos cálculos realizados tanto en
3730 el archivo de datos como en los archivos índice.
3733 Completa una estructura del tipo EMUFS_Estadisticas con las estadísticas
3734 del archivo de datos, espacio libre total, cantidad de registros, cantidad
3735 de bloques, tamaño del archivo en bytes, relaciones entre tamaños y espacios
3741 emufs_tipo3_leer_estadisticas()
3744 Compactación del archivo de datos
3747 Esta función intenta reorganizar el archivo de manera que el espacio libre
3748 sea lo menor posible, recordando siempre que un registro no puede ser almacenad
3749 o en mas de un bloque excepto que el tamaño del registro sea mayor que el
3753 Para realizar esto, se aprovecha la funcionalidad de
3755 emufs_tipo3_grabar_registro()
3757 ya que esta tiene la capacidad de determinar una posición mas eficiente
3758 en el archivo para un registro.
3759 Por esto lo que se hace es levantar uno por uno los registros y volverlos
3760 a grabar, de ese modo todos los
3764 que pudieron haberse formado por la eliminación de registros serán cubiertos
3768 Al estar utilizando recuperación de
3772 borrados, esto me asegura que el registro borrado-guardado conservará el
3776 Al finalizar este proceso se verifica si existen bloques vacíos para truncar
3778 Lo mismo se debe hacer con el archivo de espacios libres .
3782 el cual disminuye su tamaño también.
3787 void emufs_tipo3_compactar()
3790 Consideraciones y Políticas de Diseño
3793 Se han tomado ciertas consideraciones para algunos casos particulares que
3794 se pueden presentar durante el uso/ejecución de la aplicación.
3797 Cada registro tiene un encabezado que indica el
3804 Si el tamaño del registro es mayor que el tamaño del bloque el registro
3805 se particionará en la cantidad de bloques que sea necesario, pero siempre
3806 se guardará desde el comienzo de un bloque, esto quiere decir que nunca
3807 se podrá encontrar un comienzo de registro en algún lugar de un bloque
3808 que no sea el comienzo del mismo.
3811 Si el registro se divide en mas de un bloque, se le coloca el id como encabezado
3812 igualmente, pero en el archivo .
3816 solo se guarda el primer bloque.
3821 se actualizan todos los bloques con el espacio libre que realmente tienen.
3824 EMUFS View (interfaz gráfica)
3830 La interfaz de visualización de EMUFS permite interactuar con los distintos
3831 tipos de archivos para cada conjunto de datos almacenado (ya sean facturas,
3832 articulos, o notas de facturas).
3838 Para poder correr la interfaz gráfica necesitará previamente compilarla
3839 (así como compilar los programas auxiliares), para ello necesitará cumplir
3840 con los siguiente requisitos:
3843 Compilador gcc versión 3.3.x preferentemente.
3844 No podemos garantizar la compatibilidad con otras versiones debido a cambios
3845 drásticos que sufrieron las versiones anteriores.
3848 Parser XML libxml2 versión 2.6.x .
3849 Versiones 2.5 y anteriores son incompatibles en la API y no funcionarán.
3852 libncurses version 5 o superior (probado con 5.4).
3861 Para compilar la GUI solo debe ejecutar el comando make dentro del directorio
3863 Esto compilará primero una biblioteca estática con los manejadores de los
3864 3 tipos de archivo y luego compilará la GUI.
3870 Preparar el banco de pruebas
3873 Antes de comenzar a utilizar la GUI deberá generar los archivo XML desde
3874 donde serán leídos los datos para generar los archivos que luego se utilizará.
3875 Para ello el proceso de compilación creará 2 ejecutable : generar_fact
3876 y generar_art, que se ubicarán en la carpeta generar dentro de emufs_gui.
3879 Estos programas generan facturas y artículos respectivamente en forma aleatorio,
3880 utilizando diccionarios de datos para llenar los campos.
3881 Primero deberá ejecutar generar_art, ya que éste último crea un diccionario
3882 de artículos que luego utilizará generar_fact para los items de las facturas.
3885 Ambos programas reciben 2 parámetros : el nombre de archivo de salida y
3886 la cantidad de entradas a generar.
3892 El programa acepta varios parámetros, algunos de ellos opcionales, otros
3893 obligatorios dependiendo de las elecciones realizadas.
3896 Para obtener una completa descripción de los parámetros el programa acepta
3898 \begin_inset Quotes eld
3902 \begin_inset Quotes erd
3906 \begin_inset Quotes eld
3910 \begin_inset Quotes erd
3913 para mostrar una ayuda en línea.
3916 Si el programa es ejecutado sin parámetros tratará de recuperar los artículos
3917 y las facturas desde archivo previamente creados.
3920 Para crear un archivo de artículos a partir de un archivo XML bien formado,
3921 se debe ejecutar el programa con la opción
3922 \begin_inset Quotes eld
3926 \begin_inset Quotes erd
3930 Dicha opción espera que el siguiente parámetro sea el nombre del archivo
3931 a leer, y que éste útimo tenga extensión xml (notar que es solo minúsculas).
3932 A continuación espera encontrar el tipo de archivo que se quiere crear,
3933 pudiendo ser éste último 1, 2 ó 3.
3934 De ser el tipo de archivo con bloques, se le exigirá que ingrese como último
3935 parámetro el tamaño del mismo.
3938 Para crear el archivo de facturas es el mismo procedimiento, solo que utilizando
3940 \begin_inset Quotes eld
3944 \begin_inset Quotes erd
3948 El archivo de notas es creado por el sistema de tipo 2 por defecto y no
3949 puede ser cambiado desde la línea de comandos.
3950 Para ello puede utilizar la opción correspondiente del menú mantenimiento.
3953 Debe saber que estos parámetros no son mutuamente excluyentes, por lo que
3954 podrá utilizarlos al mismo tiempo.
3960 A continuación se da una lista detallada de las operaciones que son posibles
3961 hacerse desde esta interfaz :
3964 Alta, baja y modificación de Artículos.
3965 Para ello se abrirá una ventana donde se podrá editar comodamente los datos.
3968 Alta, baja y modificación
3974 En la modificación de una factura no se podrán cambiar ni la cantidad de
3975 items y los datos de los mismo!.
3976 La nota si podrá ser modificada.
3983 Ver fisicamente los registros de cualquiera de los archivos sin importar
3984 el tipo al que pertenezcan.
3985 Desde aquí podrá tambien eliminar, agregar o modificar el registro actual.
3989 Para aquellos archivos que hallan sido creados con un tipo con bloques,
3990 podrá verlos fisicamente, viendo el bloque actual y los anteriores/posteriores.
3993 Ver las estadísticas de cada archivo según su tipo, para realizar comparativas
3996 Cambiar el formato de cualquier tipo o parametros de archivo.
3999 Compactar los archivos.
4002 Decisiones de Diseño
4005 Durante el desarrollo se han tomado ciertas decisiones en el diseño o restriccio
4007 En este punto nos centraremos en las especificas tomadas por la interfaz
4008 de visualización, y no tomaremos en cuenta las que ponen los tipos de archivo
4012 La cantidad de items por factura es igual a 10 para archivos de registro
4013 de longitud fija y bloque parametrizado (TIPO 3).
4014 Esta decición fue tomada por poner un valor típico de items que puede haber
4015 en una factura, evaluando un caso de un comercio chico.
4016 Como el tipo de archivo permite cortar un registro y guardarlo en varios
4017 bloques consecutivos, la restricción de cantidad solo es un hecho de elección,
4018 y así pusieramos 100, 1000, 10000 no habría diferencia, ya que el tipo
4019 de archivo lo guardaría sin problemas.
4022 Si el archivo es de TIPO 3 y se agregan más de 10 items estos son truncados
4023 y descartados sin aviso al usuario.
4024 Esta fue una desición basada en el tiempo del proyecto.
4025 De tener que validar y consultar al usuario se hubiera perdido tiempo de
4026 mucho valor para completar objetivos más importantes del TP.
4029 Los campos son delimitados por el caracter nulo (en caso de los strings)
4030 y por la longitud del tipo de dato en caso de los campos numéricos.
4031 De esta forma se aprovechan las características de manejo de string en
4038 Un ejemplo de vista de registros es la que se observa a continuación :
4042 \begin_inset Graphics
4043 filename gui_ver_registros.eps
4052 Como puede verse el registro actual se ve resaltado respecto de los demás.
4053 También se puede observar que en este caso (el bloque es de 2000 bytes)
4054 no entra toda la información en pantalla, pero es posible desplazar utilizando
4058 Los datos binarios son convertidos a texto para ser mostrados, siendo la
4059 representación elegida :
4062 (XXX) : Representa un ID.
4063 En el caso de las facturas también aparece en los datos el número de índice
4064 de la nota asociada con esta representación.
4067 {XXX} : Representa el tamaño de los datos.
4068 Esto siempre y cuando el registro sea de longitud variable (TIPO1 y TIPO2).
4071 También es posible ejecutar acciones de edición sobre el registro seleccioado,
4072 así como buscar por ID de registro.
4075 Cuando se procesa la información en crudo (es decir, el area de datos) algunos
4076 bytes son modificados para evitar errores visuales.
4077 Un caso es cuando el bytes es compuesto por 8 bits de valor 0 (caracter
4081 Lo que se hace es cambiarlo por un caracter que tenga representacion visual
4082 (en este caso un *).
4083 Lo mismo suscede para los caracteres de control (
4089 r por ejemplo) y los espacion.
4090 Esta política fue tomada ya que estos caracteres modifican la salida en
4091 pantalla, y de no evitar su envío a la pantalla, producirían resultados
4092 inesperados en la visualización.
4098 A continuación se enumera los errores que sabemos que existen, que no hemos
4099 tenido tiempo de corregir, pero que no hacen al TP en sí :
4102 Si la consola o terminal cambia de tamaño la GUI no sigue el nuevo tamaño,
4103 pudiendose producir defectos visuales.
4104 Esto es debido a que se debe capturar una señal que envia el SO, pero no
4105 pudimos hacer que funciones con todas las terminales bajo X, por lo que
4106 se decidio dejarlo para cuando tengamos tiempo.
4109 Si la GUI fue compilada con -DDEBUG y no se utiliza un PIPE para redirigir
4110 la salida de error estandar, es posible que algun componente del programa
4111 emita un mensaje de debug o warning y esta cause defectos de visualización
4112 o el programa deje directamente de funcionar.
4113 Esto es un defecto de la biblioteca NCurses.
4119 Las comparaciones, pruebas, etc...