27 de diciembre de 2011

El obstáculo de las distribuciones regionales

En general, aplaudo cuando un gobernante defiende el uso de software libre en las administraciones: al fin y al cabo, todos sabemos a qué bolsillos van los ingresos de Microsoft u Oracle, y a nadie le gusta que un país tenga un déficit tecnológico horroroso. Y cuando se utiliza software libre en las clases de informática de los institutos, mi alegría se torna en éxtasis: ya he defendido aquí que el modelo actual por el que se dan clases de informática pagando licencias de Windows y Office es, sencillamente, una estafa. La educación pública se convierte así (y permítanme la diatriba) en un centro de formación de productos de empresas privadas financiado con dinero público, y del que se benefician, sobre todo, los accionistas de multinacionales extranjeras. Ya que se beneficiarán de que los alumnos sean educados para usar sus productos, como mínimo deberían regalar todas las licencias a los institutos, pero ni eso les exigen los gobernantes.

Dejando al lado este asunto, hay algo que cada vez me huele peor en el tema de las distribuciones regionales. Me refiero a esas distribuciones que tanto abundan en España. Y lo que huele mal es, precisamente, que haya tantas.

Es evidente que con semejante fragmentación, esto no avanza hacia ningún sitio. Hay gente que, por ejemplo, pretende en serio que los vendedores de ordenadores preinstalen Linex, la distribución de Extremadura, una región de poco más de 1 millón de habitantes. Si ya de por si resulta difícil que compañías como Dell lo hagan con Ubuntu para un mercado mundial, imagínense con Linex.

Otro argumento muy común a favor de estas distribuciones es que gracias al software libre se pueden contratar programadores y compañías locales, en lugar de depender de los de la multinacional de turno. Si bien esto es cierto (y es una de las mayores ventajas del software libre), es obvio que la fragmentación juega muy en contra de la estandarización. Ejemplo, pongamos que es usted un programador y crea un magnífico programa que por alguna razón la administración quiere comprar, pues si quiere extenderse a administraciones de más allá de su terruño tendrá que soportar todas distribuciones. Que puede merecer la pena económicamente, pero es un obstáculo más. Otro ejemplo: Trisquel, la distro de Galicia, tiene la particularidad de estar dirigidas por fanáticos del FSF que eliminan todo software que no cumpla las cuatro sagradas reglas de Stallman. Y olvidémonos de soporte comercial para el mercado de usuarios de escritorio.

Existe un espacio donde tal vez las distribuciones regionales tengan sentido, y es en la administración de sistemas de la administración (valga la redundancia). Los gobiernos regionales tienen sistemas informáticos propios lo suficientemente extensos y complejos como para poder beneficiarse de tener todo bajo control, sin embargo, este es un uso a nivel interno que a los ciudadanos no importa.

Más allá de este caso, ¿de verdad necesitan las escuelas de cada región una distribución educativa distinta?

Diría que hemos llegado a un punto en el que las distribuciones regionales, más que un beneficio están suponiendo un obstáculo para el progreso del software libre. En lugar de crear y mantener distribuciones onanistas, las administraciones deberían optar por cosas como debianedu, edubuntu, o directamente Ubuntu, o cosas así. No se trata de eliminar su inversión en software libre, sino de dirigirlo a proyectos más grandes, donde se pueda aunar esfuerzos con muchas otras personas, con muchas otras administraciones. Entre ayuntamientos, provincias, regiones y estados hay en Europa unas 200.000 administraciones, algo en común se podrá tener.

3 de diciembre de 2011

Trapos sucios de Unix: readdir()

Una de las cosas más curiosas de los sistemas Unix es cómo han ido cambiando su propia imagen a lo largo de los años. Hoy Unix se entiende como sinónimo de fiable, eficiente, buen diseño, profesional, etc; a pesar de que Unix era un sistema operativo muy simplista, con importantes fallos y carencias  que tuvieron que arreglarse o añadirse posteriormente, a menudo no de la mejor manera. Un buen ejemplo de ello es la historia de readdir(), una función que devuelve la lista de archivos y/o subdirectorios presentes dentro de un directorio.

Uno de los principios fundamentales de la filosofía Unix es el de "Todo es un archivo", es decir, la unificación de toda clase de I/O sobre un sistema de archivos jerárquico en el que los archivos, además de archivos, pueden representar a dispositivos de hardware. Tal fuerza dogmática tiene este principio que cuando se diseñó Unix se decidió, o se asumió de manera natural, que los directorios también eran archivos normales y corrientes. Así que las primeras versiones de Unix no tenían llamadas al sistema para algo tan común como listar un directorio.

