Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

Fase 3: Nodo Multitarea

Última Actualización: 05 de Abril de 2004 - Lunes

Aunque el objetivo final es implementar un esquema distribuido, para acelerar el nacimiento de la red se ha empezado por utilizar un esquema centralizado empleando las facilidades proporcionadas por los servidores IRCd de Undernet.

En estos momentos los nodos de control son:

  • OLIMPO: Este es el nodo principal de la red
  • ORACULO: Nodo secundario y de pruebas

Las operaciones que cubren esos nodos son:

  1. Control de clonos: La red sólo permite dos conexiones por IP
  2. Control de OP: Permite dar y quitar OP en los canales
  3. Control de las Bases de Datos Distribuidas: Puerta de entrada para las BDD de clonos, nicks, opers, IPs virtuales, etc.
  4. Gestión dinámica de módulos: Carga y descarga de módulos como *.so y objetos Python, sin interrumpir el servicio.
  5. Control de canales: Soporte para la gestión de canales.


Fase 1: El Nodo de Control

Fase 2: Nodo Modular


Módulos Implementados


TO DO

  • El Hash es hasta el primer espacio, pero la comprobación al buscar es la cadena completa.
  • Cuando se cambia el nick o los modos, no es necesario tocar las tres tablas de nicks-usuarios, nicks numéricos e IPs.
  • Llamadas recursivas entre borra_usuario_compress y borra_usuario_nick.
  • Simplificar el acceso a las tablas HASH indicando un único parámetro, no la pléyade Tabla, Tamaño y CANONICE, lo que es más confuso y más proclive a errores.
  • Definir un pool de estructuras lista para evitar hacer el free()/malloc() de estas estructuras de tamaño fijo.
  • Segmentación de los registros usando la rutina programada hace tiempo para ello.
  • Posibilidad de enviar notificaciones en las conexiones de usuarios individuales y/o cibercafés.
  • Todo tipo de estadísticas sobre la red: usuarios totales, usuarios por nodo, dominios, nivel de uso de las I-Lines de los cibercafés, etc., todo clasificado por día y hora.
  • Log del uso de ESNET X-MODE.
  • Identificación de nodos "maliciosos" en la red, especialmente en lo relativo a sus bases de datos.
  • G-Lines.
  • Las I-lines deberían poder validarse tanto por IP como por inversa.
  • La operación más lenta de Olimpo es la grabación de las I-lines que se van conectando. Debería trabajar con un búffer de grabación.
  • Pasar todas las operaciones de recorrido de base de datos a iteradores.
  • Olimpo debe matar a los usuarios cuyo nick esté registrado en la base de datos, pero que no tengan el flag "+r".
  • Identifica los máximos y mínimos locales de usuarios: Son los instantes que superan a todos sus vecinos durante un entorno (por ejemplo, 15 minutos antes y 15 minutos después).
  • Ojo con lo que ocurre si se recupera un archivo histórico con un Olimpo con un tamaño de paso diferente de la grabación original.
  • El contador de conexiones se hincha considerablemente si:
    • Hay splits en la red, ya que al volver a entrar los nodos, se inyectan todos sus usuarios de nuevo y de golpe.
    • Cuando Olimpo se reinicia, ya que recibe una ráfaga con todas las conexiones actuales de la red.
    Hay que tener en cuenta hechos como éstos si se quiere evaluar adecuadamente los resultados estadísticos que ofrece Olimpo.
  • En la visualización histórica, debería imprimirse tanto el número de conexiones como el número de usuarios de pico en cada intervalo.
  • La hora cargada, en los datos históricos, debería salir en negrita, además de listar realmente la hora cargada, no la ventana deslizante de 60 minutos.
  • Olimpo no implementa todas las funcionalidades de la BDD. En particular, no inicializa sus contadores ante borrados, por ejemplo.
  • ¿Cómo debe hacer frente Olimpo a la llegada de alta de registros de los cuales es responsable como nodo de control?.
  • Olimpo debería hacer log de todos los eventos de interés, como la propagación de registros o de SETTIME por terceras partes.
  • La migración a DB tiene como principal problema la posibilidad de que se queden bloqueos en la base de datos. Entre otras cosas, eso obliga a controlar las señales que nos llegan, así como tener algún mecanismo proactivo de monitorización y resolución de bloqueos.
  • Actualización de la base de datos por transacciones, para evitar su corrupción a toda costa.
  • Tanto en las altas como en los borrados de registros tenemos problemas de races, entre que actualizamos nuestra base de datos y enviamos el registro a la red, y el nodo de la red almacena el registro y lo propaga al resto de nodos.
  • Control de consistencia de las bases de datos remotas.
  • Cuando se realiza el alta de una iline no se verifica si ya existe. No pasa nada, pero se propagaría un nuevo registro por la red.
  • Dado que un usuario no se podría conectar, una iline de 0 clones no es retirada nunca por SuX, ya que no llega a ver que ha caducado porque no se conecta ningún usuario con ella. Para éste y otros casos, hay que usar el script de eliminación de I-Lines antiguas, introducido en la versión 31 de Olimpo.
  • El número de conexiones simultaneas para considerar que no hay límite debe ser de 999, porque ese es el valor máximo que permite el formulario web. Además, los IRCd modernos no permiten más de ¿255? conexiones simultaneas desde la misma IP.
  • Olimpo debería almacenar tanto el DNS inverso como la IP de cada conexión.
  • Cuando se hace JUPE sobre un servidor, debe pasarse como P10 y no como J10. Lo malo es que sin el J10 no aparece el mensaje de "net join".
  • Poder hacer JUPE sobre un nodo aunque éste no esté conectado en este momento.
  • Olimpo debería detectar colisiones de nick entre módulos cargables.
  • Cuando se hace un "profile", no se liberan módulos, no se cierran las bases de datos, etc. No debería ser un problema, porque el hijo muere de forma casi inmediata y no manipula las bases de datos, pero...
  • Implementar dependencias entre módulos, con autocarga y autodescarga de los mismos.
  • Las rutinas de impresión de estadísticas de usuarios por nodo y la rutina de gestión de SQUIT, son muy ineficientes con el cambio a numerics extendidos.
  • El fichero de cabeceras "mod_berkeleydb.h" debería regenerarse automáticamente a partir de "berkeleydb.h".
  • La apertura y cierre de ficheros debería realizarse dentro de una transacción.
  • Cuando Olimpo hace un kill por clones, se ve la IP real, desprotegida.
  • Cuando se pone un JUPE a un nodo, debería simularse la gestión de "burst", para que no nos aparezca marcado con un asterisco en las versiones recientes del IRC. El asterisco señala un nodo que está haciendo un net join, que en este caso no se completa nunca.
  • Los JUPE deben ser persistentes, hasta que se retiran. No se puede depender de reinicios de Olimpo o de squit.
  • En el API de módulos debe haber una función que nos indique cuándo se ha completado el net join de Olimpo con la red.
  • En el API de módulos debe haber una función que nos permita especificar que solo queremos recibir determinado tipo de evento si ocurre en un net join o si no ocurre en un net join.
  • Usar el Python como una librería dinámica, no estática.
  • Los módulos no pueden distinguir cuando un mensaje que reciben lo ha enviado un usuario o un servidor. Tal vez habría que hacer que los servidores apareciesen con un handle negativo, o algo por el estilo.
  • Las herramientas están programadas para que no intenten obtener un bloqueo si está cerrado, para evitar "deadlocks" y para no interferir con el funcionamiento del programa. Debo hacer, no obstante, que las herramientas impriman algún mensaje si se encuentran con este caso.
  • Si tengo un módulo Python cuyo nombre coincide con un módulo SO, se supone que puedo elegir qué modulo cargo poniendo la extensión correcta. Pero si intento cargar el módulo Python, me va a dar un error, porque Python intentará cargar un módulo nativo, usando el SO, y el SO cargado no cumple el API Python.
  • Ahora que Olimpo es capaz de soportar llamadas recursivas entre e intra módulos, debería ser posible que un módulo invocase a otro.
  • Un módulo debería poder cargar y descargar otros módulos. Esto es especialmente interesante para los módulos Python.
  • Verificar si un DBDEL inicializa correctamente el contador de registro interno.
  • Cuando liberamos mucha memoria, debería devolverse al sistema, no reternerla. El problema es que el "dlmalloc" gestiona los bloques libres en plan FIFO. Esto es bueno para las cachés y la paginación, pero supone que las páginas no están ocupadas densamente. Si en vez de ello reutilizase la memoria en orden de dirección, sí que se podría ir liberando la última página de memoria, de vez en cuando.
  • Para ocupar menos memoria, compilar la librería Python como dinámica, para compartirla con todos los programas que usen Python.
  • Olimpo no debería reutilizar los "numerics" hasta que agotase la máscara, igual que hace con el IRC. Ello evitaría reutilizar los "numerics" en un plazo corto, lo que evitaría algunos desync en situaciones de lag.
  • Olimpo debe poder usar más de 64 nicks simultaneos para sus módulos cargables.
  • La función de API "notifica_nick_registrado()", debería dar tanto el handle como el nick en sí, como optimización, en vez de dar solo el handle.
  • Definir una nueva función en el API que me dé el tiempo actual sin necesidad de que haga una llamada al sistema operativo. Se puede actualizar cada vez que se reciba algo por la red, por ejemplo. La motivación de esto es no estar haciendo "time()" en varios módulos, para los mismos datos.
  • La función que se invoca cuando se descarga un módulo debería tener un parámetro que le diga si se está descargando el módulo o, por el contrario, se está cerrando todo Olimpo. Ello permite optimizar cosas como, por ejemplo, destruir threads pendientes en vez de esperar a que terminen por sus propios medios, si sabemos que se está cerrando todo el sistema y no importa dejar basura detrás.
  • Cuando nos llega un mensaje para un nick que YA no existe (por ejemplo, acabamos de descargar su módulo, debemos enviar al origen un mensaje de error tipo "target left IRC".
  • Potencialmente, el calcular qué nodos se van de la red cuando hay un split es O(n2).
  • Deberíamos convertir las funciones "Olimpo.hace_log*()" en "Thread Safe".
  • El volcado de "tracebacks" de Python debería ser "Thread Safe".
  • Solucionar el problema de la eliminación automática de transacciones provenientes de ejecuciones previas. Más información en el thread [IRC-DEV] Cadenas de dominó curiosas.


LIMITACIONES

  • Olimpo sólo puede usar un "numeric" inferior a 64, y sólo utiliza los "numerics" cortos, lo que le limita a 4096 nicks simultaneos, para todos sus nicks propios y sus módulos dinámicos.


Historia

  • 28/Dic/01 Versión 57

    • Amplío la caché de disco de la BerkeleyDB de los actuales 4 MB a 8 MB.

    • Amplío el tamaño del buffer en memoria de logs de la BerkeleyDB, de los 32 Kbytes actuales a 384KB. Mi idea es limitar el "overflow" del buffer en presencia de transacciones muy largas o costosas, o de transacciones sin garantía de "durabilidad".

      Estas transacciones ligeras se utilizan, por ejemplo, para cosas como actualizar la fecha de la última conexión de un usuario. No importa que perdamos alguna actualización de vez en cuando, si a cambio ganamos rendimiento. También se utilizan para la fecha de último uso de "I-lines". Esto es especialmente interesante cuando nos llega un "burst" de un nuevo nodo, por ejemplo.

      Un buffer mayor tiene la ventaja adicional de que su volcado a disco es más eficiente.

    • Guarda el record de usuarios y su fecha en la base de datos, para poder rotar los logs de acceso sin perder el valor.

    • Si no había fichero de histórico de conexiones, tampoco leía el record de la base de datos. Solucionado.

    • Cuando actualizamos en la base de datos el record de conexiones, lo hacemos con transacciones "ACI", en vez de "ACID". Esto mejora mucho el rendimiento cuando estamos sobrepasando el record constantemente, algo que ocurre durante varios minutos cuando se supera el record, ya que cuando se supera el record, se suele superar varias decenas veces a lo largo de una hora, por ejemplo.

      No nos importa que la transacción sea "ACI", porque estamos guardando el record también en el histórico de conexiones y, además, la base de datos se actualizará definitivamente y con certeza cuando se realice un "Group Commiting" al finalizar la siguiente transacción que sea "ACID", o bien que se llene el buffer de logs de transacciones.

    • Cuando se cierra una base de datos, BerkeleyDB compromete a disco los logs de transacciones. Ello tiene el efecto de que, a pesar de los cambios previos, las transacciones de nuevos records de usuarios siguen siendo "ACID", con lo que ello implica para el rendimiento.

      Hago cambios en el sistema para tratar la base de datos en cuestión de forma persistente, al igual que ya se hace con la base de datos de clones ("I-lines"). Este cambio incluso simplifica código.

  • 02/Ene/02 Versión 58

    • Migración a Python 2.1. Eso incluye repasarse TODOS los módulos Python a la caza de cambios. También incluye el repasar posibles cambios en las estructuras en la interfaz de interconexión entre C y Python.

    • Migración a Python 2.2, recién salido del horno :-).

  • 04/Ene/02 Versión 59

    • Debido a un bug en Python 2.2, cambio temporalmento las llamadas a "PyMapping_DelItemString" a "PyDict_DelItemString". Volveré a dejar la llamada como estaba cuando se parchee el problema en el intérprete Python.

    • Cuando cambiamos el número de versión de Olimpo, el "make" procede a una recompilación casi completa de todo el código. Modifico las dependencias entre módulos y los ficheros "*.h" para que se recompile lo mínimo.

    • Parcheo mi Python 2.2 para implementar "PyMapping_DelItemString", y mando el parche a sus desarrolladores. Vuelvo a dejar el código de Olimpo como estaba.

    • Ampliamos el API OLIMPO con la función "nombre_modulo()", para que un módulo obtenga su propio nombre.

    • Documento la función "debug()" del API OLIMPO, existente desde hace tiempo, y que nos indica si el framework de Olimpo en el que se carga el módulo está compilado en modo desarrollo o en modo producción.

    • Añadidas al API "NOTIFY" las funciones "notifica_IRQ()" y "notifica_IRQ_handler()". Estas funciones se utilizan para la intercomunicación entre threads de un módulo y entre módulos distintos (previo acuerdo de un API personalizado caso a caso).

    • La compilación debe realizarse, bajo Solaris, con el símbolo "_REENTRANT" definido, si vamos a utilizar threads.

    • Dado que ahora hay una llamada invocable desde un thread separado, debemos proteger con un mutex:

      • La carga de módulos
      • La descarga de módulos
      • El envío de IRQs

      No es necesario proteger el listado de módulos porque no realiza cambios en las estructuras.

      No es necesario proteger la instalación de un nuevo handler de IRQs porque ese proceso se realiza desde el thread principal, y su hipotética activación (del nuevo handler) también se realiza desde el thread principal, así que nunca nos lo encontraremos en estado inconsistente.

      No es necesario proteger la invocación de las IRQs pendientes por el mismo punto que el anterior, y porque su flag está marcado como "volatile". Si el thread principal pasa sobre un módulo sin IRQ pendiente y, mientras se revisan el resto de módulos, llega un IRQ para elmódulo ya visto, el thread principal lo procesará en su siguiente repaso de IRQs pendientes.

    • Como optimización, aparte de señalización de IRQ pendiente para cada módulo, hay una señalización global de IRQ pendiente el "algún módulo". De esta forma solo repasamos los módulos a la caza de IRQs pendientes si el flag global, que es "volatile", así lo sugiere.

  • 04/Ene/02 Versión 60

    • Cuando cargamos un módulo dinámico Python se puede ejecutar código previo a la invocación de la rutina "inicio()". Debemos asegurarnos de que todo lo que puedan utilizar esté ya correctamente inicializado.

      En especial, durante la carga de un módulo y antes de la llamada a su rutina "inicio()", hay que marcarlo como "modulo_actual". En caso contrario, "Olimpo.nombre_modulo()", si se llama de forma implícita al cargar el módulo y antes de "inicio()", nos devolverá el nombre del último módulo ejecutado, no del módulo actual.

    • No debo hacer operaciones que impliquen escrituras en los "assert()", ya que si compilamos el código con ellos deshabilitados, perdemos la operación.

    • Me encuentro con un problema curioso, que identifico tras investigar durante unas horas volcados de llamadas al sistema y código fuente: cuando se integra Python en otra aplicación, como hacemos nosotros, nos encontramos el problema de que llamamos a una función Python y, cuando ésta regresa, mantiene el lock global Python, lo que bloquea otros threads.

      Una vez identificado el problema, veo que está bastante documentado en Internet:

      Defino macros "ENTER_PYTHON", "ENTER_PYTHON2", "EXIT_PYTHON" y "EXIT_PYTHON2", que distribuyo por el código, para lograr un threading mucho más fino y eficiente.

      Los cambios que hay que hacer en el código son bastante extensos.

    • Modifico los macros "ENTER_PYTHON", "ENTER_PYTHON2", "EXIT_PYTHON" y "EXIT_PYTHON2", para que permitan y gestionen adecuadamente invocaciones anidadas.

  • 08/Ene/02 Versión 61

    • Añadimos la función "id_modulo()" para que un módulo pueda obtener un identificador único por instancia.

    • Añadimos funciones "existe_nombre_modulo()" y "existe_id_modulo()" para que un módulo o thread pueda verificar la existencia y la identidad de un módulo o una instancia.

    • Cada módulo cargado en el sistema tendrá un identificador único por instancia. Olimpo garantiza su unicidad durante la vida del proceso.

    • Añado estas tres funciones como thread safe, y las protejo con el mismo mutex que protege la carga y descarga de módulos.

    • En el API "NOTIFY" cambiamos el nombre de la función "notifica_IRQ()" por "notifica_IRQ_nombre()", y añadimos la rutina "notifica_IRQ_id()".

    • Asimismo, estas dos funciones ahora indican si el destinatario del IRQ existe o no.

    • Añado el API "IPC", y muevo las rutinas de intercomunicación entre módulos y threads a dicha API.

    • Cuando se gestionaba una IRQ Python, si había algún timer programado para ese módulo, se perdía. Solucionado.

    • Añado al API "IPC" las funciones "add_obj()", "del_obj()", "obj()", "del_id_objects()" y "get_objects()". Estas funciones están disponibles exclusivamente para módulos Python.

      Estas funciones completan el sistema IPC, posibilitando la publicación y el descubrimiento de objectos Python.

    • Añado al API "IPC" la función "add_obj2()", para poder publicar objetos desde threads que no sean la principal.

  • 14/Ene/02 Versión 62

    • Añado al API "IPC" la función "purge_objects()", para poder eliminar objetos stale, cuyo módulo madre está descargado pero no los eliminó correctamente.

    • Limpio mucho código para eliminar "warnings" cuando se compila Olimpo con un nivel de optimización elevado.

    • Rectifico la interfaz API entre los módulos Python y Olimpo para que cumplan la documentación en lo relativo a la desactivación de callbacks. Es decir, que se les pueda pasar un "None" para desactivar un callback.

      Los cambios son muy amplios, ya que se ven afectadas numerosas rutinas y estructuras de datos.

    • Pequeña optimización cuando liberamos objetos Python que nunca llegaron a inicializarse.

    • Solucionamos un problema de indentación con los macros de entrada y salida del intérprete Python, en "make indent".

    • Añadimos al API "PRIVMSG" una nueva función "quit_nick()", que elimina el nick dado de alta por un módulo.

    • Solucionado un problema que hacía que no se pudiesen reutilizar numerics de nicks pertenecientes a módulos descargados.

    • Solucionado un problema en Olimpo si intentábamos utilizar más de 32 nicks a la vez.

  • 21/Feb/02 Versión 63

    • A la hora de buscar en la base de datos de clones, la búsqueda se hace "case insensible". No obstante se siguen pudiendo sobrepasar los clones si, por ejemplo, se meten clones cuya inversa juega con las mayúsculas y minúsculas. Es decir, dos clones todo en mayúsculas, dos clones todo el minúsculas, "case" mezclado, etc.

    • En "USERS", se muestra el porcentaje de usuarios que conectan por cada nodo.

    • Ampliamos el API "BERKELEYDB" para soportar transferencias bulk.

      Esto supone cambios masivos en dicho módulo, y cambios también en el resto de Olimpo.

    • Cambiamos los programas de volcado de la base de datos a ASCII para utilizar el modo bulk.

    • Actualizo el módulo interfaz Python para que procese adecuadamente las operaciones bulk con cursores.

    • Tengo que modificar algunas rutinas, ya que al realizar operaciones bulk con cursores, no se garantiza que los valores devueltos estén alineados.

    • El cambio a cursores bulk supone una mayor velocidad y una menor presión y fragmentación en la memoria utilizada, ya que el número de "malloc()" y "free()" se reducen considerablemente.

  • 20/May/02 Versión 64

    • Se amplía el API "SERVMSG" con la función "envia_raw2()", para poder enviar comandos directos a la red, cuyo remitente será el propio Olimpo.

      Es importante recordar que dichos cambios NO serán seguidos por Olimpo. Osea, que Olimpo no los ve.

    • Modifico Olimpo para que considere case insensible también los comandos "ILINEADD" e "ILINEDEL". Esto es un poco complicado, ya que tenemos entradas en la base de datos incorrectas. Nada que no se pueda resolver usando un poco de código, pero no deja de ser un coñazo...

      El problema ha sido el despliegue de dos parches incompatibles en Olimpo y en formulario de alta de I-lines.

    • En vez de enviar el "SETTIME" en los "net join" cuando se anuncia la presencia de un nuevo nodo en la red, se hace cuando dicho nodo completa el BURST. De esta forma no introducimos un error derivado del tiempo de transferencia del BURST.

    • Con la normalización de los clones metí la pata y sale un mensaje erroneo cuando te avisa de su caducidad inminente. Solucionado.

    • Solucionado un problema cuando se intentan ver los modos de un usuario cuyo "host" mide menos de dos caracteres.

    • Conjuntamente con los cambios en la Base de Datos Distribuida impolementados en DB93, modifico el comando DBQ de Olimpo para que permita preguntar a la tabla "*", lo que permite verificar la integridad de todas las tablas de toda la red con un único comando.

    • Soluciono, ¡por fin!, un viejo problema de Olimpo, que he conseguido diagnosticar hoy en un cuidadoso análisis de la situación. El problema se hace patente cuando se "jupea" otro nodo, y entre Olimpo y su HUB hay algo de lag o una cola de salida más o menos importante. El problema es el siguiente:

      • "Jupeamos" un nodo de la red. Olimpo elimina todas la referencias internas a dicho nodo y a sus nodos hijos, así como a sus usuarios. Olimpo envía la orden de "jupe" hacia su HUB.

      • Mientras tanto, el HUB, que aún no ha recibido el "jupe", sigue enviando el contenido de su cola de salida, que puede incluir usuarios de losnodos "jupeados". Olimpo no comprueba los usuarios, y los añade a sus bases de datos internas.

        Aquí tenemos el primer problema: Olimpo tendrá usuarios que, en realidad, ya no existe en el sistema.

      • Seguidamente alguien hace un "SQUIT" del nodo "jupeado". Como Olimpo no tiene constancia de dicho nodo (aunque está jupeado, no guarda constancia en sus bases de datos internas), no elimina nada de sus tablas. Los usuarios antiguos siguen aparentemente conectados, según Olimpo.

      • Ahora el nodo real re reconecta e inyecta sus usuarios, que están duplicados en las tablas internas de Olimpo, creando duplicidades e inconsistencias que, a la larga, matarán el proceso, afortunadamente sin mayores consecuencias.

      • Los procesos anteriores se pueden repetir varias veces, provocando más y más inconsistencias, que serán patentes cuando uno de esos usuarios desconecte o se desconecte el servidor.

      Una vez aclarado el problema, existen varias posibilidades:

      • Tener una tabla con los nodos presentes en la red, y rechazar cualquier usuario nuevo de un nodo inexistente. Eso obliga a mantener y gestionar una tabla de 4096 entradas.

      • Tener una tabla con los nodos "jupeados", y rechazar cualquier usuario nuevo de un nodo inexistente. Esto obliga a gestionar una tabla de tamaño dinámico, relativamente pequeña.

      • Cuando se "jupea" un nodo, usar el punto anterior, pero enviando al HUB algún tipo de PING o similar. Una vez respondido el PING o similar sabemos que el HUB ya ha recibido y procesado el "jupe", por lo que ya no hace falta guardarse nada.

    • El cambio anterior proporciona soporte para poder "jupear" un nodo no conectado a la red aunque, de momento, no abordamos esa posibilidad.

    • Ignoramos la entrada de nuevos usuarios y nodos inyectados por nodos en situación de "jupe".

    • En resumen, un nodo "jupeado" (y los nodos que cuelgan de él) son marcados de forma que su entrada de usuarios o de nodos se ignoran hasta que se reciba un "SERVER" inyectando el nodo.

  • 19/Jun/02 Versión 65

    • Ampliamos el API "SERVMSG" para poder escuchar cualquier comando enviado a Olimpo.

    • Acomodo Olimpo para hacer frente a un par de cambios en el IRCD, como el que ahora se envíen los prefijos para "PASS" y para el primer "SERVER".

    • Ampliamos el API "TOOLS" para poder convertir entre "handles" y "numerics", de nicks y de servidores.

    • Solucionado un problema introducido en la ampliación del API.

    • Ampliamos el API "NOTIFY" para que un módulo reciba notificaciones de entradas y salidas de usuarios de la red.

    • Solucionado un problema si un módulo pide una lista de nicks registrados conectados, pero no tiene definido el "callback" asociado.

    • Solucionado un problema con las notificaciones de salidas de usuarios cuando se produce un split.

    • Ampliamos el API "NOTIFY" para que un módulo reciba la notificación final de que se ha completado un split.

    • En uno de los últimos cambios introduje un "chanchullo" en el código, que no era muy claro pero que me simplificaba la gestión de un caso especial. Lamentablemente dicho "chanchullo" supone contar erroneamente el número de usuarios conectados cuando hay split.

    • Tengo que hacerme un pequeño módulo que elimine el registro "RECORD_USUARIOS" de la tabla "db.varios", ya que su valor actual es incorrecto. Pierdo el histórico, pero es un mal menor.

    • Permito que operaciones de lectura, escritura y borrado de registros de las bases de datos no necesiten estar incluidas en transacciones, necesariamente, si no lo deseamos así.

  • 20/Jun/02 Versión 66

    • Amplío el API PRIVMSG para que un módulo pueda obtener la dirección IP y el nombre de host de un usuario.

    • Actualizo Olimpo para que conserve también la IP del usuario, no solo su host. Este cambio es bastante importante, y supone también un pequeño incremento en el consumo de memoria.

    • Cuando se hace log, se guarda también la IP, no solo el host.

    • Cada instancia de Olimpo en una red es autoritativa para bases de datos distribuidas diferentes. Actualizamos Olimpo para que:

      • solo permita que un módulo introduzca un registro nuevo en una base de datos distribuida, si su Olimpo es autoritativo sobre dicha base de datos.

      • solo permita realizar "DBADD" y "DBDEL" a las bases de datos distribuidas sobre las que seamos autoritativos.

      • solo permita utilizar los comandos "ILINEADD" e "ILINEDEL" si somos autoritativos sobre la base de datos distribuida "i".

    • Detecta si algún otro nodo de la red intenta modificar una base de datos distribuida de la que somos autoritativo.

    • Si un nodo Olimpo que no es autoritativo para la base de datos distribuida "n" recibe un borrado de un nick a través de dicha tabla, informa de este hecho a sus módulos que tengan interés en la baja de nicks.

    • Guarda en disco el contador de todas las bases de datos distribuidas, con fines de auditoría y control. Esos contadores se recargan cuando se arranca Olimpo.

    • Debido al punto anterior, necesitamos otra manera de determinar si tenemos flujo abierto o no, en las bases de datos distribuidas. Tengo que modificar código.

    • Amplío el API "BDD" para que un módulo pueda saber si puede o no puede enviar un registro a través de la base de datos distribuida. Esto es importante, ya que si se intenta enviar un registro cuando Olimpo no está enlazado a su HUB, dicho registro se perdería.

      Actualmente Olimpo comprueba, mediante un "assert()" que solo se envíen registros con flujo abierto. Pero eso lo hace internamente. La ampliación del API permite que un módulo realice esas comprobaciones por sí mismo.

    • Ayer introduje un bug al añadir a las estructuras la IP de los usuarios. Resulta que los usuarios no se dan de baja correctamente cuando hay un split. Solucionado.

  • 27/Jun/02 Versión 67

    • Solucionamos un par de bugs que pueden provocar el fallo de varios "assert()" si se produce un split con el HUB de Olimpo.

    • Solucionamos algunos problemas en el "JOIN 0", que puede provocar un core dump debido a que se está afectando los canales, pero no empieza por los caracteres normales de canales.

    • Solucionamos un problema menor de un bot de control que pueda enviar mensajes a Olimpo y que tenga un numeric largo.

    • Bajo ciertas circunstancias excepcionales, un KILL de un nick que acaba de desaparecer puede llegar a comunicarse a los módulos, de forma espuria.

    • Solución de un bug introducido en una versión reciente: Cuando hay un split y se van usuarios con clones fuera y dentro del split, se eliminan más clones de los que realmente se van, de las tablas internas.

    • Cuando hay un split, primero llegan las salidas de nodos, luego la salida de usuarios y finalmente la notificación del fin del split. Lamentablemente, cuando se notifican la salida de usuarios, sus nodos asociados ya han sido dados de baja, por lo que un módulo no puede pedir esa información.

      Mantengo el orden, pero la baja efectiva de los nodos se realiza DESPUÉS de enviar las notificaciones de nicks. Y antes de eso se envían las notificaciones de salida de los nodos, aunque no se eliminan de las estructuras de datos internas hasta el final.

    • Solucionamos un problema en la conversión de handle a numeric, y viceversa.

    • Una vez solucionado el problema anterior, hay que cambiar la asignación interna de handles para los nicks introducidos por módulos Olimpo.

  • 09/Sep/02 Versión 68

    • Modificamos el API "TOOLS" de Python para que " inttobase64()" acepte tuplas como argumento. Eso nos obliga a retocar buena parte de los módulos, aunque los cambios son minúsculos.

    • Retoco un poco el "MAKEFILE" para poder recompilar un servidor de pruebas cuando ya se está ejecutando otro.

    • Añado un "assert()" en la creación de transacciones, para detectar cualquier problema cuanto más pronto mejor.

    • Solucionado un problema en la segmentación.

    • Meto publicidad de los túneles cuando los clones tradicionales están a punto de caducar.

    • Cuando se hace un "KILL" a un nick perteneciente a un módulo, Olimpo debe descargar y recargar dicho módulo.

    • Cuando se recarga un módulo por "KILL", hacemos log de ello.

    • Cuando el "KILL" se realiza al propio Olimpo, simplemente se reinyecta su nick de nuevo.

    • Olimpo tolera que se inicialice su tabla de control de números de serie de la BDD. Esta tabla se utiliza para detectar cambios no controlados en la BDD. Si dicha tabla se corrompía, cuesta mucho arrancar Olimpo.

      Con el cambio realizado, arrancar Olimpo se limita a eliminar manualmente el registro de la base de datos que contiene esta tabla de control.

  • 12/Dic/02 Versión 69

    • Todas las escrituras hacia el HUB se hacen a través de estructuras "dbuf", lo que permite realizar encolamiento y escrituras largas. Eso supone una gran mejora en el rendimiento cuando un módulo envía numerosos datos al HUB, como puede ocurrir con la agenda cuando se produce un "net join".

      Pongo un tamaño de 8192 bytes a los "dbuf". El servidor realiza las gestiones apropiadas si una escritura sobrepasa dicho valor.

    • Si se produce una desconexión del HUB, se purga lo que haya en la cola de "dbuf".

    • En el comando "STATS", se muestra la tabla "W" en vez de la tabla "T".

    • Amplío el buffer de entrada de Olimpo de 1024 bytes a 32768 bytes, con la esperanza de reducir el tiempo de "burst" cuando se produce un "net join".

    • Actualización a BerkeleyDB 4.1.24. Me supone tocar algo de código, pero la transición es bastante suave.

    • Amplío la memoria caché de la BerkeleyDB de 8 ficheros de 1 megabyte cada uno, a 4 ficheros de 4 megabytes cada uno.

    • Cuando se ejecuta el comando "DIE" hay que hacer un flush de las dbuf, para no dejarnos nada pendiente.

  • 23/Abr/03 Versión 70

    • Persiste el problema de corrupciones esporádicas de memoria cuando se descargan módulos. Ocurre, al menos, con módulos Python. No lo he comprobado con módulos dinámicos.

      Me reviso con lupa las rutinas de descarga de módulos:

      • Cuando se carga un módulo Python, inicializamos el puntero de carga dinámica a un valor definido, aunque no debería usarse en ese tipo de objetos.

      • Cuando se descarga un módulo, sólo hacemos descarga dinámica si el módulo es una librería compartida. Antes se intentaba hacer una descarga dinámica de todos los módulos, aunque sean objetos Python. Ello, junto a que ese campo tendría un valor indefinido (punto anterior) para los objetos Python, podría ser la causa del problema.

      • Movemos la liberación de interceptación de comandos al principio del proceso de descarga de un módulo.

  • 30/Abr/03 Versión 71

    • A partir del IRCD u2.10.H.06.94 hay un cambio de protocolo por medio del cual un servidor P10, cuando se conecta a la red, informa al resto de nodos del instante de su arranque. Modifico Olimpo para que envíe esa información, y para que la acepte de la red.

    • El primer comando "SERVER" que envía nuestro HUB, cuando nos conectamos a él, no puede ser interceptado por un módulo Olimpo, ya que todavía no hemos entrado dentro del bucle "normal" de ejecución.

      Modifico Olimpo para soslayar este problema.

    • Cuando la red tiene lag, nos puede llegar una segunda conexión de un nodo YA conectado. Se trata de los "ghost". Cuando así ocurre, debemos quedarnos con la última conexión, y debemos propagar a los módulos la salida de la conexión antigua y la entrada de la conexión nueva. Deben procesarse correctamente, también, los nicks que conectaban por dicho nodo. El instante de arranque que Olimpo comunicaba al resto de la red era incorrecto. Solucionado.

    • Con los cambios anteriores se destapa un "bug" antiguo: Cuando la conexión entre Olimpo y su HUB se corta de forma abrupta, y se procede a una reconexión, algunas estructuras no son inicializadas. Solucionado.

  • 31/Jul/03 Versión 72

    • Solucionado un problema cuando Olimpo usaba más de 32 nicks.

    • Aprovechamos la extensión del API de Python 2.2.*, con METH_NOARGS y METH_O. De esta forma se simplifican las rutinas y se gana rendimiento.

      El primer caso es para los métodos y funciones sin parámetros. El segundo caso es para los métodos y funciones cuyo parámetro es un (único) objeto.

    • Solucionado un problema detectado tras la introducción del bot "CHANLOG": Los mensajes enviados a canales no deben contrastarse contra los módulos cargados, porque el destino es un canal, no un "numeric" que podamos o debamos utilizar.

    • Para evitar problemas con el "multithreading", las llamadas a funciones como "ctime()" se hacen a la versión reentrante. Debemos cambiar tanto Olimpo como los módulos escritos en C.

      • Cambio "ctime()".

      • Cambio "localtime()".

      • Cambio "gmtime()".

      • Cambio "printf()", "fprintf()".

    • Parece que los problemas de multithreading son, en realidad, bugs en mi versión de Solaris, tal y como documento en la página de la agenda, entrada 1.66.2.20 del 22/Jul/03. El bug no afecta solo a las funciones "strftime" sino en general a todas las que transforman un "tiempo" en una cadena ASCII. Esto es así porque el problema parece residir en la gestión del "timezone", que no es "thread safe" a pesar de lo que diga la documentación.

      Así, debo "sincronizar" entre threads las llamadas a "ctime_r()".

    • Con estos cambios, nos aseguramos de inicializar el intérprete de Python muy al principio de la ejecución de Olimpo. En particular, antes de imprimir nada, especialmente de logs.

    • Debo sincronizar también las llamadas a "localtime_r()".

  • 26/Nov/03 Versión 73

    • Migración a Python 2.3, recién salido del horno :-).

    • Tengo que cambiar unas cuantas cosas, ya que esta versión de Python permite compilar el intérprete como librería compartida, y quiero aprovecharme de ese hecho.

    • También debo reinstalar para el nuevo Python las librerías no estándares usadas por los módulos Python de Olimpo. Para ver las que necesito, uso "grep import *.py".

    • Debo cambiar las llamadas "Olimpo.notify.notifica_timer()" de muchos módulos, para que en vez de pasar un tiempo en coma flotante, lo pasen como entero.

    • Actualización a BerkeleyDB 4.2.

  • 26/Nov/03 Versión 74

    • El que el "core" de Olimpo haga SETTIME a) cada vez que conecta un nuevo nodo y b) cada cuatro horas, pasa a ser una opción en el "config.h".

      Además, esta capacidad debería implementarse en un módulo externo, no en el "core".



Python Zope ©2001-2004 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS