[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