]> git.llucax.com Git - z.facultad/75.52/treemulator.git/blob - src/btree.cpp
Fix Memory leaks
[z.facultad/75.52/treemulator.git] / src / btree.cpp
1
2 #include "btree.h"
3
4 BTree::BTree (const std::string &name, unsigned int block_size, int kt, bool create_new_file)
5 {
6         key_type = kt;
7         uchar *node;
8         BTreeNodeHeader nh;
9
10         fp = fopen (name.c_str(), "wb+");
11         if (!fp) {
12                 /* TODO : mandar una exception ? */
13                 return;
14         }
15
16         /* Nombre de archivo */
17         filename = name;
18         
19         /* Inicializo el header */
20         header.block_size = block_size;
21         WriteFileHeader ();
22
23         /* Creo el primer bloque vacio */
24         node = new uchar[block_size];
25         ReadNodoHeader (node, &nh);
26         nh.level = 0;
27         nh.free_space = block_size - sizeof (BTreeNodeHeader);
28         nh.item_count = 0;
29         WriteNodoHeader (node, &nh);
30         WriteBlock (node, 0);
31
32         delete [] node;
33 }
34
35 BTree::~BTree ()
36 {
37         fclose (fp);
38 }
39
40 void BTree::WriteFileHeader ()
41 {
42         fseek (fp, 0L, SEEK_SET);
43         fwrite (&header, 1, sizeof (BTreeFileHeader), fp);
44 }
45
46 void BTree::WriteBlock (uchar *block, uint num)
47 {
48         fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET);
49         fwrite (block, 1, header.block_size, fp);
50 }
51
52 void BTree::AddKey (const Clave &k)
53 {
54         uint left, right;
55         Clave *kout = AddKeyR (&k, 0, left, right);
56
57         if (kout) {
58                 unsigned short level;
59                 /* Debo dejar la raiz en el nodo 0, por lo que paso el nodo
60                  * que esta usando el hijo izquierdo a un nuevo nodo */
61                 std::list<BTreeData *> node_keys;
62                 BTreeNodeHeader node_header;
63                 uchar *node = ReadBlock (left);
64                 ReadNodoHeader (node, &node_header);
65                 node_keys = ReadKeys (node, node_header);
66                 level = node_header.level + 1;
67
68                 uchar *new_node = NewBlock (left);
69                 delete [] new_node; /* No me interesa, voy a usar lo leio antes */
70                 
71                 WriteKeys (node, node_header, node_keys);
72                 WriteNodoHeader (node, &node_header);
73                 WriteBlock (node, left);
74                 DeleteKeys (node_keys);
75                 delete [] node;
76
77                 /* Leo y actualizo la Raiz */
78                 node = ReadBlock (0);
79                 ReadNodoHeader (node, &node_header);
80                 node_keys = std::list<BTreeData *>();
81
82                 node_keys.push_back (new BTreeChildData (left));
83                 node_keys.push_back (new BTreeData (kout, right));
84
85                 node_header.level = level;
86                 node_header.item_count = 1;
87
88                 WriteKeys (node, node_header, node_keys);
89                 WriteNodoHeader (node, &node_header);
90                 WriteBlock (node, 0);
91                 delete [] node;
92                 DeleteKeys (node_keys);
93                 PrintNode (0);
94
95                 delete kout;
96         }
97 }
98
99 Clave* BTree::AddKeyR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
100 {
101         uchar *node = ReadBlock (node_num);
102         BTreeNodeHeader node_header;
103         ReadNodoHeader (node, &node_header);
104         delete [] node;
105
106         if (node_header.level == 0)
107                 return AddKeyLeafR (k, node_num, left_child, right_child);
108
109         return AddKeyOtherR (k, node_num, left_child, right_child);
110 }
111
112 Clave* BTree::AddKeyLeafR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
113 {
114         Clave *kout = NULL;
115         std::list<BTreeData *> node_keys;
116
117         BTreeData *data = new BTreeLeafData (k->Clone ());
118
119         /* Leo el nodo raiz para empezar a agregar */
120         uchar *node = ReadBlock (node_num);
121         BTreeNodeHeader node_header;
122         ReadNodoHeader (node, &node_header);
123
124         if (node_header.free_space > data->Size ()) {
125                 BTreeData *datait;
126                 node_keys = ReadKeys (node, node_header);
127                 std::list<BTreeData *>::iterator it = node_keys.begin ();
128
129                 while (it != node_keys.end ()) {
130                         datait = (*it);
131                         if ((*data) < (*datait))
132                                 /* Me pase, lo agrego aca! */
133                                 break;
134                         it++;
135                 }
136                 node_keys.insert (it, data);
137                 WriteKeys (node, node_header, node_keys);
138                 WriteNodoHeader (node, &node_header);
139                 WriteBlock (node, node_num);
140                 DeleteKeys (node_keys);
141                 delete [] node;
142
143                 PrintNode (node_num);
144         } else {
145                 /* Split : Creo e inicializo el nuevo nodo */
146                 std::list<BTreeData *> new_node_keys;
147                 std::list<BTreeData *> old_node_keys;
148                 BTreeNodeHeader new_node_header;
149                 uint new_node_num;
150                 uchar *new_node = NewBlock (new_node_num);
151                 ReadNodoHeader (new_node, &new_node_header);
152                 new_node_header.level = node_header.level;
153
154                 node_keys = ReadKeys (node, node_header);
155                 new_node_keys = ReadKeys (new_node, new_node_header);
156
157                 /* Agrego la clave en la lista que ya tengo de manera ordenada */
158                 std::list<BTreeData *>::iterator it = node_keys.begin ();
159                 std::list<BTreeData *>::iterator previt = node_keys.begin ();
160
161                 while (it != node_keys.end ()) {
162                         BTreeData *datait;
163                         datait = (*it);
164                         if ((*data) < (*datait))
165                                 /* Me pase, lo agrego aca! */
166                                 break;
167                         previt = it;
168                         it++;
169                 }
170                 if (it != node_keys.end ())
171                         node_keys.insert (it, data);
172                 else
173                         node_keys.push_back (data);
174
175                 /* Tengo que guardar claves hasta ocupar nodo size/2 en cada nodo
176                  * y subir la clave del medio */
177                 node_header.item_count = 0;
178                 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
179
180                 uint total_size = 0;
181                 it = node_keys.begin ();
182                 while (it != node_keys.end ()) {
183                         BTreeData *datait;
184                         datait = (*it);
185                         total_size += datait->Size ();
186                         it++;
187                         /* Hack : Si me quedo con todas las claves, en el caso de ser
188                          * del mismo tama#o se desbalancea. Hay que ver que efecto 
189                          * puede tener en el caso de claves de long. variable
190                          */
191                         if (it == node_keys.end ())
192                                 total_size -= datait->Size ();
193                 }
194
195                 it = node_keys.begin ();
196                 uint used = 0;
197                 while (used < total_size/2) {
198                         BTreeData *d = (*it);
199                         old_node_keys.push_back (d);
200                         used += d->Size ();
201                         it++;
202                 }
203                 kout = (*it++)->getClave (); // Esta se retorna al "padre" para que se la agregue
204
205                 while (it != node_keys.end ()) {
206                         BTreeData *d = (*it);
207                         new_node_keys.push_back (d);
208                         it++;
209                 }
210         
211                 /* Guardo */
212                 WriteKeys (node, node_header, old_node_keys);
213                 WriteNodoHeader (node, &node_header);
214                 WriteBlock (node, node_num);
215                 WriteKeys (new_node, new_node_header, new_node_keys);
216                 WriteNodoHeader (new_node, &new_node_header);
217                 WriteBlock (new_node, new_node_num);
218                 DeleteKeys (old_node_keys);
219                 DeleteKeys (new_node_keys);
220
221                 PrintNode (node_num);
222                 PrintNode (new_node_num);
223
224                 /* Paso los hijos */
225                 left_child = node_num;
226                 right_child = new_node_num;
227                 delete [] new_node;
228                 delete [] node;
229         }
230
231         return kout;
232 }
233
234 Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
235 {
236         Clave *kout = NULL;
237         std::list<BTreeData *> node_keys;
238
239         BTreeData *data = new BTreeLeafData (k->Clone ());
240
241         /* Leo el nodo raiz para empezar a agregar */
242         uchar *node = ReadBlock (node_num);
243         BTreeNodeHeader node_header;
244         ReadNodoHeader (node, &node_header);
245
246         node_keys = ReadKeys (node, node_header);
247
248         std::list<BTreeData *>::iterator it = node_keys.begin ();
249         std::list<BTreeData *>::iterator posterior;
250         std::list<BTreeData *>::iterator ultima;
251         
252         /* Se supone que la primera es un hijo :) */
253         BTreeData *lchild = (*it++);
254         posterior = it;
255
256         while (it != node_keys.end ()) {
257                 if ((*data) < (*(*it)))
258                         break;
259                 ultima = it;
260                 it++;
261         }
262
263         if (it == posterior) {
264                 k = AddKeyR (k, lchild->getChild (), left_child, right_child);
265         } else {
266                 k = AddKeyR (k, (*ultima)->getChild (), left_child, right_child);
267         }
268         DeleteKeys (node_keys);
269
270         /* Nada que hacer */
271         if (data) delete data;
272         if (!k) {
273                 delete [] node;
274                 return NULL;
275         }
276
277         data = new BTreeData (k->Clone (), right_child);
278
279         if (node_header.free_space > data->Size ()) {
280                 BTreeData *datait;
281                 node_keys = ReadKeys (node, node_header);
282                 std::list<BTreeData *>::iterator it = node_keys.begin ();
283
284                 while (it != node_keys.end ()) {
285                         datait = (*it);
286                         if ((*data) < (*datait))
287                                 /* Me pase, lo agrego aca! */
288                                 break;
289                         it++;
290                 }
291                 node_keys.insert (it, data);
292                 WriteKeys (node, node_header, node_keys);
293                 WriteNodoHeader (node, &node_header);
294                 WriteBlock (node, node_num);
295                 DeleteKeys (node_keys);
296                 delete [] node;
297
298                 PrintNode (node_num);
299         } else {
300                 /* Split : Creo e inicializo el nuevo nodo */
301                 std::list<BTreeData *> new_node_keys;
302                 std::list<BTreeData *> old_node_keys;
303                 BTreeNodeHeader new_node_header;
304                 uint new_node_num;
305                 uchar *new_node = NewBlock (new_node_num);
306                 ReadNodoHeader (new_node, &new_node_header);
307                 new_node_header.level = node_header.level;
308
309                 node_keys = ReadKeys (node, node_header);
310                 new_node_keys = ReadKeys (new_node, new_node_header);
311
312                 /* Agrego la clave en la lista que ya tengo de manera ordenada */
313                 std::list<BTreeData *>::iterator it = node_keys.begin ();
314                 std::list<BTreeData *>::iterator previt = node_keys.begin ();
315
316                 previt = ++it;
317         
318                 while (it != node_keys.end ()) {
319                         BTreeData *datait;
320                         datait = (*it);
321                         if ((*data) < (*datait))
322                                 /* Me pase, lo agrego aca! */
323                                 break;
324                         previt = it;
325                         it++;
326                 }
327                 if (it != node_keys.end ())
328                         node_keys.insert (it, data);
329                 else
330                         node_keys.push_back (data);
331
332                 /* Tengo que guardar claves hasta ocupar nodo size/2 en cada nodo
333                  * y subir la clave del medio */
334                 node_header.item_count = 0;
335                 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
336
337                 uint total_size = 0;
338                 it = node_keys.begin ();
339                 while (it != node_keys.end ()) {
340                         BTreeData *datait;
341                         datait = (*it);
342                         total_size += datait->Size ();
343                         it++;
344                         /* Hack : Si me quedo con todas las claves, en el caso de ser
345                          * del mismo tama#o se desbalancea. Hay que ver que efecto 
346                          * puede tener en el caso de claves de long. variable
347                          */
348                         if (it == node_keys.end ())
349                                 total_size -= datait->Size ();
350                 }
351
352                 it = node_keys.begin ();
353                 uint used = 0;
354                 while (used < total_size/2) {
355                         BTreeData *d = (*it);
356                         old_node_keys.push_back (d);
357                         used += d->Size ();
358                         it++;
359                 }
360                 kout = (*it)->getClave (); // Esta se retorna al "padre" para que se la agregue
361
362                 new_node_keys.push_back ( new BTreeChildData ((*it)->getChild ()));
363                 it++;
364                 while (it != node_keys.end ()) {
365                         BTreeData *d = (*it);
366                         new_node_keys.push_back (d);
367                         it++;
368                 }
369         
370                 /* Guardo */
371                 WriteKeys (node, node_header, old_node_keys);
372                 WriteNodoHeader (node, &node_header);
373                 WriteBlock (node, node_num);
374                 WriteKeys (new_node, new_node_header, new_node_keys);
375                 WriteNodoHeader (new_node, &new_node_header);
376                 WriteBlock (new_node, new_node_num);
377                 DeleteKeys (old_node_keys);
378                 DeleteKeys (new_node_keys);
379
380                 PrintNode (node_num);
381                 PrintNode (new_node_num);
382
383                 /* Paso los hijos */
384                 left_child = node_num;
385                 right_child = new_node_num;
386                 delete [] new_node;
387                 delete [] node;
388         }
389
390         return kout;
391 }
392
393 void BTree::DelKey (const Clave &k) {}
394
395 void BTree::ReadNodoHeader (uchar *node, BTreeNodeHeader *header)
396 {
397         memcpy (header, node, sizeof (BTreeNodeHeader));
398 }
399
400 void BTree::WriteNodoHeader (uchar *node, BTreeNodeHeader *header)
401 {
402         memcpy (node, header, sizeof (BTreeNodeHeader));
403 }
404
405 uchar *BTree::ReadBlock (uint num)
406 {
407         uchar *out = new uchar[header.block_size];
408
409         fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET); 
410         fread (out, 1, header.block_size, fp);
411
412         return out;
413 }
414
415 std::list<BTreeData *> BTree::ReadKeys (uchar *node, BTreeNodeHeader &node_header)
416 {
417         std::list<BTreeData *> keys;
418         node += sizeof (BTreeNodeHeader);
419         uint count = node_header.item_count;
420
421         if (node_header.item_count == 0) return keys;
422
423         if (node_header.level != 0) {
424                 /* Si no es una hoja, lo primero que tengo es un BTreeChildData */
425                 BTreeChildData *d = new BTreeChildData (node);
426                 node += d->Size ();
427                 keys.push_back (d);
428                 count--;
429         }
430
431         for (uint i=0; i<count; i++) {
432                 /* TODO : El tipo de clave deberia ser usado 
433                  * dependiendo de algun dato en el header del
434                  * arbol
435                  */
436                 /* TODO : Detectar si estoy en una hoja */
437                 BTreeData *data;
438                 if (node_header.level == 0) {
439                         data = new BTreeLeafData (node, key_type);
440                 } else {
441                         data = new BTreeData (node, key_type);
442                 }
443                 node += data->Size ();
444                 keys.push_back (data);
445         }
446
447         return keys;
448 }
449
450 void BTree::WriteKeys (uchar *node, BTreeNodeHeader &node_header, std::list<BTreeData *> &keys)
451 {
452         std::list<BTreeData *>::iterator it = keys.begin ();
453
454         node += sizeof (BTreeNodeHeader);
455
456         node_header.item_count = 0;
457         node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
458
459         while (it != keys.end ()) {
460                 BTreeData *d = (*it);
461                 uchar *n = d->ToArray ();
462                 memcpy (node, n, d->Size ());
463                 delete [] n;
464                 node += d->Size ();
465                 node_header.free_space -= d->Size ();
466                 node_header.item_count++;
467                 it++;
468         }
469
470         /* TODO : incrementar node_header.item_count aca o fuera de este metodo? */
471 }
472                 
473 void BTree::PrintNode (uint num)
474 {
475         uchar *node = ReadBlock (num);
476         BTreeNodeHeader node_header;
477         ReadNodoHeader (node, &node_header);
478                 
479         std::list<BTreeData *> node_keys = ReadKeys (node, node_header);
480         std::list<BTreeData *>::iterator it = node_keys.begin ();
481
482         std::cout << "Nodo  : " << num << std::endl;
483         std::cout << "Level : " << node_header.level << std::endl;
484         std::cout << "Items : " << node_header.item_count << std::endl;
485         std::cout << "Free  : " << node_header.free_space << " (" << (header.block_size - sizeof (BTreeNodeHeader)) << ")" << std::endl;
486         while (it != node_keys.end ()) {
487                 std::string s = *(*it);
488                 std::cout << s << " "; 
489                 it++;
490         }
491         std::cout << std::endl;
492
493         delete [] node;
494         DeleteKeys (node_keys);
495 }
496
497 uchar *BTree::NewBlock (uint &num)
498 {
499         long filelen;
500         uchar *node;
501         BTreeNodeHeader nh;
502
503         fseek (fp, 0, SEEK_END);
504         filelen = ftell (fp);
505
506         num = (filelen - sizeof (BTreeFileHeader))/header.block_size;
507
508         node = new uchar[header.block_size];
509         ReadNodoHeader (node, &nh);
510         nh.level = 0;
511         nh.free_space = header.block_size - sizeof (BTreeNodeHeader);
512         nh.item_count = 0;
513         WriteNodoHeader (node, &nh);
514         WriteBlock (node, num);
515
516         return node;
517 }
518
519 bool BTree::FindKey (const Clave &k)
520 {
521         return FindKeyR (&k, 0);
522 }
523
524 bool BTree::FindKeyR (const Clave *k, uint node_num)
525 {
526         std::list<BTreeData *> node_keys;
527         BTreeNodeHeader node_header;
528
529         /* Leo el nodo raiz para empezar a agregar */
530         uchar *node = ReadBlock (node_num);
531         ReadNodoHeader (node, &node_header);
532         node_keys = ReadKeys (node, node_header);
533
534         std::list<BTreeData *>::iterator it = node_keys.begin ();
535         std::list<BTreeData *>::iterator posterior;
536         std::list<BTreeData *>::iterator ultima;
537         
538         /* Se supone que la primera es un hijo :) */
539         BTreeData *lchild;
540         if (node_header.level != 0) {
541                 lchild = (*it++);
542         }
543         posterior = it;
544
545         BTreeData *data;
546         if (node_header.level == 0)
547                 data = new BTreeLeafData ((Clave *)k);
548         else
549                 data = new BTreeData ((Clave *)k, 0);
550
551         while (it != node_keys.end ()) {
552                 if ((*data) == (*(*it))) {
553                         /* La encontre!, retorno */
554                         delete [] node;
555                         DeleteKeys (node_keys);
556                         return true;
557                 }
558
559                 if ((*data) < (*(*it)))
560                         break;
561                 ultima = it;
562                 it++;
563         }
564
565         /* TODO: Aca faltaria liberar memoria */
566         if (it == posterior)
567                 return FindKeyR (k, lchild->getChild ());
568                 
569         return FindKeyR (k, (*ultima)->getChild ());
570 }
571
572 void BTree::DeleteKeys (std::list<BTreeData *> &keys)
573 {
574         std::list<BTreeData *>::iterator it = keys.begin ();
575
576         while (it != keys.end ()) {
577                 BTreeData *d = (*it);
578                 delete d;
579                 it++;
580         }
581 }
582