// http://www.cs.msstate.edu/~cs2314/global/BTreeAnimation/algorithm.html
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "btree.h"
#include "inode.h"
#include "assert.h"
bTree::bTree(ubixfsInode * inode) : root(NULL) {
if (inode == NULL) return;
root = (bNode *)malloc(sizeof(bNode));
if (root == NULL) return;
memset(root, 0, sizeof(bNode));
root->magic1 = B_NODE_MAGIC_1;
root->magic2 = B_NODE_MAGIC_2;
root->used = 1;
root->parent = NULL;
root->leafNode = true;
root->childCount[1] = 1;
strncpy(root->keys[0], inode->name, B_MAX_NAME_LENGTH);
// insert pointer to data page to the right of the data
root->childHead[1] = (void *)inode;
root->childTail[1] = (void *)inode;
root->present[1] = true;
if (inode != NULL) {
inode->next = inode->prev = NULL;
} // if
return;
} // bTree:bTree
bool
bTree::Insert(ubixfsInode * inode) {
bNode * bnode = root;
ubixfsInode * tmpInode = NULL;
unsigned int curSlot = 0;
if (bnode == NULL || inode == NULL) return false;
/*
* Find the leaf node the inode goes into
*/
assert(bnode->used);
while (bnode != NULL && !bnode->leafNode) {
if (strcmp(inode->name, bnode->keys[0] < 0))
bnode = (bNode *)bnode->childHead[0];
else
if (strcmp(inode->name, bnode->keys[bnode->used-1]) >= 0)
bnode = (bNode *)bnode->childHead[bnode->used];
else {
for (unsigned int i = 1; i < bnode->used; i++) {
if (strcmp(inode->name, bnode->keys[i]) < 0) {
bnode = (bNode *)bnode->childHead[i];
break;
} // if
} // for i
} // else
} // while
/*
*
*/
if (strcmp(inode->name, bnode->keys[curSlot = 0]) < 0)
tmpInode = (ubixfsInode *)bnode->childHead[curSlot];
else
if (strcmp(inode->name, bnode->keys[(curSlot = bnode->used)-1]) >= 0)
tmpInode = (ubixfsInode *)bnode->childHead[bnode->used];
else {
for (curSlot = 1; curSlot < bnode->used; curSlot++) {
if (strcmp(inode->name, bnode->keys[curSlot] < 0)) {
tmpInode = (ubixfsInode *)bnode->childHead[curSlot];
break;
} // if
} // for curSlot
} // else
if (tmpInode == NULL) {
/*
* This is the first node in this leaf
*/
bnode->childHead[curSlot] = bnode->childTail[curSlot] = inode;
bnode->present[curSlot] = true;
if (curSlot == 0) {
if (bnode->childHead[1] != NULL) {
ubixfsInode * iptr = (ubixfsInode *)bnode->childHead[1];
inode->prev = iptr->prev;
inode->next = iptr;
iptr->prev = inode;
if (inode->prev != NULL) inode->prev->next = inode;
} else {
inode->next = inode->prev = NULL;
} // else
} else {
++bnode->used;
}
} else {
/*
* Add node to leaf page. Scan through to find where it goes.
*/
if (strcmp(inode->name, ((ubixfsInode *)bnode->childHead[curSlot])->name) < 0)
{
inode->next = (ubixfsInode *)bnode->childHead[curSlot];
inode->prev = inode->next->prev;
inode->next->prev = inode;
if (inode->prev != NULL) inode->prev->next = inode;
bnode->childHead[curSlot] = (void *)inode;
} else
if (strcmp(inode->name, ((ubixfsInode *)bnode->childTail[curSlot])->name) > 0) {
inode->prev = (ubixfsInode *)bnode->childTail[curSlot];
inode->next = inode->prev->next;
inode->prev->next = inode;
if (inode->next != NULL) inode->next->prev = inode;
bnode->childTail[curSlot] = inode;
} else {
ubixfsInode * tmpInode = (ubixfsInode *)bnode->childHead[curSlot];
for (unsigned int i = 1; i < bnode->childCount[curSlot]; i++) {
// cout << "strcmp(" << inode->name << ", " << tmpInode->name << ") == " <<
// strcmp(inode->name, tmpInode->name) << endl;
if (strcmp(inode->name, tmpInode->name) < 0) {
inode->next = tmpInode;
inode->prev = tmpInode->prev;
inode->next->prev = inode;
inode->prev->next = inode;
break;
} // if
tmpInode = tmpInode->next;
} // for i
} // else
} // else
if (++bnode->childCount[curSlot] == B_MAX_CHILD_COUNT) {
cout << "slot[" << curSlot << "] is full" << endl;
cout << "slot[" << curSlot+1 << "]->childCount is: " << bnode->childCount[curSlot+1] << endl;
cout << "---- before split ----" << endl;
Info();
if (curSlot != bnode->used) {
int shift = bnode->used - curSlot;
memmove(&bnode->childHead[curSlot+1],
&bnode->childHead[curSlot],
sizeof(bnode->childHead[0]) * shift);
memmove(&bnode->childTail[curSlot+1],
&bnode->childTail[curSlot],
sizeof(bnode->childTail[0]) * shift);
memmove(&bnode->present[curSlot+1],
&bnode->present[curSlot],
sizeof(bnode->present[0]) * shift);
memmove(&bnode->childCount[curSlot+1],
&bnode->childCount[curSlot],
sizeof(bnode->childCount[0]) * shift);
memmove(&bnode->keys[curSlot+1],
&bnode->keys[curSlot],
sizeof(bnode->keys[0]) * shift);
memset(bnode->keys[curSlot], 0, B_MAX_NAME_LENGTH);
} else {
bnode->childHead[curSlot+1] = bnode->childHead[curSlot];
bnode->childTail[curSlot+1] = bnode->childTail[curSlot];
bnode->childCount[curSlot+1] = bnode->childCount[curSlot];
bnode->present[curSlot+1] = bnode->present[curSlot];
} // else
ubixfsInode * tmpInode = (ubixfsInode *)bnode->childHead[curSlot];
assert(tmpInode);
for (unsigned int i = 0; i < (B_MAX_CHILD_COUNT+1) >> 1; i++) {
tmpInode = tmpInode->next;
} // for i
strncpy(bnode->keys[curSlot], tmpInode->name, B_MAX_NAME_LENGTH);
bnode->childHead[curSlot+1] = (void *)tmpInode;
bnode->childTail[curSlot] = (void *)tmpInode->prev;
bnode->childCount[curSlot] = (B_MAX_CHILD_COUNT+1) >> 1;
bnode->childCount[curSlot+1] -= bnode->childCount[curSlot];
bnode->present[curSlot] = true;
++bnode->used;
cout << "--- After split ---" << endl;
Info();
} // if leaf is full
#if 0
if (strcmp(inode->name, bnode->key[0]) < 0) {
if (bnode->leafNode) {
}
} else {
if (strcmp(inode->name, bnode->key[bnode->used]) >= 0) {
} else {
}
} // else
if (bnode->leafNode) {
if
for (unsigned int i = 0; i
} else {
} // else
/*
* first search to see if the key we're looking for already exists
* This may not be necessary, since if you've already allocated an
* i-node you might have looked first. But, we'll leave it in as a sanity
* check
*/
assert(bnode->used);
restart:
for (unsigned int i = 0; i <= tmpNode->used; i++) {
if (i == tmpNode->used) goto skipCheck;
cout << "checking " << inode->name << " against " << tmpNode->keys[i];
result = strcmp(inode->name, tmpNode->keys[i]);
cout << " result: " << result << endl;
if (result < 0) {
// our key is less than this key. Walk left
skipCheck:
// if we're in leaf nodes, just add it to the data page in the right
// place
if (tmpNode->leafNode) {
ubixfsInode * tmpInode = (ubixfsInode *)tmpNode->childHead[i];
// is this the first node in this data page?
if (tmpInode == NULL) {
if (i > 0)
inode->prev = (ubixfsInode *)tmpNode->childTail[i-1];
else
inode->prev = NULL;
if (i < B_MAX_KEYS)
inode->next = (ubixfsInode *)tmpNode->childHead[i+1];
else
inode->next = NULL;
tmpNode->childHead[i] = tmpNode->childTail[i] = inode;
if (i != 0) ++tmpNode->used;
} else {
cout << "CC[" << i << "]: " << tmpNode->childCount[i] << endl;
for (unsigned int j = 0; j <= tmpNode->childCount[i]; j++) {
if (j == tmpNode->childCount[i]) {
assert(tmpInode);
assert(inode);
inode->prev = tmpInode;
inode->next = tmpInode->next;
tmpInode->next = inode;
// if (inode->next != NULL) inode->next->prev = inode;
tmpNode->childTail[i] = inode;
break;
} // if
assert(inode);
assert(tmpInode);
cout << inode->name << endl;
cout << tmpInode->name << endl;
if (strcmp(inode->name, tmpInode->name) < 0) {
inode->next = tmpInode;
inode->prev = tmpInode->prev;
tmpInode->prev = inode;
if (j == 0) tmpNode->childHead[i] = inode;
break;
} // if
cout << "here2" << endl;
tmpInode = tmpInode->next;
cout << "here3" << endl;
} // for j
} // else
assert(inode);
if (inode->prev != NULL) inode->prev->next = inode;
if (inode->next != NULL) inode->next->prev = inode;
if (++tmpNode->childCount[i] == B_MAX_CHILD_COUNT) {
ubixfsInode * tmpInode = (ubixfsInode *)tmpNode->childHead[i];
assert(tmpInode);
for (int k = 0; k < ((B_MAX_CHILD_COUNT+1) >> 1); k++) {
tmpInode = (ubixfsInode *)tmpInode->next;
} // for k
cout << "page is full. splitting. using: " << tmpInode->name << endl;
if (tmpNode->childHead[0] == NULL) {
Print();
cout << "rotating left" << endl;
cout << "replacing " << tmpNode->keys[0] << " with " << tmpInode->name << endl;
memset(tmpNode->keys[0], 0, B_MAX_NAME_LENGTH);
strncpy(tmpNode->keys[0], tmpInode->name, B_MAX_NAME_LENGTH);
tmpNode->childHead[0] = tmpNode->childHead[1];
tmpNode->childTail[0] = (void *)tmpInode->prev;
tmpNode->childHead[1] = (void *)tmpInode;
cout << "CC[0]: " << (int)tmpNode->childCount[0] << endl;
cout << "CC[1]: " << (int)tmpNode->childCount[1] << endl;
tmpNode->childCount[0] = (B_MAX_CHILD_COUNT+1) >> 1;
tmpNode->childCount[1] -= tmpNode->childCount[i];
tmpNode->present[0] = true;
cout << "CC[0]: " << (int)tmpNode->childCount[0] << endl;
cout << "CC[1]: " << (int)tmpNode->childCount[1] << endl;
Print();
return true;
}
if (i != tmpNode->used) {
// if we're the last node, don't move things over
// shift denotes how many items to move over
int shift = tmpNode->used - i;
cout << "shift: " << shift << endl;
memmove(&tmpNode->childHead[i+1],
&tmpNode->childHead[i],
sizeof(tmpNode->childHead[0]) * shift);
memmove(&tmpNode->childTail[i+1],
&tmpNode->childTail[i],
sizeof(tmpNode->childTail[0]) * shift);
memmove(&tmpNode->present[i+1],
&tmpNode->present[i],
sizeof(tmpNode->present[0]) * shift);
memmove(&tmpNode->childCount[i+1],
&tmpNode->childCount[i],
sizeof(tmpNode->childCount[0]) * shift);
memmove(&tmpNode->keys[i+1],
&tmpNode->keys[i],
sizeof(tmpNode->keys[0]) * shift);
memset(tmpNode->keys[i], 0, B_MAX_NAME_LENGTH);
} else {
tmpNode->childHead[i+1] = tmpNode->childHead[i];
tmpNode->childTail[i+1] = tmpNode->childTail[i];
tmpNode->childCount[i+1] = tmpNode->childCount[i];
tmpNode->present[i+1] = tmpNode->present[i];
}
strncpy(tmpNode->keys[i], tmpInode->name, B_MAX_NAME_LENGTH);
tmpNode->childHead[i+1] = (void *)tmpInode;
tmpNode->childTail[i] = (void *)tmpInode->prev;
tmpNode->childCount[i] = (B_MAX_CHILD_COUNT+1) >> 1;
tmpNode->childCount[i+1] -= tmpNode->childCount[i];
tmpNode->present[i] = true;
++tmpNode->used;
} // if
return true;
} else {
tmpNode = (bNode *)tmpNode->childHead[i];
goto restart;
} // else !leafNode
} // if result < 0
} // for i
#endif
return true;
} // bTree::Insert
void
bTree::Info(void) {
ubixfsInode * inode = NULL;
if (root == NULL) return;
cout << "root->used: " << root->used << endl;
for (unsigned int i = 0; i <= root->used; i++) {
inode = (ubixfsInode *)root->childHead[i];
for (unsigned int j = 0; j < root->childCount[i]; j++) {
assert(inode);
cout << "[" << i << "].[" << j << "]->" << inode->name << endl;
inode = inode->next;
} // for j
} // for i
} // bTree::Info
void
bTree::Print(void) {
ubixfsInode * node = GetFirstNode();
while (node != NULL) {
cout << node->name << endl;
node = node->next;
}
} // bTree::Print
ubixfsInode *
bTree::Find(const char * key) {
return treeSearch(root, key);
} // bTree::Find
ubixfsInode *
bTree::inodeSearch(ubixfsInode * inode, const char * key) {
if (inode == NULL || key == NULL) return NULL;
int result = strcmp(inode->name, key);
if (result == 0) return inode;
if (result < 0) {
inode = inode->next;
while (inode != NULL && (result = strcmp(inode->name, key) >= 0)) {
inode = inode->next;
} // while
} else {
inode = inode->prev;
while (inode != NULL && (result = strcmp(inode->name, key) <= 0)) {
inode = inode->prev;
} // while
} // else
return (result == 0 ? inode : NULL);
} // bTree::inodeSearch
ubixfsInode *
bTree::treeSearch(bNode * bnode, const char * key) {
if (bnode == NULL || key == NULL) return NULL;
if (bnode->used == 0) return NULL;
if (bnode->leafNode)
if (bnode->childHead[0] != NULL)
return inodeSearch((ubixfsInode *)bnode->childHead[0], key);
else
return inodeSearch((ubixfsInode *)bnode->childHead[1], key);
cout << "key: " << key << " keys[0]: " << bnode->keys[0] << " result: " << strcmp(key, bnode->keys[0]) << endl;
if (strcmp(key, bnode->keys[0]) < 0)
return treeSearch((bNode *)bnode->childHead[0], key);
if (strcmp(key, bnode->keys[bnode->used-1]) >= 0)
return treeSearch((bNode *)bnode->childHead[bnode->used], key);
for (unsigned int i = 1; i < bnode->used; i++) {
if (strcmp(key, bnode->keys[i]) < 0)
return treeSearch((bNode *)bnode->childHead[i], key);
} // for i
return NULL;
#if 0
restart:
for (unsigned int i = 0; i <= bnode->used; i++) {
// if we're at the end of the list, follow the last link and continue
if (i == bnode->used) {
if (bnode->leafNode) {
inode = (ubixfsInode *)bnode->childHead[i];
goto inodeSearch;
} else {
bnode = (bNode *)bnode->childHead[i];
}
goto restart;
} // if
result = strcmp(key, bnode->keys[i]);
if (result < 0) {
// what we're looking for is somewhere down the left branch
// if we're in leaf nodes we need to scan through the inode list
if (bnode->leafNode) {
inode = (ubixfsInode *)bnode->childHead[i];
inodeSearch:
while (inode != NULL) {
result = strcmp(inode->name, key);
if (result == 0) return inode;
if (result > 0) return NULL;
inode = inode->next;
} // while
return NULL;
} else {
// since we aren't in leaf nodes yet, travel left
bnode = (bNode *)bnode->childHead[i];
goto restart;
} // else
} // if result < 0
} // for
return NULL;
#endif
} // bTree::treeSearch
ubixfsInode *
bTree::GetFirstNode(void) {
bNode * tmpNode = root;
if (tmpNode == NULL) return NULL;
if (root->leafNode) {
if (root->used == 0) return NULL;
if (root->used == 1 && root->childHead[0] == NULL)
return (ubixfsInode *) root->childHead[1];
else
return (ubixfsInode *) root->childHead[0];
} // if
while (!tmpNode->leafNode) tmpNode = (bNode *)tmpNode->childHead[0];
return (ubixfsInode *)tmpNode->childHead[0];
} // bTree::GetFirstNode
bool
bTree::Save(const char * filename) {
if (filename == NULL) return false;
return true;
} // bTree::Save
bool
bTree::Load(const char * filename) {
if (filename == NULL) return false;
return true;
} // bTree::Load
bool
bTree::Delete(const char * key) {
if (key == NULL) return false;
return true;
} // bTree::Delete