// 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