4 BTree::BTree (const std::string &name, unsigned int block_size, bool create_new_file)
9 fp = fopen (name.c_str(), "wb+");
11 /* TODO : mandar una exception ? */
15 /* Nombre de archivo */
18 /* Inicializo el header */
19 header.block_size = block_size;
22 /* Creo el primer bloque vacio */
23 node = new uchar[block_size];
24 ReadNodoHeader (node, &nh);
26 nh.free_space = block_size - sizeof (BTreeNodeHeader);
28 WriteNodoHeader (node, &nh);
39 void BTree::WriteFileHeader ()
41 fseek (fp, 0L, SEEK_SET);
42 fwrite (&header, 1, sizeof (BTreeFileHeader), fp);
45 void BTree::WriteBlock (uchar *block, uint num)
47 fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET);
48 fwrite (block, 1, header.block_size, fp);
51 void BTree::AddKey (const Clave &k)
54 Clave *kout = AddKeyR (&k, 0, left, right);
58 /* Debo dejar la raiz en el nodo 0, por lo que paso el nodo
59 * que esta usando el hijo izquierdo a un nuevo nodo */
60 std::list<BTreeData *> node_keys;
61 BTreeNodeHeader node_header;
62 uchar *node = ReadBlock (left);
63 ReadNodoHeader (node, &node_header);
64 node_keys = ReadKeys (node, node_header);
65 level = node_header.level + 1;
67 uchar *new_node = NewBlock (left);
68 delete [] new_node; /* No me interesa, voy a usar lo leio antes */
70 WriteKeys (node, node_header, node_keys);
71 WriteNodoHeader (node, &node_header);
72 WriteBlock (node, left);
75 /* Leo y actualizo la Raiz */
77 ReadNodoHeader (node, &node_header);
78 node_keys = std::list<BTreeData *>();
80 node_keys.push_back (new BTreeChildData (left));
81 node_keys.push_back (new BTreeData (kout, right));
83 node_header.level = level;
84 node_header.item_count = 1;
86 WriteKeys (node, node_header, node_keys);
87 WriteNodoHeader (node, &node_header);
93 Clave* BTree::AddKeyR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
95 uchar *node = ReadBlock (node_num);
96 BTreeNodeHeader node_header;
97 ReadNodoHeader (node, &node_header);
100 if (node_header.level == 0)
101 return AddKeyLeafR (k, node_num, left_child, right_child);
103 return AddKeyOtherR (k, node_num, left_child, right_child);
106 Clave* BTree::AddKeyLeafR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
109 std::list<BTreeData *> node_keys;
111 BTreeData *data = new BTreeLeafData (k->Clone ());
113 /* Leo el nodo raiz para empezar a agregar */
114 uchar *node = ReadBlock (node_num);
115 BTreeNodeHeader node_header;
116 ReadNodoHeader (node, &node_header);
118 if (node_header.free_space > data->Size ()) {
120 node_keys = ReadKeys (node, node_header);
121 std::list<BTreeData *>::iterator it = node_keys.begin ();
123 while (it != node_keys.end ()) {
125 if ((*data) < (*datait))
126 /* Me pase, lo agrego aca! */
130 node_keys.insert (it, data);
131 WriteKeys (node, node_header, node_keys);
132 WriteNodoHeader (node, &node_header);
133 WriteBlock (node, node_num);
135 PrintNode (node_num);
137 /* Split : Creo e inicializo el nuevo nodo */
138 std::list<BTreeData *> new_node_keys;
139 std::list<BTreeData *> old_node_keys;
140 BTreeNodeHeader new_node_header;
142 uchar *new_node = NewBlock (new_node_num);
143 ReadNodoHeader (new_node, &new_node_header);
144 new_node_header.level = node_header.level;
146 node_keys = ReadKeys (node, node_header);
147 new_node_keys = ReadKeys (new_node, new_node_header);
149 /* Agrego la clave en la lista que ya tengo de manera ordenada */
150 std::list<BTreeData *>::iterator it = node_keys.begin ();
151 std::list<BTreeData *>::iterator previt = node_keys.begin ();
153 while (it != node_keys.end ()) {
156 if ((*data) < (*datait))
157 /* Me pase, lo agrego aca! */
162 if (it != node_keys.end ())
163 node_keys.insert (it, data);
165 node_keys.push_back (data);
167 /* Tengo que guardar claves hasta ocupar nodo size/2 en cada nodo
168 * y subir la clave del medio */
169 node_header.item_count = 0;
170 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
173 it = node_keys.begin ();
174 while (it != node_keys.end ()) {
177 total_size += datait->Size ();
179 /* Hack : Si me quedo con todas las claves, en el caso de ser
180 * del mismo tama#o se desbalancea. Hay que ver que efecto
181 * puede tener en el caso de claves de long. variable
183 if (it == node_keys.end ())
184 total_size -= datait->Size ();
187 it = node_keys.begin ();
189 while (used < total_size/2) {
190 BTreeData *d = (*it);
191 old_node_keys.push_back (d);
195 kout = (*it++)->getClave (); // Esta se retorna al "padre" para que se la agregue
197 while (it != node_keys.end ()) {
198 BTreeData *d = (*it);
199 new_node_keys.push_back (d);
204 WriteKeys (node, node_header, old_node_keys);
205 WriteNodoHeader (node, &node_header);
206 WriteBlock (node, node_num);
207 WriteKeys (new_node, new_node_header, new_node_keys);
208 WriteNodoHeader (new_node, &new_node_header);
209 WriteBlock (new_node, new_node_num);
211 PrintNode (node_num);
212 PrintNode (new_node_num);
215 left_child = node_num;
216 right_child = new_node_num;
224 Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uint &right_child)
227 std::list<BTreeData *> node_keys;
229 BTreeData *data = new BTreeLeafData (k->Clone ());
231 /* Leo el nodo raiz para empezar a agregar */
232 uchar *node = ReadBlock (node_num);
233 BTreeNodeHeader node_header;
234 ReadNodoHeader (node, &node_header);
236 node_keys = ReadKeys (node, node_header);
238 std::list<BTreeData *>::iterator it = node_keys.begin ();
239 std::list<BTreeData *>::iterator posterior;
240 std::list<BTreeData *>::iterator ultima;
242 /* Se supone que la primera es un hijo :) */
243 BTreeData *lchild = (*it++);
246 while (it != node_keys.end ()) {
247 if ((*data) < (*(*it)))
253 if (it == posterior) {
254 k = AddKeyR (k, lchild->getChild (), left_child, right_child);
256 k = AddKeyR (k, (*ultima)->getChild (), left_child, right_child);
262 data = new BTreeData (k->Clone (), right_child);
264 if (node_header.free_space > data->Size ()) {
266 node_keys = ReadKeys (node, node_header);
267 std::list<BTreeData *>::iterator it = node_keys.begin ();
269 while (it != node_keys.end ()) {
271 if ((*data) < (*datait))
272 /* Me pase, lo agrego aca! */
276 node_keys.insert (it, data);
277 WriteKeys (node, node_header, node_keys);
278 WriteNodoHeader (node, &node_header);
279 WriteBlock (node, node_num);
281 PrintNode (node_num);
283 /* Split : Creo e inicializo el nuevo nodo */
284 std::list<BTreeData *> new_node_keys;
285 std::list<BTreeData *> old_node_keys;
286 BTreeNodeHeader new_node_header;
288 uchar *new_node = NewBlock (new_node_num);
289 ReadNodoHeader (new_node, &new_node_header);
290 new_node_header.level = node_header.level;
292 node_keys = ReadKeys (node, node_header);
293 new_node_keys = ReadKeys (new_node, new_node_header);
295 /* Agrego la clave en la lista que ya tengo de manera ordenada */
296 std::list<BTreeData *>::iterator it = node_keys.begin ();
297 std::list<BTreeData *>::iterator previt = node_keys.begin ();
301 while (it != node_keys.end ()) {
304 if ((*data) < (*datait))
305 /* Me pase, lo agrego aca! */
310 if (it != node_keys.end ())
311 node_keys.insert (it, data);
313 node_keys.push_back (data);
315 /* Tengo que guardar claves hasta ocupar nodo size/2 en cada nodo
316 * y subir la clave del medio */
317 node_header.item_count = 0;
318 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
321 it = node_keys.begin ();
322 while (it != node_keys.end ()) {
325 total_size += datait->Size ();
327 /* Hack : Si me quedo con todas las claves, en el caso de ser
328 * del mismo tama#o se desbalancea. Hay que ver que efecto
329 * puede tener en el caso de claves de long. variable
331 if (it == node_keys.end ())
332 total_size -= datait->Size ();
335 it = node_keys.begin ();
337 while (used < total_size/2) {
338 BTreeData *d = (*it);
339 old_node_keys.push_back (d);
343 kout = (*it)->getClave (); // Esta se retorna al "padre" para que se la agregue
345 new_node_keys.push_back ( new BTreeChildData ((*it)->getChild ()));
347 while (it != node_keys.end ()) {
348 BTreeData *d = (*it);
349 new_node_keys.push_back (d);
354 WriteKeys (node, node_header, old_node_keys);
355 WriteNodoHeader (node, &node_header);
356 WriteBlock (node, node_num);
357 WriteKeys (new_node, new_node_header, new_node_keys);
358 WriteNodoHeader (new_node, &new_node_header);
359 WriteBlock (new_node, new_node_num);
361 PrintNode (node_num);
362 PrintNode (new_node_num);
365 left_child = node_num;
366 right_child = new_node_num;
374 void BTree::DelKey (const Clave &k) {}
376 void BTree::ReadNodoHeader (uchar *node, BTreeNodeHeader *header)
378 memcpy (header, node, sizeof (BTreeNodeHeader));
381 void BTree::WriteNodoHeader (uchar *node, BTreeNodeHeader *header)
383 memcpy (node, header, sizeof (BTreeNodeHeader));
386 uchar *BTree::ReadBlock (uint num)
388 uchar *out = new uchar[header.block_size];
390 fseek (fp, num*header.block_size + sizeof (BTreeFileHeader), SEEK_SET);
391 fread (out, 1, header.block_size, fp);
396 std::list<BTreeData *> BTree::ReadKeys (uchar *node, BTreeNodeHeader &node_header)
398 std::list<BTreeData *> keys;
399 node += sizeof (BTreeNodeHeader);
400 uint count = node_header.item_count;
402 if (node_header.item_count == 0) return keys;
404 if (node_header.level != 0) {
405 /* Si no es una hoja, lo primero que tengo es un BTreeChildData */
406 BTreeChildData *d = new BTreeChildData (node);
412 for (uint i=0; i<count; i++) {
413 /* TODO : El tipo de clave deberia ser usado
414 * dependiendo de algun dato en el header del
417 /* TODO : Detectar si estoy en una hoja */
419 if (node_header.level == 0) {
420 data = new BTreeLeafData (node);
422 data = new BTreeData (node);
424 node += data->Size ();
425 keys.push_back (data);
431 void BTree::WriteKeys (uchar *node, BTreeNodeHeader &node_header, std::list<BTreeData *> &keys)
433 std::list<BTreeData *>::iterator it = keys.begin ();
435 node += sizeof (BTreeNodeHeader);
437 node_header.item_count = 0;
438 node_header.free_space = header.block_size - sizeof (BTreeNodeHeader);
440 while (it != keys.end ()) {
441 BTreeData *d = (*it);
442 memcpy (node, d->ToArray(), d->Size ());
444 node_header.free_space -= d->Size ();
445 node_header.item_count++;
449 /* TODO : incrementar node_header.item_count aca o fuera de este metodo? */
452 void BTree::PrintNode (uint num)
454 uchar *node = ReadBlock (num);
455 BTreeNodeHeader node_header;
456 ReadNodoHeader (node, &node_header);
458 std::list<BTreeData *> node_keys = ReadKeys (node, node_header);
459 std::list<BTreeData *>::iterator it = node_keys.begin ();
461 std::cout << "Nodo : " << num << std::endl;
462 std::cout << "Level : " << node_header.level << std::endl;
463 std::cout << "Items : " << node_header.item_count << std::endl;
464 std::cout << "Free : " << node_header.free_space << " (" << (header.block_size - sizeof (BTreeNodeHeader)) << ")" << std::endl;
465 while (it != node_keys.end ()) {
466 std::string s = *(*it);
467 std::cout << s << " ";
470 std::cout << std::endl;
475 uchar *BTree::NewBlock (uint &num)
481 fseek (fp, 0, SEEK_END);
482 filelen = ftell (fp);
484 num = (filelen - sizeof (BTreeFileHeader))/header.block_size;
486 node = new uchar[header.block_size];
487 ReadNodoHeader (node, &nh);
489 nh.free_space = header.block_size - sizeof (BTreeNodeHeader);
491 WriteNodoHeader (node, &nh);
492 WriteBlock (node, num);