]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/indice_b.c
2e0ff5d64f543cd62aa173a67bb200298394c693
[z.facultad/75.06/emufs.git] / emufs / indice_b.c
1
2 #include "indice_b.h"
3 #include "common.h"
4
5 /* Cantidad de claves por nodo */
6 #define CANT_HIJOS(x) ((x->tam_bloque-sizeof(B_NodoHeader))/sizeof(B_NodoEntry))
7 #define CANT_NODOS(x) (CANT_HIJOS(x)+1)
8 #define MIN_HIJOS(x) (CANT_HIJOS(x)/2)
9
10 /* Auxiliares */
11 static void b_grabar_nodo(INDICE *idx, int id, char *data);
12 static int b_ultimo_id(INDICE *idx);
13 static char *b_leer_nodo(INDICE *idx, int id);
14 static char *b_crear_nodo(INDICE *idx, int *i);
15 static void b_leer_header(char *src, B_NodoHeader *header);
16 static void b_actualizar_header(char *src, B_NodoHeader *header);
17 static B_NodoEntry *b_leer_claves(char *src, B_NodoHeader *header);
18 static void b_insertar_en_nodo(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2);
19 const int b_elegir_izquierdo(INDICE *idx, int a, int b);
20
21 void emufs_indice_b_crear(INDICE *idx)
22 {
23         FILE *fp;
24         char *bloque;
25         B_NodoHeader header;
26
27         header.cant = 0;
28         header.nivel = 0;
29         header.padre = -1;
30         header.hijo_izquierdo = -1;
31
32         fp = fopen(idx->filename, "w");
33         PERR("Creando indice");
34         fprintf(stderr, "Archivo = (%s)\n", idx->filename);
35         if (fp == NULL) {
36                 PERR("Error al crear el archivo");
37                 return;
38         }
39         
40         /* Creo el archivo con el Nodo raiz */
41         bloque = (char *)malloc(idx->tam_bloque);
42         memset(bloque, -1, idx->tam_bloque);
43
44         memcpy(bloque, &header, sizeof(B_NodoHeader));
45
46         fwrite(bloque, idx->tam_bloque, 1, fp);
47         fclose(fp);
48 }
49
50 int emufs_indice_b_insertar(INDICE *idx, CLAVE clave, INDICE_DATO dato)
51 {
52         int i, nodo_id, padre_id;
53         B_NodoHeader header;
54         B_NodoEntry *claves;
55         char *nodo, *padre;
56         
57         /* Leo la raiz */
58         nodo = b_leer_nodo(idx, 0);
59         padre_id = nodo_id = 0;
60         padre = NULL;
61         while (nodo) {
62                 if (padre) free(padre);
63                 padre = nodo;
64                 padre_id = nodo_id;
65                 b_leer_header(nodo, &header);
66                 claves = b_leer_claves(nodo, &header);
67                 i=0;
68                 while ((i<header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) i++;
69                 if ((i<header.cant) && (emufs_indice_es_igual(idx, claves[i].clave, clave))) {
70                         /* CLAVE DUPLICADA! */
71                         return 0;
72                 } else {
73                         if (i == 0) {
74                                 if (header.nivel != 0) {
75                                         nodo = b_leer_nodo(idx, header.hijo_izquierdo);
76                                         nodo_id = header.hijo_izquierdo;
77                                 } else {
78                                         nodo = NULL;
79                                         nodo_id = -1;
80                                 }
81                         } else {
82                                 if (header.nivel != 0) {
83                                         nodo = b_leer_nodo(idx, claves[i-1].dato.bloque);
84                                         nodo_id = claves[i-1].dato.bloque;
85                                 } else {
86                                         nodo = NULL;
87                                         nodo_id = -1;
88                                 }
89                         }
90                 }
91         }
92
93         if (nodo) free(nodo);
94         nodo = padre;
95         nodo_id = padre_id;
96         b_insertar_en_nodo(idx, clave, dato, nodo_id, nodo, -1, -1);
97         return 1; /* Agregar OK! */
98 }
99
100 INDICE_DATO emufs_indice_b_buscar(INDICE *idx, CLAVE clave)
101 {
102         int i;
103         INDICE_DATO ret;
104         B_NodoHeader header;
105         B_NodoEntry *claves;
106         char *nodo, *tmp;
107         
108         /* Leo la raiz */
109         nodo = b_leer_nodo(idx, 0);
110         while (nodo) {
111                 b_leer_header(nodo, &header);
112                 claves = b_leer_claves(nodo, &header);
113                 i=0;
114                 while ((i<header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) i++;
115                 if (emufs_indice_es_igual(idx, claves[i].clave, clave)) {
116                                 ret = claves[i].dato;
117                                 free(nodo);
118                                 return ret;
119                 } else {
120                         tmp = nodo;
121                         if (i == 0) {
122                                 nodo = b_leer_nodo(idx, header.hijo_izquierdo);
123                         } else {
124                                 nodo = b_leer_nodo(idx, claves[i-1].dato.bloque);
125                         }
126                         free(tmp);
127                 }
128         }
129
130         /* Nodo no encontrado */
131         ret.id = ret.bloque = -1;
132         return ret;
133 }
134
135 static int b_ultimo_id(INDICE *idx)
136 {
137         int i;
138         FILE *fp;
139         fp = fopen(idx->filename, "r");
140         fseek(fp, 0, SEEK_END);
141         i = ftell(fp)/idx->tam_bloque;
142         fclose(fp);
143
144         return i;
145 }
146
147 static char *b_crear_nodo(INDICE *idx, int *id)
148 {
149         char *bloque;
150         B_NodoHeader header;
151
152         (*id) = b_ultimo_id(idx);
153
154         header.cant = 0;
155         header.nivel = 0;
156         header.hijo_izquierdo = -1;
157         header.padre = -1;
158
159         bloque = (char *)malloc(idx->tam_bloque);
160         memset(bloque, -1, idx->tam_bloque);
161         memcpy(bloque, &header, sizeof(B_NodoHeader));
162
163         b_grabar_nodo(idx, *id, bloque);
164
165         return bloque;
166 }
167
168 static char *b_leer_nodo(INDICE *idx, int id)
169 {
170         FILE *fp;
171         char *out;
172
173         if (id < 0) return NULL;
174
175         fp = fopen(idx->filename, "r");
176         if (fp == NULL) return NULL;
177
178         fseek(fp, id*idx->tam_bloque, SEEK_SET);
179
180         out = (char *)malloc(idx->tam_bloque);
181         if (out == NULL) {
182                 fclose(fp);
183                 return NULL;
184         }
185
186         if (fread(out, 1, idx->tam_bloque, fp) != idx->tam_bloque) {
187                 free(out);
188                 /* No se puso leer el nodo */
189                 fclose(fp);
190                 return NULL;
191         }
192
193         fclose(fp);
194         return out;
195 }
196
197 static void b_grabar_nodo(INDICE *idx, int id, char *data)
198 {
199         FILE *fp;
200
201 /*      if (id > b_ultimo_id()) {
202                 printf("AGREGANDO AL FINAL\n");
203                 fp = fopen(FILENAME, "a");
204                 if (fp == NULL) {
205                 _("No se pudo abrir archivo\n");
206                         return;
207                 }
208         } else {
209                 fp = fopen(FILENAME, "w");
210                 if (fp == NULL) {
211                 _("No se pudo abrir archivo\n");
212                         return;
213                 }
214                 fseek(fp, id*BLOCK_SIZE, SEEK_SET);
215                 printf("SOLO GUARDO DATA\n");
216         }*/
217
218         fp = fopen(idx->filename, "r+");
219         fseek(fp, id*idx->tam_bloque, SEEK_SET);
220         fwrite(data, 1, idx->tam_bloque, fp);
221         fclose(fp);
222 }
223
224 static void b_leer_header(char *src, B_NodoHeader *header)
225 {
226         if (!src) return;
227
228         memcpy(header, src, sizeof(B_NodoHeader));
229 }
230
231 static void b_actualizar_header(char *src, B_NodoHeader *header)
232 {
233         if (!src) return;
234         memcpy(src, header, sizeof(B_NodoHeader));
235 }
236
237 static B_NodoEntry *b_leer_claves(char *src, B_NodoHeader *header)
238 {
239         return (B_NodoEntry *)(src+sizeof(B_NodoHeader));
240 }
241
242 static void b_insertar_en_nodo(INDICE *idx, CLAVE clave, INDICE_DATO dato, int nodo_id, char *nodo, int hijo1, int hijo2)
243 {
244         char *padre, *nuevo;
245         int nuevo_id;
246         int i, j;
247         static int rompi=0;
248         char salir = 0;
249         B_NodoHeader nodo_header, nuevo_header;
250         B_NodoEntry *claves, *tmp_claves, *claves_nuevo;
251
252         do {
253                 if (!nodo) {
254                         /* CREAR NODO? */
255                         nodo = b_crear_nodo(idx, &nodo_id);
256                 }
257                 b_leer_header(nodo, &nodo_header);
258                 claves = b_leer_claves(nodo, &nodo_header);
259
260                 padre = b_leer_nodo(idx, nodo_header.padre);
261
262                 if (nodo_header.cant == CANT_HIJOS(idx)) {
263                         int total;
264                         nuevo = b_crear_nodo(idx, &nuevo_id);
265                         i=0;
266                         /* Creo una lista ordenada de los nodos a partir */
267                         tmp_claves = (B_NodoEntry *)malloc(sizeof(B_NodoEntry)*(nodo_header.cant+1));
268                         total = nodo_header.cant;
269                         while ((i<nodo_header.cant) && (emufs_indice_es_menor(idx, claves[i].clave, clave))) {
270                                 tmp_claves[i] = claves[i];
271                                 i++;
272                         }
273                         tmp_claves[i].clave = clave;
274                         tmp_claves[i].dato = dato;
275                         while (i < nodo_header.cant) {
276                                 tmp_claves[i+1] = claves[i];
277                                 i++;
278                         }
279                         
280                         /* Asigno a cada nodo lo que corresponde */
281                         b_leer_header(nuevo, &nuevo_header);
282
283                         nuevo_header.nivel = nodo_header.nivel;
284                         nodo_header.cant = total/2;
285                         nuevo_header.cant = total - nodo_header.cant;
286
287                         memset(claves, '*', idx->tam_bloque-sizeof(B_NodoHeader));
288                         for(j=0; j<nodo_header.cant; j++)
289                                 claves[j] = tmp_claves[j];
290
291                         claves_nuevo = b_leer_claves(nuevo, &nuevo_header);
292                         memset(claves_nuevo, '*', idx->tam_bloque-sizeof(B_NodoHeader));
293                         for(j=0; j<nuevo_header.cant; j++)
294                                 claves_nuevo[j] = tmp_claves[j+total/2+1];
295
296                         b_actualizar_header(nodo, &nodo_header);
297                         b_actualizar_header(nuevo, &nuevo_header);
298
299                         if (nodo_id != 0) {
300                                 clave = tmp_claves[total/2].clave;
301                                 dato.bloque = nuevo_id;
302
303                                 b_grabar_nodo(idx, nodo_id, nodo);
304                                 b_grabar_nodo(idx, nuevo_id, nuevo);
305                                 free(nodo);
306                                 free(nuevo);
307                                 free(tmp_claves);
308
309                                 hijo1 = nodo_id;
310                                 hijo2 = nuevo_id;
311
312                                 nodo = padre;
313                                 nodo_id = nodo_header.padre;
314                         } else {
315                                 /* Oops, parti el raiz, y este debe quedar en 0, lo paso a otro bloque
316                                  * y dejo el padre vacio
317                                  */
318                                 char *tmp_nuevo = b_crear_nodo(idx, &nodo_id);
319                                 memcpy(tmp_nuevo, nodo, idx->tam_bloque);
320                                 free(nodo);
321                                 nodo = tmp_nuevo;
322         
323                                 clave = tmp_claves[total/2].clave;
324                                 dato.bloque = nuevo_id;
325
326                                 b_grabar_nodo(idx, nuevo_id+1, nodo);
327                                 b_grabar_nodo(idx, nuevo_id, nuevo);
328                 
329                                 free(nodo);
330                                 free(nuevo);
331                                 free(tmp_claves);
332
333                                 hijo1 = nuevo_id+1;
334                                 hijo2 = nuevo_id;
335
336                                 /* Limpio al padre */
337                                 nuevo = b_leer_nodo(idx, 0);
338
339                                 b_leer_header(nuevo, &nuevo_header);
340                                 nuevo_header.cant = 0;
341                                 nuevo_header.padre = -1;
342                                 nuevo_header.nivel = nodo_header.nivel+1;
343                                 memset(nuevo, -1, idx->tam_bloque);
344                                 b_actualizar_header(nuevo, &nuevo_header);
345                                 b_grabar_nodo(idx, 0, nuevo);
346
347                                 nodo_id = 0;
348                                 nodo = nuevo;
349                                 rompi = 1;
350                         }
351                 } else {
352                         /* La clave entra en este nodo!! */
353                         i = 0;
354                         if (nodo_header.cant > 0) {
355                                 while ((emufs_indice_es_menor(idx, claves[i].clave, clave)) && (i < nodo_header.cant)) i++;
356                                 for(j=nodo_header.cant; j > i; j--)
357                                         claves[j] = claves[j-1];
358                         }
359                         nodo_header.cant++;
360                         claves[i].clave = clave;
361                         claves[i].dato = dato;
362                         nodo_header.hijo_izquierdo = b_elegir_izquierdo(idx, nodo_header.hijo_izquierdo, hijo1);
363
364                         b_actualizar_header(nodo, &nodo_header);
365                         b_grabar_nodo(idx, nodo_id, nodo);
366
367                         /* Debo actualizar los punteros al padre de los hijos */
368                         if (hijo1 != -1) {
369                                 nuevo = b_leer_nodo(idx, hijo1);
370                                 if (nuevo != NULL) {
371                                         b_leer_header(nuevo, &nuevo_header);
372                                         nuevo_header.padre = nodo_id;
373                                         b_actualizar_header(nuevo, &nuevo_header);
374                                         b_grabar_nodo(idx, hijo1, nuevo);
375                                         free(nuevo);
376                                 } else printf("FUCK! hijo1=%d no existe!\n", hijo1);
377                         }
378                         if (hijo2 != -1) {
379                                 nuevo = b_leer_nodo(idx, hijo2);
380                                 if (nuevo != NULL) {
381                                         b_leer_header(nuevo, &nuevo_header);
382                                         nuevo_header.padre = nodo_id;
383                                         b_actualizar_header(nuevo, &nuevo_header);
384                                         b_grabar_nodo(idx, hijo2, nuevo);
385                                         free(nuevo);
386                                 } else printf("FUCK! hijo2=%d no existe!\n", hijo2);
387                         }
388                         salir = 1;
389                 }
390         } while (!salir);
391 }
392
393 const int b_elegir_izquierdo(INDICE *idx, int a, int b)
394 {
395         int cual;
396         char *nodo1, *nodo2;
397         B_NodoHeader header1, header2;
398         B_NodoEntry *claves1, *claves2;
399
400         if (a==-1) return b;
401         if (b==-1) return a;
402
403         nodo1 = b_leer_nodo(idx, a);
404         nodo2 = b_leer_nodo(idx, b);
405
406         b_leer_header(nodo1, &header1);
407         b_leer_header(nodo2, &header2);
408
409         claves1 = b_leer_claves(nodo1, &header1);
410         claves2 = b_leer_claves(nodo2, &header2);
411
412         if (emufs_indice_es_menor(idx, claves1[0].clave, claves2[0].clave))
413                 cual = a;
414         else
415                 cual = b;
416
417         free(nodo1);
418         free(nodo2);
419         return cual;
420 }
421
422 INDICE_DATO *emufs_indice_b_buscar_muchos(INDICE *idx, CLAVE clave, int *cant)
423 {
424         /* Si el indice es primario no tiene sentido hacer nada */
425         if (idx->funcion == IND_PRIMARIO) {
426                 *cant = 0;
427                 return NULL;
428         }
429
430         /* TODO Implementar indices con repeticion */
431         return NULL;
432 }
433