4 BTree::BTree (const std::string &name, unsigned int block_size, int kt, bool create_new_file)
10 fp = fopen (name.c_str(), "wb+");
12 /* TODO : mandar una exception ? */
16 /* Nombre de archivo */
19 /* Inicializo el header */
20 header.block_size = block_size;
23 /* Creo el primer bloque vacio */
24 node = new uchar[block_size];
25 ReadNodoHeader (node, &nh);
27 nh.free_space = block_size - sizeof (BTreeNodeHeader);
29 WriteNodoHeader (node, &nh);
40 void BTree::WriteFileHeader ()
42 fseek (fp, 0L, SEEK_SET);
43 fwrite (&header, 1, sizeof (BTreeFileHeader), fp);
46 void BTree::WriteBlock (uchar *block, uint num)
48 fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET);
49 fwrite (block, 1, header.block_size, fp);
52 void BTree::AddKey (const Clave &k)
55 Clave *kout = AddKeyR (&k, 0, left, right);
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;
68 uchar *new_node = NewBlock (left);
69 delete [] new_node; /* No me interesa, voy a usar lo leio antes */
71 WriteKeys (node, node_header, node_keys);
72 WriteNodoHeader (node, &node_header);
73 WriteBlock (node, left);
74 DeleteKeys (node_keys);
77 /* Leo y actualizo la Raiz */
79 ReadNodoHeader (node, &node_header);
80 node_keys = std::list<BTreeData *>();
82 node_keys.push_back (new BTreeChildData (left));
83 node_keys.push_back (new BTreeData (kout, right));
85 node_header.level = level;
86 node_header.item_count = 1;
88 WriteKeys (node, node_header, node_keys);
89 WriteNodoHeader (node, &node_header);
92 DeleteKeys (node_keys);
99 Clave* BTree::AddKeyR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
101 uchar *node = ReadBlock (node_num);
102 BTreeNodeHeader node_header;
103 ReadNodoHeader (node, &node_header);
106 if (node_header.level == 0)
107 return AddKeyLeafR (k, node_num, left_child, right_child);
109 return AddKeyOtherR (k, node_num, left_child, right_child);
112 Clave* BTree::AddKeyLeafR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
115 std::list<BTreeData *> node_keys;
117 BTreeData *data = new BTreeLeafData (k->Clone ());
119 /* Leo el nodo raiz para empezar a agregar */
120 uchar *node = ReadBlock (node_num);
121 BTreeNodeHeader node_header;
122 ReadNodoHeader (node, &node_header);
124 if (node_header.free_space > data->Size ()) {
126 node_keys = ReadKeys (node, node_header);
127 std::list<BTreeData *>::iterator it = node_keys.begin ();
129 while (it != node_keys.end ()) {
131 if ((*data) < (*datait))
132 /* Me pase, lo agrego aca! */
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);
143 PrintNode (node_num);
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;
150 uchar *new_node = NewBlock (new_node_num);
151 ReadNodoHeader (new_node, &new_node_header);
152 new_node_header.level = node_header.level;
154 node_keys = ReadKeys (node, node_header);
155 new_node_keys = ReadKeys (new_node, new_node_header);
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 ();
161 while (it != node_keys.end ()) {
164 if ((*data) < (*datait))
165 /* Me pase, lo agrego aca! */
170 if (it != node_keys.end ())
171 node_keys.insert (it, data);
173 node_keys.push_back (data);
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);
181 it = node_keys.begin ();
182 while (it != node_keys.end ()) {
185 total_size += datait->Size ();
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
191 if (it == node_keys.end ())
192 total_size -= datait->Size ();
195 it = node_keys.begin ();
197 while (used < total_size/2) {
198 BTreeData *d = (*it);
199 old_node_keys.push_back (d);
203 kout = (*it++)->getClave (); // Esta se retorna al "padre" para que se la agregue
205 while (it != node_keys.end ()) {
206 BTreeData *d = (*it);
207 new_node_keys.push_back (d);
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);
221 PrintNode (node_num);
222 PrintNode (new_node_num);
225 left_child = node_num;
226 right_child = new_node_num;
234 Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
237 std::list<BTreeData *> node_keys;
239 BTreeData *data = new BTreeLeafData (k->Clone ());
241 /* Leo el nodo raiz para empezar a agregar */
242 uchar *node = ReadBlock (node_num);
243 BTreeNodeHeader node_header;
244 ReadNodoHeader (node, &node_header);
246 node_keys = ReadKeys (node, node_header);
248 std::list<BTreeData *>::iterator it = node_keys.begin ();
249 std::list<BTreeData *>::iterator posterior;
250 std::list<BTreeData *>::iterator ultima;
252 /* Se supone que la primera es un hijo :) */
253 BTreeData *lchild = (*it++);
256 while (it != node_keys.end ()) {
257 if ((*data) < (*(*it)))
263 if (it == posterior) {
264 k = AddKeyR (k, lchild->getChild (), left_child, right_child);
266 k = AddKeyR (k, (*ultima)->getChild (), left_child, right_child);
268 DeleteKeys (node_keys);
271 if (data) delete data;
277 data = new BTreeData (k->Clone (), right_child);
279 if (node_header.free_space > data->Size ()) {
281 node_keys = ReadKeys (node, node_header);
282 std::list<BTreeData *>::iterator it = node_keys.begin ();
284 while (it != node_keys.end ()) {
286 if ((*data) < (*datait))
287 /* Me pase, lo agrego aca! */
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);
298 PrintNode (node_num);
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;
305 uchar *new_node = NewBlock (new_node_num);
306 ReadNodoHeader (new_node, &new_node_header);
307 new_node_header.level = node_header.level;
309 node_keys = ReadKeys (node, node_header);
310 new_node_keys = ReadKeys (new_node, new_node_header);
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 ();
318 while (it != node_keys.end ()) {
321 if ((*data) < (*datait))
322 /* Me pase, lo agrego aca! */
327 if (it != node_keys.end ())
328 node_keys.insert (it, data);
330 node_keys.push_back (data);
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);
338 it = node_keys.begin ();
339 while (it != node_keys.end ()) {
342 total_size += datait->Size ();
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
348 if (it == node_keys.end ())
349 total_size -= datait->Size ();
352 it = node_keys.begin ();
354 while (used < total_size/2) {
355 BTreeData *d = (*it);
356 old_node_keys.push_back (d);
360 kout = (*it)->getClave (); // Esta se retorna al "padre" para que se la agregue
362 new_node_keys.push_back ( new BTreeChildData ((*it)->getChild ()));
364 while (it != node_keys.end ()) {
365 BTreeData *d = (*it);
366 new_node_keys.push_back (d);
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);
380 PrintNode (node_num);
381 PrintNode (new_node_num);
384 left_child = node_num;
385 right_child = new_node_num;
393 void BTree::DelKey (const Clave &k) {}
395 void BTree::ReadNodoHeader (uchar *node, BTreeNodeHeader *header)
397 memcpy (header, node, sizeof (BTreeNodeHeader));
400 void BTree::WriteNodoHeader (uchar *node, BTreeNodeHeader *header)
402 memcpy (node, header, sizeof (BTreeNodeHeader));
405 uchar *BTree::ReadBlock (uint num)
407 uchar *out = new uchar[header.block_size];
409 fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET);
410 fread (out, 1, header.block_size, fp);
415 std::list<BTreeData *> BTree::ReadKeys (uchar *node, BTreeNodeHeader &node_header)
417 std::list<BTreeData *> keys;
418 node += sizeof (BTreeNodeHeader);
419 uint count = node_header.item_count;
421 if (node_header.item_count == 0) return keys;
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);
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
436 /* TODO : Detectar si estoy en una hoja */
438 if (node_header.level == 0) {
439 data = new BTreeLeafData (node, key_type);
441 data = new BTreeData (node, key_type);
443 node += data->Size ();
444 keys.push_back (data);
450 void BTree::WriteKeys (uchar *node, BTreeNodeHeader &node_header, std::list<BTreeData *> &keys)
452 std::list<BTreeData *>::iterator it = keys.begin ();
454 node += sizeof (BTreeNodeHeader);
456 node_header.item_count = 0;
457 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
459 while (it != keys.end ()) {
460 BTreeData *d = (*it);
461 uchar *n = d->ToArray ();
462 memcpy (node, n, d->Size ());
465 node_header.free_space -= d->Size ();
466 node_header.item_count++;
470 /* TODO : incrementar node_header.item_count aca o fuera de este metodo? */
473 void BTree::PrintNode (uint num)
475 uchar *node = ReadBlock (num);
476 BTreeNodeHeader node_header;
477 ReadNodoHeader (node, &node_header);
479 std::list<BTreeData *> node_keys = ReadKeys (node, node_header);
480 std::list<BTreeData *>::iterator it = node_keys.begin ();
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 << " ";
491 std::cout << std::endl;
494 DeleteKeys (node_keys);
497 uchar *BTree::NewBlock (uint &num)
503 fseek (fp, 0, SEEK_END);
504 filelen = ftell (fp);
506 num = (filelen - sizeof (BTreeFileHeader))/header.block_size;
508 node = new uchar[header.block_size];
509 ReadNodoHeader (node, &nh);
511 nh.free_space = header.block_size - sizeof (BTreeNodeHeader);
513 WriteNodoHeader (node, &nh);
514 WriteBlock (node, num);
519 bool BTree::FindKey (const Clave &k)
521 return FindKeyR (&k, 0);
524 bool BTree::FindKeyR (const Clave *k, uint node_num)
526 std::list<BTreeData *> node_keys;
527 BTreeNodeHeader node_header;
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);
534 std::list<BTreeData *>::iterator it = node_keys.begin ();
535 std::list<BTreeData *>::iterator posterior;
536 std::list<BTreeData *>::iterator ultima;
538 /* Se supone que la primera es un hijo :) */
540 if (node_header.level != 0) {
546 if (node_header.level == 0)
547 data = new BTreeLeafData ((Clave *)k);
549 data = new BTreeData ((Clave *)k, 0);
551 while (it != node_keys.end ()) {
552 if ((*data) == (*(*it))) {
553 /* La encontre!, retorno */
555 DeleteKeys (node_keys);
559 if ((*data) < (*(*it)))
565 /* TODO: Aca faltaria liberar memoria */
567 return FindKeyR (k, lchild->getChild ());
569 return FindKeyR (k, (*ultima)->getChild ());
572 void BTree::DeleteKeys (std::list<BTreeData *> &keys)
574 std::list<BTreeData *>::iterator it = keys.begin ();
576 while (it != keys.end ()) {
577 BTreeData *d = (*it);