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