]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/indice_b.c
df096183359c6a03096021cf6c8d48fca81e319c
[z.facultad/75.06/emufs.git] / emufs / indice_b.c
1
2 #include "indice_b.h"
3 #include "common.h"
4 #include "emufs.h"
5
6 /* Cantidad de claves por nodo */
7 #define CANT_HIJOS(x) ((x->tam_bloque-sizeof(B_NodoHeader))/sizeof(B_NodoEntry))
8 #define CANT_NODOS(x) (CANT_HIJOS(x)+1)
9 #define MIN_HIJOS(x) (CANT_HIJOS(x)/2)
10
11 /* Auxiliares */
12 /** Graba el nodo en el archivo */
13 static void b_grabar_nodo(INDICE *idx, int id, char *data);
14 /** Da el ID del proximo nodo a poder ser utilizado */
15 static int b_ultimo_id(INDICE *idx);
16 /** Lee un nodo desde el archivo */
17 static char *b_leer_nodo(INDICE *idx, int id);
18 /** Crea un nodo en el archivo y lo retorna. En i se pone el ID asignado */
19 static char *b_crear_nodo(INDICE *idx, int *i);
20 /** Lee el header de un nodo y lo guarda en header */
21 static void b_leer_header(char *src, B_NodoHeader *header);
22 /** Actualiza el header de un nodo desde header */
23 static void b_actualizar_header(char *src, B_NodoHeader *header);
24 /** Retorna el array de claves del nodo (esta data modifica directamente el bloque
25  *  por eso no es necesario usar un actualizar_claves 
26  */
27 static B_NodoEntry *b_leer_claves(char *src, B_NodoHeader *header);
28 /** Inserta una clave en el nodo de manera iterativa.
29  * \param idx Índice en donde insertar la clave.
30  * \param clave Clave a insertar.
31  * \param dato Dato a insertar
32  * \param nodo_id Id del nodo en el cual insertar la nueva clave.
33  * \param nodo FIXME Nodo en donde insertar??? No entiendo por que char*.
34  * \param hijo1 Id del nodo hijo de la izquierda del insertado.
35  * \param hijo2 Id del nodo hijo de la derecha del insertado.
36  */
37 static void b_insertar_en_nodo(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2);
38 /** Inserta en un nodo en el que se sabe positivamente que hay lugar. */
39 static void b_insertar_en_nodo_con_lugar(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2);
40 /** Esto es para asegurar el orden de los hijos luego de partir, en el caso de que
41  *  lo que se parta sea la raiz
42  */
43 static int b_elegir_izquierdo(INDICE *idx, int a, int b);
44 /** Borra una clave del arbol */
45 static void b_borrar_clave(INDICE *idx, char *nodo, int nodo_id, CLAVE k);
46 /** Le pide al hermano derecho del nodo una clave cuando se eliminan claves */
47 static void b_pedir_clave_derecha(char *, int, char *, int, char *, int, int);
48 /** Le pide al hermano izquierdo una clave cuando se eliminan claves */
49 static void b_pedir_clave_izquierda(char *, int, char *, int, char *, int, int);
50 /** Le pasa al hermano derecho del nodo una clave cuando se insertan claves */
51 static void b_pasar_clave_a_derecha(INDICE*, char*, int, char*, int, int, B_NodoEntry);
52 /** Le pasa al hermano izquierdo una clave cuando se insertan claves */
53 static void b_pasar_clave_a_izquierda(INDICE*, char*, int, char*, int, int, B_NodoEntry);
54 /** Junta 2 nodos y hace uno solo */
55 static void b_fundir_nodo(char *, int, char *, int, char *, int, int);
56                         
57 static EMUFS_REG_ID b_insertar_dup_en_pos(INDICE *idx, INDICE_DATO pos, INDICE_DATO nuevo);
58
59 static void abreviar_claves(INDICE *idx, B_NodoEntry *array, B_NodoHeader *header);
60 static void desabreviar_claves(INDICE *idx, B_NodoEntry *array, B_NodoHeader *header);
61
62 void emufs_indice_b_crear(INDICE *idx)
63 {
64         FILE *fp;
65         char *bloque;
66         B_NodoHeader header;
67
68         header.cant = 0;
69         header.nivel = 0;
70         header.padre = -1;
71         header.hijo_izquierdo = -1;
72
73         fp = fopen(idx->filename, "w");
74         PERR("Creando indice");
75         fprintf(stderr, "Archivo = (%s)\n", idx->filename);
76         if (fp == NULL) {
77                 PERR("Error al crear el archivo");
78                 return;
79         }
80         
81         /* Creo el archivo con el Nodo raiz */
82         bloque = (char *)malloc(idx->tam_bloque);
83         memset(bloque, -1, idx->tam_bloque);
84
85         memcpy(bloque, &header, sizeof(B_NodoHeader));
86
87         fwrite(bloque, idx->tam_bloque, 1, fp);
88         fclose(fp);
89 }
90
91 int emufs_indice_b_insertar(INDICE *idx, CLAVE clave, INDICE_DATO dato)
92 {
93         int i, nodo_id, padre_id;
94         B_NodoHeader header;
95         B_NodoEntry *claves;
96         char *nodo, *padre;
97         INDICE_DATO dummy;
98         
99         /* Leo la raiz */
100         nodo = b_leer_nodo(idx, 0);
101         padre_id = nodo_id = 0;
102         padre = NULL;
103         while (nodo) {
104                 if (padre) free(padre);
105                 padre = nodo;
106                 padre_id = nodo_id;
107                 b_leer_header(nodo, &header);
108                 claves = b_leer_claves(nodo, &header);
109                 i=0;
110                 while ((i<header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) i++;
111                 if ((i<header.cant) && (emufs_indice_es_igual(idx, claves[i].clave, clave))) {
112                         if (idx->funcion == IND_PRIMARIO) {
113                                 PERR("Indice primario no puede contener claves duplicadas!");
114                                 PERR(idx->nombre);
115                                 return 0;
116                         }
117                         
118                         /* TODO : Implementar carga de valor en clave duplicada! */
119                         b_insertar_dup_en_pos(idx, claves[i].dato, dato);
120                 
121                         if (idx->tipo_dato == IDX_STRING) {
122                                 /* Tengo que sacar el texto repetido del archivo de textos */
123                                 PERR("Eliminando string duplicado");
124                                 idx->emu_string->borrar_registro(idx->emu_string, clave);
125                         }
126                         return 1;
127                 } else {
128                         if (i == 0) {
129                                 nodo = b_leer_nodo(idx, header.hijo_izquierdo);
130                                 nodo_id = header.hijo_izquierdo;
131                         } else {
132                                 nodo = b_leer_nodo(idx, claves[i-1].hijo_derecho);
133                                 nodo_id = claves[i-1].hijo_derecho;
134                         }
135                 }
136         }
137
138         if (nodo) free(nodo);
139         nodo = padre;
140         nodo_id = padre_id;
141
142         if (idx->funcion != IND_PRIMARIO) {
143                 /* Agrego el DATO real al archivo de claves repetiras
144                  * y me guardo el ID para poner en el indice
145                  */
146                 dummy.id = -1;
147                 dato.id = b_insertar_dup_en_pos(idx, dummy, dato);
148                 if (dato.id != -1)
149                         PERR("NODO INSERTADO EN POS GENERADA NUEVA");
150         PERR("Ahora inserto");
151         fprintf(stderr, "Nombre del coso = %s\n", idx->nombre);
152         }
153
154         b_insertar_en_nodo(idx, clave, dato, nodo_id, nodo, -1, -1);
155         return 1; /* Agregar OK! */
156 }
157
158 INDICE_DATO emufs_indice_b_buscar(INDICE *idx, CLAVE clave)
159 {
160         int i;
161         INDICE_DATO ret;
162         B_NodoHeader header;
163         B_NodoEntry *claves;
164         char *nodo, *tmp;
165         
166         /* Leo la raiz */
167         nodo = b_leer_nodo(idx, 0);
168         while (nodo) {
169                 b_leer_header(nodo, &header);
170                 claves = b_leer_claves(nodo, &header);
171                 i=0;
172                 while ((i<header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) i++;
173                 if ((i<header.cant) && (emufs_indice_es_igual(idx, claves[i].clave, clave))) {
174                                 ret = claves[i].dato;
175                                 free(nodo);
176                                 return ret;
177                 } else {
178                         tmp = nodo;
179                         if (i == 0) {
180                                 nodo = b_leer_nodo(idx, header.hijo_izquierdo);
181                         } else {
182                                 nodo = b_leer_nodo(idx, claves[i-1].hijo_derecho);
183                         }
184                         free(tmp);
185                 }
186         }
187
188         /* Nodo no encontrado */
189         ret.id = ret.bloque = -1;
190         return ret;
191 }
192
193 int emufs_indice_b_borrar(INDICE *idx, CLAVE k)
194 {
195         /* Busco el nodo que contiene la clave,si es que esta existe */
196         char *nodo;
197         int nodo_id, i;
198         char encontrado=0;
199         B_NodoHeader header;
200         B_NodoEntry *claves;
201
202         nodo_id = 0; /* Tomo la raiz */
203         nodo = b_leer_nodo(idx, nodo_id);
204         PERR("Buscando clave a borrar");
205         while (nodo && !encontrado) {
206                 /* Obtengo los datos del nodo */
207                 b_leer_header(nodo, &header);
208                 claves = b_leer_claves(nodo, &header);
209
210                 i=0;
211                 while ((i<header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, k))) i++;
212
213                 if ((emufs_indice_es_igual(idx, claves[i].clave, k)) && (i<header.cant))
214                         encontrado = 1;
215                 else {
216                         if (i==0) {
217                                 free(nodo);
218                                 nodo_id = header.hijo_izquierdo;
219                                 nodo = b_leer_nodo(idx, nodo_id);
220                         } else {
221                                 nodo_id = claves[i-1].hijo_derecho;
222                                 free(nodo);
223                                 nodo = b_leer_nodo(idx, nodo_id);
224                         }
225                 }
226         }
227
228         if (encontrado) {
229                 PERR("Clave encontrada, borrando ...");
230                 b_borrar_clave(idx, nodo, nodo_id, k);
231         } else {
232                 PERR("Clave no encontrada");
233         }
234         return 0;
235 }
236
237 static int b_ultimo_id(INDICE *idx)
238 {
239         int i;
240         FILE *fp;
241         fp = fopen(idx->filename, "r");
242         fseek(fp, 0, SEEK_END);
243         i = ftell(fp)/idx->tam_bloque;
244         fclose(fp);
245
246         return i;
247 }
248
249 static char *b_crear_nodo(INDICE *idx, int *id)
250 {
251         char *bloque;
252         B_NodoHeader header;
253
254         (*id) = b_ultimo_id(idx);
255
256         header.cant = 0;
257         header.nivel = 0;
258         header.hijo_izquierdo = -1;
259         header.padre = -1;
260
261         bloque = (char *)malloc(idx->tam_bloque);
262         memset(bloque, -1, idx->tam_bloque);
263         memcpy(bloque, &header, sizeof(B_NodoHeader));
264
265         b_grabar_nodo(idx, *id, bloque);
266
267         return bloque;
268 }
269
270 static char *b_leer_nodo(INDICE *idx, int id)
271 {
272         FILE *fp;
273         char *out;
274         B_NodoHeader header;
275         B_NodoEntry *claves;
276
277         if (id < 0) return NULL;
278
279         fp = fopen(idx->filename, "r");
280         if (fp == NULL) return NULL;
281
282         fseek(fp, id*idx->tam_bloque, SEEK_SET);
283
284         out = (char *)malloc(idx->tam_bloque);
285         if (out == NULL) {
286                 fclose(fp);
287                 return NULL;
288         }
289
290         if (fread(out, 1, idx->tam_bloque, fp) != idx->tam_bloque) {
291                 free(out);
292                 /* No se puso leer el nodo */
293                 fclose(fp);
294                 return NULL;
295         }
296
297         /* Si estoy manejando string tengo que sacar las abreviaturas */
298         if (idx->tipo_dato == IDX_STRING) {
299                 b_leer_header(out, &header);
300                 claves = b_leer_claves(out, &header);
301                 desabreviar_claves(idx, claves, &header);
302         }
303         fclose(fp);
304         return out;
305 }
306
307 static void b_grabar_nodo(INDICE *idx, int id, char *data)
308 {
309         FILE *fp;
310         B_NodoHeader header;
311         B_NodoEntry *claves;
312
313         /* Si las claves son de tipo string debo abreviar antes de guardar */
314         if (idx->tipo_dato == IDX_STRING) {
315                 b_leer_header(data, &header);
316                 claves = b_leer_claves(data, &header);
317                 abreviar_claves(idx, claves, &header);
318         }
319         fp = fopen(idx->filename, "r+");
320         fseek(fp, id*idx->tam_bloque, SEEK_SET);
321         fwrite(data, 1, idx->tam_bloque, fp);
322         fclose(fp);
323 }
324
325 static void b_leer_header(char *src, B_NodoHeader *header)
326 {
327         if (!src) return;
328
329         memcpy(header, src, sizeof(B_NodoHeader));
330 }
331
332 static void b_actualizar_header(char *src, B_NodoHeader *header)
333 {
334         if (!src) return;
335         memcpy(src, header, sizeof(B_NodoHeader));
336 }
337
338 static B_NodoEntry *b_leer_claves(char *src, B_NodoHeader *header)
339 {
340         return (B_NodoEntry *)(src+sizeof(B_NodoHeader));
341 }
342
343 static void b_insertar_en_nodo(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2)
344 {
345         char *padre, *nuevo;
346         int nuevo_id;
347         int i, j;
348         static int rompi=0;
349         char salir = 0;
350         B_NodoHeader nodo_header, nuevo_header;
351         B_NodoEntry *claves, *tmp_claves, *claves_nuevo;
352
353         do {
354                 if (!nodo) {
355                         /* CREAR NODO? */
356                         nodo = b_crear_nodo(idx, &nodo_id);
357                 }
358                 b_leer_header(nodo, &nodo_header);
359                 claves = b_leer_claves(nodo, &nodo_header);
360
361                 padre = b_leer_nodo(idx, nodo_header.padre);
362
363                 if (nodo_header.cant == CANT_HIJOS(idx)) {
364                         int total;
365                         /* TODO: Si es B*, hay que chequear si alguno de los 2
366                          *       nodos hermanos pueden prestarme espacio (y
367                          *       desplazar si es así). Si no pueden, hay que
368                          *       hacer un split de 2 nodos en 3.
369                          *       Si no es B*, hay que hacer lo que sigue:
370                          */
371                         nuevo = b_crear_nodo(idx, &nuevo_id);
372                         i=0;
373                         /* Creo una lista ordenada de los nodos a partir */
374                         tmp_claves = (B_NodoEntry *)malloc(sizeof(B_NodoEntry)*(nodo_header.cant+1));
375                         total = nodo_header.cant;
376                         while ((i<nodo_header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) {
377                                 tmp_claves[i] = claves[i];
378                                 i++;
379                         }
380                         tmp_claves[i].clave = clave;
381                         tmp_claves[i].dato = dato;
382                         tmp_claves[i].hijo_derecho = hijo1;
383                         if (i<nodo_header.cant)
384                                 tmp_claves[i+1].hijo_derecho = hijo2;
385                         while (i < nodo_header.cant) {
386                                 tmp_claves[i+1] = claves[i];
387                                 i++;
388                         }
389                         
390                         /* Asigno a cada nodo lo que corresponde */
391                         b_leer_header(nuevo, &nuevo_header);
392
393                         nuevo_header.nivel = nodo_header.nivel;
394                         nodo_header.cant = total/2;
395                         nuevo_header.cant = total - nodo_header.cant;
396
397                         memset(claves, '*', idx->tam_bloque-sizeof(B_NodoHeader));
398                         for(j=0; j<nodo_header.cant; j++)
399                                 claves[j] = tmp_claves[j];
400
401                         claves_nuevo = b_leer_claves(nuevo, &nuevo_header);
402                         memset(claves_nuevo, '*', idx->tam_bloque-sizeof(B_NodoHeader));
403                         for(j=0; j<nuevo_header.cant; j++)
404                                 claves_nuevo[j] = tmp_claves[j+total/2+1];
405
406                         b_actualizar_header(nodo, &nodo_header);
407                         b_actualizar_header(nuevo, &nuevo_header);
408
409                         if (nodo_id != 0) {
410                                 clave = tmp_claves[total/2].clave;
411                                 dato = tmp_claves[total/2].dato;
412
413                                 b_grabar_nodo(idx, nodo_id, nodo);
414                                 b_grabar_nodo(idx, nuevo_id, nuevo);
415                                 free(nodo);
416                                 free(nuevo);
417                                 free(tmp_claves);
418
419                                 hijo1 = nodo_id;
420                                 hijo2 = nuevo_id;
421
422                                 nodo = padre;
423                                 nodo_id = nodo_header.padre;
424                         } else {
425                                 /* Oops, parti el raiz, y este debe quedar en 0, lo paso a otro bloque
426                                  * y dejo el padre vacio
427                                  */
428                                 char *tmp_nuevo = b_crear_nodo(idx, &nodo_id);
429                                 memcpy(tmp_nuevo, nodo, idx->tam_bloque);
430                                 free(nodo);
431                                 nodo = tmp_nuevo;
432         
433                                 clave = tmp_claves[total/2].clave;
434                                 dato = tmp_claves[total/2].dato;
435
436                                 b_grabar_nodo(idx, nuevo_id+1, nodo);
437                                 b_grabar_nodo(idx, nuevo_id, nuevo);
438                 
439                                 free(nodo);
440                                 free(nuevo);
441                                 free(tmp_claves);
442
443                                 hijo1 = nuevo_id+1;
444                                 hijo2 = nuevo_id;
445
446                                 /* Limpio al padre */
447                                 nuevo = b_leer_nodo(idx, 0);
448
449                                 b_leer_header(nuevo, &nuevo_header);
450                                 nuevo_header.cant = 0;
451                                 nuevo_header.padre = -1;
452                                 nuevo_header.nivel = nodo_header.nivel+1;
453                                 memset(nuevo, -1, idx->tam_bloque);
454                                 b_actualizar_header(nuevo, &nuevo_header);
455                                 b_grabar_nodo(idx, 0, nuevo);
456
457                                 nodo_id = 0;
458                                 nodo = nuevo;
459                                 rompi = 1;
460                         }
461                 } else {
462                         /* La clave entra en este nodo!! */
463                         b_insertar_en_nodo_con_lugar(idx, clave, dato, nodo_id, nodo, hijo1, hijo2);
464                         salir = 1;
465                 }
466         } while (!salir);
467 }
468
469 void b_insertar_en_nodo_con_lugar(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2)
470 {
471         int i = 0;
472         B_NodoHeader nodo_header;
473         B_NodoEntry* claves;
474         b_leer_header(nodo, &nodo_header);
475         claves = b_leer_claves(nodo, &nodo_header);
476         if (nodo_header.cant > 0) {
477                 int j;
478                 while ((i < nodo_header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) i++;
479                 for(j=nodo_header.cant; j > i; j--)
480                         claves[j] = claves[j-1];
481         }
482         nodo_header.cant++;
483         claves[i].clave = clave;
484         claves[i].dato = dato;
485         claves[i].hijo_derecho = hijo2;
486         nodo_header.hijo_izquierdo = b_elegir_izquierdo(idx, nodo_header.hijo_izquierdo, hijo1);
487
488         b_actualizar_header(nodo, &nodo_header);
489         b_grabar_nodo(idx, nodo_id, nodo);
490
491         /* Debo actualizar los punteros al padre de los hijos */
492         if (hijo1 != -1) {
493                 char* nuevo = b_leer_nodo(idx, hijo1);
494                 if (nuevo != NULL) {
495                         B_NodoHeader nuevo_header;
496                         b_leer_header(nuevo, &nuevo_header);
497                         nuevo_header.padre = nodo_id;
498                         b_actualizar_header(nuevo, &nuevo_header);
499                         b_grabar_nodo(idx, hijo1, nuevo);
500                         free(nuevo);
501                 } else printf("FUCK! hijo1=%d no existe!\n", hijo1);
502         }
503         if (hijo2 != -1) {
504                 char* nuevo = b_leer_nodo(idx, hijo2);
505                 if (nuevo != NULL) {
506                         B_NodoHeader nuevo_header;
507                         b_leer_header(nuevo, &nuevo_header);
508                         nuevo_header.padre = nodo_id;
509                         b_actualizar_header(nuevo, &nuevo_header);
510                         b_grabar_nodo(idx, hijo2, nuevo);
511                         free(nuevo);
512                 } else printf("FUCK! hijo2=%d no existe!\n", hijo2);
513         }
514 }
515
516 static int b_elegir_izquierdo(INDICE *idx, int a, int b)
517 {
518         int cual;
519         char *nodo1, *nodo2;
520         B_NodoHeader header1, header2;
521         B_NodoEntry *claves1, *claves2;
522
523         if (a==-1) return b;
524         if (b==-1) return a;
525
526         nodo1 = b_leer_nodo(idx, a);
527         nodo2 = b_leer_nodo(idx, b);
528
529         b_leer_header(nodo1, &header1);
530         b_leer_header(nodo2, &header2);
531
532         claves1 = b_leer_claves(nodo1, &header1);
533         claves2 = b_leer_claves(nodo2, &header2);
534
535         if (emufs_indice_es_menor(idx, claves1[0].clave, claves2[0].clave))
536                 cual = a;
537         else
538                 cual = b;
539
540         free(nodo1);
541         free(nodo2);
542         return cual;
543 }
544
545 INDICE_DATO *emufs_indice_b_buscar_muchos(INDICE *idx, CLAVE clave, int *cant)
546 {
547         EMUFS_REG_SIZE tam;
548         int error=0;
549         char *leido;
550         CLAVE k;
551         INDICE_DATO dato, *ret;
552
553         /* Si el indice es primario no tiene sentido hacer nada */
554         if (idx->funcion == IND_PRIMARIO) {
555                 *cant = 0;
556                 PERR("INDICE PRIMARIO NO SOPORTA BUSQUEDA MULTIPLE");
557                 return NULL;
558         }
559
560         /* Busco la clave en el arbol */
561         dato = emufs_indice_b_buscar(idx, clave);
562
563         if (dato.id == -1) {
564                 PERR("CLAvE NO ENCONTRADA EN EL ARBOL!");
565         }
566
567         /* Leo el contenido actual */
568         k.i_clave = dato.id;
569         error = 0;
570         leido = (char *)idx->emu_mult->leer_registro(idx->emu_mult, k, &tam, &error);
571
572         /* Incremento en 1 la cantidad */
573         if (leido != NULL)
574                 (*cant) = *((int *)leido);
575         else
576                 (*cant) = 0;
577
578         ret = malloc(sizeof(INDICE_DATO)*(*cant));
579         memcpy(ret, leido+sizeof(int), (*cant)*sizeof(INDICE_DATO));
580         free(leido);
581         fprintf(stderr, "TENGO QUE ESTA CLAVE TIENE %d ITEMS\n", *cant);
582         return ret;
583 }
584
585 static void b_borrar_clave(INDICE *idx, char *nodo, int nodo_id, CLAVE k)
586 {
587         int pos, actual_id, padre_id, i, pos_padre, izquierda_id, derecha_id;
588         B_NodoHeader header, header_actual, header_padre, header_izq, header_der;
589         B_NodoEntry *claves, *claves_actual, *claves_padre;/*, *claves_izq, *claves_der;*/
590         char *actual, *padre, *izq, *der;
591
592         b_leer_header(nodo, &header);
593         claves = b_leer_claves(nodo, &header);
594
595         pos = 0;
596         /* Busco la posicion dentro de la lista de claves */
597         while (emufs_indice_es_menor(idx, claves[pos].clave, k)) pos++;
598
599         /* Es el nodo una hoja? */
600         if (header.hijo_izquierdo != -1) {
601                 /* No!, es un nodo intermedio!! */
602                 if (pos == 0)
603                         actual = b_leer_nodo(idx, header.hijo_izquierdo);
604                 else
605                         actual = b_leer_nodo(idx, claves[pos+1].hijo_derecho);
606
607                 b_leer_header(actual, &header_actual);
608                 while (header_actual.hijo_izquierdo != -1) {
609                         actual_id = header_actual.hijo_izquierdo;
610                         free(actual);
611                         actual = b_leer_nodo(idx, actual_id);
612                         b_leer_header(actual, &header_actual);
613                 }
614                 claves_actual = b_leer_claves(actual, &header);
615
616                 claves[pos] = claves_actual[0];
617                 pos = 0;
618                 b_grabar_nodo(idx, nodo_id, nodo);
619         } else {
620                 actual = nodo;
621         }
622
623         /* Borro la clave */
624         for(i=pos; i < header_actual.cant; i++) {
625                 claves_actual[i] = claves_actual[i+1];
626         }
627         header_actual.cant--;
628         /* Guardo los cambios */
629         b_actualizar_header(actual, &header_actual);
630         b_grabar_nodo(idx, actual_id, actual);
631
632         /* Se cumple la condicion de hijos? */
633         if (header_actual.cant >= MIN_HIJOS(idx)) {
634                 PERR("Borrar completo sin fundir");
635                 return;
636         }
637
638         /* Tengo que pasar datos o fundir nodos :-( */
639         do {
640                 padre_id = header.padre;
641                 padre = b_leer_nodo(idx, padre_id);
642                 b_leer_header(padre, &header_padre);
643                 claves_padre = b_leer_claves(padre, &header_padre);
644                 /* TODO Tengo el hijo_izquierdo para revisar!! XXX */
645                 if (header_padre.hijo_izquierdo == actual_id) {
646                         izquierda_id = -1; /* No tengo hermano izquierdo */
647                         /* Mi hermano derecho es el primer nodo del padre */
648                         derecha_id = claves_padre[0].hijo_derecho;
649                         der = b_leer_nodo(idx, derecha_id);
650                         b_leer_header(der, &header_der);
651                 } else {
652                         for(pos_padre=0; claves_padre[pos_padre].hijo_derecho != actual_id; pos_padre++)        {       }
653
654                         /* Busco mis hermanos a derecha e izquierda, si es que existen */
655                         if (pos_padre >= 0) {
656                                 if (pos_padre == 0)
657                                         izquierda_id = header_padre.hijo_izquierdo;
658                                 else
659                                         izquierda_id = claves_padre[pos_padre-1].hijo_derecho;
660                                 izq = b_leer_nodo(idx, izquierda_id);
661                                 b_leer_header(izq, &header_izq);
662                         } else {
663                                 izquierda_id = -1;
664                         }
665                         if (pos_padre < header_padre.cant) {
666                                 derecha_id = claves_padre[pos_padre+1].hijo_derecho;
667                                 der = b_leer_nodo(idx, derecha_id);
668                                 b_leer_header(der, &header_der);
669                         } else {
670                                 derecha_id = -1;
671                         }
672                 }
673                 /* Intendo pasar una clave desde un hermano hacia mi */
674                 if ((derecha_id != -1) && (header_der.cant > MIN_HIJOS(idx))) {
675                         b_pedir_clave_derecha(der, derecha_id, padre, padre_id, actual, actual_id, pos_padre);
676                 } else if ((izquierda_id != -1) && (header_izq.cant > MIN_HIJOS(idx))) {
677                         b_pedir_clave_izquierda(izq, izquierda_id, padre, padre_id, actual, actual_id, pos_padre-1);
678                 } else {
679                         /* No pude pasar clave, tengo que fundir :-( */
680                         if (derecha_id != -1) {
681                                 b_fundir_nodo(actual, actual_id, padre, padre_id, der, derecha_id, pos_padre);
682                         } else {
683                                 b_fundir_nodo(izq, izquierda_id, padre, padre_id, actual, actual_id, pos_padre-1);
684                         }
685                 }
686
687                 /* TODO que guardo ?, todo ? */
688                 b_grabar_nodo(idx, actual_id, actual);
689                 b_grabar_nodo(idx, izquierda_id, izq);
690                 b_grabar_nodo(idx, derecha_id, der);
691                 b_grabar_nodo(idx, padre_id, padre);
692                 if (actual_id != -1) free(actual);
693                 /*if (padre_id != -1) free(padre);*/
694                 if (derecha_id != -1) free(der);
695                 if (izquierda_id != -1) free(izq);
696                 actual = padre;
697                 actual_id = padre_id;
698         } while ((actual_id != -1) && (header_actual.cant < MIN_HIJOS(idx)));
699 }
700
701 static void b_pedir_clave_derecha(char *der, int der_id, char *padre, int padre_id, char *nodo, int nodo_id, int pos_clave)
702 {
703         int i;
704         B_NodoHeader h_der, h_padre, h_nodo;
705         B_NodoEntry *c_der, *c_padre, *c_nodo;
706
707         b_leer_header(nodo, &h_nodo);
708         c_nodo = b_leer_claves(nodo, &h_nodo);
709         b_leer_header(der, &h_der);
710         c_der = b_leer_claves(der, &h_der);
711         b_leer_header(padre, &h_padre);
712         c_padre = b_leer_claves(padre, &h_padre);
713
714         c_nodo[h_nodo.cant] = c_padre[pos_clave];
715         c_nodo[h_nodo.cant].hijo_derecho = -1; /* XXX */
716
717         c_padre[pos_clave] = c_der[0];
718         c_padre[pos_clave].hijo_derecho = der_id;
719         
720         /* Muevo las claves de derecho */
721         for(i=0; i<h_der.cant; i++) {
722                 c_der[i] = c_der[i+1];
723         }
724         h_der.cant--;
725         h_nodo.cant++;
726
727         b_actualizar_header(der, &h_der);
728         b_actualizar_header(nodo, &h_nodo);
729 }
730
731 void b_pasar_clave_a_derecha(INDICE *idx, char *der, int der_id, char *padre, int padre_id, int padre_pos, B_NodoEntry entry)
732 {
733         B_NodoHeader der_h, padre_h;
734         B_NodoEntry *der_entries, *padre_entries;
735         /* Leo claves y cabecera del nodo de la derecha y del padre */
736         b_leer_header(der, &der_h);
737         der_entries = b_leer_claves(der, &der_h);
738         b_leer_header(padre, &padre_h);
739         padre_entries = b_leer_claves(padre, &padre_h);
740         /* Inserto en el hijo derecho la clave del padre */
741         b_insertar_en_nodo_con_lugar(idx, padre_entries[padre_pos].clave, padre_entries[padre_pos].dato,
742                         der_id, der, entry.hijo_derecho, der_h.hijo_izquierdo);
743         /* Reemplazo clave del padre por clave nueva */
744         entry.hijo_derecho = der_id;
745         padre_entries[padre_pos] = entry;
746 }
747
748 void b_pedir_clave_izquierda(char *izq, int izq_id, char *padre, int padre_id, char *nodo, int nodo_id, int pos_clave)
749 {
750         int i;
751         B_NodoHeader h_izq, h_padre, h_nodo;
752         B_NodoEntry *c_izq, *c_padre, *c_nodo;
753
754         b_leer_header(nodo, &h_nodo);
755         c_nodo = b_leer_claves(nodo, &h_nodo);
756         b_leer_header(izq, &h_izq);
757         c_izq = b_leer_claves(izq, &h_izq);
758         b_leer_header(padre, &h_padre);
759         c_padre = b_leer_claves(padre, &h_padre);
760
761         for(i=h_nodo.cant; i>0;i++)
762                 c_nodo[i] = c_nodo[i-1];
763
764         h_nodo.cant++;
765         c_nodo[0] = c_padre[pos_clave];
766         c_nodo[0].hijo_derecho = -1; /* XXX */
767         c_padre[pos_clave] = c_izq[h_izq.cant-1];
768         c_padre[pos_clave].hijo_derecho = izq_id;
769         h_izq.cant--;
770
771         b_actualizar_header(izq, &h_izq);
772         b_actualizar_header(padre, &h_padre);
773         b_actualizar_header(nodo, &h_nodo);
774 }
775
776 void b_pasar_clave_a_izquierda(INDICE* idx, char *izq, int izq_id, char *padre, int padre_id, int padre_pos, B_NodoEntry entry)
777 {
778 /*      int i;
779         B_NodoHeader h_izq, h_padre, h_nodo;
780         B_NodoEntry *c_izq, *c_padre, *c_nodo;
781
782         b_leer_header(nodo, &h_nodo);
783         c_nodo = b_leer_claves(nodo, &h_nodo);
784         b_leer_header(izq, &h_izq);
785         c_izq = b_leer_claves(izq, &h_izq);
786         b_leer_header(padre, &h_padre);
787         c_padre = b_leer_claves(padre, &h_padre);
788
789         for(i=h_nodo.cant; i>0;i++)
790                 c_nodo[i] = c_nodo[i-1];
791
792         h_nodo.cant++;
793         c_nodo[0] = c_padre[pos_clave];
794         c_nodo[0].hijo_derecho = -1; / * XXX * /
795         c_padre[pos_clave] = c_izq[h_izq.cant-1];
796         c_padre[pos_clave].hijo_derecho = izq_id;
797         h_izq.cant--;
798
799         b_actualizar_header(izq, &h_izq);
800         b_actualizar_header(padre, &h_padre);
801         b_actualizar_header(nodo, &h_nodo);
802 */
803 }
804
805 static void b_fundir_nodo(char *izq, int izq_id, char *padre, int padre_id, char *der, int der_id, int pos_clave)
806 {
807 }
808
809 static EMUFS_REG_ID b_insertar_dup_en_pos(INDICE *idx, INDICE_DATO pos, INDICE_DATO nuevo)
810 {
811         int cant;
812         EMUFS_REG_SIZE tam;
813         int error=0;
814         INDICE_DATO *array;
815         char *leido;
816         CLAVE k;
817
818         /* Leo el contenido actual */
819         k.i_clave = pos.id;
820         error = 0;
821         leido = (char *)idx->emu_mult->leer_registro(idx->emu_mult, k, &tam, &error);
822
823         /* Incremento en 1 la cantidad */
824         if (leido != NULL)
825                 cant = *((int *)leido);
826         else
827                 cant = 0;
828         cant++;
829
830         /* Obtengo un nuevo lugar para el dato nuevo */
831         /* Aca todo bien, si leido es NULL se compota como malloc */
832         leido = realloc(leido, cant*sizeof(INDICE_DATO)+sizeof(int));
833         array = (INDICE_DATO *)(leido+sizeof(int));
834
835         /* Pongo el dato nuevo */
836         array[cant-1] = nuevo;
837
838         /* Actualizo la cantidad */
839         (*((int *)leido)) = cant;
840
841         /* Salvo */
842         if (k.i_clave == -1) {
843                 /* Creo uno nuevo */
844                 error = 0;
845                 PERR("GRABADO REGISTRO NUEVO");
846                 k.i_clave = idx->emu_mult->grabar_registro(idx->emu_mult,
847                         leido,
848                         cant*sizeof(INDICE_DATO)+sizeof(int),
849                         &error
850                 );
851                 if (k.i_clave == -1) PERR("ALGO NO GRABO BIEN!!");
852         } else {
853                 /* Modifico el que ya existia! */
854                 PERR("MODIFICANDO REGISTRO EXISTENTE");
855                 error = 0;
856                 idx->emu_mult->modificar_registro(idx->emu_mult,
857                         k.i_clave,
858                         leido,
859                         cant*sizeof(INDICE_DATO)+sizeof(int),
860                         &error
861                 );
862         }
863         /* Clean up! */
864         free(leido);
865         return k.i_clave;
866 }
867
868 char *abreviar(char *primera, char *actual, int *iguales)
869 {
870         (*iguales) = 0;
871         while (((*primera) != '\0') && ((*actual) != '\0')) {
872                 if ((*primera) == (*actual)) {
873                         primera++;
874                         actual++;
875                         (*iguales)++;
876                 } else {
877                         /* No coinciden mas! */
878                         break;
879                 }
880         }
881
882         return actual;
883 }
884
885 static void abreviar_claves(INDICE *idx, B_NodoEntry *array, B_NodoHeader *header)
886 {
887         char *primera, *actual, *resto, salvar[100];
888         EMUFS_REG_SIZE size;
889         int error, i;
890         int iguales;
891
892         /* Agarro la primer clave entera como referencia */
893         primera = (char *)idx->emu_string->leer_registro(idx->emu_string, array[0].clave, &size, &error);
894         for(i=1; i<header->cant; i++) {
895                 actual = (char *)idx->emu_string->leer_registro(idx->emu_string, array[i].clave, &size, &error);
896                 resto = abreviar(primera, actual, &iguales);
897                 /* Para que tenga sentido abreviar tengo que tener
898                  * mas de 2 letras iguales, si no no gano nada y complica las cosas
899                  */
900                 if (iguales > 1) {
901                         sprintf(salvar, "%d|%s", iguales, resto);
902                         free(actual);
903                         error = 0;
904                         idx->emu_string->modificar_registro(idx->emu_string, array[i].clave.i_clave, salvar, strlen(salvar)+1, &error);
905                 } else {
906                         free(primera);
907                         primera = actual;
908                 }
909         }
910         
911         free(primera);
912 }
913
914 static void desabreviar_claves(INDICE *idx, B_NodoEntry *array, B_NodoHeader *header)
915 {
916         char *primera, *actual, *resto, salvar[100];
917         EMUFS_REG_SIZE size;
918         int error, i;
919         int iguales;
920
921         /* Agarro la primer clave entera como referencia */
922         primera = (char *)idx->emu_string->leer_registro(idx->emu_string, array[0].clave, &size, &error);
923         for(i=1; i<header->cant; i++) {
924                 actual = (char *)idx->emu_string->leer_registro(idx->emu_string, array[i].clave, &size, &error);
925                 iguales = strtol(actual, &resto, 10);
926                 if ((iguales > 0) && (*resto == '|')) {
927                         fprintf(stderr, "%s %s %d\n", primera, actual, iguales); 
928                         strncpy(salvar, primera, iguales);
929                         salvar[iguales] = '\0';
930                         strcat(salvar, resto+1); /* +1 para saltar el separador */
931                         idx->emu_string->modificar_registro(idx->emu_string, array[i].clave.i_clave, salvar, strlen(salvar)+1, &error);
932                         free(actual);
933                 } else {
934                         free(primera);
935                         primera = actual;
936                 }
937         }
938         
939         free(primera);
940 }
941