¿Cómo averiguaba entonces un programa, como por ejemplo ls, los contenidos de un directorio? Pues tratándolos literalmente como archivos. Se abría el directorio con fopen() y se leía el contenido con fread(). El contenido de los archivos de tipo directorio era simplemente una lista consecutiva de parejas nombre/número de inodo, cada una representando un archivo y/o subdirectorio. Y el programa tenía que echar un ojo a esas estructuras e interpretarlas él mismo para saber qué había dentro del directorio, no existía ninguna llamada al sistema que lo hiciera por ti.

Por esa razón, la primera función readdir() no fue una llamada al sistema, sino una función implementada dentro de los programas que lo necesitaban. Si no lo creen, pueden verlo ustedes mismos en la función readdir() del ls.c de Unix Version 7, de 1979. Cuando los diferentes sistemas Unix fueron incorporando características que hacían de esta manera de trabajar con directorios un inconveniente, acabaron añadiendo llamadas al sistema (getdents()) que sirvieran de ayuda para implementar readdir(), la cual se acabaría incorporando a la libc.

Como prueba de esta herencia, han quedado ciertos retazos en algunos sistemas Unix (por ejemplo, FreeBSD), en los que el comando cat directorio es un comando válido, que se ejecuta sin errores, e imprime en la pantalla algo que parece "basura" sin formato del tipo de /dev/random pero que, en realidad, es el contenido del directorio, tal y como ocurría en los Unix originales (en Linux esto no ocurre, se ha asumido que los directorios son directorios, y tratar de leer un directorio como archivo devuelve el error EISDIR).

Pero no se acaba aquí esta historia. Que el diseño original de Unix tuviera estos entresijos acabaría teniendo consecuencias que se heredaron con el tiempo, hasta llegar a hoy.

El hecho de que los directorios originales de Unix fueran simples concatenaciones lineales de parejas nombre/númerodeinodo hizo que las interfaces asumieran que el contenido de un directorio sería siempre lineal. De ese modo surgieron APIs como telldir(), la cual obtiene la posición de un elemento dentro del listado de un directorio. Esta posición puede utilizarse en seekdir() para mover un listado a una posición determinada del directorio. Es decir, se trata a un directorio como un archivo en el que un programa puede moverse de un lado a otro sin problemas.

Esto causó un gran problema con el advenimiento de los sistemas de archivos modernos, basados en estructuras de árbol. Las estructuras de árbol utilizadas en sistemas de archivo (B-Tree y similares) tienen como una de sus características fundamentales el rebalanceo para redistribuir los nodos del árbol a medida que se crean o eliminan archivos. Este rebalanceo puede cambiar el orden en el que un determinado elemento aparece en un listado de directorio, es decir, no se garantiza que usar seekdir() en una posición determinada dos veces consecutivas nos lleve al mismo elemento.

¿Que han hecho los sistemas de archivo Unix basados en B-Trees para lidiar con este problema? Esencialmente, tratar de parchear el problema (resolverlo no es posible, siempre habrá que mantener la compatibilidad con la tradición Unix). Por ejemplo, JFS tiene un B-Tree extra exclusivamente dedicado a mantener una doble indexación que permita satisfacer las garantías de readdir() y compañía. Btrfs, un sistema de archivos de última generación, también mantiene una doble indexación, por cada elemento añadido a un directorio se crean dos items: uno ordenado por hash y otro ordenado secuencialmente. Ext3/4 por su parte sólo ordena los elementos por hash, pero trata de mantener la secuencialidad leyendo los contenidos del directorio por el orden de hash.

Estas técnicas suponen, por supuesto, un trabajo y E/S extra que tiene un impacto en el rendimiento. ¡Ah, y por supuesto, la concepción lineal de los directorios implica que listarlos con readdir() y operar con ellos puede tener una complejidad algorítmica lineal! Así que resulta que Unix, culmen del buen diseño de sistemas operativos, implementa los directorios de una forma verdaderamente patética, y nos hacer pagar sus errores con impacto en el rendimiento (hay software que usa diferentes trucos para evitar acumular miles de archivos en un mismo directorio).

La lección de toda esta historia es que por muy genial que sea el diseño de tu software, obsesionarse con abstracciones perfectas e intentar imponerlas bajo la creencia de que su pureza es la única forma decente de hacer las cosas puede llegar a ser un gran error.