]> git.llucax.com Git - z.facultad/75.06/emufs.git/blob - emufs/b_plus.c
b_plus_insertar_clave, deprecated and removed from source
[z.facultad/75.06/emufs.git] / emufs / b_plus.c
1 /** Arbol B+ */
2 #include "b_plus.h"
3 #define INDEXSPECS INDICE
4 /**#*#*#*#*#**#*#*#*#*#* Private prototypes*#*#*#*#*#**#*#*#*#*#**#*#*#*/
5 /* numerando los bloques */
6 int b_plus_grabar_nodo(INDEXSPECS *idx, NODO_B_PLUS *nodo, int num_node);
7 /*NODO_B_PLUS *b_plus_leer_nodo(INDEXSPECS *idx, int num_node);*/
8 NODO_B_PLUS *b_plus_crearnodo(INDEXSPECS *idx);
9 int b_plus_destruir_nodo(NODO_B_PLUS *nodo);
10 /*int b_plus_insertar_clave(INDEXSPECS *idx, INDEX_DAT *query);*/
11 int b_plus_split_child(INDEXSPECS *idx, int numparent, NODO_B_PLUS *parent, int ithchild, NODO_B_PLUS *fullnode);
12 int b_plus_insert_nonfull(INDEXSPECS *idx, NODO_B_PLUS *nodo, int num_nodo, INDEX_DAT *query);
13 int b_plus_insertar(INDEXSPECS *idx, INDEX_DAT *query);
14 int b_plus_get_num_nodo(INDEXSPECS *idx);
15 /**#*#*#*#*#**#*#*#*#*#*FIN PROTOTYPES*#*#*#*#*#**#*#*#*#*#**#*#*#*#*#*/
16
17 /** Crea un nuevo nodo y lo inicializa */
18 NODO_B_PLUS *b_plus_crearnodo(INDEXSPECS *idx) {
19         
20         NODO_B_PLUS *nodo = (NODO_B_PLUS*)malloc(sizeof(NODO_B_PLUS));
21         if (nodo == NULL) return NULL;
22         nodo->nivel = 0;
23         nodo->cant_claves = 0;
24
25     /* Calculamos lo que ocupan las cadenas de bytes claves + hijos */
26         nodo->claves = (int*)malloc(idx->size_claves);
27         nodo->hijos = (int*)malloc(idx->size_hijos);
28         memset(nodo->claves,-1,idx->size_claves);
29         memset(nodo->hijos,-1,idx->size_hijos);
30         
31     return nodo;        
32 }
33
34 /** Crea el archivo indice B+ */
35 int emufs_b_plus_crear(INDEXSPECS *idx) {
36         
37         FILE *fp;
38         NODO_B_PLUS *raiz;
39         int error = 0;
40                 
41         /* Creamos el archivo que contendra el indice */
42         fp = fopen(idx->filename, "w");
43         PERR("Creando indice con nodo raiz");
44         if (fp == NULL) {
45                 PERR("Error al crear el archivo");
46                 return -1;
47         }
48         fclose(fp);
49         
50         /* Creamos el nodo raiz y lo guardamos el en indice */
51         raiz = b_plus_crearnodo(idx);
52         error = b_plus_grabar_nodo(idx,raiz,0);
53         
54         /* Liberamos areas de memoria reservadas */
55         free(raiz->claves);
56         free(raiz->hijos);
57         free(raiz);
58         
59         return error;
60 }
61
62
63 /** Busca el nro de bloque donde se debe guardar un reg con clave X.
64  *  Posibilidades: return 0 - Encontro un bloque potencial
65  *                 return -1 - No hay clave, inserto clave de nuevo bloques
66  *                 return 1 - Hubo falla de lectura de un nodo, Abortar
67  */
68 int emufs_b_plus_get_bloque(INDEXSPECS *idx, INDEX_DAT *query, int num_node) {
69
70         NODO_B_PLUS *nodo;
71         nodo = b_plus_leer_nodo(idx,num_node);
72         if (nodo == NULL) return 1;
73         int i = nodo->cant_claves - 1;
74         int exitcode = 0;
75         
76         /* Si es un hoja, busco dentro de la hoja, otherwise, busco la hoja */
77         if (nodo->nivel == 0) {
78         /* Vemos en que bloque deberia ir */
79                 while ( i >= 0 && query->clave.i_clave < nodo->claves[i] ) i--;
80                 if (i < 0) {
81                         /* La clave es menor que todas, debo insertarla */
82                         b_plus_destruir_nodo(nodo);                     
83                         emufs_b_plus_insertar(idx,query);                       
84                         return -1;
85                 }
86                 else {
87                         /* Encontre un bloque potencial */
88                         query->num_bloque = nodo->hijos[i];
89                         b_plus_destruir_nodo(nodo);                     
90                         return 0;
91                 }
92         }
93         else {
94                 /* Buscamos por donde descender al siguiente nivel */
95                 while ( i >= 0 && query->clave.i_clave < nodo->claves[i] ) i--;
96         i++;
97         num_node = nodo->hijos[i];
98                 b_plus_destruir_nodo(nodo);
99                 exitcode = emufs_b_plus_get_bloque(idx,query,num_node);
100                 return exitcode;                
101         }
102 }
103
104 NODO_B_PLUS *b_plus_leer_nodo(INDEXSPECS *idx, int num_node) {
105
106         /*int i = 0;*/
107         FILE *fp;
108         NODO_B_PLUS *memnode = b_plus_crearnodo(idx);   
109         char *disknode = (char*)malloc(idx->tam_bloque);
110         
111         if (num_node < 0) {
112                 PERR("Se intento leer nodo negativo!!\n");
113                 exit(1);
114         }
115         if (disknode == NULL) return NULL;
116         if (memnode == NULL) return NULL;
117         
118     /* Open up file */
119         fp = fopen(idx->filename, "r+");
120         if (fp == NULL) {
121                 free(disknode);
122                 b_plus_destruir_nodo(memnode);
123                 return NULL;
124         }
125
126         /* Intentamos leer un nodo, sino podemos error! */
127         fseek(fp, num_node*idx->tam_bloque, SEEK_SET);
128         if (fread(disknode, idx->tam_bloque, 1, fp) != 1) {
129                 free(disknode);
130                 fclose(fp);
131                 return NULL;
132         }
133         fclose(fp);
134         
135         /* Pudimos leer un nodo de disco, ahora lo transformamos a nodo mem */
136         memcpy(memnode,disknode,SIZE_B_PLUS_HEADER);
137         memcpy(memnode->claves,disknode+SIZE_B_PLUS_HEADER,idx->size_claves);
138         memcpy(memnode->hijos,disknode+SIZE_B_PLUS_HEADER+idx->size_claves,idx->size_hijos);
139         free(disknode);
140         
141         /*printf("Dumping Node_%i\n",num_node);
142         printf("Nivel: %i  Cant Claves: %i\n",memnode->nivel,memnode->cant_claves);
143         printf("Claves:");
144         for (i = 0; i < idx->size_claves/sizeof(int); ++i) printf(" %i",memnode->claves[i]);
145         printf("\nHijos:");
146         for (i = 0; i < idx->size_hijos/sizeof(int); ++i) printf(" %i",memnode->hijos[i]);
147         printf("\nEnd Dump\n"); */
148         
149         return memnode;
150         
151 }
152
153 int b_plus_grabar_nodo(INDEXSPECS *idx, NODO_B_PLUS *nodo, int num_node)
154 {
155         FILE *fp;
156         
157         fp = fopen(idx->filename, "r+");
158         if (fp == NULL) return -1;
159                 
160         fseek(fp,num_node*(SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos),SEEK_SET);      
161         fwrite(nodo,SIZE_B_PLUS_HEADER,1,fp);
162         fwrite(nodo->claves,idx->size_claves,1,fp);
163         fwrite(nodo->hijos,idx->size_hijos,1,fp);
164         fclose(fp);
165         
166         return 0;
167 }
168
169 int b_plus_destruir_nodo(NODO_B_PLUS *nodo)
170 {
171         free(nodo->claves);
172         free(nodo->hijos);
173         free(nodo);
174         return 0;
175 }
176
177 int b_plus_split_child(INDEXSPECS *idx, int numparent, NODO_B_PLUS *parent, int ithchild, NODO_B_PLUS *fullnode)
178 {
179         /* locals */
180         int minclaves = ceil(idx->size_hijos/sizeof(int)/2)-1;
181         int numbrother,j = 0;
182         int es_interno = 1;
183         
184         NODO_B_PLUS *brother = b_plus_crearnodo(idx);
185         brother->nivel = fullnode->nivel; /* Idem nivel que el que se parte */
186         
187         /* Si estoy en una hoja, la parte derecha del partido tendra minclaves+1 */
188         /* pues el ancla se debe repetir ademas de subir */
189         if (brother->nivel == 0) {
190                 brother->cant_claves = minclaves+1;
191                 es_interno = 0;
192         }
193         else brother->cant_claves = minclaves;
194         
195         /* Copio las claves al brother derecho */
196         for (j = 0; j < brother->cant_claves; ++j)
197                 brother->claves[j] = fullnode->claves[j+minclaves+es_interno];
198         
199         /* Copio los hijos ya sea para hoja o no hoja. */
200         for (j = 0; j < brother->cant_claves+1; ++j)
201                 brother->hijos[j] = fullnode->hijos[j+minclaves+es_interno];
202         
203         /* Ahora me ocupo del nodo que se partio */
204         fullnode->cant_claves = minclaves;
205         /* Obtengo numero de nodo para brother y encadeno si es hoja */
206         numbrother = b_plus_get_num_nodo(idx);
207         if (fullnode->nivel == 0) fullnode->hijos[minclaves] = numbrother;
208         
209         /* Ahora fixeamos el padre, apuntando al nuevo hijo */
210         for (j = parent->cant_claves; j > ithchild; --j)
211                 parent->hijos[j+1] = parent->hijos[j];
212         parent->hijos[ithchild+1] = numbrother;
213         
214         /* Idem pero subo la median key */
215         for (j = parent->cant_claves-1; j >= ithchild; --j)
216                 parent->claves[j+1] = parent->claves[j];
217         parent->claves[ithchild] = fullnode->claves[minclaves];
218         parent->cant_claves++;
219         
220         /* Grabo los nodos en disco */
221         b_plus_grabar_nodo(idx,fullnode,parent->hijos[ithchild]);
222         b_plus_grabar_nodo(idx,brother,numbrother);
223         b_plus_grabar_nodo(idx,parent,numparent);
224         
225         b_plus_destruir_nodo(brother);
226         
227         return 0;
228 }
229
230
231 int b_plus_insert_nonfull(INDEXSPECS *idx, NODO_B_PLUS *nodo, int num_nodo, INDEX_DAT *query)
232 {
233     int i, num_nodo_hijo;
234     NODO_B_PLUS *hijo;
235     
236     i = nodo->cant_claves-1; 
237     if ( nodo->nivel == 0 ){
238         while ( i >= 0 && query->clave.i_clave < nodo->claves[i] ){
239             nodo->claves[i+1] = nodo->claves[i];
240                         nodo->hijos[i+2] = nodo->hijos[i+1];
241                         nodo->hijos[i+1] = nodo->hijos[i];
242             i--;
243         }
244         nodo->claves[i+1] = query->clave.i_clave;
245                 nodo->hijos[i+1] = query->num_bloque;
246         nodo->cant_claves++;
247         b_plus_grabar_nodo(idx, nodo, num_nodo);
248     } else { 
249         while ( i >= 0 && query->clave.i_clave < nodo->claves[i] ) 
250             i--;
251         i++;
252         num_nodo_hijo = nodo->hijos[i];
253         hijo = b_plus_leer_nodo(idx, num_nodo_hijo);
254         if ( hijo->cant_claves == idx->size_claves/sizeof(int) ) {
255             b_plus_split_child(idx, num_nodo, nodo, i, hijo);
256             if ( query->clave.i_clave > nodo->claves[i] )
257                 i++;
258         }
259                 if (hijo) b_plus_destruir_nodo(hijo);
260                 hijo = b_plus_leer_nodo(idx, nodo->hijos[i]);
261         b_plus_insert_nonfull(idx, hijo, nodo->hijos[i], query);
262                 if (hijo) b_plus_destruir_nodo(hijo);   
263     }
264         
265         return 0;
266 }    
267
268 int emufs_b_plus_insertar(INDEXSPECS *idx, INDEX_DAT *query)
269 {
270     NODO_B_PLUS *raiz;
271     
272     raiz = b_plus_leer_nodo(idx, 0);
273     if ( raiz->cant_claves == idx->size_claves/sizeof(int) ) {
274         NODO_B_PLUS *new_root = b_plus_crearnodo(idx);
275         new_root->nivel = raiz->nivel + 1;
276         new_root->hijos[0] = b_plus_get_num_nodo(idx);
277         b_plus_grabar_nodo(idx, raiz, new_root->hijos[0]);
278         b_plus_grabar_nodo(idx, new_root, 0);
279             b_plus_split_child(idx, 0, new_root, 0, raiz);
280         b_plus_insert_nonfull(idx, new_root, 0, query);
281                 b_plus_destruir_nodo(new_root);
282     } else 
283         {
284                 b_plus_insert_nonfull(idx, raiz, 0, query);
285         }
286         
287         b_plus_destruir_nodo(raiz);
288     
289     return 0;
290 }
291
292 int b_plus_get_num_nodo(INDEXSPECS *idx)
293 {
294         FILE *fp;
295         int num;
296         
297         fp = fopen(idx->filename, "ab");
298         if (fp == NULL) return -1;
299     
300     num = ftell(fp)/(SIZE_B_PLUS_HEADER+idx->size_claves+idx->size_hijos);
301         printf("Num Nodo Nuevo: %i\n",num);
302     fclose(fp);
303     return num;
304 }