[IRC-DEV] Unreal Data Base (Era: La comunidad de desarrolladoreshispanos)

Trocotronic trocotronic at rallados.net
Fri Mar 25 18:02:50 CET 2005


"¿Podrias explicar con detalles internos el sistema de los bloques?
Parece bastante interesante. ¿Se utiliza alguna base de datos
existente adaptada?."

La idea es que TODO son el mismo tipo de datos (UDB *). La estructura es:
struct _udb
{
 char *item; /* si queremos darle un nombre */
 int id; /* si queremos darle una id */
 char *data_char; /* su valor char */
 u_long data_long; /* su valor numérico */
 struct _udb *hsig, *up, *mid, *down; /* punteros enlazados bla bla bla */
};
Contienen el nombre del dato, su id (no es que lo use, pero nunca se sabe), 
data_char que es lo que contiene (es NULL si solo es un nombre, por ejemplo 
::accesos::), data_long por si los datos son numéricos, y los punteros 
enlazados: hsig al siguiente de su slot en la tabla hash, up al registro 
superior, mid a su siguiente y down si tiene sucesivos.
Por ejemplo, en el bloque N el mapa sería:
N
| - Trocotronic
|                   | - pass
|                   | - desafio
|                   | - vhost
|                   | - modos
| - Fourier
|             | - pass
|             | - desafio
            (etc)

Así pues, para la unidad "Trocotronic", item apunta a este nick, data_char a 
NULL (puesto que no tiene contenidos) y data_long a 0L. *up apunta a la 
unidad N, *down apunta a pass (el *mid de pass a desafio, el *mid de desafio 
a vhost, etc) y el *mid a Fourier (y el *mid de Fourier al siguiente nick, 
etc).
Entonces tenemos todas estas unidades una vez enlazadas se ponen en tablas 
hash para agilizar su búsqueda.
La función de búsqueda para nicks por ejemplo sería:
Udb *busca_unidad(char *item, Udb *root);
Si queremos ver si un nick está en nuestra base de datos usamos if 
(busca_unidad("Trocotronic", bloque_N)) /* ok! */, o si queremos que nos 
devuelva su pass busca_unidad("pass", busca_unidad("Trocotronic", 
bloque_N))->data_char;
Como puede verse, hay que buscar varias veces hasta que nos devuelve el 
campo que deseamos. Cuanta más profunidad tenga, más búsquedas habrá que 
hacer. Están optimizadas por tablas hash pero aun así, hay que pasar por la 
piedra.
Esto contesta a tu pregunta que no, no es una búsqueda exponencial, puesto 
que no se trata como si fueran ramas o un árbol, si no que son unidades 
(independientes a primera vista) con las que algunas están enlazadas entre 
sí.

La idea no es limitar la profunidad, porque lo que tengo en mente es hacer 
un bloque maestro (la unidad Udb *) que sea igual para todos los campos y no 
haya que especificar si es un registro de primer nivel, de segundo, o de 
enésima profunidad.

Los registros especiales sí, pueden estar como la llamada tabla.z. Es pura 
cuestión de estética. Imaginemos el campo "clave". En el bloque N 
correspondría a la clave del nick, en el bloque I a la clave de cifrado y en 
el bloque C a la clave del canal, por ejemplo. Un mismo nombre para la 
función que desempeña.

Referente al protocolo tiene bastante miga (suficientes quebraderos me ha 
llevado).
En vez de números de serie va por bytes. Es decir, en el momento que se 
linkan dos nodos se intercambian los md5 (y timestamp del último OPT, 
veremos más adelante). Si los md5 son idénticos todo ok (estoy pensando en 
usar crc32 por agilidad). Si no son idénticos, se pasan los RESúmenes. Lo 
que se intercambia no son los registros, si no que se resumen los archivos. 
Así se consigue una correcta sincronización íntegra y a prueba de errores, 
puesto que si al insertar no se corresponde con el byte que toca, no se 
inserta y no se propaga.
Al principio cuesta entender este sistema, es algo nuevo imagino. La única 
limitación es el tamaño del archivo, que debe ser el sizeof(long). Por esta 
razón está el comando OPT para optimizar el archivo y que sólo tenga lo que 
tiene que tener (fuera registros repetidos o borrados).
La versión 3.0 no incluía OPT, con lo cual los archivos iban creciendo y 
creciendo. Había que encontrar la forma de optimizarlos, y que toda la red 
estuviera sincronizada. Pero no daba con la solución, puesto que siempre 
encontraba algún caso (recóndito, pero posible) en los que me lo tiraban al 
aire.
Así pues, decidí que las optimizaciones se guardaran en algún sitio. Y al 
linkar se pasan estos TS. Si son dispares, el que tenga menor TS borra TODO 
su bloque y lo solicita de nuevo, puesto que significa que en algún momento 
de split la red se había optimizado.

Para los errores existe el comando ERR. Su función inicial era simplemente 
para debug: ver qué fallab (si el open(), si el read(), etc.). El error más 
común era insertar un registro en un byte que no tocaba. Más adelante añadí 
una funcionalidad a este comando. Si se recibe un E_UDB_LEN byte, el nodo 
que lo recibe manda borrar a la red que tiene por detrás a partir del byte y 
así mantener la sincronización. Esto no tiene porque suceder, puesto que si 
se hace bien, todo funciona. Estos errores saltan cuando se programan 
servicios que, o bien no se sigue un orden, o bien falta algún +/- 1 por ahí 
que lo cambia todo.
El método de propagación es por el comando DB:
:<nodo emisor> DB <destino> <comando> <parámetros>

La esencia vendría a ser toda esta parrafada. Entiendo que pueda parecer 
denso (lo leo yo mismo y me duermo).
Todas las críticas que puedan mejorar este sistema, sobretodo los métodos de 
búsqueda, serán gratamente bienvenidas.

Saludos, Trocotronic.





More information about the IRC-Dev mailing list