]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/indice_bplus.c
7d2891c86f760c6386b204410ed4872b7af6488b
[z.facultad/75.06/emufs.git] / emufs / indice_bplus.c
1 /** Arbol B+ */
2 #include "tipo1.h"
3 #include "tipo3.h"
4 #include "indices.h"
5 #include "indice_bplus.h"
6
7 /**#*#*#*#*#**#*#*#*#*#* Private prototypes*#*#*#*#*#**#*#*#*#*#**#*#*#*/
8 int b_plus_grabar_nodo(INDICE *idx, NODO_B_PLUS *nodo, int num_node);
9 NODO_B_PLUS *b_plus_leer_nodo(INDICE *idx, int num_node);
10 NODO_B_PLUS *b_plus_crearnodo(INDICE *idx);
11 int b_plus_destruir_nodo(NODO_B_PLUS *nodo);
12 int b_plus_split_child(INDICE *idx, int numparent, NODO_B_PLUS *parent, int ithchild, NODO_B_PLUS *fullnode);
13 int b_plus_insert_nonfull(INDICE *idx, NODO_B_PLUS *nodo, int num_nodo, INDEX_DAT *query);
14 int b_plus_insertar(INDICE *idx, INDEX_DAT *query);
15 int b_plus_get_num_nodo(INDICE *idx);
16 /**#*#*#*#*#**#*#*#*#*#*FIN PROTOTYPES*#*#*#*#*#**#*#*#*#*#**#*#*#*#*#*/
17
18 /** Crea un nuevo nodo y lo inicializa */
19 NODO_B_PLUS *b_plus_crearnodo(INDICE *idx) {
20         
21         NODO_B_PLUS *nodo = (NODO_B_PLUS*)malloc(sizeof(NODO_B_PLUS));
22         if (nodo == NULL) return NULL;
23         nodo->nivel = 0;
24         nodo->cant_claves = 0;
25
26     /* Calculamos lo que ocupan las cadenas de bytes claves + hijos */
27         nodo->claves = (CLAVE*)malloc(idx->size_claves);
28         nodo->hijos = (int*)malloc(idx->size_hijos);
29         memset(nodo->claves,-1,idx->size_claves);
30         memset(nodo->hijos,-1,idx->size_hijos);
31         
32     return nodo;
33 }
34
35 /** Crea el archivo indice B+ */
36 int emufs_b_plus_crear(INDICE *idx) {
37         
38         FILE *fp;
39         NODO_B_PLUS *raiz;
40         int error = 0;
41                 
42         /* Creamos el archivo que contendra el indice */
43         fp = fopen(idx->filename, "w");
44         PERR("Creando indice con nodo raiz");
45         if (fp == NULL) {
46                 PERR("Error al crear el archivo");
47                 return -1;
48         }
49         fclose(fp);
50         
51         /* Creamos el nodo raiz y lo guardamos el en indice */
52         raiz = b_plus_crearnodo(idx);
53         error = b_plus_grabar_nodo(idx,raiz,0);
54         
55         /* Liberamos areas de memoria reservadas */
56         free(raiz->claves);
57         free(raiz->hijos);
58         free(raiz);
59         
60         return error;
61 }
62
63
64 /** Busca el nro de bloque donde se debe guardar un reg con clave X.
65  *  Posibilidades: return 0 - Encontro un bloque potencial
66  *                 return -1 - No hay clave, inserto clave de nuevo bloques
67  *                 return 1 - Hubo falla de lectura de un nodo, Abortar
68  */
69 int emufs_b_plus_get_bloque(INDICE *idx, INDEX_DAT *query, int num_node) {
70
71         int i,exitcode = 0;
72         NODO_B_PLUS *nodo;
73         nodo = b_plus_leer_nodo(idx,num_node);
74         if (nodo == NULL) return 1;
75         i = nodo->cant_claves - 1;
76                 
77         /* Si es un hoja, busco dentro de la hoja, otherwise, busco la hoja */
78         if (nodo->nivel == 0) {
79         /* Vemos en que bloque deberia ir */
80                 while ( i >= 0 && emufs_indice_es_menor(idx,query->clave,nodo->claves[i])) i--;
81                 if (i < 0) {
82                         /* La clave es menor que todas, debo insertarla */
83                         b_plus_destruir_nodo(nodo);                     
84                         /*emufs_b_plus_insertar(idx,query);     */
85                         return -1;
86                 }
87                 else {
88                         /* Encontre un bloque potencial */
89                         query->num_bloque = nodo->hijos[i];
90                         b_plus_destruir_nodo(nodo);                     
91                         return 0;
92                 }
93         }
94         else {
95                 /* Buscamos por donde descender al siguiente nivel */
96                 while ( i >= 0 && emufs_indice_es_menor(idx,query->clave,nodo->claves[i])) i--;
97         i++;
98         num_node = nodo->hijos[i];
99                 b_plus_destruir_nodo(nodo);
100                 exitcode = emufs_b_plus_get_bloque(idx,query,num_node);
101                 return exitcode;                
102         }
103 }
104
105 NODO_B_PLUS *b_plus_leer_nodo(INDICE *idx, int num_node) {
106
107         /*int i = 0;*/
108         FILE *fp;
109         NODO_B_PLUS *memnode = b_plus_crearnodo(idx);   
110         char *disknode = (char*)malloc(idx->tam_bloque);
111         
112         if (num_node < 0) {
113                 PERR("Se intento leer nodo negativo!!\n");
114                 exit(1);
115         }
116         if (disknode == NULL) return NULL;
117         if (memnode == NULL) return NULL;
118         
119     /* Open up file */
120         fp = fopen(idx->filename, "r+");
121         if (fp == NULL) {
122                 free(disknode);
123                 b_plus_destruir_nodo(memnode);
124                 return NULL;
125         }
126
127         /* Intentamos leer un nodo, sino podemos error! */
128         fseek(fp, num_node*idx->tam_bloque, SEEK_SET);
129         if (fread(disknode, idx->tam_bloque, 1, fp) != 1) {
130                 free(disknode);
131                 fclose(fp);
132                 return NULL;
133         }
134         fclose(fp);
135         
136         /* Pudimos leer un nodo de disco, ahora lo transformamos a nodo mem */
137         memcpy(memnode,disknode,SIZE_B_PLUS_HEADER);
138         memcpy(memnode->claves,disknode+SIZE_B_PLUS_HEADER,idx->size_claves);
139         memcpy(memnode->hijos,disknode+SIZE_B_PLUS_HEADER+idx->size_claves,idx->size_hijos);
140         free(disknode);
141         
142         /*printf("Dumping Node_%i\n",num_node);
143         printf("Nivel: %i  Cant Claves: %i\n",memnode->nivel,memnode->cant_claves);
144         printf("Claves:");
145         for (i = 0; i < idx->size_claves/sizeof(CLAVE); ++i) printf(" %i",memnode->claves[i].i_clave);
146         printf("\nHijos:");
147         for (i = 0; i < idx->size_hijos/sizeof(int); ++i) printf(" %i",memnode->hijos[i]);
148         printf("\nEnd Dump\n"); */
149         
150         return memnode;
151         
152 }
153
154 int b_plus_grabar_nodo(INDICE *idx, NODO_B_PLUS *nodo, int num_node)
155 {
156         FILE *fp;
157         
158         fp = fopen(idx->filename, "r+");
159         if (fp == NULL) return -1;
160                 
161         fseek(fp,num_node*(SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos),SEEK_SET);      
162         fwrite(nodo,SIZE_B_PLUS_HEADER,1,fp);
163         fwrite(nodo->claves,idx->size_claves,1,fp);
164         fwrite(nodo->hijos,idx->size_hijos,1,fp);
165         fclose(fp);
166         
167         return 0;
168 }
169
170 int b_plus_destruir_nodo(NODO_B_PLUS *nodo)
171 {
172         free(nodo->claves);
173         free(nodo->hijos);
174         free(nodo);
175         return 0;
176 }
177
178 int b_plus_split_child(INDICE *idx, int numparent, NODO_B_PLUS *parent, int ithchild, NODO_B_PLUS *fullnode)
179 {
180         /* locals */
181         int minclaves = ceil(idx->size_hijos/sizeof(CLAVE)/2)-1;
182         int numbrother,j = 0;
183         int es_interno = 1;
184         
185         NODO_B_PLUS *brother = b_plus_crearnodo(idx);
186         brother->nivel = fullnode->nivel; /* Idem nivel que el que se parte */
187         
188         /* Si estoy en una hoja, la parte derecha del partido tendra minclaves+1 */
189         /* pues el ancla se debe repetir ademas de subir */
190         if (brother->nivel == 0) {
191                 brother->cant_claves = minclaves+1;
192                 es_interno = 0;
193         }
194         else brother->cant_claves = minclaves;
195         
196         /* Copio las claves al brother derecho */
197         for (j = 0; j < brother->cant_claves; ++j)
198                 brother->claves[j] = fullnode->claves[j+minclaves+es_interno];
199         
200         /* Copio los hijos ya sea para hoja o no hoja. */
201         for (j = 0; j < brother->cant_claves+1; ++j)
202                 brother->hijos[j] = fullnode->hijos[j+minclaves+es_interno];
203         
204         /* Ahora me ocupo del nodo que se partio */
205         fullnode->cant_claves = minclaves;
206         /* Obtengo numero de nodo para brother y encadeno si es hoja */
207         numbrother = b_plus_get_num_nodo(idx);
208         if (fullnode->nivel == 0) fullnode->hijos[minclaves] = numbrother;
209         
210         /* Ahora fixeamos el padre, apuntando al nuevo hijo */
211         for (j = parent->cant_claves; j > ithchild; --j)
212                 parent->hijos[j+1] = parent->hijos[j];
213         parent->hijos[ithchild+1] = numbrother;
214         
215         /* Idem pero subo la median key */
216         for (j = parent->cant_claves-1; j >= ithchild; --j)
217                 parent->claves[j+1] = parent->claves[j];
218         parent->claves[ithchild] = fullnode->claves[minclaves];
219         parent->cant_claves++;
220         
221         /* Grabo los nodos en disco */
222         b_plus_grabar_nodo(idx,fullnode,parent->hijos[ithchild]);
223         b_plus_grabar_nodo(idx,brother,numbrother);
224         b_plus_grabar_nodo(idx,parent,numparent);
225         
226         b_plus_destruir_nodo(brother);
227         
228         return 0;
229 }
230
231
232 int b_plus_insert_nonfull(INDICE *idx, NODO_B_PLUS *nodo, int num_nodo, INDEX_DAT *query)
233 {
234     int i, num_nodo_hijo;
235     NODO_B_PLUS *hijo;
236     
237     i = nodo->cant_claves-1; 
238     if ( nodo->nivel == 0 ){
239                 /* Muevo siempre el encadenamiento */
240                 nodo->hijos[i+2] = nodo->hijos[i+1];
241                 /* Ahora muevo las claves y sus punteros a bloques del dat */
242         while ( i >= 0 && emufs_indice_es_menor(idx,query->clave,nodo->claves[i])){
243             nodo->claves[i+1] = nodo->claves[i];                        
244                         nodo->hijos[i+1] = nodo->hijos[i];
245             i--;
246         }
247         nodo->claves[i+1] = query->clave;
248                 nodo->hijos[i+1] = query->num_bloque;
249         nodo->cant_claves++;
250         b_plus_grabar_nodo(idx, nodo, num_nodo);
251     } else { 
252         while ( i >= 0 && emufs_indice_es_menor(idx,query->clave,nodo->claves[i])) 
253             i--;
254         i++;
255         num_nodo_hijo = nodo->hijos[i];
256         hijo = b_plus_leer_nodo(idx, num_nodo_hijo);
257         if ( hijo->cant_claves == idx->size_claves/sizeof(CLAVE) ) {
258             b_plus_split_child(idx, num_nodo, nodo, i, hijo);
259                         /* OjO Utilizo el menor pero con el proposito de clave > nodo->clave) */
260             if (emufs_indice_es_menor(idx,nodo->claves[i],query->clave))
261                 i++;
262         }
263                 if (hijo) b_plus_destruir_nodo(hijo);
264                 hijo = b_plus_leer_nodo(idx, nodo->hijos[i]);
265         b_plus_insert_nonfull(idx, hijo, nodo->hijos[i], query);
266                 if (hijo) b_plus_destruir_nodo(hijo);   
267     }
268         
269         return 0;
270 }    
271
272 int emufs_b_plus_insertar(INDICE *idx, INDEX_DAT *query)
273 {
274     NODO_B_PLUS *raiz;
275     
276     raiz = b_plus_leer_nodo(idx, 0);
277     if ( raiz->cant_claves == idx->size_claves/sizeof(CLAVE) ) {
278         NODO_B_PLUS *new_root = b_plus_crearnodo(idx);
279         new_root->nivel = raiz->nivel + 1;
280         new_root->hijos[0] = b_plus_get_num_nodo(idx);
281         b_plus_grabar_nodo(idx, raiz, new_root->hijos[0]);
282         b_plus_grabar_nodo(idx, new_root, 0);
283             b_plus_split_child(idx, 0, new_root, 0, raiz);
284         b_plus_insert_nonfull(idx, new_root, 0, query);
285                 b_plus_destruir_nodo(new_root);
286     } else 
287         {
288                 b_plus_insert_nonfull(idx, raiz, 0, query);
289         }
290         
291         b_plus_destruir_nodo(raiz);
292     
293     return 0;
294 }
295
296 /** Busca una clave dentro del arbol e indica si existe o no
297  *  Posibilidades: return 1 - Encontro la clave
298  *                 return 0 - No encontro la clave
299  *                 return -1 - Hubo falla de lectura de un nodo, Abortar
300  */
301 int b_plus_existe_clave(INDICE *idx, INDEX_DAT *query, int num_node)
302 {
303         int i,exitcode = 0;
304         NODO_B_PLUS *nodo;
305         nodo = b_plus_leer_nodo(idx,num_node);
306         if (nodo == NULL) return -1;
307         i = nodo->cant_claves - 1;
308                 
309         /* Si es un hoja, busco dentro de la hoja, otherwise, busco la hoja */
310         if (nodo->nivel == 0) {
311         /* Vemos si esta la clave */
312                 while ( i >= 0 && !emufs_indice_es_igual(idx,query->clave,nodo->claves[i])) i--;
313                 if (i < 0)
314                 {
315                         b_plus_destruir_nodo(nodo);
316                         return 0; /* No encontre la clave */
317                 } else  {
318                         /* Encontre la clave, guardo el nodo donde esta! */
319                         query->num_bloque = num_node;
320                         b_plus_destruir_nodo(nodo);
321                         return 1;
322                 }
323         }
324         else {
325                 /* Buscamos por donde descender al siguiente nivel */
326                 while ( i >= 0 && emufs_indice_es_menor(idx,query->clave,nodo->claves[i])) i--;
327         i++;
328         num_node = nodo->hijos[i];
329                 b_plus_destruir_nodo(nodo);
330                 exitcode = b_plus_existe_clave(idx,query,num_node);
331                 return exitcode;
332         }
333 }
334
335 int b_plus_cant_claves_nodo(INDICE *idx, int num_node)
336 {
337         NODO_B_PLUS *nodo =     b_plus_leer_nodo(idx,num_node);
338         if (nodo == NULL) return -1;
339         return nodo->cant_claves;
340 }
341
342 /* Search_Type: 0 - Predecesor, 1 - Sucesor
343    Exitcode: 1 - Encontre lo buscado, 0 - No lo encontre, -1 Error */
344 int b_plus_buscar_prepost(INDICE *idx, CLAVE key, int num_node, INDEX_DAT *prepostkey, int search_type)
345 {
346         int i = 0, exitcode = 0;
347         NODO_B_PLUS *child = NULL;
348         NODO_B_PLUS *nodo = b_plus_leer_nodo(idx,num_node);
349         if (nodo == NULL) return -1;
350         i = nodo->cant_claves - 1;
351         
352         if (nodo->nivel == 0) {         
353                 while ( i >= 0 && emufs_indice_es_menor(idx,key,nodo->claves[i])) --i;          
354                 switch (search_type) {                  
355                         /* Busco predecesor en la hoja */                       
356                         case 0: if (i <= 0) exitcode = 0;
357                                         else {                                          
358                                                 if (emufs_indice_es_igual(idx,nodo->claves[i],key))     {
359                                                         prepostkey->clave = nodo->claves[i-1];
360                                                         prepostkey->num_bloque = nodo->hijos[i-1];
361                                                 } else {
362                                                         prepostkey->clave = nodo->claves[i];
363                                                         prepostkey->num_bloque = nodo->hijos[i];
364                                                 }
365                                                 exitcode = 1;
366                                         }
367                                         break;                                  
368                         /* Busco sucesor en la hoja */                                                          
369                         case 1: if (i == nodo->cant_claves-1) exitcode = 0;
370                                         else {                                                                                          
371                                                 prepostkey->clave = nodo->claves[i+1];                                          
372                                                 prepostkey->num_bloque = nodo->hijos[i+1];
373                                                 exitcode = 1;
374                                         }
375                                         break;
376                 }                                                                                                                               
377         } else {
378                 /* Veo por que rama debo seguir buscando el pre o post */
379                 while ( i >= 0 && emufs_indice_es_menor(idx,key,nodo->claves[i])) --i;          
380                 if (search_type == 0) {
381                         if (i < 0) exitcode = b_plus_buscar_prepost(idx,key,nodo->hijos[i+1],prepostkey,search_type);
382                         else {
383                                 /* Busco primero por la rama derecha, sino por la izquierda */
384                                 exitcode = b_plus_buscar_prepost(idx,key,nodo->hijos[i+1],prepostkey,search_type);
385                                 if (exitcode == 0)                      
386                                         exitcode = b_plus_buscar_prepost(idx,key,nodo->hijos[i],prepostkey,search_type);
387                         }
388                         /* Handleo busqueda de clave menor o igual que todas */
389                         if (exitcode == 0) exitcode = -1;
390                 } else  {
391                         /* Busco un sucesor como get bloque */                  
392                         exitcode = b_plus_buscar_prepost(idx,key,nodo->hijos[i+1],prepostkey,search_type);
393                         /* Veo si tengo que devolver la clave izquierda del padre del que acabo de buscar */
394                         if (exitcode == 0) 
395                         {
396                                 if (i < nodo->cant_claves-1) {
397                                         child = b_plus_leer_nodo(idx,nodo->hijos[i+2]);                                 
398                                         prepostkey->clave = child->claves[0];
399                                         prepostkey->num_bloque = child->hijos[0];
400                                         exitcode = 1;
401                                 } else  exitcode = -1;
402                         }
403                 }               
404         }
405         
406         /* Libero y devuelvo exitcode */
407         b_plus_destruir_nodo(nodo);
408         return(exitcode);               
409 }
410
411 int emufs_b_plus_reemplazar_clave(INDICE *idx, CLAVE key, INDEX_DAT query, int num_node)
412 {
413         NODO_B_PLUS *nodo;
414         int i;
415         INDEX_DAT auxquery;
416         auxquery.clave = key;   
417                 
418         /* Comienzo buscando la clave y obteniendo el nodo en donde esta */
419         if (b_plus_existe_clave(idx,&auxquery,num_node) == 1) {                                 
420                 
421                 /* Levanto el nodo y busco donde esta la clave */               
422                 /*printf("El reemplazar encontro la clave %i y en el nodo %i\n",auxquery.clave.i_clave,(int)auxquery.num_bloque);*/
423                 nodo = b_plus_leer_nodo(idx,auxquery.num_bloque);
424                 if (nodo == NULL) return -1;
425                 i = nodo->cant_claves - 1;
426                 
427                 /* Busco la clave y reemplazo */
428                 while ( i >= 0 && !emufs_indice_es_igual(idx,key,nodo->claves[i])) --i;
429                 if (i < 0) return -1; /* Error, no esta la clave */
430                 
431                 /* Cheque por las dudas si es hoja o interno, aunque deberia ser hoja */
432                 if (nodo->nivel > 0) {                  
433                         nodo->claves[i] = query.clave;
434                 } else {
435                         nodo->claves[i] = query.clave;
436                         nodo->hijos[i] = query.num_bloque;
437                 }
438                 b_plus_grabar_nodo(idx,nodo,auxquery.num_bloque);
439                 b_plus_destruir_nodo(nodo);
440                 return 0;
441         }
442         else return -1;
443 }
444
445 int emufs_b_plus_eliminar(INDICE *idx, CLAVE key, int num_node)
446 {
447         INDEX_DAT prepostkey;
448         int i = 0,j = 0,minclaves = 0, nivel_mayor1 = 0,cant_claves_child = 0;
449         int cant_claves_rsibling = 0, cant_claves_lsibling = 0, es_hoja = 0;
450         int leftoffset = 0;
451         NODO_B_PLUS *nodo = b_plus_leer_nodo(idx,num_node);
452         NODO_B_PLUS *node_y,*node_z,*mergenode,*siblingnode;
453         if (nodo == NULL) { PERR("No leyo nodo bien"); return -1; }
454         i = nodo->cant_claves - 1;
455         minclaves = ceil(idx->size_hijos/sizeof(CLAVE)/2)-1;
456
457         /* Si es hoja, borro directamente la clave. No se producira underflow
458        pues lo asegura la recursividad del delete */    
459         if (nodo->nivel == 0) {         
460                 while ( i >= 0 && !emufs_indice_es_igual(idx,key,nodo->claves[i])) --i;
461                 if (i < 0) return -1;
462                 /* Encontre la clave en la pos i, la borro */
463                 for (j = i; j < nodo->cant_claves-1; ++j) {
464                         nodo->claves[j] = nodo->claves[j+1];
465                         nodo->hijos[j] = nodo->hijos[j+1];
466                 }
467                 nodo->hijos[j] = nodo->hijos[j+1];
468         nodo->cant_claves--;
469                 
470                 /* Grabo el nodo actualizado en disco */
471                 b_plus_grabar_nodo(idx,nodo,num_node);
472                 b_plus_destruir_nodo(nodo);
473                 return 0;
474         } else {
475                 /* Me debo fijar si esta la clave en este nodo interno, sino busco */           
476                 while ( i >= 0 && !emufs_indice_es_igual(idx,key,nodo->claves[i])) --i;
477                 if (i < 0) {
478                         PERR("Entre caso 3 del eliminar");                              
479                         /* No esta en este nodo interno, caso 3. Determino en que rama debe estar */
480                         i = nodo->cant_claves - 1;
481                         while ( i >= 0 && emufs_indice_es_menor(idx,key,nodo->claves[i])) --i;
482                 i++;
483                 cant_claves_child = b_plus_cant_claves_nodo(idx,nodo->hijos[i]);
484                         if (cant_claves_child > minclaves) emufs_b_plus_eliminar(idx,key,nodo->hijos[i]);
485                         else {
486                                 /* Vemos si estamos en caso 3a o 3b, mirando cant_claves de sus siblings */
487                                 if (i < nodo->cant_claves) cant_claves_rsibling = b_plus_cant_claves_nodo(idx,nodo->hijos[i+1]);
488                                 if (i > 0) cant_claves_lsibling = b_plus_cant_claves_nodo(idx,nodo->hijos[i-1]);
489                                 printf ("El sibling derecho si existe tiene %i claves\n", cant_claves_rsibling);
490                                 printf ("El sibling izquierdo si existe tiene %i claves\n", cant_claves_lsibling);      
491                                 if (cant_claves_rsibling > minclaves) {
492                                         /* El sibling derecho me dara una key mediante rotacion. Caso 3a */
493                                         PERR("Entre caso 3a right sibling del eliminar");
494                                         node_y = b_plus_leer_nodo(idx,nodo->hijos[i]);
495                                         node_z = b_plus_leer_nodo(idx,nodo->hijos[i+1]);
496                                         if (node_z->nivel == 0) es_hoja = 1;
497                                         /* Le bajo la del padre a NodeY y muevo el apropiado child de NodoZ a NodoY */
498                                         node_y->claves[cant_claves_child] = nodo->claves[i];
499                                         node_y->hijos[cant_claves_child+1] = node_y->hijos[cant_claves_child];
500                                         node_y->hijos[cant_claves_child+1-es_hoja] = node_z->hijos[0];
501                                         node_y->cant_claves++;
502                                         /* Le subo al padre desde el NodoZ, teniendo en cuenta si es hoja o no */
503                                         nodo->claves[i] = node_z->claves[es_hoja];
504                                         /* Hago shifting en el sibling para quitar la que subio */
505                                         for (j = 0; j < node_z->cant_claves-1; ++j) {
506                                                 node_z->claves[j] = node_z->claves[j+1];
507                                                 node_z->hijos[j] = node_z->hijos[j+1];
508                                         }
509                                         node_z->hijos[j] = node_z->hijos[j+1];
510                                 node_z->cant_claves--;
511                                         /* Grabo los cambios */                                 
512                                         b_plus_grabar_nodo(idx,node_z,nodo->hijos[i+1]);
513                                         b_plus_grabar_nodo(idx,node_y,nodo->hijos[i]);
514                                         b_plus_grabar_nodo(idx,nodo,num_node);
515                                         b_plus_destruir_nodo(node_y);
516                                         b_plus_destruir_nodo(node_z);                                   
517                                         /* Borro recursivamente KEY entrando por Child que ahora tiene minclaves+1 */
518                                         emufs_b_plus_eliminar(idx,key,nodo->hijos[i]);
519                                 }
520                                 else if (cant_claves_lsibling > minclaves) {
521                                                 /* el sibling izquierdo me dara una key mediante rotacion Caso 3a */
522                                                 PERR("Entre caso 3a left sibling del eliminar");
523                                                 node_z = b_plus_leer_nodo(idx,nodo->hijos[i]);  
524                                                 node_y = b_plus_leer_nodo(idx,nodo->hijos[i-1]);                                        
525                                                 if (node_z->nivel == 0) es_hoja = 1;
526                                             /* Hago lugar en NodoZ para la clave que bajara desde el padre */                                           
527                                                 /* Muevo el ultimo y restantes claves/punteros */
528                                                 j = node_z->cant_claves - 1;                                                                                            
529                                                 node_z->hijos[j+2] = node_z->hijos[j+1];
530                                         while (j >= 0){
531                                         node_z->claves[j+1] = node_z->claves[j];                        
532                                                         node_z->hijos[j+1] = node_z->hijos[j];
533                                         j--;
534                                         }                                               
535                                                 /* Hago la rotacion final segun sea hoja o no */
536                                                 if (es_hoja) {
537                                                         nodo->claves[i-1] = node_y->claves[cant_claves_lsibling-1];
538                                                         node_z->claves[0] = node_y->claves[cant_claves_lsibling-1];
539                                                         node_z->hijos[0] = node_y->hijos[cant_claves_lsibling-1];
540                                                         node_y->hijos[cant_claves_lsibling-1] = node_y->hijos[cant_claves_lsibling]; /* cadena */
541                                                         node_y->cant_claves--;
542                                                         node_z->cant_claves++;
543                                                 } else {
544                                                         node_z->claves[0] = nodo->claves[i-1];
545                                                         node_z->hijos[0] = node_y->hijos[cant_claves_lsibling];
546                                                         nodo->claves[i-1] = node_y->claves[cant_claves_lsibling-1];
547                                                         node_y->cant_claves--;
548                                                         node_z->cant_claves++;
549                                                 }
550                                                 /* Grabo los cambios */                                         
551                                                 b_plus_grabar_nodo(idx,node_y,nodo->hijos[i-1]);
552                                                 b_plus_grabar_nodo(idx,node_z,nodo->hijos[i]);
553                                                 b_plus_grabar_nodo(idx,nodo,num_node);
554                                                 b_plus_destruir_nodo(node_y);
555                                                 b_plus_destruir_nodo(node_z);                                   
556                                                 /* Borro recursivamente KEY entrando por Child que ahora tiene minclaves+1 */
557                                                 emufs_b_plus_eliminar(idx,key,nodo->hijos[i]);                                          
558                                         } else {
559                                                 /* Caso 3b, debo bajar una clave y unificar con sibling disponible */
560                                                 PERR("Entre caso 3b del eliminar");                                             
561                                                 if (cant_claves_lsibling == minclaves) {
562                                                         PERR("Hago merge con sibling izquierdo");
563                                                         leftoffset = 1;
564                                                         siblingnode = b_plus_leer_nodo(idx,nodo->hijos[i]);     /* Este es el root de la rama! */
565                                                         mergenode = b_plus_leer_nodo(idx,nodo->hijos[i-1]); /* Aca va todo */
566                                                 } else {
567                                                         PERR("Hago merge con sibling derecho");
568                                                         leftoffset = 0;
569                                                         mergenode = b_plus_leer_nodo(idx,nodo->hijos[i]);
570                                                         siblingnode = b_plus_leer_nodo(idx,nodo->hijos[i+1]);
571                                                 }
572                                                 
573                                                 /* Bajo una clave del Padre Nodo a MergeNode y muevo todo lo SiblingNode a MergeNode */
574                                                 /* Si es nivel mayor a 1, bajo clave, otherwise no bajo pues se repetiria */
575                                                 nivel_mayor1 = 0;
576                                                 if (nodo->nivel > 1) {
577                                                         nivel_mayor1 = 1;
578                                                         mergenode->claves[minclaves] = nodo->claves[i-leftoffset];                                                      
579                                                 }               
580                                                 for (j = 0; j < minclaves; ++j) mergenode->claves[j+minclaves+nivel_mayor1] = siblingnode->claves[j];
581                                                 for (j = 0; j < minclaves+1; ++j) mergenode->hijos[j+minclaves+nivel_mayor1] = siblingnode->hijos[j];
582                                                 mergenode->cant_claves = minclaves*2+nivel_mayor1;                                      
583                                                 
584                                                 /* Shifteo en el nodo padre NODO, para quitar la que bajo */
585                                                 for (j = i-leftoffset; j < nodo->cant_claves-1; ++j) {
586                                                         nodo->claves[j] = nodo->claves[j+1];
587                                                         nodo->hijos[j+1] = nodo->hijos[j+2];
588                                                 }
589                                                 nodo->cant_claves--;
590                                                 b_plus_grabar_nodo(idx,nodo,num_node);
591                                                 b_plus_grabar_nodo(idx,mergenode,nodo->hijos[i-leftoffset]);                                                                                                                                            
592                                                 b_plus_destruir_nodo(mergenode);
593                                                 b_plus_destruir_nodo(siblingnode);                                      
594                                                 /* Elimino recursivamente Key de la rama apropiada segun el Merge que se hizo */
595                                                 emufs_b_plus_eliminar(idx,key,nodo->hijos[i-leftoffset]);
596                                                 /* Caso muy particular, si hize un merge de la unica clave de una raiz con sus hijos */
597                                                 if ((nodo->nivel == 1) && (nodo->cant_claves == 0)) {
598                                                         /* Debo establecer como nueva raiz, el NodoY */
599                                                         mergenode = b_plus_leer_nodo(idx,nodo->hijos[i-leftoffset]);
600                                                         b_plus_grabar_nodo(idx,mergenode,0);
601                                                         truncate(idx->filename,SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos);
602                                                 }
603                                                 /* End 3b */                                            
604                                                 }
605                                         }                       
606                 } else {
607                         /* Esta en el nodo interno, caso 2 */
608                         cant_claves_child = b_plus_cant_claves_nodo(idx,nodo->hijos[i]);
609                         if (cant_claves_child > minclaves) {
610                                 PERR("Entre caso 2a del eliminar");                             
611                                 /* Caso 2a, comienzo buscando la clave previa inmediata */
612                                 b_plus_buscar_prepost(idx,key,nodo->hijos[i],&prepostkey,0);
613                                 /* La elimino recursivamente */
614                                 emufs_b_plus_eliminar(idx,prepostkey.clave,nodo->hijos[i]); /* CHEAT */
615                                 /* Remplazo mi clave key por la encontrada prekey */
616                                 nodo->claves[i] = prepostkey.clave;
617                                 b_plus_grabar_nodo(idx,nodo,num_node);
618                                 /* Remplazo la otra instancia de key en una hoja seguro por prekey */
619                                 emufs_b_plus_reemplazar_clave(idx,key,prepostkey,nodo->hijos[i+1]);
620                         } else { 
621                                 cant_claves_child = b_plus_cant_claves_nodo(idx,nodo->hijos[i+1]);
622                                 if (cant_claves_child > minclaves) {
623                                         PERR("Entre caso 2b del eliminar");
624                                         /* Caso 2b, comienzo buscando la clave sucesor inmediata */
625                                         b_plus_buscar_prepost(idx,key,nodo->hijos[i+1],&prepostkey,1);                                  
626                                         /* La elimino recursivamente */
627                                         emufs_b_plus_eliminar(idx,prepostkey.clave,nodo->hijos[i+1]); /* CHEAT */
628                                         /* Remplazo mi clave key por la encontrada postkey */
629                                         nodo->claves[i] = prepostkey.clave;
630                                         b_plus_grabar_nodo(idx,nodo,num_node);
631                                         /* Remplazo la otra instancia de key en una hoja seguro por postkey */
632                                         emufs_b_plus_reemplazar_clave(idx,key,prepostkey,nodo->hijos[i+1]);                                     
633                                 } else {
634                                         PERR("Entre caso 2c del eliminar");
635                                         /* Caso 2c debo hacer un merge de la clave con hijo izq y der */
636                                         node_y = b_plus_leer_nodo(idx,nodo->hijos[i]);
637                                         node_z = b_plus_leer_nodo(idx,nodo->hijos[i+1]);
638                                         /* Bajo la clave Key a NodoY y muevo todo lo de NodoZ a NodoY */
639                                         /* Si es nivel mayor a 1, bajo clave pues no esta en NodoZ, otherwise no bajo */
640                                         if (nodo->nivel > 1) {
641                                                 nivel_mayor1 = 1;
642                                                 node_y->claves[minclaves] = key;
643                                         }               
644                                         for (j = 0; j < minclaves; ++j) node_y->claves[j+minclaves+nivel_mayor1] = node_z->claves[j];
645                                         for (j = 0; j < minclaves+1; ++j) node_y->hijos[j+minclaves+nivel_mayor1] = node_z->hijos[j];
646                                         node_y->cant_claves = minclaves*2+nivel_mayor1;                                 
647                                         /* Shifteo en el nodo padre NODO, para quitar la que bajo */
648                                         for (j = i; j < nodo->cant_claves-1; ++j) {
649                                                 nodo->claves[j] = nodo->claves[j+1];
650                                                 nodo->hijos[j+1] = nodo->hijos[j+2];
651                                         }
652                                         nodo->cant_claves--;
653                                         b_plus_grabar_nodo(idx,nodo,num_node);
654                                         b_plus_grabar_nodo(idx,node_y,nodo->hijos[i]);
655                                         b_plus_destruir_nodo(node_y);
656                                         b_plus_destruir_nodo(node_z);                                   
657                                         /* Elimino recursivamente Key de NodeY, entrando por ese subtree */
658                                         emufs_b_plus_eliminar(idx,key,nodo->hijos[i]);                                  
659                                         /* Caso muy particular, si hize un merge de la unica clave de una raiz con sus hijos */
660                                         if ((nodo->nivel == 1) && (nodo->cant_claves == 0)) {
661                                                 /* Debo establecer como nueva raiz, el NodoY */
662                                                 node_y = b_plus_leer_nodo(idx,nodo->hijos[i]);
663                                                 b_plus_grabar_nodo(idx,node_y,0);
664                                                 truncate(idx->filename,SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos);
665                                                 b_plus_destruir_nodo(node_y);
666                                         }                                                                               
667                                 }
668                         }
669                 }                       
670                 /* Termine caso 2 o 3, libero el nodo */
671                 b_plus_destruir_nodo(nodo);
672                 return 0;                       
673         }
674         
675         return -1;
676 }
677
678 int b_plus_get_num_nodo(INDICE *idx)
679 {
680         FILE *fp;
681         int num;
682         
683         fp = fopen(idx->filename, "ab");
684         if (fp == NULL) return -1;
685     
686     num = ftell(fp)/(SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos);      
687     fclose(fp);
688     return num;
689 }
690
691 CLAVE emufs_b_plus_obtener_menor_clave(INDICE *idx) {
692         
693         CLAVE key;
694         NODO_B_PLUS *node;
695         int num_child = 0;
696         node = b_plus_leer_nodo(idx,0);
697         if (node == NULL) {
698                 key.i_clave = -1;
699                 return key;
700         }
701         
702         while (node->nivel > 0) {
703                 /* Deciendo por la rama de mas hacia la izquierda */            
704                 if (node->cant_claves > 0) {
705                         num_child = node->hijos[0];
706                         b_plus_destruir_nodo(node);                     
707                         node = b_plus_leer_nodo(idx,num_child);
708                 }
709                 else break;             
710         }
711         
712         /* Ahora estoy en la primer hoja del arbol, devuelvo la primer clave */
713         key = node->claves[0];
714         b_plus_destruir_nodo(node);
715         
716         return key;
717 }
718           
719 CLAVE emufs_b_plus_obtener_mayor_clave(INDICE *idx) {
720         
721         CLAVE key;
722         NODO_B_PLUS *node;
723         int num_child = 0, cant_claves = 0;
724         node = b_plus_leer_nodo(idx,0);
725         if (node == NULL) {
726                 key.i_clave = -1;
727                 return key;
728         }
729         
730         cant_claves = node->cant_claves;
731         while (node->nivel > 0) {
732                 /* Deciendo por la rama de mas hacia la derecha */              
733                 if (node->cant_claves > 0) {
734                         num_child = node->hijos[cant_claves];
735                         b_plus_destruir_nodo(node);                     
736                         node = b_plus_leer_nodo(idx,num_child);
737                         cant_claves = node->cant_claves;
738                 }
739                 else return key;                
740         }
741         
742         /* Ahora estoy en la primer hoja del arbol, devuelvo la ultima clave */
743         key = node->claves[cant_claves-1];
744         b_plus_destruir_nodo(node);
745         
746         return key;
747 }
748
749 CLAVE emufs_b_plus_obtener_sig_clave(EMUFS *emu, CLAVE key) {
750         
751         INDICE *idx = emu->indices;
752         INDEX_DAT query;
753         int i = 0;
754         query.clave = key;
755         
756         /* Si aun no tengo un array, obtengo uno */
757         if (emu->indices->keybucket == NULL) {
758                 /* Busco el ancla para esta key */
759                 emufs_b_plus_get_bloque(idx,&query,0);          
760                 idx->keybucket = emufs_tipo3_obtener_claves_raw(emu,query.num_bloque);
761                 printf ("\nLevante bloque nro: %li y obtuve un bucket con %i keys\n",query.num_bloque,idx->keybucket->cant_keys);                                               
762                 return (idx->keybucket->claves[0]);
763         } 
764         else {
765                 /* Veo si la ultima clave retornada es la ultima del array */
766                 if (idx->keybucket->current_key == idx->keybucket->cant_keys-1) {                       
767                         /* Debo obtener un nuevo bucket de claves */            
768                         if (b_plus_buscar_prepost(idx,idx->keybucket->claves[0],0,&query,1) != -1) {                            
769                                 idx->keybucket = emufs_tipo3_obtener_claves_raw(emu,query.num_bloque);                          
770                                 printf ("\nLevante bloque nro: %li y obtuve un bucket con %i keys\n",query.num_bloque,idx->keybucket->cant_keys);                               
771                                 printf ("\nLa primera clave del bucket que devuelvo es: %i\n",idx->keybucket->claves[0]);                               
772                         }
773                         else return key;
774                 }
775         }
776                 
777         /* Busco la clave en el array de atras hacia adelante. */
778         if (idx->keybucket->current_key < idx->keybucket->cant_keys-1) {
779                 i = idx->keybucket->cant_keys - 1;              
780                 while (i >= 0 && emufs_indice_es_menor(idx,key,idx->keybucket->claves[i])) --i;
781                 ++i;            
782                 idx->keybucket->current_key = i;                
783                 return (idx->keybucket->claves[i]);
784         }
785         else return key;
786 }